<commit_before>'use strict';

import { assert, expect, should } from 'chai';
import { relations } from '../../src/defaults/processors';
import colors from 'colors';

// -- Mock

describe('ProcessorRelations', () => {

  let state;

  beforeEach( () => state = {sentence: '', nlp: {}})

  it('Up & Running', () => {
    state.sentence = 'hello world';
    const nlp = relations(state).nlp.relations;

    expect(Object.keys(nlp).length).equal(1);
    expect(nlp).to.have.all.keys('object');

    expect(nlp.object).to.have.all.keys('text', 'tag');
    expect(nlp.object.text).equal('world');
    expect(nlp.object.tag).equal('noun');
  });

  it('Analize complex sentences', () => {
    state.sentence = "Ava, Do you know if tomorrow will rain in Bangkok?"
    const nlp = relations(state).nlp.relations;

    expect(nlp).to.have.all.keys('subject', 'action', 'when', 'object', 'location');

    expect(nlp.subject).to.have.all.keys('text', 'tag');
    expect(nlp.subject.text).equal('ava');
    expect(nlp.subject.tag).equal('person');

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.text).equal('will');
    expect(nlp.action.tag).equal('verb');

    expect(nlp.when).to.have.all.keys('text', 'tag');
    // expect(nlp.when.text).equal('Sun Jun 12 2016 12:00:00 GMT+0700 (ICT)');
    expect(nlp.when.tag).equal('date');

    expect(nlp.object).to.have.all.keys('text', 'tag');
    expect(nlp.object.text).equal('rain');
    expect(nlp.object.tag).equal('noun');

    expect(nlp.location).to.have.all.keys('text', 'tag');
    expect(nlp.location.text).equal('bangkok');
    expect(nlp.location.tag).equal('place');
  });

  it('Can detect if action is a past tense', () => {
    state.sentence = "I was there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.tense).equal('past');
  });

  it('Can detect if action is a future tense', () => {
    state.sentence = "I will be there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.tense).equal('future');
  });

  it('Can detect if action is negative', () => {
    state.sentence = "I won't be there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.negative).equal(true);
  });

  it('Can detect dates and parse to JavaScript type', () => {
    state.sentence = "I will be there tomorrow at 2pm"
    const nlp = relations(state).nlp.relations;

    expect(nlp.when.text instanceof Date).equal(true)
  });

});
<commit_msg>Something wrong with lexicons and Compromise 6.2.1<commit_after>'use strict';

import { assert, expect, should } from 'chai';
import { relations } from '../../src/defaults/processors';
import colors from 'colors';

// -- Mock

describe('ProcessorRelations', () => {

  let state;

  beforeEach( () => state = {sentence: '', nlp: {}})

  it('Up & Running', () => {
    state.sentence = 'hello world';
    const nlp = relations(state).nlp.relations;

    expect(Object.keys(nlp).length).equal(1);
    expect(nlp).to.have.all.keys('object');

    expect(nlp.object).to.have.all.keys('text', 'tag');
    expect(nlp.object.text).equal('world');
    expect(nlp.object.tag).equal('noun');
  });

  it('Analize complex sentences', () => {
    state.sentence = "Ava, Do you know if tomorrow will rain in Bangkok?"
    const nlp = relations(state).nlp.relations;

    expect(nlp).to.have.all.keys('subject', 'action', 'when', 'object', 'location');

    expect(nlp.subject).to.have.all.keys('text', 'tag');
    expect(nlp.subject.text).equal('you');
    expect(nlp.subject.tag).equal('pronoun');

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.text).equal('will');
    expect(nlp.action.tag).equal('verb');

    expect(nlp.when).to.have.all.keys('text', 'tag');
    // expect(nlp.when.text).equal('Sun Jun 12 2016 12:00:00 GMT+0700 (ICT)');
    expect(nlp.when.tag).equal('date');

    expect(nlp.object).to.have.all.keys('text', 'tag');
    expect(nlp.object.text).equal('rain');
    expect(nlp.object.tag).equal('noun');

    expect(nlp.location).to.have.all.keys('text', 'tag');
    expect(nlp.location.text).equal('bangkok');
    expect(nlp.location.tag).equal('place');
  });

  it('Can detect if action is a past tense', () => {
    state.sentence = "I was there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.tense).equal('past');
  });

  it('Can detect if action is a future tense', () => {
    state.sentence = "I will be there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.tense).equal('future');
  });

  it('Can detect if action is negative', () => {
    state.sentence = "I won't be there"
    const nlp = relations(state).nlp.relations;

    expect(nlp.action).to.have.all.keys('text', 'tag', 'verb');
    expect(nlp.action.verb.negative).equal(true);
  });

  it('Can detect dates and parse to JavaScript type', () => {
    state.sentence = "I will be there tomorrow at 2pm"
    const nlp = relations(state).nlp.relations;

    expect(nlp.when.text instanceof Date).equal(true)
  });

});
<|endoftext|>


<commit_before>import Component from '@ember/component';
import layout from './template';
import { inject as service } from '@ember/service';
import { computed, get, set } from '@ember/object';
import Semver from 'semver';
import { satisfies } from 'shared/utils/parse-version';
import { sortVersions } from 'shared/utils/sort';
import C from 'shared/utils/constants';
import { alias } from '@ember/object/computed';

export default Component.extend({
  settings:        service(),
  releaseVersions: service(),
  intl:            service(),
  globalStore:     service(),

  layout,

  editing:     false,
  configField: 'k3sConfig',

  supportedK8sVersionRange: alias(`settings.${ C.SETTING.VERSION_K8S_SUPPORTED_RANGE }`),

  config: computed('cluster.{k3sConfig,rke2Config}', 'configField', function() {
    return get(this, `cluster.${ this.configField }`);
  }),

  showAce: computed('cluster.{internal,k3sConfig,rancherKubernetesEngineConfig,rke2Config,rke2config}', function() {
    // Hide on the local cluster
    if ( get(this, 'cluster.internal') ) {
      return false;
    }

    return !!get(this, 'cluster.rancherKubernetesEngineConfig') ||
           !!get(this, 'cluster.k3sConfig') ||
           !!get(this, 'cluster.rke2Config') ||
           false;
  }),

  upgradeStrategy: computed('config.{k3supgradeStrategy,rke2upgradeStrategy}', 'configField', function() {
    const { configField } = this;
    const upgradeStrategyPath = configField === 'k3sConfig' ? 'k3supgradeStrategy' : 'rke2upgradeStrategy';

    return get(this.config, upgradeStrategyPath);
  }),

  serverConcurrency: computed('upgradeStrategy.serverConcurrency', {
    get() {
      return get(this, 'upgradeStrategy.serverConcurrency');
    },

    set(key, value) {
      set(this, 'upgradeStrategy.serverConcurrency', this.coerceToInt(value));

      return value;
    }
  }),

  workerConcurrency: computed('upgradeStrategy.workerConcurrency', {
    get() {
      return get(this, 'upgradeStrategy.workerConcurrency');
    },

    set(key, value) {
      set(this, 'upgradeStrategy.workerConcurrency', this.coerceToInt(value));

      return value;
    }
  }),

  allVersions: computed('releaseVersions.allVersions.[]', 'supportedK8sVersionRange', function() {
    const currentVersion = get(this, `config.kubernetesVersion`);
    const versionsMapped = [];
    let allVersions    = this.releaseVersions.allVersions || [];

    if (!allVersions.includes(currentVersion)) {
      allVersions.unshift(currentVersion);
    }

    allVersions = [...sortVersions(allVersions).reverse()];

    allVersions.forEach((v) => {
      let experimental = false

      if (this.supportedK8sVersionRange) {
        experimental = !satisfies(v, this.supportedK8sVersionRange);
      }

      if (Semver.gte(v, currentVersion)) {
        versionsMapped.pushObject({
          value: v,
          label: `${ v } ${ experimental ? this.intl.t('generic.experimental') : '' }`,
        });
      }
    });

    return versionsMapped;
  }),

  coerceToInt(value) {
    let errors;
    let coerced = value;

    errors = set(this, 'errors', []);

    coerced = parseInt(value, 10);

    if (isNaN(coerced)) {
      errors.push(this.intl.t('managedImportClusterInfo.error.int'));

      set(this, 'errors', errors);

      return value;
    }

    return coerced;
  },

});
<commit_msg>Remove unused globalStore<commit_after>import Component from '@ember/component';
import layout from './template';
import { inject as service } from '@ember/service';
import { computed, get, set } from '@ember/object';
import Semver from 'semver';
import { satisfies } from 'shared/utils/parse-version';
import { sortVersions } from 'shared/utils/sort';
import C from 'shared/utils/constants';
import { alias } from '@ember/object/computed';

export default Component.extend({
  settings:        service(),
  releaseVersions: service(),
  intl:            service(),

  layout,

  editing:     false,
  configField: 'k3sConfig',

  supportedK8sVersionRange: alias(`settings.${ C.SETTING.VERSION_K8S_SUPPORTED_RANGE }`),

  config: computed('cluster.{k3sConfig,rke2Config}', 'configField', function() {
    return get(this, `cluster.${ this.configField }`);
  }),

  showAce: computed('cluster.{internal,k3sConfig,rancherKubernetesEngineConfig,rke2Config,rke2config}', function() {
    // Hide on the local cluster
    if ( get(this, 'cluster.internal') ) {
      return false;
    }

    return !!get(this, 'cluster.rancherKubernetesEngineConfig') ||
           !!get(this, 'cluster.k3sConfig') ||
           !!get(this, 'cluster.rke2Config') ||
           false;
  }),

  upgradeStrategy: computed('config.{k3supgradeStrategy,rke2upgradeStrategy}', 'configField', function() {
    const { configField } = this;
    const upgradeStrategyPath = configField === 'k3sConfig' ? 'k3supgradeStrategy' : 'rke2upgradeStrategy';

    return get(this.config, upgradeStrategyPath);
  }),

  serverConcurrency: computed('upgradeStrategy.serverConcurrency', {
    get() {
      return get(this, 'upgradeStrategy.serverConcurrency');
    },

    set(key, value) {
      set(this, 'upgradeStrategy.serverConcurrency', this.coerceToInt(value));

      return value;
    }
  }),

  workerConcurrency: computed('upgradeStrategy.workerConcurrency', {
    get() {
      return get(this, 'upgradeStrategy.workerConcurrency');
    },

    set(key, value) {
      set(this, 'upgradeStrategy.workerConcurrency', this.coerceToInt(value));

      return value;
    }
  }),

  allVersions: computed('releaseVersions.allVersions.[]', 'supportedK8sVersionRange', function() {
    const currentVersion = get(this, `config.kubernetesVersion`);
    const versionsMapped = [];
    let allVersions    = this.releaseVersions.allVersions || [];

    if (!allVersions.includes(currentVersion)) {
      allVersions.unshift(currentVersion);
    }

    allVersions = [...sortVersions(allVersions).reverse()];

    allVersions.forEach((v) => {
      let experimental = false

      if (this.supportedK8sVersionRange) {
        experimental = !satisfies(v, this.supportedK8sVersionRange);
      }

      if (Semver.gte(v, currentVersion)) {
        versionsMapped.pushObject({
          value: v,
          label: `${ v } ${ experimental ? this.intl.t('generic.experimental') : '' }`,
        });
      }
    });

    return versionsMapped;
  }),

  coerceToInt(value) {
    let errors;
    let coerced = value;

    errors = set(this, 'errors', []);

    coerced = parseInt(value, 10);

    if (isNaN(coerced)) {
      errors.push(this.intl.t('managedImportClusterInfo.error.int'));

      set(this, 'errors', errors);

      return value;
    }

    return coerced;
  },

});
<|endoftext|>


<commit_before>/*! jQuery Navigate plugin - v1.0.1 - 2014-05-02
* https://github.com/jongha/jquery-navigate
* Copyright (c) 2014 Jong-Ha Ahn; Licensed MIT */
!function(a){var b=a.ajaxSettings.xhr;a.ajaxSetup({xhr:function(){var a=b(),c=this;return a&&("function"==typeof a.addEventListener&&void 0!==c.progress&&a.addEventListener("progress",function(a){c.progress(a)},!1),"object"==typeof a.upload&&void 0!==c.progressUpload&&a.upload.addEventListener("progress",function(a){c.progressUpload(a)},!1)),a}})}(jQuery),function(a){a.fn.navigate=function(b){b&&"string"==typeof b&&(b={url:b});var c=a.extend({height:"3px",backgroundColor:"red",min:0,max:100,position:"absolute",top:0,left:0,id:"_navigation_id"},b);b=a.extend(c,b);var d=a("#"+b.id);d.length&&d.remove(),d=a("

").css({height:b.height,"background-color":b.backgroundColor,width:b.min+"%",position:b.position,top:b.top,left:b.left}).attr({id:b.id}),a("body").append(d),a.ajax({url:b.url,data:{},success:function(c){d.animate({width:"100%"},400,function(){a(this).remove(),a("html").html(c),window.history.pushState(b,"Navition to "+b.url,b.url)})},fail:function(){d.remove()},progress:function(a){if(a.lengthComputable)d.animate({width:a.loaded/a.total*100+"%"});else{var b=Math.min(50,a.loaded/204800*100);d.animate({width:b+"%"})}}})}}(jQuery);<commit_msg>Rebuild and commit.<commit_after>/*! jQuery Navigate plugin - v1.0.1 - 2014-05-04
* https://github.com/jongha/jquery-navigate
* Copyright (c) 2014 Jong-Ha Ahn; Licensed MIT */
!function(a){var b=a.ajaxSettings.xhr;a.ajaxSetup({xhr:function(){var a=b(),c=this;return a&&("function"==typeof a.addEventListener&&void 0!==c.progress&&a.addEventListener("progress",function(a){c.progress(a)},!1),"object"==typeof a.upload&&void 0!==c.progressUpload&&a.upload.addEventListener("progress",function(a){c.progressUpload(a)},!1)),a}})}(jQuery),function(a){a.fn.navigate=function(b){b&&"string"==typeof b&&(b={url:b});var c=a.extend({height:"3px",backgroundColor:"red",min:0,max:100,position:"absolute",top:0,left:0,id:"_navigation_id"},b);b=a.extend(c,b);var d=a("#"+b.id);d.length&&d.remove(),d=a("

").css({height:b.height,"background-color":b.backgroundColor,width:b.min+"%",position:b.position,top:b.top,left:b.left}).attr({id:b.id}),a("body").append(d),a.ajax({url:b.url,data:{},success:function(c){d.animate({width:"100%"},400,function(){a(this).remove(),a("html").html(c),window.history.pushState(b,"Navition to "+b.url,b.url)})},fail:function(){d.remove()},progress:function(a){if(a.lengthComputable)d.animate({width:a.loaded/a.total*100+"%"});else{var b=Math.min(50,a.loaded/204800*100);d.animate({width:b+"%"})}}})}}(jQuery);<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief arango datafile debugger
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var console = require("console");
var fs = require("fs");

var printf = internal.printf;

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief remove datafile
////////////////////////////////////////////////////////////////////////////////

function RemoveDatafile (collection, type, datafile) {
  var backup = datafile + ".corrupt";

  fs.move(datafile, backup);

  printf("Removed %s at %s\n", type, datafile);
  printf("Backup is in %s\n", backup);
  printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief wipe entries
////////////////////////////////////////////////////////////////////////////////

function WipeDatafile (collection, type, datafile, lastGoodPos) {
  collection.truncateDatafile(datafile, lastGoodPos);

  printf("Truncated and sealed datafile\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a journal
////////////////////////////////////////////////////////////////////////////////

function DeepCheckJournal (collection, type, datafile, scan, lastGoodPos) {
  var entries = scan.entries;

  if (entries.length == 0) {
    printf("WARNING: The journal is empty. Even the header is missing. Going\n");
    printf("         to remove the datafile.\n");
    printf("\n");

    RemoveDatafile(collection, type, datafile);

    return;
  }

  if (entries.length === lastGoodPos + 3 && entries[lastGoodPos + 2].status === 2) {
    printf("WARNING: The journal was not closed properly, the last entry is corrupted.\n");
    printf("         This might happen ArangoDB was killed and the last entry was not\n");
    printf("         fully written to disk. Going to remove the last entry.\n");
    printf("\n");
  }
  else {
    printf("WARNING: The journal was not closed properly, the last entries is corrupted.\n");
    printf("         This might happen ArangoDB was killed and the last entries were not\n");
    printf("         fully written to disk.\n");
    printf("\n");

    printf("Wipe the last entries (Y/N)? ");
    var line = console.getline();

    if (line !== "yes" && line !== "YES" && line !== "y" && line !== "Y") {
      printf("ABORTING\n");
      return;
    }
  }

  var entry = entries[lastGoodPos];

  WipeDatafile(collection, type, datafile, entry.position + entry.size);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile
////////////////////////////////////////////////////////////////////////////////

function DeepCheckDatafile (collection, type, datafile, scan, lastGoodPos) {
  var entries = scan.entries;

  if (entries.length == 0) {
    printf("WARNING: The datafile is empty. Even the header is missing. Going\n");
    printf("         to remove the datafile. This should never happen. Datafiles\n");
    printf("         are append-only. Make sure your hard disk does not contain\n");
    printf("         any hardware errors.\n");
    printf("\n");

    RemoveDatafile(collection, type, datafile);

    return;
  }

  printf("WARNING: The datafile contains corrupt entries. This should never happen.\n");
  printf("         Datafiles are append-only. Make sure your hard disk does not contain\n");
  printf("         any hardware errors.\n");
  printf("\n");

  printf("Wipe the last entries (Y/N)? ");
  var line = console.getline();

  if (line !== "yes" && line !== "YES" && line !== "y" && line !== "Y") {
    printf("ABORTING\n");
    return;
  }

  var entry = entries[lastGoodPos];

  WipeDatafile(collection, type, datafile, entry.position + entry.size);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile deeply
////////////////////////////////////////////////////////////////////////////////

function DeepCheckDatafile (collection, type, datafile, scan) {
  var entries = scan.entries;

  printf("Entries\n");

  var lastGood = 0;
  var lastGoodPos = 0;
  var stillGood = true;

  for (var i = 0;  i < entries.length;  ++i) {
    var entry = entries[i];
    var s = "unknown";

    switch (entry.status) {
      case 1: s = "OK";  break;
      case 2: s = "OK (end)";  break;
      case 3: s = "FAILED (empty)";  break;
      case 4: s = "FAILED (too small)";  break;
      case 5: s = "FAILED (crc mismatch)";  break;
    }

    printf("  %d: status %s type %d size %d\n", i, s, entry.type, entry.size);

    if (entry.status === 1 || entry.status === 2) {
      if (stillGood) {
        lastGood = entry;
        lastGoodPos = i;
      }
    }
    else {
      stillGood = false;
    }
  }

  if (! stillGood) {
    printf("  Last good position: %d\n", lastGood.position + lastGood.size);
    printf("\n");

    if (type === "journal" || type === "compactor") {
      DeepCheckJournal(collection, type, datafile, scan, lastGoodPos);
    }
    else {
      DeepCheckDatafile(collection, type, datafile, scan, lastGoodPos);
    }
  }

  printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile
////////////////////////////////////////////////////////////////////////////////

function CheckDatafile (collection, type, datafile, issues) {
  printf("Datafile\n");
  printf("  path: %s\n", datafile);
  printf("  type: %s\n", type);

  var scan = collection.datafileScan(datafile);

  printf("  current size: %d\n", scan.currentSize);
  printf("  maximal size: %d\n", scan.maximalSize);
  printf("  total used: %d\n", scan.endPosition);
  printf("  # of entries: %d\n", scan.numberMarkers);

  // set default value to unknown
  var statusMessage = "UNKNOWN (" + scan.status + ")";
  var color = internal.COLORS.COLOR_YELLOW;

  switch (scan.status) {
    case 1:
      statusMessage = "OK";
      color = internal.COLORS.COLOR_GREEN;
      break;

    case 1:
      statusMessage = "NOT OK (reached empty marker)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 3:
      statusMessage = "FATAL (reached corrupt marker)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 4:
      statusMessage = "FATAL (crc failed)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 5:
      statusMessage = "FATAL (cannot open datafile or too small)";
      color = internal.COLORS.COLOR_RED;
      break;
  }

  printf(color);
  printf("  status: %s\n\n", statusMessage);
  printf(internal.COLORS.COLOR_RESET);

  if (scan.status !== 1) {
    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });
  }

  if (scan.numberMarkers === 0) {
    statusMessage = "datafile contains no entries";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.entries[0].type !== 1000) {
    // asserting a TRI_DF_MARKER_HEADER as first marker
    statusMessage = "datafile contains no datafile header marker at pos #0!";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.entries.length == 2 && scan.entries[1].type !== 2000) {
    // asserting a TRI_COL_MARKER_HEADER as second marker
    statusMessage = "datafile contains no collection header marker at pos #1!";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.status === 1) {
    return;
  }

  DeepCheckDatafile(collection, type, datafile, scan);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a collection
////////////////////////////////////////////////////////////////////////////////

function CheckCollection (collection, issues) {
  printf("Database\n");
  printf("  name: %s\n", internal.db._name());
  printf("  path: %s\n", internal.db._path());
  printf("\n");

  printf("Collection\n");
  printf("  name: %s\n", collection.name());
  printf("  identifier: %s\n", collection._id);
  printf("\n");

  var datafiles = collection.datafiles();

  printf("Datafiles\n");
  printf("  # of journals: %d\n", datafiles.journals.length);
  printf("  # of compactors: %d\n", datafiles.compactors.length);
  printf("  # of datafiles: %d\n", datafiles.datafiles.length);
  printf("\n");

  for (var i = 0;  i < datafiles.journals.length;  ++i) {
    CheckDatafile(collection, "journal", datafiles.journals[i], issues);
  }

  for (var i = 0;  i < datafiles.datafiles.length;  ++i) {
    CheckDatafile(collection, "datafiles", datafiles.datafiles[i], issues);
  }

  for (var i = 0;  i < datafiles.compactors.length;  ++i) {
    CheckDatafile(collection, "compactor", datafiles.compactors[i], issues);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief select and check a collection
////////////////////////////////////////////////////////////////////////////////

function main (argv) {
  var argc = argv.length;
  var databases = internal.db._listDatabases();
  var i;

  var collectionSorter = function (l, r) {
    var lName = l.name().toLowerCase();
    var rName = r.name().toLowerCase();

    if (lName !== rName) {
      return lName < rName ? -1 : 1;
    }

    return 0;
  };

  printf("%s\n", "    ___      _         __ _ _           ___  ___    ___ ");
  printf("%s\n", "   /   \\__ _| |_ __ _ / _(_) | ___     /   \\/ __\\  / _ \\");
  printf("%s\n", "  / /\\ / _` | __/ _` | |_| | |/ _ \\   / /\\ /__\\// / /_\\/");
  printf("%s\n", " / /_// (_| | || (_| |  _| | |  __/  / /_// \\/  \\/ /_\\\\ ");
  printf("%s\n", "/___,' \\__,_|\\__\\__,_|_| |_|_|\\___| /___,'\\_____/\\____/ ");
  printf("\n");

  if (databases.length == 0) {
    printf("No databases available. Exiting\n");
    return;
  }

  databases.sort();
  printf("Available databases:\n");

  for (i = 0;  i < databases.length;  ++i) {
    printf("  %d: %s\n", i, databases[i]);
  }

  printf("Database to check: ");
  while (true) {
    var line = console.getline();

    if (line == "") {
      printf("Exiting. Please wait.\n");
      return;
    }
    else {
      var l = parseInt(line);

      if (l < 0 || l >= databases.length || l === null || l === undefined || isNaN(l)) {
        printf("Please select a number between 0 and %d: ", databases.length - 1);
      }
      else {
        internal.db._useDatabase(databases[l]);
        break;
      }
    }
  }

  printf("\n");

  var collections = internal.db._collections();
  if (collections.length == 0) {
    printf("No collections available. Exiting\n");
    return;
  }

  // sort the collections
  collections.sort(collectionSorter);

  printf("Available collections:\n");

  for (i = 0;  i < collections.length;  ++i) {
    printf("  %d: %s\n", i, collections[i].name());
  }

  printf("  *: all\n");

  printf("\n");

  printf("Collection to check: ");
  var a = [];

  while (true) {
    var line = console.getline();

    if (line == "") {
      printf("Exiting. Please wait.\n");
      break;
    }

    if (line === "*") {
      for (i = 0;  i < collections.length;  ++i) {
        a.push(i);
      }

      break;
    }
    else {
      var l = parseInt(line);

      if (l < 0 || l >= collections.length || l === null || l === undefined || isNaN(l)) {
        printf("Please select a number between 0 and %d: ", collections.length - 1);
      }
      else {
        a.push(l);
        break;
      }
    }
  }

  var issues = [ ];

  for (i = 0;  i < a.length;  ++i) {
    var collection = collections[a[i]];

    printf("Checking collection #%d: %s\n", a[i], collection.name());
    printf("-------------------------------------------------------------------\n");

    var last = Math.round(internal.time());

    // unload all collections not yet unloaded (2) & not corrupted (0)
    while (collection.status() !== 2 && collection.status() !== 0) {
      collection.unload();

      var next = Math.round(internal.time());

      if (next != last) {
        printf("Trying to unload collection '%s'\n", collection.name());
        last = next;
      }
    }

    printf("\n");

    CheckCollection(collection, issues);
  }

  if (issues.length > 0) {
    // report issues
    printf("\n%d issue(s) found:\n------------------------------------------\n", issues.length);

    for (i = 0; i < issues.length; ++i) {
      var issue = issues[i];
      printf("  issue #%d\n    collection: %s\n    path: %s\n    type: %s\n",
             i,
             issue.collection,
             issue.path,
             String(issue.type));

      printf("%s", issue.color);
      printf("    message: %s", issue.message);
      printf("%s", internal.COLORS.COLOR_RESET);
      printf("\n\n");
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<commit_msg>report status at end<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief arango datafile debugger
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var internal = require("internal");
var console = require("console");
var fs = require("fs");

var printf = internal.printf;

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief remove datafile
////////////////////////////////////////////////////////////////////////////////

function RemoveDatafile (collection, type, datafile) {
  var backup = datafile + ".corrupt";

  fs.move(datafile, backup);

  printf("Removed %s at %s\n", type, datafile);
  printf("Backup is in %s\n", backup);
  printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief wipe entries
////////////////////////////////////////////////////////////////////////////////

function WipeDatafile (collection, type, datafile, lastGoodPos) {
  collection.truncateDatafile(datafile, lastGoodPos);

  printf("Truncated and sealed datafile\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a journal
////////////////////////////////////////////////////////////////////////////////

function DeepCheckJournal (collection, type, datafile, scan, lastGoodPos) {
  var entries = scan.entries;

  if (entries.length == 0) {
    printf("WARNING: The journal is empty. Even the header is missing. Going\n");
    printf("         to remove the datafile.\n");
    printf("\n");

    RemoveDatafile(collection, type, datafile);

    return;
  }

  if (entries.length === lastGoodPos + 3 && entries[lastGoodPos + 2].status === 2) {
    printf("WARNING: The journal was not closed properly, the last entry is corrupted.\n");
    printf("         This might happen ArangoDB was killed and the last entry was not\n");
    printf("         fully written to disk. Going to remove the last entry.\n");
    printf("\n");
  }
  else {
    printf("WARNING: The journal was not closed properly, the last entries is corrupted.\n");
    printf("         This might happen ArangoDB was killed and the last entries were not\n");
    printf("         fully written to disk.\n");
    printf("\n");

    printf("Wipe the last entries (Y/N)? ");
    var line = console.getline();

    if (line !== "yes" && line !== "YES" && line !== "y" && line !== "Y") {
      printf("ABORTING\n");
      return;
    }
  }

  var entry = entries[lastGoodPos];

  WipeDatafile(collection, type, datafile, entry.position + entry.size);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile
////////////////////////////////////////////////////////////////////////////////

function DeepCheckDatafile (collection, type, datafile, scan, lastGoodPos) {
  var entries = scan.entries;

  if (entries.length == 0) {
    printf("WARNING: The datafile is empty. Even the header is missing. Going\n");
    printf("         to remove the datafile. This should never happen. Datafiles\n");
    printf("         are append-only. Make sure your hard disk does not contain\n");
    printf("         any hardware errors.\n");
    printf("\n");

    RemoveDatafile(collection, type, datafile);

    return;
  }

  printf("WARNING: The datafile contains corrupt entries. This should never happen.\n");
  printf("         Datafiles are append-only. Make sure your hard disk does not contain\n");
  printf("         any hardware errors.\n");
  printf("\n");

  printf("Wipe the last entries (Y/N)? ");
  var line = console.getline();

  if (line !== "yes" && line !== "YES" && line !== "y" && line !== "Y") {
    printf("ABORTING\n");
    return;
  }

  var entry = entries[lastGoodPos];

  WipeDatafile(collection, type, datafile, entry.position + entry.size);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile deeply
////////////////////////////////////////////////////////////////////////////////

function DeepCheckDatafile (collection, type, datafile, scan) {
  var entries = scan.entries;

  printf("Entries\n");

  var lastGood = 0;
  var lastGoodPos = 0;
  var stillGood = true;

  for (var i = 0;  i < entries.length;  ++i) {
    var entry = entries[i];
    var s = "unknown";

    switch (entry.status) {
      case 1: s = "OK";  break;
      case 2: s = "OK (end)";  break;
      case 3: s = "FAILED (empty)";  break;
      case 4: s = "FAILED (too small)";  break;
      case 5: s = "FAILED (crc mismatch)";  break;
    }

    printf("  %d: status %s type %d size %d\n", i, s, entry.type, entry.size);

    if (entry.status === 1 || entry.status === 2) {
      if (stillGood) {
        lastGood = entry;
        lastGoodPos = i;
      }
    }
    else {
      stillGood = false;
    }
  }

  if (! stillGood) {
    printf("  Last good position: %d\n", lastGood.position + lastGood.size);
    printf("\n");

    if (type === "journal" || type === "compactor") {
      DeepCheckJournal(collection, type, datafile, scan, lastGoodPos);
    }
    else {
      DeepCheckDatafile(collection, type, datafile, scan, lastGoodPos);
    }
  }

  printf("\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a datafile
////////////////////////////////////////////////////////////////////////////////

function CheckDatafile (collection, type, datafile, issues) {
  printf("Datafile\n");
  printf("  path: %s\n", datafile);
  printf("  type: %s\n", type);

  var scan = collection.datafileScan(datafile);

  printf("  current size: %d\n", scan.currentSize);
  printf("  maximal size: %d\n", scan.maximalSize);
  printf("  total used: %d\n", scan.endPosition);
  printf("  # of entries: %d\n", scan.numberMarkers);

  // set default value to unknown
  var statusMessage = "UNKNOWN (" + scan.status + ")";
  var color = internal.COLORS.COLOR_YELLOW;

  switch (scan.status) {
    case 1:
      statusMessage = "OK";
      color = internal.COLORS.COLOR_GREEN;
      break;

    case 1:
      statusMessage = "NOT OK (reached empty marker)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 3:
      statusMessage = "FATAL (reached corrupt marker)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 4:
      statusMessage = "FATAL (crc failed)";
      color = internal.COLORS.COLOR_RED;
      break;

    case 5:
      statusMessage = "FATAL (cannot open datafile or too small)";
      color = internal.COLORS.COLOR_RED;
      break;
  }

  printf(color);
  printf("  status: %s\n\n", statusMessage);
  printf(internal.COLORS.COLOR_RESET);

  if (scan.status !== 1) {
    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });
  }

  if (scan.numberMarkers === 0) {
    statusMessage = "datafile contains no entries";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.entries[0].type !== 1000) {
    // asserting a TRI_DF_MARKER_HEADER as first marker
    statusMessage = "datafile contains no datafile header marker at pos #0!";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.entries.length == 2 && scan.entries[1].type !== 2000) {
    // asserting a TRI_COL_MARKER_HEADER as second marker
    statusMessage = "datafile contains no collection header marker at pos #1!";
    color = internal.COLORS.COLOR_YELLOW;

    issues.push({
      collection: collection.name(),
      path: datafile,
      type: type,
      status: scan.status,
      message: statusMessage,
      color: color
    });

    printf(color);
    printf("WARNING: %s\n", statusMessage);
    printf(internal.COLORS.COLOR_RESET);
    RemoveDatafile(collection, type, datafile);
    return;
  }

  if (scan.status === 1) {
    return;
  }

  DeepCheckDatafile(collection, type, datafile, scan);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief checks a collection
////////////////////////////////////////////////////////////////////////////////

function CheckCollection (collection, issues) {
  printf("Database\n");
  printf("  name: %s\n", internal.db._name());
  printf("  path: %s\n", internal.db._path());
  printf("\n");

  printf("Collection\n");
  printf("  name: %s\n", collection.name());
  printf("  identifier: %s\n", collection._id);
  printf("\n");

  var datafiles = collection.datafiles();

  printf("Datafiles\n");
  printf("  # of journals: %d\n", datafiles.journals.length);
  printf("  # of compactors: %d\n", datafiles.compactors.length);
  printf("  # of datafiles: %d\n", datafiles.datafiles.length);
  printf("\n");

  for (var i = 0;  i < datafiles.journals.length;  ++i) {
    CheckDatafile(collection, "journal", datafiles.journals[i], issues);
  }

  for (var i = 0;  i < datafiles.datafiles.length;  ++i) {
    CheckDatafile(collection, "datafiles", datafiles.datafiles[i], issues);
  }

  for (var i = 0;  i < datafiles.compactors.length;  ++i) {
    CheckDatafile(collection, "compactor", datafiles.compactors[i], issues);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief select and check a collection
////////////////////////////////////////////////////////////////////////////////

function main (argv) {
  var argc = argv.length;
  var databases = internal.db._listDatabases();
  var i;

  var collectionSorter = function (l, r) {
    var lName = l.name().toLowerCase();
    var rName = r.name().toLowerCase();

    if (lName !== rName) {
      return lName < rName ? -1 : 1;
    }

    return 0;
  };

  printf("%s\n", "    ___      _         __ _ _           ___  ___    ___ ");
  printf("%s\n", "   /   \\__ _| |_ __ _ / _(_) | ___     /   \\/ __\\  / _ \\");
  printf("%s\n", "  / /\\ / _` | __/ _` | |_| | |/ _ \\   / /\\ /__\\// / /_\\/");
  printf("%s\n", " / /_// (_| | || (_| |  _| | |  __/  / /_// \\/  \\/ /_\\\\ ");
  printf("%s\n", "/___,' \\__,_|\\__\\__,_|_| |_|_|\\___| /___,'\\_____/\\____/ ");
  printf("\n");

  if (databases.length == 0) {
    printf("No databases available. Exiting\n");
    return;
  }

  databases.sort();
  printf("Available databases:\n");

  for (i = 0;  i < databases.length;  ++i) {
    printf("  %d: %s\n", i, databases[i]);
  }

  printf("Database to check: ");
  while (true) {
    var line = console.getline();

    if (line == "") {
      printf("Exiting. Please wait.\n");
      return;
    }
    else {
      var l = parseInt(line);

      if (l < 0 || l >= databases.length || l === null || l === undefined || isNaN(l)) {
        printf("Please select a number between 0 and %d: ", databases.length - 1);
      }
      else {
        internal.db._useDatabase(databases[l]);
        break;
      }
    }
  }

  printf("\n");

  var collections = internal.db._collections();
  if (collections.length == 0) {
    printf("No collections available. Exiting\n");
    return;
  }

  // sort the collections
  collections.sort(collectionSorter);

  printf("Available collections:\n");

  for (i = 0;  i < collections.length;  ++i) {
    printf("  %d: %s\n", i, collections[i].name());
  }

  printf("  *: all\n");

  printf("\n");

  printf("Collection to check: ");
  var a = [];

  while (true) {
    var line = console.getline();

    if (line == "") {
      printf("Exiting. Please wait.\n");
      return;
    }

    if (line === "*") {
      for (i = 0;  i < collections.length;  ++i) {
        a.push(i);
      }

      break;
    }
    else {
      var l = parseInt(line);

      if (l < 0 || l >= collections.length || l === null || l === undefined || isNaN(l)) {
        printf("Please select a number between 0 and %d: ", collections.length - 1);
      }
      else {
        a.push(l);
        break;
      }
    }
  }

  var issues = [ ];

  for (i = 0;  i < a.length;  ++i) {
    var collection = collections[a[i]];

    printf("Checking collection #%d: %s\n", a[i], collection.name());
    printf("-------------------------------------------------------------------\n");

    var last = Math.round(internal.time());

    // unload all collections not yet unloaded (2) & not corrupted (0)
    while (collection.status() !== 2 && collection.status() !== 0) {
      collection.unload();

      var next = Math.round(internal.time());

      if (next != last) {
        printf("Trying to unload collection '%s'\n", collection.name());
        last = next;
      }
    }

    printf("\n");

    CheckCollection(collection, issues);
  }

  if (issues.length > 0) {
    // report issues
    printf("\n%d issue(s) found:\n------------------------------------------\n", issues.length);

    for (i = 0; i < issues.length; ++i) {
      var issue = issues[i];
      printf("  issue #%d\n    collection: %s\n    path: %s\n    type: %s\n",
             i,
             issue.collection,
             issue.path,
             String(issue.type));

      printf("%s", issue.color);
      printf("    message: %s", issue.message);
      printf("%s", internal.COLORS.COLOR_RESET);
      printf("\n\n");
    }
  }
  else {
    printf("\nNo issues found.\n");
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<|endoftext|>


<commit_before>'use strict';
var childProcess = require('child_process');
var fs = require('fs');
var Path = require('path');
var timers = require('timers');
var extend = require('util')._extend;

function copyFile(source, target, cb) {
    var cbCalled = false;

    console.log('Copy file %s to %s', source, target);
    var rd = fs.createReadStream(source);
    rd.on("error", function(err) {
        done(err);
    });
    var wr = fs.createWriteStream(target);
    wr.on("error", function(err) {
        done(err);
    });
    wr.on("close", function(ex) {
        done();
    });
    rd.pipe(wr);

    function done(err) {
        if (!cbCalled) {
            cb(err);
            cbCalled = true;
        }
    }
}

function msm(args, callback) {
    console.log('> /usr/local/bin/msm ' + args.join(' '));
    childProcess.execFile('/usr/local/bin/msm', args, {
        cwd: __dirname,
        timeout: 60000
    }, function (err, stdOut, stdErr) {
        if (err) {
            console.log(err.message);
            return callback(err);
        }
        if (stdErr.length) {
            console.log('! ' + stdErr.toString());
        }
        if (stdOut.length) {
            console.log('< ' + stdOut.toString());
        }

        callback();
    });
}

function playerInfo(username) {

    var gameBase = '/opt/msm/servers/survival/';
    var players = {};
    JSON.parse(fs.readFileSync(gameBase + 'whitelist.json'))
        .forEach(function(p) { players[p.name.toLowerCase()] = p.uuid; });
    var uuid = players[username.toLowerCase()];
    var pthData = Path.join(gameBase + 'world/playerdata/', (uuid || '') + '.dat');
    if (!uuid || !fs.existsSync(pthData)) {
        throw new Error('Unable to locate player data.');
    }
    var pthBack = Path.join(gameBase + 'playerStore/', uuid + '.dat');
    return {
        name: username,
        uuid: uuid,
        dat: pthData,
        bak: pthBack
    };
}

var config = {
    minecraft: {
        log: '/opt/msm/servers/survival/logs/latest.log',
        cwd: '.',
        timeout: 10000,
        logFormat: /^\[\d\d:\d\d:\d\d] \[Server thread\/INFO]: [<\[](\w+)[>\]] #(\/.*)\s*$/i,
        badCommand: /^\[\d\d:\d\d:\d\d] \[Server thread\/INFO]: (Failed to execute '.*') as (\w+)\s*$/i
    },
    mcexec: {
        file: '/usr/local/bin/msm',
        args: ['survival', 'cmd']
    },
    mcrunas: {
        args: ['/execute @p[name={username},x=-2000,y=64,z=-250,r=2000] ~ ~ ~ {command}']
    },
    mctell: {
        args: ['/tell {username} {command}']
    },
    commands: {
        tp: { match: /^\/tp @p ~|\d/i },
        fill: { match: /^\/fill /i },
        clone: { match: /^\/clone /i },
        blockdata: { match: /^\/blockdata /i },
        setblock: { match: /^\/setblock /i },
        summon: { match: /^\/summon /i },
        weather: { match: /^\/weather /i },
        'map-update': {
            match: /^\/map-update/i,
            file: '/opt/msm/scripts/update.sh',
            started: 'Started updating the map.',
            complete: 'Finished updating the map.'
        },
        'gamemode creative': {
            match: /^\/gamemode\s+c(reative)?$/i,
            file: 'gamemode',
            action: function(mcrun, data, complete) {
                mcrun('/tell ' + data.username + ' going to creative!');
                var fail = function(message) {
                    mcrun('/tell ' + data.username + ' ' + (message || 'Something went wrong.'));
                    return complete();
                };

                var player;
                try { player = playerInfo(data.username); }
                catch(ex) { return fail(ex.message); }
                if (fs.existsSync(player.bak)) {
                    return fail('You are already in creative.');
                }

                msm(['survival', 'save', 'all'], function (err) {
                    if (err) {
                        //return fail('Unable to save the world.');
                    }

                    copyFile(player.dat, player.bak, function (ecopy) {
                        if (ecopy) {
                            return fail('Unable to create backup.');
                        }

                        mcrun('/tp @p 143 60 5083');
                        complete();
                    });
                });
            }
        },
        'gamemode survival': {
            match: /^\/gamemode\s+s(urvival)?$/i,
            file: 'gamemode',
            action: function (mcrun, data, complete) {
                mcrun('/tell ' + data.username + ' going to survival, you will momentarily booted off!');
                var fail = function (message) {
                    mcrun('/tell ' + data.username + ' ' + (message || 'Something went wrong.'));
                    return complete();
                };

                var player;
                try {
                    player = playerInfo(data.username);
                }
                catch (ex) {
                    return fail(ex.message);
                }
                if (!fs.existsSync(player.bak)) {
                    return fail('You are already in survival.');
                }

                msm(['survival', 'kick', data.username], function () {
                    msm(['survival', 'bl', 'player', 'add', data.username], function () {
                        msm(['survival', 'save', 'all'], function () {
                            copyFile(player.bak, player.dat, function (ecopy) {
                                if (!ecopy) {
                                    fs.unlink(player.bak, function(erm) {
                                        if (erm) { console.error(erm); }
                                    });
                                }
                                msm(['survival', 'bl', 'player', 'remove', data.username], function () {
                                    if (ecopy) {
                                        return fail('Unable to create backup.');
                                    }
                                    complete();
                                });
                            });
                        });
                    });
                });
            }
        }
    }
};

module.exports = config;
<commit_msg>Added adventure mode<commit_after>'use strict';
var childProcess = require('child_process');
var fs = require('fs');
var Path = require('path');
var timers = require('timers');
var extend = require('util')._extend;

function copyFile(source, target, cb) {
    var cbCalled = false;

    console.log('Copy file %s to %s', source, target);
    var rd = fs.createReadStream(source);
    rd.on("error", function(err) {
        done(err);
    });
    var wr = fs.createWriteStream(target);
    wr.on("error", function(err) {
        done(err);
    });
    wr.on("close", function(ex) {
        done();
    });
    rd.pipe(wr);

    function done(err) {
        if (!cbCalled) {
            cb(err);
            cbCalled = true;
        }
    }
}

function msm(args, callback) {
    console.log('> /usr/local/bin/msm ' + args.join(' '));
    childProcess.execFile('/usr/local/bin/msm', args, {
        cwd: __dirname,
        timeout: 60000
    }, function (err, stdOut, stdErr) {
        if (err) {
            console.log(err.message);
            return callback(err);
        }
        if (stdErr.length) {
            console.log('! ' + stdErr.toString());
        }
        if (stdOut.length) {
            console.log('< ' + stdOut.toString());
        }

        callback();
    });
}

function playerInfo(username) {

    var gameBase = '/opt/msm/servers/survival/';
    var players = {};
    JSON.parse(fs.readFileSync(gameBase + 'whitelist.json'))
        .forEach(function(p) { players[p.name.toLowerCase()] = p.uuid; });
    var uuid = players[username.toLowerCase()];
    var pthData = Path.join(gameBase + 'world/playerdata/', (uuid || '') + '.dat');
    if (!uuid || !fs.existsSync(pthData)) {
        throw new Error('Unable to locate player data.');
    }
    var pthBack = Path.join(gameBase + 'playerStore/', uuid + '.dat');
    return {
        name: username,
        uuid: uuid,
        dat: pthData,
        bak: pthBack
    };
}

var config = {
    minecraft: {
        log: '/opt/msm/servers/survival/logs/latest.log',
        cwd: '.',
        timeout: 10000,
        logFormat: /^\[\d\d:\d\d:\d\d] \[Server thread\/INFO]: [<\[](\w+)[>\]] #(\/.*)\s*$/i,
        badCommand: /^\[\d\d:\d\d:\d\d] \[Server thread\/INFO]: (Failed to execute '.*') as (\w+)\s*$/i
    },
    mcexec: {
        file: '/usr/local/bin/msm',
        args: ['survival', 'cmd']
    },
    mcrunas: {
        args: ['/execute @p[name={username},x=-2000,y=64,z=-250,r=2000] ~ ~ ~ {command}']
    },
    mctell: {
        args: ['/tell {username} {command}']
    },
    commands: {
        tp: { match: /^\/tp @p ~|\d/i },
        fill: { match: /^\/fill /i },
        clone: { match: /^\/clone /i },
        blockdata: { match: /^\/blockdata /i },
        setblock: { match: /^\/setblock /i },
        summon: { match: /^\/summon /i },
        weather: { match: /^\/weather /i },
        'map-update': {
            match: /^\/map-update/i,
            file: '/opt/msm/scripts/update.sh',
            started: 'Started updating the map.',
            complete: 'Finished updating the map.'
        },
        'gamemode creative': {
            match: /^\/gamemode\s+c(reative)?$/i,
            file: 'gamemode',
            action: function(mcrun, data, complete) {
                mcrun('/tell ' + data.username + ' going to creative!');
                var fail = function(message) {
                    mcrun('/tell ' + data.username + ' ' + (message || 'Something went wrong.'));
                    return complete();
                };

                var player;
                try { player = playerInfo(data.username); }
                catch(ex) { return fail(ex.message); }
                if (fs.existsSync(player.bak)) {
                    return fail('You are already in adventure/creative mode.');
                }

                msm(['survival', 'save', 'all'], function (err) {
                    if (err) {
                        //return fail('Unable to save the world.');
                    }

                    copyFile(player.dat, player.bak, function (ecopy) {
                        if (ecopy) {
                            return fail('Unable to create backup.');
                        }

                        mcrun('/tp @p 143 60 5083');
                        complete();
                    });
                });
            }
        },
        'gamemode adventure': {
            match: /^\/gamemode\s+a(dventure)?$/i,
            file: 'gamemode',
            action: function(mcrun, data, complete) {
                mcrun('/tell ' + data.username + ' going to adventure!');
                var fail = function(message) {
                    mcrun('/tell ' + data.username + ' ' + (message || 'Something went wrong.'));
                    return complete();
                };

                var player;
                try { player = playerInfo(data.username); }
                catch(ex) { return fail(ex.message); }
                if (fs.existsSync(player.bak)) {
                    return fail('You are already in adventure/creative mode.');
                }

                msm(['survival', 'save', 'all'], function (err) {
                    if (err) {
                        //return fail('Unable to save the world.');
                    }

                    copyFile(player.dat, player.bak, function (ecopy) {
                        if (ecopy) {
                            return fail('Unable to create backup.');
                        }

                        mcrun('/tp @p 129 60 5083');
                        complete();
                    });
                });
            }
        },
        'gamemode survival': {
            match: /^\/gamemode\s+s(urvival)?$/i,
            file: 'gamemode',
            action: function (mcrun, data, complete) {
                mcrun('/tell ' + data.username + ' going to survival, you will momentarily booted off!');
                var fail = function (message) {
                    mcrun('/tell ' + data.username + ' ' + (message || 'Something went wrong.'));
                    return complete();
                };

                var player;
                try {
                    player = playerInfo(data.username);
                }
                catch (ex) {
                    return fail(ex.message);
                }
                if (!fs.existsSync(player.bak)) {
                    return fail('You are already in survival.');
                }

                msm(['survival', 'kick', data.username], function () {
                    msm(['survival', 'bl', 'player', 'add', data.username], function () {
                        msm(['survival', 'save', 'all'], function () {
                            copyFile(player.bak, player.dat, function (ecopy) {
                                if (!ecopy) {
                                    fs.unlink(player.bak, function(erm) {
                                        if (erm) { console.error(erm); }
                                    });
                                }
                                msm(['survival', 'bl', 'player', 'remove', data.username], function () {
                                    if (ecopy) {
                                        return fail('Unable to create backup.');
                                    }
                                    complete();
                                });
                            });
                        });
                    });
                });
            }
        }
    }
};

module.exports = config;
<|endoftext|>


<commit_before>const fs      = require('fs')
const path    = require('path')
const {spawn} = require('child_process')

const progressRegex = /([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})\s+(\(\d+\))/gi;
const durationRegex = /Duration:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;
const startRegex = /Start:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;

const option  = (params, name, value) => value !== undefined ? params.push(name, value) : undefined
const seconds = (string) => string.split(':')
    .map((e, i) => (i < 3) ? +e * Math.pow(60, 2 - i) : +e * 10e-6)
    .reduce((acc, val) => acc + val);

/**
 * This task creates rendering process
 */
module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] rendering job...`);

    // create container for our parameters
    let params = [];

    // setup parameters
    params.push('-project', job.template.dest);
    params.push('-comp',    job.template.composition);
    params.push('-output',  job.output);

    option(params, '-OMtemplate', job.template.outputModule);
    option(params, '-RStemplate', job.template.settingsTemplate);
    option(params, '-s', job.template.frameStart);
    option(params, '-e', job.template.frameEnd);
    option(params, '-i', job.template.incrementFrame);
    option(params, '-r', job.scriptfile);

    if (settings.multiFrames) params.push('-mp');
    if (settings.reuse) params.push('-reuse');
    if (job.template.continueOnMissing) params.push('-continueOnMissingFootage')

    if (settings.imageCachePercent || settings.maxMemoryPercent) {
        option(params, '-mem_usage', `${settings.imageCachePercent || 50} ${settings.maxMemoryPercent || 50}`)
    }

    // tracks progress
    let projectDuration  = null;
    let currentProgress  = null;
    let previousProgress = undefined;
    let renderStopwatch  = null;
    let projectStart     = null;

    const parse = (data) => {
        const string = (''+data).replace(/;/g, ':'); /* sanitize string */

        // Only execute startRegex if project start hasnt been found
        const matchStart = isNaN(parseInt(projectStart)) ? startRegex.exec(string) : false;
        // Only execute durationRegex if project duration hasnt been found
        const matchDuration = isNaN(parseInt(projectDuration)) ? durationRegex.exec(string) : false;
        // Only execute progressRegex if project duration has been found
        const matchProgress = !isNaN(parseInt(projectDuration)) ? progressRegex.exec(string) : null;
        // If durationRegex has a match convert tstamp to seconds and define projectDuration only once
        projectDuration = (matchDuration) ? seconds(matchDuration[1]) : projectDuration;
        // If startRegex has a match convert tstamp to seconds and define projectStart only once
        projectStart = (matchStart) ? seconds(matchStart[1]) : projectStart;

        if (matchProgress) {
            currentProgress = Math.ceil((seconds(matchProgress[1]) - projectStart) * 100 / projectDuration);

            if (previousProgress !== currentProgress) {
                settings.logger.log(`[${job.uid}] rendering progress ${currentProgress}%...`);
                previousProgress = currentProgress;
                job.renderProgress = currentProgress;
            }
        }

        return data;
    }

    // spawn process and begin rendering
    return new Promise((resolve, reject) => {
        renderStopwatch = Date.now();

        if (settings.debug) {
            settings.logger.log(`[${job.uid}] spawning aerender process: ${settings.binary} ${params.join(' ')}`);
        }

        const output = [];
        const instance = spawn(settings.binary, params, {
            // NOTE: disabled PATH for now, there were a few
            // issues related to plugins not working properly
            // env: { PATH: path.dirname(settings.binary) },
        });

        instance.on('error', err => reject(new Error(`Error starting aerender process: ${err}`)));
        instance.stdout.on('data', (data) => output.push(parse(data.toString('utf8'))));
        instance.stderr.on('data', (data) => output.push(data.toString('utf8')));

        /* on finish (code 0 - success, other - error) */
        instance.on('close', (code) => {
            const outputStr = output
                .map(a => ''+a).join('');

            if (code !== 0) {
                return reject(outputStr)
            }

            settings.logger.log(`[${job.uid}] rendering took ~${(Date.now() - renderStopwatch)/1000} sec.`);

            const logPath = path.resolve(job.workpath, `../aerender-${job.uid}.log`)
            settings.logger.log(`[${job.uid}] writing aerender job log to: ${logPath}`);
            fs.writeFileSync(logPath, outputStr);

            resolve(job)
        });
    })
};
<commit_msg>Add callback for render progress to job object.<commit_after>const fs      = require('fs')
const path    = require('path')
const {spawn} = require('child_process')

const progressRegex = /([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})\s+(\(\d+\))/gi;
const durationRegex = /Duration:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;
const startRegex = /Start:\s+([\d]{1,2}:[\d]{2}:[\d]{2}:[\d]{2})/gi;

const option  = (params, name, value) => value !== undefined ? params.push(name, value) : undefined
const seconds = (string) => string.split(':')
    .map((e, i) => (i < 3) ? +e * Math.pow(60, 2 - i) : +e * 10e-6)
    .reduce((acc, val) => acc + val);

/**
 * This task creates rendering process
 */
module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] rendering job...`);

    // create container for our parameters
    let params = [];

    // setup parameters
    params.push('-project', job.template.dest);
    params.push('-comp',    job.template.composition);
    params.push('-output',  job.output);

    option(params, '-OMtemplate', job.template.outputModule);
    option(params, '-RStemplate', job.template.settingsTemplate);
    option(params, '-s', job.template.frameStart);
    option(params, '-e', job.template.frameEnd);
    option(params, '-i', job.template.incrementFrame);
    option(params, '-r', job.scriptfile);

    if (settings.multiFrames) params.push('-mp');
    if (settings.reuse) params.push('-reuse');
    if (job.template.continueOnMissing) params.push('-continueOnMissingFootage')

    if (settings.imageCachePercent || settings.maxMemoryPercent) {
        option(params, '-mem_usage', `${settings.imageCachePercent || 50} ${settings.maxMemoryPercent || 50}`)
    }

    // tracks progress
    let projectDuration  = null;
    let currentProgress  = null;
    let previousProgress = undefined;
    let renderStopwatch  = null;
    let projectStart     = null;

    const parse = (data) => {
        const string = (''+data).replace(/;/g, ':'); /* sanitize string */

        // Only execute startRegex if project start hasnt been found
        const matchStart = isNaN(parseInt(projectStart)) ? startRegex.exec(string) : false;
        // Only execute durationRegex if project duration hasnt been found
        const matchDuration = isNaN(parseInt(projectDuration)) ? durationRegex.exec(string) : false;
        // Only execute progressRegex if project duration has been found
        const matchProgress = !isNaN(parseInt(projectDuration)) ? progressRegex.exec(string) : null;
        // If durationRegex has a match convert tstamp to seconds and define projectDuration only once
        projectDuration = (matchDuration) ? seconds(matchDuration[1]) : projectDuration;
        // If startRegex has a match convert tstamp to seconds and define projectStart only once
        projectStart = (matchStart) ? seconds(matchStart[1]) : projectStart;

        if (matchProgress) {
            currentProgress = Math.ceil((seconds(matchProgress[1]) - projectStart) * 100 / projectDuration);

            if (previousProgress !== currentProgress) {
                settings.logger.log(`[${job.uid}] rendering progress ${currentProgress}%...`);
                previousProgress = currentProgress;

                job.renderProgress = currentProgress;
                if (job.onRenderProgress) {
                    job.onRenderProgress(job, job.renderProgress);
                }
            }
        }

        return data;
    }

    // spawn process and begin rendering
    return new Promise((resolve, reject) => {
        renderStopwatch = Date.now();

        if (settings.debug) {
            settings.logger.log(`[${job.uid}] spawning aerender process: ${settings.binary} ${params.join(' ')}`);
        }

        const output = [];
        const instance = spawn(settings.binary, params, {
            // NOTE: disabled PATH for now, there were a few
            // issues related to plugins not working properly
            // env: { PATH: path.dirname(settings.binary) },
        });

        instance.on('error', err => reject(new Error(`Error starting aerender process: ${err}`)));
        instance.stdout.on('data', (data) => output.push(parse(data.toString('utf8'))));
        instance.stderr.on('data', (data) => output.push(data.toString('utf8')));

        /* on finish (code 0 - success, other - error) */
        instance.on('close', (code) => {
            const outputStr = output
                .map(a => ''+a).join('');

            if (code !== 0) {
                return reject(outputStr)
            }

            settings.logger.log(`[${job.uid}] rendering took ~${(Date.now() - renderStopwatch)/1000} sec.`);

            const logPath = path.resolve(job.workpath, `../aerender-${job.uid}.log`)
            settings.logger.log(`[${job.uid}] writing aerender job log to: ${logPath}`);
            fs.writeFileSync(logPath, outputStr);

            resolve(job)
        });
    })
};
<|endoftext|>


<commit_before>const assert = require('assert')
const linter = require('./../../../lib/index')
const { funcWith, contractWith } = require('./../../common/contract-builder')

describe('Linter - mark-callable-contracts', () => {
  it('should return error that external contract is not marked as trusted / untrusted', () => {
    const code = funcWith('Bank.withdraw(100);')

    const report = linter.processStr(code, {
      rules: { 'mark-callable-contracts': 'warn' }
    })

    assert.equal(report.warningCount, 1)
    assert.ok(report.reports[0].message.includes('trusted'))
  })

  it('should not return error for a struct', () => {
    const code = contractWith(`
  struct Token {
    address tokenAddress;
    string tokenSymbol;
  }

  mapping(address => Token) public acceptedTokens;

  function b(address tokenAddress, string memory tokenSymbol) public {
    Token memory token = Token(tokenAddress, tokenSymbol);
    acceptedTokens[tokenAddress] = token;
  }
    `)

    const report = linter.processStr(code, {
      rules: { 'mark-callable-contracts': 'warn' }
    })

    console.log(report);
    assert.equal(report.warningCount, 0)
  })
})
<commit_msg>remove debugging log<commit_after>const assert = require('assert')
const linter = require('./../../../lib/index')
const { funcWith, contractWith } = require('./../../common/contract-builder')

describe('Linter - mark-callable-contracts', () => {
  it('should return error that external contract is not marked as trusted / untrusted', () => {
    const code = funcWith('Bank.withdraw(100);')

    const report = linter.processStr(code, {
      rules: { 'mark-callable-contracts': 'warn' }
    })

    assert.equal(report.warningCount, 1)
    assert.ok(report.reports[0].message.includes('trusted'))
  })

  it('should not return error for a struct', () => {
    const code = contractWith(`
  struct Token {
    address tokenAddress;
    string tokenSymbol;
  }

  mapping(address => Token) public acceptedTokens;

  function b(address tokenAddress, string memory tokenSymbol) public {
    Token memory token = Token(tokenAddress, tokenSymbol);
    acceptedTokens[tokenAddress] = token;
  }
    `)

    const report = linter.processStr(code, {
      rules: { 'mark-callable-contracts': 'warn' }
    })

    assert.equal(report.warningCount, 0)
  })
})
<|endoftext|>


<commit_before>/**

  Utils.js

  Various helper functions.

  • getRegExpMatches
  • isIndexFile
  • isProduction
  • makePathAbsolute
  • makeRoutes
  • mapFiles
  • readDirectory
  • readFileHead
  • sequence
  • uniqueExtensions
  • watch

**/

//
//  Dependencies
//

var fs       = require("fs"),
    url      = require("url"),
    path     = require("path"),
    chokidar = require("chokidar"),
    Promise  = require("bluebird"),
    reorg    = require("reorg"),
    zlib     = require("zlib"),
    Utils;

module.exports = Utils = {};

/**

  Makes a path absolute (if not already)

  @param {String} p Path
  @returns {String} Absolute path version of a string

**/

Utils.makePathAbsolute = function(p) {

  if (path.isAbsolute(p))
    return p;
  else
    return path.resolve(process.cwd(), p || "");

};

/**

  Tests to see if a file is of form "index*"

  @param {Stats} file File as returned by fs.lstat
  @returns {Boolean} true if a file is index-like

*/

Utils.isIndexFile = function(file) {
  return /^index[^\/]*$/i.test(file.name);
};

/**

  Retrieves all unique file extensions from a directory

  @param {String} p Directory path
  @returns {Array} Array of strings of extensions

**/

Utils.uniqueExtensions = function(p) {
  var exts = {};
  Utils.readDirectory(p).forEach(function(file) {
    if (file.ext && "" !== file.ext) exts[file.ext.toLowerCase()] = 1;
  });
  return Object.keys(exts);
};

/**

  Finds index files and marks as "bundles", then removes sibling and
  sub-diretories

  @param {String} p Absolute path
  @param {Array} files Array of file stats

**/

Utils.flagBundles = function(p, files, ext) {

  var indices = [],
      i, j, n;

  // Filter out index files (outside of master directory)
  i = files.length;
  while (i-- > 0)
    if ((p !== files[i].dir) && Utils.isIndexFile(files[i]))
      indices.push(files.splice(i, 1)[0]);

  // Remove indices that are subdirectories of each other
  i = indices.length;
  while (i-- > 0)
    for (j = 0, n = indices.length; j < n; j++)
      if (i !== j && 0 === indices[i].path.indexOf(indices[j].dir)) {
        indices.splice(i, 1);
        break;
      }

  // Remove files in subdirectories of indices
  i = files.length;
  while (i-- > 0)
    for (j = 0, n = indices.length; j < n; j++)
      if (0 === files[i].path.indexOf(indices[j].dir)) {
        files.splice(i, 1);
        break;
      }

  // Denote indices as bundles
  indices.forEach(function(file) {
    file.bundle = true;
    file.ignored = [
      path.join(file.dir, "*"),
      file.dir + "." + ext
    ];
  });

  // Rejoin indices back into files
  return files.concat(indices);

};

/**

  Sorts and preprocesses files in a directory. Adds absolute and relative paths.

  @param {String} p Path to map
  @param {Object} [options.recursive] If true, processes recursively
  @param {Boolean} [options.bundleFolders] If true, automatically bundles appropriate folders
  @param {String} [options.type] The file type of the bundles (e.g. js)

**/

Utils.mapFiles = function(p, options) {

  var files, i, indices, results = [];
  options = options || {};

  // Make path absolute before call (for comparison after)
  p = Utils.makePathAbsolute(p);
  files = Utils.readDirectory(p, options.recursive, p);

  // Sort in reverse order so that directory calls come last
  files.sort(function(a, b) { return (a.path < b.path) ? -1 : (a.path > b.path) ? 1 : 0; }).reverse();

  // Move "index" to end so that routes are from specific to unspecific
  i = files.length;
  while (i-- > 0)
    if (Utils.isIndexFile(files[i]))
      Array.prototype.push.apply(files, files.splice(i, 1));

  // Remove subdirectory files if index.* is encountered
  if (options.bundleFolders) files = Utils.flagBundles(p, files, options.type);

  return files;

};

/**

  Parses a file name and adds additional information

**/

Utils.parse = function(p, base) {

  var parsed;

  p = Utils.makePathAbsolute(p);
  parsed = path.parse(p);

  // Get rid of leading dot for an extension
  parsed.ext = parsed.ext.replace(/^\./, "");
  parsed.path = p;

  if (base) {
    base = Utils.makePathAbsolute(base);
    parsed.basePath = base;
    parsed.folder = path.relative(base, parsed.path.replace(new RegExp(parsed.base + "$"), ""));
  }

  return parsed;

};

/**

  Creates appropriate routes for a file: for example, /about/index.html needs
  /about/, /about/index, and /about/index.html.

  Files named "template" are special cases and serve as wildcard route handlers.

  @param {String} baseRoute Base route from which to build
  @param {Stat} file File object (as returned from fs.lStat)
  @param {Object} options Options
  @param {String} [options.type] Default file type (e.g. js for coffee)
  @returns {Array} Array of route strings

**/

Utils.makeRoutes = function(baseRoute, file, options) {

  var re = /\/\/+$/,
      route,
      routes,
      ext;

  options = options || {};

  // By defaulting to file type, we address templating and transpiling. We can
  // resolve coffee files to js, etc. We also remove leading dot.
  ext = options.type || file.ext || "";
  ext = ext.replace(/^\./, "");

  // Create the file's route by appending the folder to the base route. This
  // process is prone to double "//", which must be removed.
  route = (url.resolve((baseRoute + "/").replace(re, "/"), file.folder) + "/").replace(re, "/");

  // HTML-like files named "template" pull their route from the parent directory
  // and pass the subsequent URL on as a "query" parameter. Note that $ are not
  // allowed in params.
  if (Utils.isTemplate(file, ext)) {
    route = route.split("/").slice(0, -1).join("/");
    return [route + "/" + (options.params || ":slug").replace(/^\//, "")];
  }

  // Add file and default extension
  routes = [url.resolve(route, file.name + "." + ext)];

  // HTML files are special: not only can they be accessed sans extension, if
  // they are named "index", we allow access via a folder.
  if ("html" === ext) {
    routes.push(url.resolve(route, file.name));
    if (Utils.isIndexFile(file)) routes.push(route);
  }

  return routes;

};

/**

  Reads all files in a directory

  @param {String} p Path to read
  @param {Boolean} recursive Whether to read recursively (default: true)
  @param [String] base Optional base path from which to parse

**/

Utils.readDirectory = function(p, recursive, base) {

  var results = [];

  // Set defaults
  if ("undefined" == typeof recursive) recursive = true;
  p = Utils.makePathAbsolute(p);

  // If directory doesn't exist, return nothing
  try {
    fs.lstatSync(p);
  } catch (err) {
    return results;
  }

  // Read in files
  fs.readdirSync(p).forEach(function(file) {

    var stats, parsed;

    // Read file and stats
    file = path.join(p, file);
    stats = fs.lstatSync(file);

    // Recursively walk directory, or add file
    if (stats.isDirectory()) {
      if (recursive)
        results = results.concat(Utils.readDirectory(file, true, base));
    } else {
      results.push(Utils.parse(file, base || p));
    }

  });

  return results;

};

/**

 Reads a limited number of characters from a file.

 @param {String} path Path to file
 @param {Number} chars Number of chars (defaults to 500)
 @returns {String} First characters for a file

**/

Utils.readFileHead = function(path, chars) {

  var buffer = new Buffer(chars || 500),
      file   = fs.openSync(path, "r"),
      str,
      len;

  // Read in file
  len = fs.readSync(file, buffer, 0, chars, 0);

  // Convert to lines, and discard any fragments
  // (so that we can use template engines without through errors)
  str = buffer.slice(0, len).toString().split("\n");

  return str.slice(0, str.length - 1).join("\n");

};

/**

  Returns all regex matches for an expression

  @param {String} str String to search
  @param {RegExp} pattern Pattern to search with
  @param {Number} [idx] Search component to use
  @returns {Array} Array of strings with matches

**/

Utils.getRegExpMatches = function(str, pattern, idx) {

  var match,
      matches = [];

  // Clone the RE and add global flag (otherwise has endless loop)
  pattern = new RegExp(pattern);
  pattern.global = true;

  // Set default idx
  idx = idx || 0;

  while ((match = pattern.exec(str)))
    matches.push(match[idx]);

  return matches;

};

/**

  Watches a directory via chokidar

  @param {String} sourceDir The source directory (without wildcards)
  @param {String} sourceExt The source extension (defaults to "*")
  @param {Object} [options.chokidar] Options to pass to chokidar
  @param {Function} [options.*] Event handlers (file, compiled) where * is name of event

**/

Utils.watch = reorg(function(sourceDir, sourceExt, options) {

  var p;

  // Don't watch in production
  if (Utils.isProduction()) return;

  // For source extension, if not wildcard, convert to "*.ext"
  if ("*" !== sourceExt) sourceExt = "*." + sourceExt.replace(/^[\*\.]+/g, "");

  // Ensure we have chokidar options and that chokidar's cwd is root
  p = Utils.makePathAbsolute(path.join(sourceDir, "**", sourceExt));
  options.chokidar = options.chokidar || {};
  options.chokidar.cwd = path.parse(p).root;

  chokidar.watch(p, options.chokidar).on("all", function(event, file) {

    var parsed, compiled;

    if (options[event] || options.all) {

      // File is missing root directory
      file = path.join(options.chokidar.cwd, file);

      // Map file to compiled version
      if (options.type) {
        parsed = path.parse(file);
        compiled = path.join(parsed.root, parsed.dir, parsed.name + "." + options.type);
      }

      // Callback
      if (options[event]) options[event](file, compiled);
      if (options.all) options.all(file, compiled);

    }

  });

}, "string!", ["string", "*"], "object");

/**

  Determines whether environment is production

  @returns {Boolean} True if is a production environment

**/

Utils.isProduction = function() {
  return /^prod/i.test(process.env.NODE_ENV);
};

/**

  Runs a sequence of promises, similar to when.js

  @param {Array} tasks Array of "tasks" (functions that return promises)
  @param {*} initial Initial value to call task with

**/

Utils.sequence = function(tasks, initial) {
  return Promise.reduce(tasks || [], function(val, task) {
    return task(val);
  }, initial);
};

/**

  Tests whether a file is a template (HTML-like and named properly)

  @param {Stats} file File as returned by fs.lstat
  @param {String} type The type of file extension
  @returns {Boolean} Returns true is is a template

**/

Utils.isTemplate = function(file, type) {
  return ("template" === file.name) && Utils.isHTML(type);
};

/**

  Tests whether a type is HTML-like

  @param {String} type Type of file
  @returns {Boolean} Returns true if is HTML-like

**/

Utils.isHTML = function(type) {
  return /^\*?\.?html?$/i.test(type);
};

/**

  Tests that an input is a non-array object.

  @param {*} input The item to check
  @returns {Boolean} Returns true if is an object, but not an array

**/

Utils.isPlainObject = function(input) {
  return ("object" == typeof input) && !Array.isArray(input);
};

/**

  Tests for an array of type

  @param {*} input The item to check
  @param {String} type The requisite type
  @returns {Boolean} Returns true if is an array of strings

**/

Utils.isArrayOfType = function(input, type) {
  if (!Array.isArray(input)) return false;
  for (var i = 0, n = input.length; i < n; i++)
    if (type !== typeof input[i]) return false;
  return true;
};

/**

  Traverses a JSON-object and calls function on each end point.

**/

Utils.traverse = function(obj, fn) {

  var key, val;

  for (key in obj) {
    val = obj[key];
    if ("string" === typeof val)
      fn(obj, key, val);
    else if (Utils.isPlainObject(val))
      Utils.traverse(val, fn);
  }

};

/**

  Escapes regex. From lodash.com by John Dalton.

  @param {String} str The string to escape

**/

Utils.escapeRegex = function(str) {
  return str.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
};

/**

  Compresses a string.

  @param {String} method The compression method
  @param {String} str The string to compress
  @param {Boolean} maxCompress If true, maximum compression level
  @param {Function} next Callback of form (err, compressed)

**/

Utils.compress = function(method, str, level, next) {

  var zip = ("gzip" === method) ? zlib.gzip : zlib.deflate;

  level = level ? zlib.Z_BEST_COMPRESSION : zlib.Z_DEFAULT_COMPRESSION;
  zip(str, { level : level }, next);

};

/**

  Sends a compressed or uncompressed response.

  @param {Response} res The response
  @param {String} type The file type
  @param {Buffer} buf The buffer to send
  @param {String} method The method to use

**/

Utils.send = function(res, type, buf, method) {

  res.type(type);

  if ("raw" === method || !method) {
    res.send(buf);
  } else {
    res.setHeader("Content-Encoding", method);
    res.removeHeader("Content-Length");
    res.send(buf);
  }

};
<commit_msg>Utils#send: changes "method" to "enc" (better name)<commit_after>/**

  Utils.js

  Various helper functions.

  • getRegExpMatches
  • isIndexFile
  • isProduction
  • makePathAbsolute
  • makeRoutes
  • mapFiles
  • readDirectory
  • readFileHead
  • sequence
  • uniqueExtensions
  • watch

**/

//
//  Dependencies
//

var fs       = require("fs"),
    url      = require("url"),
    path     = require("path"),
    chokidar = require("chokidar"),
    Promise  = require("bluebird"),
    reorg    = require("reorg"),
    zlib     = require("zlib"),
    Utils;

module.exports = Utils = {};

/**

  Makes a path absolute (if not already)

  @param {String} p Path
  @returns {String} Absolute path version of a string

**/

Utils.makePathAbsolute = function(p) {

  if (path.isAbsolute(p))
    return p;
  else
    return path.resolve(process.cwd(), p || "");

};

/**

  Tests to see if a file is of form "index*"

  @param {Stats} file File as returned by fs.lstat
  @returns {Boolean} true if a file is index-like

*/

Utils.isIndexFile = function(file) {
  return /^index[^\/]*$/i.test(file.name);
};

/**

  Retrieves all unique file extensions from a directory

  @param {String} p Directory path
  @returns {Array} Array of strings of extensions

**/

Utils.uniqueExtensions = function(p) {
  var exts = {};
  Utils.readDirectory(p).forEach(function(file) {
    if (file.ext && "" !== file.ext) exts[file.ext.toLowerCase()] = 1;
  });
  return Object.keys(exts);
};

/**

  Finds index files and marks as "bundles", then removes sibling and
  sub-diretories

  @param {String} p Absolute path
  @param {Array} files Array of file stats

**/

Utils.flagBundles = function(p, files, ext) {

  var indices = [],
      i, j, n;

  // Filter out index files (outside of master directory)
  i = files.length;
  while (i-- > 0)
    if ((p !== files[i].dir) && Utils.isIndexFile(files[i]))
      indices.push(files.splice(i, 1)[0]);

  // Remove indices that are subdirectories of each other
  i = indices.length;
  while (i-- > 0)
    for (j = 0, n = indices.length; j < n; j++)
      if (i !== j && 0 === indices[i].path.indexOf(indices[j].dir)) {
        indices.splice(i, 1);
        break;
      }

  // Remove files in subdirectories of indices
  i = files.length;
  while (i-- > 0)
    for (j = 0, n = indices.length; j < n; j++)
      if (0 === files[i].path.indexOf(indices[j].dir)) {
        files.splice(i, 1);
        break;
      }

  // Denote indices as bundles
  indices.forEach(function(file) {
    file.bundle = true;
    file.ignored = [
      path.join(file.dir, "*"),
      file.dir + "." + ext
    ];
  });

  // Rejoin indices back into files
  return files.concat(indices);

};

/**

  Sorts and preprocesses files in a directory. Adds absolute and relative paths.

  @param {String} p Path to map
  @param {Object} [options.recursive] If true, processes recursively
  @param {Boolean} [options.bundleFolders] If true, automatically bundles appropriate folders
  @param {String} [options.type] The file type of the bundles (e.g. js)

**/

Utils.mapFiles = function(p, options) {

  var files, i, indices, results = [];
  options = options || {};

  // Make path absolute before call (for comparison after)
  p = Utils.makePathAbsolute(p);
  files = Utils.readDirectory(p, options.recursive, p);

  // Sort in reverse order so that directory calls come last
  files.sort(function(a, b) { return (a.path < b.path) ? -1 : (a.path > b.path) ? 1 : 0; }).reverse();

  // Move "index" to end so that routes are from specific to unspecific
  i = files.length;
  while (i-- > 0)
    if (Utils.isIndexFile(files[i]))
      Array.prototype.push.apply(files, files.splice(i, 1));

  // Remove subdirectory files if index.* is encountered
  if (options.bundleFolders) files = Utils.flagBundles(p, files, options.type);

  return files;

};

/**

  Parses a file name and adds additional information

**/

Utils.parse = function(p, base) {

  var parsed;

  p = Utils.makePathAbsolute(p);
  parsed = path.parse(p);

  // Get rid of leading dot for an extension
  parsed.ext = parsed.ext.replace(/^\./, "");
  parsed.path = p;

  if (base) {
    base = Utils.makePathAbsolute(base);
    parsed.basePath = base;
    parsed.folder = path.relative(base, parsed.path.replace(new RegExp(parsed.base + "$"), ""));
  }

  return parsed;

};

/**

  Creates appropriate routes for a file: for example, /about/index.html needs
  /about/, /about/index, and /about/index.html.

  Files named "template" are special cases and serve as wildcard route handlers.

  @param {String} baseRoute Base route from which to build
  @param {Stat} file File object (as returned from fs.lStat)
  @param {Object} options Options
  @param {String} [options.type] Default file type (e.g. js for coffee)
  @returns {Array} Array of route strings

**/

Utils.makeRoutes = function(baseRoute, file, options) {

  var re = /\/\/+$/,
      route,
      routes,
      ext;

  options = options || {};

  // By defaulting to file type, we address templating and transpiling. We can
  // resolve coffee files to js, etc. We also remove leading dot.
  ext = options.type || file.ext || "";
  ext = ext.replace(/^\./, "");

  // Create the file's route by appending the folder to the base route. This
  // process is prone to double "//", which must be removed.
  route = (url.resolve((baseRoute + "/").replace(re, "/"), file.folder) + "/").replace(re, "/");

  // HTML-like files named "template" pull their route from the parent directory
  // and pass the subsequent URL on as a "query" parameter. Note that $ are not
  // allowed in params.
  if (Utils.isTemplate(file, ext)) {
    route = route.split("/").slice(0, -1).join("/");
    return [route + "/" + (options.params || ":slug").replace(/^\//, "")];
  }

  // Add file and default extension
  routes = [url.resolve(route, file.name + "." + ext)];

  // HTML files are special: not only can they be accessed sans extension, if
  // they are named "index", we allow access via a folder.
  if ("html" === ext) {
    routes.push(url.resolve(route, file.name));
    if (Utils.isIndexFile(file)) routes.push(route);
  }

  return routes;

};

/**

  Reads all files in a directory

  @param {String} p Path to read
  @param {Boolean} recursive Whether to read recursively (default: true)
  @param [String] base Optional base path from which to parse

**/

Utils.readDirectory = function(p, recursive, base) {

  var results = [];

  // Set defaults
  if ("undefined" == typeof recursive) recursive = true;
  p = Utils.makePathAbsolute(p);

  // If directory doesn't exist, return nothing
  try {
    fs.lstatSync(p);
  } catch (err) {
    return results;
  }

  // Read in files
  fs.readdirSync(p).forEach(function(file) {

    var stats, parsed;

    // Read file and stats
    file = path.join(p, file);
    stats = fs.lstatSync(file);

    // Recursively walk directory, or add file
    if (stats.isDirectory()) {
      if (recursive)
        results = results.concat(Utils.readDirectory(file, true, base));
    } else {
      results.push(Utils.parse(file, base || p));
    }

  });

  return results;

};

/**

 Reads a limited number of characters from a file.

 @param {String} path Path to file
 @param {Number} chars Number of chars (defaults to 500)
 @returns {String} First characters for a file

**/

Utils.readFileHead = function(path, chars) {

  var buffer = new Buffer(chars || 500),
      file   = fs.openSync(path, "r"),
      str,
      len;

  // Read in file
  len = fs.readSync(file, buffer, 0, chars, 0);

  // Convert to lines, and discard any fragments
  // (so that we can use template engines without through errors)
  str = buffer.slice(0, len).toString().split("\n");

  return str.slice(0, str.length - 1).join("\n");

};

/**

  Returns all regex matches for an expression

  @param {String} str String to search
  @param {RegExp} pattern Pattern to search with
  @param {Number} [idx] Search component to use
  @returns {Array} Array of strings with matches

**/

Utils.getRegExpMatches = function(str, pattern, idx) {

  var match,
      matches = [];

  // Clone the RE and add global flag (otherwise has endless loop)
  pattern = new RegExp(pattern);
  pattern.global = true;

  // Set default idx
  idx = idx || 0;

  while ((match = pattern.exec(str)))
    matches.push(match[idx]);

  return matches;

};

/**

  Watches a directory via chokidar

  @param {String} sourceDir The source directory (without wildcards)
  @param {String} sourceExt The source extension (defaults to "*")
  @param {Object} [options.chokidar] Options to pass to chokidar
  @param {Function} [options.*] Event handlers (file, compiled) where * is name of event

**/

Utils.watch = reorg(function(sourceDir, sourceExt, options) {

  var p;

  // Don't watch in production
  if (Utils.isProduction()) return;

  // For source extension, if not wildcard, convert to "*.ext"
  if ("*" !== sourceExt) sourceExt = "*." + sourceExt.replace(/^[\*\.]+/g, "");

  // Ensure we have chokidar options and that chokidar's cwd is root
  p = Utils.makePathAbsolute(path.join(sourceDir, "**", sourceExt));
  options.chokidar = options.chokidar || {};
  options.chokidar.cwd = path.parse(p).root;

  chokidar.watch(p, options.chokidar).on("all", function(event, file) {

    var parsed, compiled;

    if (options[event] || options.all) {

      // File is missing root directory
      file = path.join(options.chokidar.cwd, file);

      // Map file to compiled version
      if (options.type) {
        parsed = path.parse(file);
        compiled = path.join(parsed.root, parsed.dir, parsed.name + "." + options.type);
      }

      // Callback
      if (options[event]) options[event](file, compiled);
      if (options.all) options.all(file, compiled);

    }

  });

}, "string!", ["string", "*"], "object");

/**

  Determines whether environment is production

  @returns {Boolean} True if is a production environment

**/

Utils.isProduction = function() {
  return /^prod/i.test(process.env.NODE_ENV);
};

/**

  Runs a sequence of promises, similar to when.js

  @param {Array} tasks Array of "tasks" (functions that return promises)
  @param {*} initial Initial value to call task with

**/

Utils.sequence = function(tasks, initial) {
  return Promise.reduce(tasks || [], function(val, task) {
    return task(val);
  }, initial);
};

/**

  Tests whether a file is a template (HTML-like and named properly)

  @param {Stats} file File as returned by fs.lstat
  @param {String} type The type of file extension
  @returns {Boolean} Returns true is is a template

**/

Utils.isTemplate = function(file, type) {
  return ("template" === file.name) && Utils.isHTML(type);
};

/**

  Tests whether a type is HTML-like

  @param {String} type Type of file
  @returns {Boolean} Returns true if is HTML-like

**/

Utils.isHTML = function(type) {
  return /^\*?\.?html?$/i.test(type);
};

/**

  Tests that an input is a non-array object.

  @param {*} input The item to check
  @returns {Boolean} Returns true if is an object, but not an array

**/

Utils.isPlainObject = function(input) {
  return ("object" == typeof input) && !Array.isArray(input);
};

/**

  Tests for an array of type

  @param {*} input The item to check
  @param {String} type The requisite type
  @returns {Boolean} Returns true if is an array of strings

**/

Utils.isArrayOfType = function(input, type) {
  if (!Array.isArray(input)) return false;
  for (var i = 0, n = input.length; i < n; i++)
    if (type !== typeof input[i]) return false;
  return true;
};

/**

  Traverses a JSON-object and calls function on each end point.

**/

Utils.traverse = function(obj, fn) {

  var key, val;

  for (key in obj) {
    val = obj[key];
    if ("string" === typeof val)
      fn(obj, key, val);
    else if (Utils.isPlainObject(val))
      Utils.traverse(val, fn);
  }

};

/**

  Escapes regex. From lodash.com by John Dalton.

  @param {String} str The string to escape

**/

Utils.escapeRegex = function(str) {
  return str.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
};

/**

  Compresses a string.

  @param {String} method The compression method
  @param {String} str The string to compress
  @param {Boolean} maxCompress If true, maximum compression level
  @param {Function} next Callback of form (err, compressed)

**/

Utils.compress = function(method, str, level, next) {

  var zip = ("gzip" === method) ? zlib.gzip : zlib.deflate;

  level = level ? zlib.Z_BEST_COMPRESSION : zlib.Z_DEFAULT_COMPRESSION;
  zip(str, { level : level }, next);

};

/**

  Sends a compressed or uncompressed response.

  @param {Response} res The response
  @param {String} type The file type
  @param {Buffer} buf The buffer to send
  @param {String} enc The encoding to use

**/

Utils.send = function(res, type, buf, enc) {

  res.type(type);

  // Raw versus compressed
  if ("identity" === enc || !enc) {
    res.send(buf);
  } else {
    res.setHeader("Content-Encoding", enc);
    res.removeHeader("Content-Length");
    res.send(buf);
  }

};
<|endoftext|>