<commit_before>'use strict';

import { bind, unbind } from '@scola/bind';

export default class WebSocketWrapper {
  constructor(url, protocols, wsClass = WebSocket) {
    this._url = url;
    this._protocols = protocols;
    this._binaryType = typeof WebSocket === 'undefined' ?
      'nodebuffer' : 'blob';

    this._onclose = new Set();
    this._onopen = new Set();
    this._onerror = new Set();
    this._onmessage = new Set();

    this._class = wsClass;

    this._websocket = null;
    this._attempts = 0;
    this._timeout = null;

    this.maxAttempts = 10;
    this.codes = [1000, 1001, 1006];

    this.open();
  }

  open() {
    this._websocket = new this._class(this._url, this._protocols);
    this._websocket.binaryType = this._binaryType;
    this._bindSocket();
  }

  close(code, reason) {
    this._websocket.close(code, reason);
    this._unbindSocket();

    clearTimeout(this._timeout);

    this._websocket = null;
    this._attempts = 0;
    this._timeout = null;
  }

  send(data) {
    this._websocket.send(data);
  }

  addEventListener(type, listener) {
    this['_on' + type].add(listener);
  }

  removeEventListener(type, listener) {
    this['_on' + type].forEach((registered) => {
      if (registered === listener) {
        this['_on' + type].delete(listener);
      }
    });
  }

  _bindSocket() {
    bind(this, this._websocket, 'close', this._handleClose);
    bind(this, this._websocket, 'error', this._handleError);
    bind(this, this._websocket, 'message', this._handleMessage);
    bind(this, this._websocket, 'open', this._handleOpen);
  }

  _unbindSocket() {
    unbind(this, this._websocket, 'close', this._handleClose);
    unbind(this, this._websocket, 'error', this._handleError);
    unbind(this, this._websocket, 'message', this._handleMessage);
    unbind(this, this._websocket, 'open', this._handleOpen);
  }

  _handleOpen() {
    this._onopen.forEach((listener) => {
      listener(this._attempts);
    });

    this._attempts = 0;
  }

  _handleMessage(event) {
    this._onmessage.forEach((listener) => {
      listener(event);
    });
  }

  _handleError(event) {
    if (this._websocket.readyState === this._websocket.CLOSED) {
      return;
    }

    this._onerror.forEach((listener) => {
      listener(event);
    });
  }

  _handleClose(event) {
    if (typeof event === 'number') {
      event = {
        code: event,
        reason: arguments[1]
      };
    }

    this._unbindSocket();

    if (this._attempts === 0 || this._attempts === this.maxAttempts) {
      event.final = this._attempts === this.maxAttempts;

      this._onclose.forEach((listener) => {
        listener(event);
      });
    }

    if (this.codes.indexOf(event.code) !== -1 &&
      this._attempts < this.maxAttempts) {

      this._handleReconnect(event);
      return;
    }
  }

  _handleReconnect(event) {
    let delay = Math.pow(2, this._attempts);
    this._attempts += 1;

    if (event.reason) {
      const match = event.reason.match(/delay=(\d+)/);

      if (match) {
        delay = Number(match[1]);
      }
    }

    this._timeout = setTimeout(this.open.bind(this), delay * 1000);
  }

  get binaryType() {
    return this._websocket.binaryType;
  }

  set binaryType(binaryType) {
    this._binaryType = binaryType;
    this._websocket.binaryType = binaryType;
  }

  get bufferedAmount() {
    return this._websocket.bufferedAmount;
  }

  get extensions() {
    return this._websocket.extensions;
  }

  get onclose() {
    return [...this._onclose][0];
  }

  set onclose(listener) {
    this._onclose.clear();
    this._onclose.add(listener);
  }

  get onerror() {
    return [...this._onerror][0];
  }

  set onerror(listener) {
    this._onerror.clear();
    this._onerror.add(listener);
  }

  get onmessage() {
    return [...this._onmessage][0];
  }

  set onmessage(listener) {
    this._onmessage.clear();
    this._onmessage.add(listener);
  }

  get onopen() {
    return [...this._onopen][0];
  }

  set onopen(listener) {
    this._onopen.clear();
    this._onopen.add(listener);
  }

  get protocol() {
    return this._websocket.protocol;
  }

  get readyState() {
    return this._websocket.readyState;
  }

  get url() {
    return this._websocket.url;
  }

  get CONNECTING() {
    return this._websocket.CONNECTING;
  }

  get OPEN() {
    return this._websocket.OPEN;
  }

  get CLOSING() {
    return this._websocket.CLOSING;
  }

  get CLOSED() {
    return this._websocket.CLOSED;
  }
}
<commit_msg>Bind listeners with arrow functions<commit_after>export default class WebSocketWrapper {
  constructor(url, protocols, wsClass = WebSocket) {
    this._url = url;
    this._protocols = protocols;
    this._binaryType = typeof WebSocket === 'undefined' ?
      'nodebuffer' : 'blob';

    this._onclose = new Set();
    this._onopen = new Set();
    this._onerror = new Set();
    this._onmessage = new Set();

    this._class = wsClass;

    this._websocket = null;
    this._attempts = 0;
    this._timeout = null;

    this.maxAttempts = 10;
    this.codes = [1000, 1001, 1006];

    this._handleClose = (e) => this._close(e);
    this._handleError = (e) => this._error(e);
    this._handleMessage = (e) => this._message(e);
    this._handleOpen = (e) => this._open(e);

    this.open();
  }

  open() {
    this._websocket = new this._class(this._url, this._protocols);

    this._websocket.binaryType = this._binaryType;
    this._websocket.removeEventListener =
      this._websocket.removeEventListener || this._websocket.removeListener;

    this._bindSocket();
  }

  close(code, reason) {
    this._websocket.close(code, reason);
    this._unbindSocket();

    clearTimeout(this._timeout);

    this._websocket = null;
    this._attempts = 0;
    this._timeout = null;
  }

  send(data) {
    this._websocket.send(data);
  }

  addEventListener(type, listener) {
    this['_on' + type].add(listener);
  }

  addListener(type, listener) {
    this.addEventListener(type, listener);
  }

  removeEventListener(type, listener) {
    this['_on' + type].forEach((registered) => {
      if (registered === listener) {
        this['_on' + type].delete(listener);
      }
    });
  }

  removeListener(type, listener) {
    this.removeEventListener(type, listener);
  }

  _bindSocket() {
    this._websocket.addEventListener('close', this._handleClose);
    this._websocket.addEventListener('error', this._handleError);
    this._websocket.addEventListener('message', this._handleMessage);
    this._websocket.addEventListener('open', this._handleOpen);
  }

  _unbindSocket() {
    this._websocket.removeEventListener('close', this._handleClose);
    this._websocket.removeEventListener('error', this._handleError);
    this._websocket.removeEventListener('message', this._handleMessage);
    this._websocket.removeEventListener('open', this._handleOpen);
  }

  _open() {
    this._onopen.forEach((listener) => {
      listener(this._attempts);
    });

    this._attempts = 0;
  }

  _message(event) {
    this._onmessage.forEach((listener) => {
      listener(event);
    });
  }

  _error(event) {
    if (this._websocket.readyState === this._websocket.CLOSED) {
      return;
    }

    this._onerror.forEach((listener) => {
      listener(event);
    });
  }

  _close(event) {
    if (typeof event === 'number') {
      event = {
        code: event,
        reason: arguments[1]
      };
    }

    this._unbindSocket();

    if (this._attempts === 0 || this._attempts === this.maxAttempts) {
      event.final = this._attempts === this.maxAttempts;

      this._onclose.forEach((listener) => {
        listener(event);
      });
    }

    if (this.codes.indexOf(event.code) !== -1 &&
      this._attempts < this.maxAttempts) {

      this._reconnect(event);
      return;
    }
  }

  _reconnect(event) {
    let delay = Math.pow(2, this._attempts);
    this._attempts += 1;

    if (event.reason) {
      const match = event.reason.match(/delay=(\d+)/);

      if (match) {
        delay = Number(match[1]);
      }
    }

    this._timeout = setTimeout(() => this.open(), delay * 1000);
  }

  get binaryType() {
    return this._websocket.binaryType;
  }

  set binaryType(binaryType) {
    this._binaryType = binaryType;
    this._websocket.binaryType = binaryType;
  }

  get bufferedAmount() {
    return this._websocket.bufferedAmount;
  }

  get extensions() {
    return this._websocket.extensions;
  }

  get onclose() {
    return [...this._onclose][0];
  }

  set onclose(listener) {
    this._onclose.clear();
    this._onclose.add(listener);
  }

  get onerror() {
    return [...this._onerror][0];
  }

  set onerror(listener) {
    this._onerror.clear();
    this._onerror.add(listener);
  }

  get onmessage() {
    return [...this._onmessage][0];
  }

  set onmessage(listener) {
    this._onmessage.clear();
    this._onmessage.add(listener);
  }

  get onopen() {
    return [...this._onopen][0];
  }

  set onopen(listener) {
    this._onopen.clear();
    this._onopen.add(listener);
  }

  get protocol() {
    return this._websocket.protocol;
  }

  get readyState() {
    return this._websocket.readyState;
  }

  get url() {
    return this._websocket.url;
  }

  get CONNECTING() {
    return this._websocket.CONNECTING;
  }

  get OPEN() {
    return this._websocket.OPEN;
  }

  get CLOSING() {
    return this._websocket.CLOSING;
  }

  get CLOSED() {
    return this._websocket.CLOSED;
  }
}
<|endoftext|>


<commit_before>var SockJS = require('node-sockjs-client');

function Websocket(apiUrl, apiAuthToken) {
  this._jobList = {};
  this.connect(apiUrl + '/websocket', apiAuthToken);
}

Websocket.prototype.connect = function(url, authToken) {
  var sock = new SockJS(url);
  if (authToken) {
    sock.onopen = function() {
      return sock.send(JSON.stringify({
        token: authToken
      }));
    };
  }

  sock.onmessage = function(msg) {
    var data = JSON.parse(msg.data);
    if (this._isJobEvent(data.event)) {
      var jobData = data.job;
      var job = this._jobList[jobData.id];
      if (!job) {
        return;
      }
      job.setData(jobData);

      switch (data.event) {
        case 'job.change':
          this.updateJob(job);
          break;
        case 'job.close':
          this.closeJob(job);
          break;
      }
    }
  }.bind(this);

  sock.onclose = function() {
    this.connect(url, authToken);
  }.bind(this);
};

Websocket.prototype._isJobEvent = function(event) {
  return event.indexOf('job.') === 0;
};

Websocket.prototype.updateJob = function(job) {
  job.emit('change');
};

Websocket.prototype.closeJob = function(job) {
  delete this._jobList[job.data.id];
  if ('FINISHED' === job.data.status) {
    job.emit('success');
  } else {
    job.emit('error', 'Job finished with status `' + job.data.status + '`.');
  }
};

Websocket.prototype.addJob = function(job) {
  this._jobList[job.data.id] = job;
};

module.exports = Websocket;
<commit_msg>Fix sockjs-client import<commit_after>var SockJS = require('sockjs-client');

function Websocket(apiUrl, apiAuthToken) {
  this._jobList = {};
  this.connect(apiUrl + '/websocket', apiAuthToken);
}

Websocket.prototype.connect = function(url, authToken) {
  var sock = new SockJS(url);
  if (authToken) {
    sock.onopen = function() {
      return sock.send(JSON.stringify({
        token: authToken
      }));
    };
  }

  sock.onmessage = function(msg) {
    var data = JSON.parse(msg.data);
    if (this._isJobEvent(data.event)) {
      var jobData = data.job;
      var job = this._jobList[jobData.id];
      if (!job) {
        return;
      }
      job.setData(jobData);

      switch (data.event) {
        case 'job.change':
          this.updateJob(job);
          break;
        case 'job.close':
          this.closeJob(job);
          break;
      }
    }
  }.bind(this);

  sock.onclose = function() {
    this.connect(url, authToken);
  }.bind(this);
};

Websocket.prototype._isJobEvent = function(event) {
  return event.indexOf('job.') === 0;
};

Websocket.prototype.updateJob = function(job) {
  job.emit('change');
};

Websocket.prototype.closeJob = function(job) {
  delete this._jobList[job.data.id];
  if ('FINISHED' === job.data.status) {
    job.emit('success');
  } else {
    job.emit('error', 'Job finished with status `' + job.data.status + '`.');
  }
};

Websocket.prototype.addJob = function(job) {
  this._jobList[job.data.id] = job;
};

module.exports = Websocket;
<|endoftext|>


<commit_before>/**
 * Philip Crotwell
 * University of South Carolina, 2016
 * http://www.seis.sc.edu
 */

import * as miniseed from 'seisplotjs-miniseed';
import * as RSVP from 'rsvp';
import moment from 'moment';

/* reexport */
export { miniseed };

RSVP.on('error', function(reason) {
  console.assert(false, reason);
});

export class SeedlinkConnection {

  /** creates a seedlink connection to the given url.
    * requestConfig is an array of seedlink commands
    * like:
    *   [ 'STATION JSC CO',
    *     'SELECT 00BHZ.D' ]
    * and receiveMiniseedFn is the callback function that
    * will be invoked for each seedlink packet received
    * which contains 'sequence', a sequence number
    * and 'miniseed', a single miniseed record.
    * The connection is not made until the connect() method is called.
    */
  constructor(url, requestConfig, receiveMiniseedFn, errorFn) {
    this.url = url;
    this.requestConfig = requestConfig;
    this.receiveMiniseedFn = receiveMiniseedFn;
    this.errorFn = errorFn;
    this.command = 'DATA';
  }

  setTimeCommand(startDate) {
    this.command = "TIME "+moment(startDate).format("YYYY,MM,DD,HH,mm,ss");
  }

  connect() {
    this.webSocket = new WebSocket(this.url, "seedlink");
//    this.webSocket.onmessage(this.handle);
    this.webSocket.binaryType = 'arraybuffer';
    const that = this;
    this.webSocket.onopen = function(event) {
      console.log("In onopen");
      that.sendHello(that.webSocket)
      .then(function(val) {
        return that.sendCmdArray(that.webSocket, that.requestConfig);
      })
      .then(function(val) {
        console.log("before send "+that.command);
        return that.sendCmdArray(that.webSocket, [ that.command ]);
      })
      .then(function(val) {
        console.log("wait for miniseed ");
        that.webSocket.onmessage = function(event) {
          that.handle(event);
        };
        that.webSocket.send('END\r');
        return val;
      }, function(err) {
        console.log("reject: "+err);
        that.close();
      });
    };
  }

  close() {
    console.log("Closing webSocket.");
    if (this.webSocket) {
      this.webSocket.close();
    }
  }

  handle(event) {
    if (event.data.byteLength < 64) {
      //assume text
      console.log("handle text: "+event.data.byteLength+" "+arrayBufferToString(event.data));
    } else {
console.log("handle miniseed: "+event.data.byteLength);
      this.handleMiniseed(event);
    }
  }

  handleMiniseed(event) {
    try {
       // let arrBuf = new ArrayBuffer(event.data);
        if (event.data.byteLength < 64) {
          errorFn("message too small to be miniseed: "+event.data.byteLength +" "+arrayBufferToString(event.data));
console.log("message too small to be miniseed: "+event.data.byteLength);
          return;
        }
        let slHeader = new DataView(event.data, 0, 8);
        // check for 'SL' at start
        if (slHeader.getInt8(0) === 83 && slHeader.getInt8(1) === 76) {
          let seqStr = '';
          for (let i=0; i<6; i++) {
            seqStr = seqStr + String.fromCharCode(slHeader.getInt8(2+i));
          }
          let dataView = new DataView(event.data, 8, event.data.byteLength-8);
          let out = {
            rawsequence: seqStr,
            sequence: parseInt(seqStr, 16),
            miniseed: new miniseed.DataRecord(dataView)
          }
          this.receiveMiniseedFn(out);
        } else {
          errorFn("Not a seedlink packet, no starting SL: "+slHeader.getInt8(0)+' '+slHeader.getInt8(1));
        }
     } catch(e) {
console.log("catch "+e);
        this.close();
     }
  }

  sendHello(webSocket) {
console.log("in sendHello");
  let promise = new RSVP.Promise(function(resolve, reject) {
console.log('in sendHello promise');
    webSocket.onmessage = function(event) {
      console.log("msg: "+event);
      let replyMsg = arrayBufferToString(event.data);
      console.log("HELLO resp: "+replyMsg);
      let lines = replyMsg.trim().split('\r');
      if (lines.length == 2) {
        resolve(lines);
      } else {
        reject("not 2 lines: "+replyMsg);
      }
    };
console.log("send HELLO");
    webSocket.send("HELLO\r");
  });
  return promise;
}

  sendCmdArray(webSocket, cmd) {
    console.log('in sendCmdArray');
    let that = this;
    return cmd.reduce(function(cur, next) {
      return cur.then(function() {
        return that.createCmdPromise(webSocket, next);
      });
    }, RSVP.resolve());
  }

  createCmdPromise(webSocket, mycmd) {
console.log("create cmd promise for "+mycmd+" "+webSocket);
    let promise = new RSVP.Promise(function(resolve, reject) {
      console.log("my cmd: "+mycmd);
      webSocket.onmessage = function(event) {
        let replyMsg = arrayBufferToString(event.data).trim();
        console.log("resp: "+replyMsg);
        if (replyMsg === 'OK') {
console.log("sendCmd "+mycmd+" resp is OK");
          resolve(replyMsg);
        } else {
console.log("sendCmd "+mycmd+" resp is NOT ok "+replyMsg);
          reject("msg not OK: "+replyMsg);
        }
      }
      console.log("seedlink send cmd: "+mycmd);
      webSocket.send(mycmd+'\r\n');
    });
    return promise;
  }
};

export function arrayBufferToString(arrBuf) {
  let dataView = new DataView(arrBuf);
  let out = "";
  for (let i=0; i< dataView.byteLength; i++) {
    out += String.fromCharCode(dataView.getUint8(i));
  }
  return out;
};
<commit_msg>do not send protocol string until/if server supports it, causes chrome to not work<commit_after>/**
 * Philip Crotwell
 * University of South Carolina, 2016
 * http://www.seis.sc.edu
 */

import * as miniseed from 'seisplotjs-miniseed';
import * as RSVP from 'rsvp';
import moment from 'moment';

/* reexport */
export { miniseed };

RSVP.on('error', function(reason) {
  console.assert(false, reason);
});

export class SeedlinkConnection {

  /** creates a seedlink connection to the given url.
    * requestConfig is an array of seedlink commands
    * like:
    *   [ 'STATION JSC CO',
    *     'SELECT 00BHZ.D' ]
    * and receiveMiniseedFn is the callback function that
    * will be invoked for each seedlink packet received
    * which contains 'sequence', a sequence number
    * and 'miniseed', a single miniseed record.
    * The connection is not made until the connect() method is called.
    */
  constructor(url, requestConfig, receiveMiniseedFn, errorFn) {
    this.url = url;
    this.requestConfig = requestConfig;
    this.receiveMiniseedFn = receiveMiniseedFn;
    this.errorFn = errorFn;
    this.command = 'DATA';
  }

  setTimeCommand(startDate) {
    this.command = "TIME "+moment(startDate).format("YYYY,MM,DD,HH,mm,ss");
  }

  connect() {
//    this.webSocket = new WebSocket(this.url, "seedlink");
    this.webSocket = new WebSocket(this.url);
//    this.webSocket.onmessage(this.handle);
    this.webSocket.binaryType = 'arraybuffer';
    const that = this;
    this.webSocket.onopen = function(event) {
      console.log("In onopen");
      that.sendHello(that.webSocket)
      .then(function(val) {
        return that.sendCmdArray(that.webSocket, that.requestConfig);
      })
      .then(function(val) {
        console.log("before send "+that.command);
        return that.sendCmdArray(that.webSocket, [ that.command ]);
      })
      .then(function(val) {
        console.log("wait for miniseed ");
        that.webSocket.onmessage = function(event) {
          that.handle(event);
        };
        that.webSocket.send('END\r');
        return val;
      }, function(err) {
        console.log("reject: "+err);
        that.close();
      });
    };
  }

  close() {
    console.log("Closing webSocket.");
    if (this.webSocket) {
      this.webSocket.close();
    }
  }

  handle(event) {
    if (event.data.byteLength < 64) {
      //assume text
      console.log("handle text: "+event.data.byteLength+" "+arrayBufferToString(event.data));
    } else {
console.log("handle miniseed: "+event.data.byteLength);
      this.handleMiniseed(event);
    }
  }

  handleMiniseed(event) {
    try {
       // let arrBuf = new ArrayBuffer(event.data);
        if (event.data.byteLength < 64) {
          errorFn("message too small to be miniseed: "+event.data.byteLength +" "+arrayBufferToString(event.data));
console.log("message too small to be miniseed: "+event.data.byteLength);
          return;
        }
        let slHeader = new DataView(event.data, 0, 8);
        // check for 'SL' at start
        if (slHeader.getInt8(0) === 83 && slHeader.getInt8(1) === 76) {
          let seqStr = '';
          for (let i=0; i<6; i++) {
            seqStr = seqStr + String.fromCharCode(slHeader.getInt8(2+i));
          }
          let dataView = new DataView(event.data, 8, event.data.byteLength-8);
          let out = {
            rawsequence: seqStr,
            sequence: parseInt(seqStr, 16),
            miniseed: new miniseed.DataRecord(dataView)
          }
          this.receiveMiniseedFn(out);
        } else {
          errorFn("Not a seedlink packet, no starting SL: "+slHeader.getInt8(0)+' '+slHeader.getInt8(1));
        }
     } catch(e) {
console.log("catch "+e);
        this.close();
     }
  }

  sendHello(webSocket) {
console.log("in sendHello");
  let promise = new RSVP.Promise(function(resolve, reject) {
console.log('in sendHello promise');
    webSocket.onmessage = function(event) {
      console.log("msg: "+event);
      let replyMsg = arrayBufferToString(event.data);
      console.log("HELLO resp: "+replyMsg);
      let lines = replyMsg.trim().split('\r');
      if (lines.length == 2) {
        resolve(lines);
      } else {
        reject("not 2 lines: "+replyMsg);
      }
    };
console.log("send HELLO");
    webSocket.send("HELLO\r");
  });
  return promise;
}

  sendCmdArray(webSocket, cmd) {
    console.log('in sendCmdArray');
    let that = this;
    return cmd.reduce(function(cur, next) {
      return cur.then(function() {
        return that.createCmdPromise(webSocket, next);
      });
    }, RSVP.resolve());
  }

  createCmdPromise(webSocket, mycmd) {
console.log("create cmd promise for "+mycmd+" "+webSocket);
    let promise = new RSVP.Promise(function(resolve, reject) {
      console.log("my cmd: "+mycmd);
      webSocket.onmessage = function(event) {
        let replyMsg = arrayBufferToString(event.data).trim();
        console.log("resp: "+replyMsg);
        if (replyMsg === 'OK') {
console.log("sendCmd "+mycmd+" resp is OK");
          resolve(replyMsg);
        } else {
console.log("sendCmd "+mycmd+" resp is NOT ok "+replyMsg);
          reject("msg not OK: "+replyMsg);
        }
      }
      console.log("seedlink send cmd: "+mycmd);
      webSocket.send(mycmd+'\r\n');
    });
    return promise;
  }
};

export function arrayBufferToString(arrBuf) {
  let dataView = new DataView(arrBuf);
  let out = "";
  for (let i=0; i< dataView.byteLength; i++) {
    out += String.fromCharCode(dataView.getUint8(i));
  }
  return out;
};
<|endoftext|>


<commit_before>'use strict'

const fs = require('fs')
const path = require('path')
const _ = require('lodash')
const mkdirp = require('mkdirp')
const rimraf = require('rimraf')
const async = require('async')

class Directory {

    constructor (root, stat) {
        this.type = 0

        this.root = root
        this.stat = stat || fs.statSync(root)

        return this
    }

    ensure (mode) {
        return mkdirp.sync(this.root, mode || '0770')
    }

    move (newPath) {
        _.forEach(this.getItems(), (files, dirPath) => {
            let revPath = path.relative(this.root + '/..', dirPath)
            let newRevPath = path.resolve(newPath, revPath)

            _.forEach(files, (oldFilePath) => {
                let fileName = path.basename(oldFilePath)
                let newFilePath = path.join(newRevPath, fileName)
                let newDirPath = path.dirname(newFilePath)

                mkdirp.sync(newDirPath, '0770')
                fs.renameSync(oldFilePath, newFilePath)
            })
        })
        return rimraf.sync(this.root)
    }

    moveAsync (newPath, done = _.noop) {
        return async.parallel(_.map(this.getItems(), (files, dirPath) => {
            let revPath = path.relative(this.root + '/..', dirPath)
            let newRevPath = path.resolve(newPath, revPath)

            return (callback) => {
                return async.parallel(_.map(files, (oldFilePath) => {
                    let fileName = path.basename(oldFilePath)
                    let newFilePath = path.join(newRevPath, fileName)
                    let newDirPath = path.dirname(newFilePath)

                    return (cb) => {
                        return mkdirp(newDirPath, { mode: '0770' }, (error) => {
                            if (error) return cb(error)
                            return fs.rename(oldFilePath, newFilePath, cb)
                        })
                    }
                }), callback)
            }
        }), (error, results) => {
            return rimraf(this.root, () => done(error, results))
        })
    }

    delete () {
        return rimraf.sync(this.root)
    }

    deleteAsync (done = _.noop) {
        return rimraf(this.root, done)
    }

    joinPaths (dirs) {
        dirs = _.chain(arguments)
            .toArray()
            .compact()
            .flatten()
            .value()
        dirs.unshift(this.root)
        return path.join.apply(this, dirs)
    }

    getChildItems (filter) {
        var _super = this
        return _(fs.readdirSync(this.root))
            .chain()
            .map(function(item) {
                return path.resolve(process.cwd(), _super.root, item)
            })
            .filter(function(item) {
                return _super._parseFilter(filter, item)
            })
            .value()
    }

    getItems (filter, options) {
        options = (options || {})
        _.defaults(options, {
            excludes: ['\\.git', '\\.svn', 'node_modules'],
            deep: Number.MAX_VALUE
        })

        var _super = this, directoryItems = {}, level = 1
        var excludePattern = '.*('+options.excludes.join('|')+').*'

        return (function collectItems(srcPath) {
            var level = _.chain(
                path.relative(_super.root, srcPath).split(path.sep)
            ).compact().size().value()

            if (level >= options.deep) return

            var items = (new Directory(srcPath)).getChildItems(true)

            directoryItems[srcPath] = _.filter(items, function(item) {
                return fs.statSync(item).isFile() && _super._parseFilter(filter, item)
            })

            var directories = _.filter(items, function(item) {
                return fs.statSync(item).isDirectory()
                    && _.isEqual(new RegExp(excludePattern, 'g').test(item), false)
            })

            _.forEach(directories, collectItems)
            return directoryItems
        })(this.root)
    }

    _parseFilter (filter, item) {
        if (_.isFunction(filter)) return _(filter(item)).isEqual(true)
        if (_.isRegExp(filter)) return (new RegExp(filter)).test(item)
        return true
    }
}

module.exports = Directory
<commit_msg>update<commit_after>'use strict'

const fs = require('fs')
const path = require('path')
const _ = require('lodash')
const mkdirp = require('mkdirp')
const rimraf = require('rimraf')
const async = require('async')

class Directory {

    constructor (root, stat) {
        this.type = 0

        this.root = root
        this.stat = stat || fs.statSync(root)

        return this
    }

    ensure (mode) {
        return mkdirp.sync(this.root, mode || '0770')
    }

    rename (newName) {
        let dirPath = path.dirname(this.root)
        let newPath = path.join(dirPath, newName)
        return fs.renameSync(this.root, newPath)
    }

    renameAsync (newName, done = _.noop) {
        let dirPath = path.dirname(this.root)
        let newPath = path.join(dirPath, newName)
        return fs.rename(this.root, newPath, done)
    }

    move (newPath) {
        _.forEach(this.getItems(), (files, dirPath) => {
            let revPath = path.relative(this.root + '/..', dirPath)
            let newRevPath = path.resolve(newPath, revPath)

            _.forEach(files, (oldFilePath) => {
                let fileName = path.basename(oldFilePath)
                let newFilePath = path.join(newRevPath, fileName)
                let newDirPath = path.dirname(newFilePath)

                mkdirp.sync(newDirPath, '0770')
                fs.renameSync(oldFilePath, newFilePath)
            })
        })
        return rimraf.sync(this.root)
    }

    moveAsync (newPath, done = _.noop) {
        return async.parallel(_.map(this.getItems(), (files, dirPath) => {
            let revPath = path.relative(this.root + '/..', dirPath)
            let newRevPath = path.resolve(newPath, revPath)

            return (callback) => {
                return async.parallel(_.map(files, (oldFilePath) => {
                    let fileName = path.basename(oldFilePath)
                    let newFilePath = path.join(newRevPath, fileName)
                    let newDirPath = path.dirname(newFilePath)

                    return (cb) => {
                        return mkdirp(newDirPath, { mode: '0770' }, (error) => {
                            if (error) return cb(error)
                            return fs.rename(oldFilePath, newFilePath, cb)
                        })
                    }
                }), callback)
            }
        }), (error, results) => {
            return rimraf(this.root, () => done(error, results))
        })
    }

    delete () {
        return rimraf.sync(this.root)
    }

    deleteAsync (done = _.noop) {
        return rimraf(this.root, done)
    }

    joinPaths (dirs) {
        dirs = _.chain(arguments)
            .toArray()
            .compact()
            .flatten()
            .value()
        dirs.unshift(this.root)
        return path.join.apply(this, dirs)
    }

    getChildItems (filter) {
        var _super = this
        return _(fs.readdirSync(this.root))
            .chain()
            .map(function(item) {
                return path.resolve(process.cwd(), _super.root, item)
            })
            .filter(function(item) {
                return _super._parseFilter(filter, item)
            })
            .value()
    }

    getItems (filter, options) {
        options = (options || {})
        _.defaults(options, {
            excludes: ['\\.git', '\\.svn', 'node_modules'],
            deep: Number.MAX_VALUE
        })

        var _super = this, directoryItems = {}, level = 1
        var excludePattern = '.*('+options.excludes.join('|')+').*'

        return (function collectItems(srcPath) {
            var level = _.chain(
                path.relative(_super.root, srcPath).split(path.sep)
            ).compact().size().value()

            if (level >= options.deep) return

            var items = (new Directory(srcPath)).getChildItems(true)

            directoryItems[srcPath] = _.filter(items, function(item) {
                return fs.statSync(item).isFile() && _super._parseFilter(filter, item)
            })

            var directories = _.filter(items, function(item) {
                return fs.statSync(item).isDirectory()
                    && _.isEqual(new RegExp(excludePattern, 'g').test(item), false)
            })

            _.forEach(directories, collectItems)
            return directoryItems
        })(this.root)
    }

    _parseFilter (filter, item) {
        if (_.isFunction(filter)) return _(filter(item)).isEqual(true)
        if (_.isRegExp(filter)) return (new RegExp(filter)).test(item)
        return true
    }
}

module.exports = Directory
<|endoftext|>


<commit_before>"use strict";

var dns = require('dns');
var stream = require('stream');
var util = require('util');

var vasync = require('vasync');

var DNSBLQuery = require('./dnsbl');

function DNSFilter(config) {
  if (!(this instanceof DNSFilter))
    return new DNSFilter(config);

  stream.Transform.call(this, {
    objectMode: true,
    highWaterMark: 0,
  });

  this.dnsfltr_config = config.dnsbl;
}
util.inherits(DNSFilter, stream.Transform);

DNSFilter.prototype._transform = function dnsfltrTransform(client, enc, cb) {
  var self = this;

  var work = vasync.parallel({
    funcs: [
      function reverseDns(next) {
        dns.reverse(client.remoteAddress, next);
      },
      function dnsblQuery(next) {
        DNSBLQuery({
          ip: client.remoteAddress,
          servers: self.dnsfltr_config.servers,
        }, next);
      },
    ],
  }, function (err, results) {
    var reverse = results.operations[0].result;

    if (reverse && reverse.length)
      client.hostname = reverse[0];
    else
      client.hostname = client.remoteAddress;

    var score = results.operations[1].result;

    if (score) {
      client.score = score.total;

      if (score.total > self.dnsfltr_config.maxScore) {
        console.error('client exceeded dnsbl score', score.total, 'max of',
          self.dnsfltr_config.maxScore);
        client.end('Administratively refused');
        return client.destroy();
      }

      if (score.cloak)
        client.cloak = score.cloak;

      client.isTor = !!score.isTor;
    }

    self.push(client);
  });

  return cb();
};

module.exports = DNSFilter;
<commit_msg>report dnsfilter reasons<commit_after>"use strict";

var dns = require('dns');
var stream = require('stream');
var util = require('util');

var vasync = require('vasync');

var DNSBLQuery = require('./dnsbl');

function DNSFilter(config) {
  if (!(this instanceof DNSFilter))
    return new DNSFilter(config);

  stream.Transform.call(this, {
    objectMode: true,
    highWaterMark: 0,
  });

  this.dnsfltr_config = config.dnsbl;
}
util.inherits(DNSFilter, stream.Transform);

DNSFilter.prototype._transform = function dnsfltrTransform(client, enc, cb) {
  var self = this;

  var work = vasync.parallel({
    funcs: [
      function reverseDns(next) {
        dns.reverse(client.remoteAddress, next);
      },
      function dnsblQuery(next) {
        DNSBLQuery({
          ip: client.remoteAddress,
          servers: self.dnsfltr_config.servers,
        }, next);
      },
    ],
  }, function (err, results) {
    var reverse = results.operations[0].result;

    if (reverse && reverse.length)
      client.hostname = reverse[0];
    else
      client.hostname = client.remoteAddress;

    var score = results.operations[1].result;

    if (score) {
      client.score = score.total;

      if (score.total > self.dnsfltr_config.maxScore) {
        console.error('client', client.remoteAddress,
                      'exceeded dnsbl score', score.total, 'max of',
                      self.dnsfltr_config.maxScore, 'reasons:',
                      score.reasons.join('|'));
        client.end('Administratively refused');
        return client.destroy();
      }

      if (score.cloak)
        client.cloak = score.cloak;

      client.isTor = !!score.isTor;
    }

    self.push(client);
  });

  return cb();
};

module.exports = DNSFilter;
<|endoftext|>


<commit_before>function Document(children) {
    return {
        type: "document",
        children: children
    };
}

function Paragraph(children, properties) {
    properties = properties || {};
    return {
        type: "paragraph",
        children: children,
        styleName: properties.styleName || null,
        numbering: properties.numbering || null
    };
}

function Run(children, properties) {
    properties = properties || {};
    return {
        type: "run",
        children: children,
        styleName: properties.styleName || null,
        isBold: properties.isBold,
        isItalic: properties.isItalic,
        alignment: properties.alignment || null
    };
}

function Text(value) {
    return {
        type: "text",
        value: value
    };
}

function Tab(value) {
    return {
        type: "tab"
    };
}

function Hyperlink(children, options) {
    return {
        type: "hyperlink",
        children: children,
        href: options.href
    };
}

function ElementWithChildren(type) {
    return function(children, properties) {
        return {
            type: type,
            children: children,
            properties: properties || {}
        };
    };
}

function Image(options) {
    return {
        type: "image",
        read: options.readImage,
        altText: options.altText,
        contentType: options.contentType
    };
}

exports.Document = Document;
exports.Paragraph = Paragraph;
exports.Run = Run;
exports.Text = Text;
exports.Tab = Tab;
exports.Hyperlink = Hyperlink;
exports.Image = Image;
<commit_msg>Fixing initialization of "alignment" to paragraphs from runs<commit_after>function Document(children) {
    return {
        type: "document",
        children: children
    };
}

function Paragraph(children, properties) {
    properties = properties || {};
    return {
        type: "paragraph",
        children: children,
        styleName: properties.styleName || null,
        numbering: properties.numbering || null,
        alignment: properties.alignment || null
    };
}

function Run(children, properties) {
    properties = properties || {};
    return {
        type: "run",
        children: children,
        styleName: properties.styleName || null,
        isBold: properties.isBold,
        isItalic: properties.isItalic
    };
}

function Text(value) {
    return {
        type: "text",
        value: value
    };
}

function Tab(value) {
    return {
        type: "tab"
    };
}

function Hyperlink(children, options) {
    return {
        type: "hyperlink",
        children: children,
        href: options.href
    };
}

function ElementWithChildren(type) {
    return function(children, properties) {
        return {
            type: type,
            children: children,
            properties: properties || {}
        };
    };
}

function Image(options) {
    return {
        type: "image",
        read: options.readImage,
        altText: options.altText,
        contentType: options.contentType
    };
}

exports.Document = Document;
exports.Paragraph = Paragraph;
exports.Run = Run;
exports.Text = Text;
exports.Tab = Tab;
exports.Hyperlink = Hyperlink;
exports.Image = Image;
<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = function(window, pending, execUser) {
  window.nextTick = function(callback) {
    // Not cancelable, so no advantage to giving a proper identifier
    pending.push('nextTick', 1, function() {});
    process.nextTick(function() {
      pending.pop('nextTick', 1);
      execUser(callback);
    });
  };

  window.setTimeout = function(callback, timeout/*, [args...]*/ ) {
    // Implement parameter passing. This is not supported by node's native implemention
    // so we have to implement it ourselves.
    if (arguments.length > 2) {
      var args = _.toArray(arguments);
      args[1] = window;
      callback = _.bind.apply(_, args);
    }

    timeout = setTimeout(function() {
      pending.pop('timeout', timeout);
      execUser(callback);
    }, timeout);

    pending.push('timeout', timeout, function() {
      clearTimeout(timeout);
    });
    return timeout;
  };
  window.clearTimeout = function(timeout) {
    pending.cancel('timeout', timeout, true);
  };

  window.setImmediate = function(callback) {
    var id = setImmediate(function() {
      pending.pop('immediate', id);
      execUser(callback);
    });

    pending.push('immediate', id, function() {
      clearImmediate(id);
    });
    return id;
  };
  window.clearImmediate = function(id) {
    pending.cancel('immediate', id, true);
  };
};
<commit_msg>Simplify setTimeout implementation<commit_after>var _ = require('lodash');

module.exports = function(window, pending, execUser) {
  window.nextTick = function(callback) {
    // Not cancelable, so no advantage to giving a proper identifier
    pending.push('nextTick', 1, function() {});
    process.nextTick(function() {
      pending.pop('nextTick', 1);
      execUser(callback);
    });
  };

  window.setTimeout = function(callback /*, timeout, [args...]*/ ) {
    // Remap the callback with our own callback to ensure proper event loop tracking
    var args = _.toArray(arguments);
    args[0] = function() {
      pending.pop('timeout', timeout);

      var args = arguments;
      execUser(function() {
        callback.apply(this, args);
      });
    };

    var timeout = setTimeout.apply(this, args);

    pending.push('timeout', timeout, function() {
      clearTimeout(timeout);
    });
    return timeout;
  };
  window.clearTimeout = function(timeout) {
    pending.cancel('timeout', timeout, true);
  };

  window.setImmediate = function(callback) {
    var id = setImmediate(function() {
      pending.pop('immediate', id);
      execUser(callback);
    });

    pending.push('immediate', id, function() {
      clearImmediate(id);
    });
    return id;
  };
  window.clearImmediate = function(id) {
    pending.cancel('immediate', id, true);
  };
};
<|endoftext|>


<commit_before>'use strict';

/** @jsx React.DOM */
var React = require('react/addons');
var invariant = require('react/lib/invariant');
var emptyFunction = require('react/lib/emptyFunction');

function createUIEvent(draggable) {
	return {
		position: {
			top: draggable.state.clientY,
			left: draggable.state.clientX
		}
	};
}

function canDragY(draggable) {
	return draggable.props.axis === 'both' ||
			draggable.props.axis === 'y';
}

function canDragX(draggable) {
	return draggable.props.axis === 'both' ||
			draggable.props.axis === 'x';
}

function isFunction(fn) {
	return typeof fn === 'function';
}

function matchesSelector(el, selector) {
	if (isFunction(el.matches)) {
		return el.matches(selector);
	} else if (isFunction(el.webkitMatchesSelector)) {
		return el.webkitMatchesSelector(selector);
	} else if (isFunction(el.mozMatchesSelector)) {
		return el.mozMatchesSelector(selector);
	} else if (isFunction(el.msMatchesSelector)) {
		return el.msMatchesSelector(selector);
	} else if (isFunction(el.oMatchesSelector)) {
		return el.oMatchesSelector(selector);
	} else if (isFunction(el.webkitMatchesSelector)) {
		return el.webkitMatchesSelector(selector);
	}
}

function addEvent(el, event, handler) {
	if (!el) { return; }
	if (el.attachEvent) {
		el.attachEvent('on' + event, handler);
	} else if (el.addEventListener) {
		el.addEventListener(event, handler, true);
	} else {
		el['on' + event] = handler;
	}
}

function removeEvent(el, event, handler) {
	if (!el) { return; }
	if (el.detachEvent) {
		el.detachEvent('on' + event, handler);
	} else if (el.removeEventListener) {
		el.removeEventListener(event, handler, true);
	} else {
		el['on' + event] = null;
	}
}

module.exports = React.createClass({
	displayName: 'Draggable',

	propTypes: {
		/**
		 * `axis` determines which axis the draggable can move.
		 *
		 * 'both' allows movement horizontally and vertically.
		 * 'x' limits movement to horizontal axis.
		 * 'y' limits movement to vertical axis.
		 *
		 * Defaults to 'both'.
		 */
		axis: React.PropTypes.oneOf(['both', 'x', 'y']),

		/**
		 * `handle` specifies a selector to be used as the handle that initiates drag.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	    	return (
		 * 	    	 	<Draggable handle=".handle">
		 * 	    	 	  <div>
		 * 	    	 	      <div className="handle">Click me to drag</div>
		 * 	    	 	      <div>This is some other content</div>
		 * 	    	 	  </div>
		 * 	    		</Draggable>
		 * 	    	);
		 * 	    }
		 * 	});
		 * ```
		 */
		handle: React.PropTypes.string,

		/**
		 * `cancel` specifies a selector to be used to prevent drag initialization.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return(
		 * 	            <Draggable cancel=".cancel">
		 * 	                <div>
		 * 	                	<div className="cancel">You can't drag from here</div>
		 *						<div>Dragging here works fine</div>
		 * 	                </div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		cancel: React.PropTypes.string,

		/**
		 * `grid` specifies the x and y that dragging should snap to.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return (
		 * 	            <Draggable grid={[25, 25]}>
		 * 	                <div>I snap to a 25 x 25 grid</div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		grid: React.PropTypes.arrayOf(React.PropTypes.number),

		/**
		 * `zIndex` specifies the zIndex to use while dragging.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return (
		 * 	            <Draggable zIndex={100}>
		 * 	                <div>I have a zIndex</div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		zIndex: React.PropTypes.number,

		/**
		 * Called when dragging starts.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onStart: React.PropTypes.func,

		/**
		 * Called while dragging.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onDrag: React.PropTypes.func,

		/**
		 * Called when dragging stops.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onStop: React.PropTypes.func
	},

	getDefaultProps: function () {
		return {
			axis: 'both',
			handle: null,
			cancel: null,
			grid: null,
			zIndex: NaN,
			onStart: emptyFunction,
			onDrag: emptyFunction,
			onStop: emptyFunction
		};
	},

	getInitialState: function () {
		return {
			// Whether or not currently dragging
			dragging: false,

			// Start top/left of this.getDOMNode()
			startX: 0, startY: 0,

			// Offset between start top/left and mouse top/left
			offsetX: 0, offsetY: 0,

			// Current top/left of this.getDOMNode()
			clientX: 0, clientY: 0
		};
	},

	handleMouseDown: function (e) {
		var node = this.getDOMNode();

		// Short circuit if handle or cancel prop was provided and selector doesn't match
		if ((this.props.handle && !matchesSelector(e.target, this.props.handle)) ||
			(this.props.cancel && matchesSelector(e.target, this.props.cancel))) {
			return;
		}

		// Initiate dragging
		this.setState({
			dragging: true,
			offsetX: e.clientX,
			offsetY: e.clientY,
			startX: parseInt(node.style.left, 10) || 0,
			startY: parseInt(node.style.top, 10) || 0
		});

		// Call event handler
		this.props.onStart(e, createUIEvent(this));

		// Add event handlers
		addEvent(window, 'mousemove', this.handleMouseMove);
		addEvent(window, 'mouseup', this.handleMouseUp);
	},

	handleMouseUp: function (e) {
		// Short circuit if not currently dragging
		if (!this.state.dragging) {
			return;
		}

		// Turn off dragging
		this.setState({
			dragging: false
		});

		// Call event handler
		this.props.onStop(e, createUIEvent(this));

		// Remove event handlers
		removeEvent(window, 'mousemove', this.handleMouseMove);
		removeEvent(window, 'mouseup', this.handleMouseUp);
	},

	handleMouseMove: function (e) {
		// Calculate top and left
		var clientX = (this.state.startX + (e.clientX - this.state.offsetX));
		var clientY = (this.state.startY + (e.clientY - this.state.offsetY));

		// Snap to grid if prop has been provided
		if (Array.isArray(this.props.grid)) {
			clientX = Math.abs(clientX - this.state.clientX) >= this.props.grid[0]
					? clientX
					: this.state.clientX;

			clientY = Math.abs(clientY - this.state.clientY) >= this.props.grid[1]
					? clientY
					: this.state.clientY;
		}

		// Update top and left
		this.setState({
			clientX: clientX,
			clientY: clientY
		});

		// Call event handler
		this.props.onDrag(e, createUIEvent(this));
	},

	render: function () {
		var style = {
			// Set top if vertical drag is enabled
			top: canDragY(this)
				? this.state.clientY
				: this.state.startY,

			// Set left if horizontal drag is enabled
			left: canDragX(this)
				? this.state.clientX
				: this.state.startX
		};

		// Set zIndex if currently dragging and prop has been provided
		if (this.state.dragging && !isNaN(this.props.zIndex)) {
			style.zIndex = this.props.zIndex;
		}

		// Reuse the child provided
		// This makes it flexible to use whatever element is wanted (div, ul, etc)
		return React.addons.cloneWithProps(React.Children.only(this.props.children), {
			style: style,
			className: 'react-draggable',
			onMouseUp: this.handleMouseUp,
			onMouseDown: this.handleMouseDown
		});
	}
});
<commit_msg>Ensure event handlers are destroyed on unmount.<commit_after>'use strict';

/** @jsx React.DOM */
var React = require('react/addons');
var invariant = require('react/lib/invariant');
var emptyFunction = require('react/lib/emptyFunction');

function createUIEvent(draggable) {
	return {
		position: {
			top: draggable.state.clientY,
			left: draggable.state.clientX
		}
	};
}

function canDragY(draggable) {
	return draggable.props.axis === 'both' ||
			draggable.props.axis === 'y';
}

function canDragX(draggable) {
	return draggable.props.axis === 'both' ||
			draggable.props.axis === 'x';
}

function isFunction(fn) {
	return typeof fn === 'function';
}

function matchesSelector(el, selector) {
	if (isFunction(el.matches)) {
		return el.matches(selector);
	} else if (isFunction(el.webkitMatchesSelector)) {
		return el.webkitMatchesSelector(selector);
	} else if (isFunction(el.mozMatchesSelector)) {
		return el.mozMatchesSelector(selector);
	} else if (isFunction(el.msMatchesSelector)) {
		return el.msMatchesSelector(selector);
	} else if (isFunction(el.oMatchesSelector)) {
		return el.oMatchesSelector(selector);
	} else if (isFunction(el.webkitMatchesSelector)) {
		return el.webkitMatchesSelector(selector);
	}
}

function addEvent(el, event, handler) {
	if (!el) { return; }
	if (el.attachEvent) {
		el.attachEvent('on' + event, handler);
	} else if (el.addEventListener) {
		el.addEventListener(event, handler, true);
	} else {
		el['on' + event] = handler;
	}
}

function removeEvent(el, event, handler) {
	if (!el) { return; }
	if (el.detachEvent) {
		el.detachEvent('on' + event, handler);
	} else if (el.removeEventListener) {
		el.removeEventListener(event, handler, true);
	} else {
		el['on' + event] = null;
	}
}

module.exports = React.createClass({
	displayName: 'Draggable',

	propTypes: {
		/**
		 * `axis` determines which axis the draggable can move.
		 *
		 * 'both' allows movement horizontally and vertically.
		 * 'x' limits movement to horizontal axis.
		 * 'y' limits movement to vertical axis.
		 *
		 * Defaults to 'both'.
		 */
		axis: React.PropTypes.oneOf(['both', 'x', 'y']),

		/**
		 * `handle` specifies a selector to be used as the handle that initiates drag.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	    	return (
		 * 	    	 	<Draggable handle=".handle">
		 * 	    	 	  <div>
		 * 	    	 	      <div className="handle">Click me to drag</div>
		 * 	    	 	      <div>This is some other content</div>
		 * 	    	 	  </div>
		 * 	    		</Draggable>
		 * 	    	);
		 * 	    }
		 * 	});
		 * ```
		 */
		handle: React.PropTypes.string,

		/**
		 * `cancel` specifies a selector to be used to prevent drag initialization.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return(
		 * 	            <Draggable cancel=".cancel">
		 * 	                <div>
		 * 	                	<div className="cancel">You can't drag from here</div>
		 *						<div>Dragging here works fine</div>
		 * 	                </div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		cancel: React.PropTypes.string,

		/**
		 * `grid` specifies the x and y that dragging should snap to.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return (
		 * 	            <Draggable grid={[25, 25]}>
		 * 	                <div>I snap to a 25 x 25 grid</div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		grid: React.PropTypes.arrayOf(React.PropTypes.number),

		/**
		 * `zIndex` specifies the zIndex to use while dragging.
		 *
		 * Example:
		 *
		 * ```jsx
		 * 	var App = React.createClass({
		 * 	    render: function () {
		 * 	        return (
		 * 	            <Draggable zIndex={100}>
		 * 	                <div>I have a zIndex</div>
		 * 	            </Draggable>
		 * 	        );
		 * 	    }
		 * 	});
		 * ```
		 */
		zIndex: React.PropTypes.number,

		/**
		 * Called when dragging starts.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onStart: React.PropTypes.func,

		/**
		 * Called while dragging.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onDrag: React.PropTypes.func,

		/**
		 * Called when dragging stops.
		 *
		 * Example:
		 *
		 * ```js
		 *	function (event, ui) {}
		 * ```
		 *
		 * `event` is the Event that was triggered.
		 * `ui` is an object:
		 *
		 * ```js
		 *	{
		 *		position: {top: 0, left: 0}
		 *	}
		 * ```
		 */
		onStop: React.PropTypes.func
	},

	componentWillUnmount: function() {
		// Remove any leftover event handlers
		removeEvent(window, 'mousemove', this.handleMouseMove);
		removeEvent(window, 'mouseup', this.handleMouseUp);
	},

	getDefaultProps: function () {
		return {
			axis: 'both',
			handle: null,
			cancel: null,
			grid: null,
			zIndex: NaN,
			onStart: emptyFunction,
			onDrag: emptyFunction,
			onStop: emptyFunction
		};
	},

	getInitialState: function () {
		return {
			// Whether or not currently dragging
			dragging: false,

			// Start top/left of this.getDOMNode()
			startX: 0, startY: 0,

			// Offset between start top/left and mouse top/left
			offsetX: 0, offsetY: 0,

			// Current top/left of this.getDOMNode()
			clientX: 0, clientY: 0
		};
	},

	handleMouseDown: function (e) {
		var node = this.getDOMNode();

		// Short circuit if handle or cancel prop was provided and selector doesn't match
		if ((this.props.handle && !matchesSelector(e.target, this.props.handle)) ||
			(this.props.cancel && matchesSelector(e.target, this.props.cancel))) {
			return;
		}

		// Initiate dragging
		this.setState({
			dragging: true,
			offsetX: e.clientX,
			offsetY: e.clientY,
			startX: parseInt(node.style.left, 10) || 0,
			startY: parseInt(node.style.top, 10) || 0
		});

		// Call event handler
		this.props.onStart(e, createUIEvent(this));

		// Add event handlers
		addEvent(window, 'mousemove', this.handleMouseMove);
		addEvent(window, 'mouseup', this.handleMouseUp);
	},

	handleMouseUp: function (e) {
		// Short circuit if not currently dragging
		if (!this.state.dragging) {
			return;
		}

		// Turn off dragging
		this.setState({
			dragging: false
		});

		// Call event handler
		this.props.onStop(e, createUIEvent(this));

		// Remove event handlers
		removeEvent(window, 'mousemove', this.handleMouseMove);
		removeEvent(window, 'mouseup', this.handleMouseUp);
	},

	handleMouseMove: function (e) {
		// Calculate top and left
		var clientX = (this.state.startX + (e.clientX - this.state.offsetX));
		var clientY = (this.state.startY + (e.clientY - this.state.offsetY));

		// Snap to grid if prop has been provided
		if (Array.isArray(this.props.grid)) {
			clientX = Math.abs(clientX - this.state.clientX) >= this.props.grid[0]
					? clientX
					: this.state.clientX;

			clientY = Math.abs(clientY - this.state.clientY) >= this.props.grid[1]
					? clientY
					: this.state.clientY;
		}

		// Update top and left
		this.setState({
			clientX: clientX,
			clientY: clientY
		});

		// Call event handler
		this.props.onDrag(e, createUIEvent(this));
	},

	render: function () {
		var style = {
			// Set top if vertical drag is enabled
			top: canDragY(this)
				? this.state.clientY
				: this.state.startY,

			// Set left if horizontal drag is enabled
			left: canDragX(this)
				? this.state.clientX
				: this.state.startX
		};

		// Set zIndex if currently dragging and prop has been provided
		if (this.state.dragging && !isNaN(this.props.zIndex)) {
			style.zIndex = this.props.zIndex;
		}

		// Reuse the child provided
		// This makes it flexible to use whatever element is wanted (div, ul, etc)
		return React.addons.cloneWithProps(React.Children.only(this.props.children), {
			style: style,
			className: 'react-draggable',
			onMouseUp: this.handleMouseUp,
			onMouseDown: this.handleMouseDown
		});
	}
});
<|endoftext|>


<commit_before>/*
 * should.js - assertion library
 * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca>
 * Copyright(c) 2013-2016 Denis Bardadym <bardadymchik@gmail.com>
 * MIT Licensed
 */

export default function(should, Assertion) {
  /**
   * Simple chaining. It actually do nothing.
   *
   * @memberOf Assertion
   * @name be
   * @property {should.Assertion} be
   * @alias Assertion#an
   * @alias Assertion#of
   * @alias Assertion#a
   * @alias Assertion#and
   * @alias Assertion#been
   * @alias Assertion#have
   * @alias Assertion#has
   * @alias Assertion#with
   * @alias Assertion#is
   * @alias Assertion#which
   * @alias Assertion#the
   * @alias Assertion#it
   * @category assertion chaining
   */
  ['an', 'of', 'a', 'and', 'be', 'been', 'has', 'have', 'with', 'is', 'which', 'the', 'it'].forEach(function(name) {
    Assertion.addChain(name);
  });
}
<commit_msg>Minor grammar correction<commit_after>/*
 * should.js - assertion library
 * Copyright(c) 2010-2013 TJ Holowaychuk <tj@vision-media.ca>
 * Copyright(c) 2013-2016 Denis Bardadym <bardadymchik@gmail.com>
 * MIT Licensed
 */

export default function(should, Assertion) {
  /**
   * Simple chaining to improve readability. Does nothing.
   *
   * @memberOf Assertion
   * @name be
   * @property {should.Assertion} be
   * @alias Assertion#an
   * @alias Assertion#of
   * @alias Assertion#a
   * @alias Assertion#and
   * @alias Assertion#been
   * @alias Assertion#have
   * @alias Assertion#has
   * @alias Assertion#with
   * @alias Assertion#is
   * @alias Assertion#which
   * @alias Assertion#the
   * @alias Assertion#it
   * @category assertion chaining
   */
  ['an', 'of', 'a', 'and', 'be', 'been', 'has', 'have', 'with', 'is', 'which', 'the', 'it'].forEach(function(name) {
    Assertion.addChain(name);
  });
}
<|endoftext|>


<commit_before>/**
 * 1.1.1 = 1*100*100 + 1*100 + 1
 * 1.2.2 = 1*100*100 + 2*100 + 3
 *
 * 1 = 0*100 +1
 */
function encode_id_with_array(opts,arr) {
	var result = 0;
  	for(var z = 0; z < arr.length; z++ ) {
		result += factor(opts, arr.length - z ,arr[z]);
  	}

	return result;
}

/**
 * 1.1.1 = 1*100*100 + 1*100 + 1
 * 1.2.2 = 1*100*100 + 2*100 + 3
 *
 * 1 = 0*100 +1

	1,1 = 100

 */
function get_parent_id_with_array(opts,arr) {
	var result_arr = [];

  	for(var z = 0; z < arr.length; z++ ) {
		result_arr.push(arr[z]);
  	}

	result_arr.pop();

	var result = 0;
  	for(var z = 0; z < result_arr.length; z++ ) {
		result += factor(opts,result_arr.length - z,result_arr[z]);
  	}

	return result;
}

function factor(opts ,count,current) {
	if(1 == count) {
		return current;
	}

	var str = '';
	for(var i = count - 1;i > 0; i-- ) {
		str += current * opts.step+'*';
	}

	return eval( str + '1' );
}

;(function($) {
	/*
	 * 根据header创建目录内容
	 */
	function create_toc(opts) {
		$(opts.documment_selector).find(':header').each(function() {
			var level = parseInt(this.nodeName.substring(1), 10);

			_rename_header_content(opts,this,level);

			_add_header_node(opts,$(this));
		});//end each
	}

	/*
	 * 渲染ztree
	 */
	function render_with_ztree(opts) {
		var t = $(opts._zTree);
		t = $.fn.zTree.init(t,opts.ztreeSetting,opts._header_nodes).expandAll(opts.is_expand_all);
		// alert(opts._headers * 88);
		// $(opts._zTree).height(opts._headers  * 33 + 33);

		if(opts.is_posion_top == true){
			opts.ztreeStyle.top = '0px';

			if( opts.ztreeStyle.hasOwnProperty('bottom') )
				delete opts.ztreeStyle.bottom ;
		}else{
			opts.ztreeStyle.bottom = '0px';

			if( opts.ztreeStyle.hasOwnProperty('top') )
				delete opts.ztreeStyle.top;
		}

		$(opts._zTree).css(opts.ztreeStyle);
	}

	/*
	 * 将已有header编号，并重命名
	 */
	function _rename_header_content(opts ,header_obj ,level) {
		if(opts._headers.length == level) {
			opts._headers[level - 1]++;
		} else if(opts._headers.length > level) {
			opts._headers = opts._headers.slice(0, level);
			opts._headers[level - 1] ++;
		} else if(opts._headers.length < level) {
			for(var i = 0; i < (level - opts._headers.length); i++) {
			  // console.log('push 1');
			  opts._headers.push(1);
			}
		}

		if(opts.is_auto_number == true) {
			//另存为的文件里会有编号，所以有编号的就不再重新替换
			if($(header_obj).text().indexOf( opts._headers.join('.') ) != -1){

			}else{
				$(header_obj).text(opts._headers.join('.') + '. ' + $(header_obj).text());
			}
		}
	}

	/*
	 * 给ztree用的header_nodes增加数据
	 */
	function _add_header_node(opts ,header_obj) {
		var id  = encode_id_with_array(opts,opts._headers);
		var pid = get_parent_id_with_array(opts,opts._headers);

      	// 设置锚点id
		$(header_obj).attr('id',id);

		log($(header_obj).text());

		opts._header_offsets.push($(header_obj).offset().top - opts.highlight_offset);

		log('h offset ='+( $(header_obj).offset().top - opts.highlight_offset ) );

		opts._header_nodes.push({
			id:id,
			pId:pid ,
			name:$(header_obj).text()||'null',
			open:true,
			url:'#'+ id,
			target:'_self'
		});
	}

	/*
	 * 根据滚动确定当前位置，并更新ztree
	 */
	function bind_scroll_event_and_update_postion(opts) {
		var timeout;
	    var highlight_on_scroll = function(e) {
			if (timeout) {
				clearTimeout(timeout);
			}

			timeout = setTimeout(function() {
				var top = $(window).scrollTop(),highlighted;

				if(opts.debug) console.log('top='+top);

				for (var i = 0, c = opts._header_offsets.length; i < c; i++) {
					// fixed: top+5防止点击ztree的时候，出现向上抖动的情况
					if (opts._header_offsets[i] >= (top + 5) ) {
						console.log('opts._header_offsets['+ i +'] = '+opts._header_offsets[i]);
						$('a').removeClass('curSelectedNode');

						// 由于有root节点，所以i应该从1开始
				  		var obj = $('#tree_' + (i+1) + '_a').addClass('curSelectedNode');
						break;
					}
				}
			}, opts.refresh_scroll_time);
		};

	    if (opts.highlight_on_scroll) {
	      $(window).bind('scroll', highlight_on_scroll);
	      highlight_on_scroll();
	    }
	}

	/*
	 * 初始化
	 */
	function init_with_config(opts) {
		opts.highlight_offset = $(opts.documment_selector).offset().top;
	}

	/*
	 * 日志
	 */
	function log(str) {
		return;
		if($.fn.ztree_toc.defaults.debug == true) {
			console.log(str);
		}
	}

	$.fn.ztree_toc = function(options) {
		// 将defaults 和 options 参数合并到{}
		var opts = $.extend({},$.fn.ztree_toc.defaults,options);

		return this.each(function() {
			opts._zTree = $(this);

			// 初始化
			init_with_config(opts);

			// 创建table of content，获取元数据_headers
			create_toc(opts);

			// 根据_headers生成ztree
			render_with_ztree(opts);

			// 根据滚动确定当前位置，并更新ztree
		    bind_scroll_event_and_update_postion(opts);
		});
		// each end
	}

	//定义默认
	$.fn.ztree_toc.defaults = {
		_zTree: null,
		_headers: [],
		_header_offsets: [],
		_header_nodes: [{ id:1, pId:0, name:"Table of Content",open:true}],
		debug: true,
		highlight_offset: 0,
		highlight_on_scroll: true,
		/*
		 * 计算滚动判断当前位置的时间，默认是50毫秒
		 */
		refresh_scroll_time: 50,
		documment_selector: 'body',
		/*
		 * ztree的位置，默认是在上部
		 */
		is_posion_top: true,
		/*
		 * 默认是否显示header编号
		 */
		is_auto_number: false,
		/*
		 * 默认是否展开全部
		 */
		is_expand_all: true,
		/*
		 * 是否对选中行，显示高亮效果
		 */
		is_highlight_selected_line: true,
		step: 100,
		ztreeStyle: {
			width:'260px',
			overflow: 'auto',
			position: 'fixed',
			'z-index': 2147483647,
			border: '0px none',
			left: '0px',
			bottom: '0px',
			// height:'100px'
		},
		ztreeSetting: {
			view: {
				dblClickExpand: false,
				showLine: true,
				showIcon: false,
				selectedMulti: false
			},
			data: {
				simpleData: {
					enable: true,
					idKey : "id",
					pIdKey: "pId",
					// rootPId: "0"
				}
			},
			callback: {
				beforeClick: function(treeId, treeNode) {
					$('a').removeClass('curSelectedNode');
					if(treeNode.id == 1){
						// TODO: when click root node
						console.log('click root table of content');
					}
					if($.fn.ztree_toc.defaults.is_highlight_selected_line == true) {
						$('#' + treeNode.id).css('color' ,'red').fadeOut("slow" ,function() {
						    // Animation complete.
							$(this).show().css('color','black');
						});
					}
				},
				onRightClick: function(event, treeId, treeNode) {
					if(treeNode.id == 1){
						// TODO: when right_click root node:table content
						console.log('right_click root table of content');
					}
				}
			}
		}
	};

})(jQuery);<commit_msg>add scroll selector option<commit_after>/**
 * 1.1.1 = 1*100*100 + 1*100 + 1
 * 1.2.2 = 1*100*100 + 2*100 + 3
 *
 * 1 = 0*100 +1
 */
function encode_id_with_array(opts,arr) {
	var result = 0;
  for(var z = 0; z < arr.length; z++ ) {
		result += factor(opts, arr.length - z ,arr[z]);
  }

	return result;
}

/**
 * 1.1.1 = 1*100*100 + 1*100 + 1
 * 1.2.2 = 1*100*100 + 2*100 + 3
 *
 * 1 = 0*100 +1

	1,1 = 100

 */
function get_parent_id_with_array(opts,arr) {
	var result_arr = [];

  for(var z = 0; z < arr.length; z++ ) {
		result_arr.push(arr[z]);
  }

	result_arr.pop();

	var result = 0;
  for(var z = 0; z < result_arr.length; z++ ) {
		result += factor(opts,result_arr.length - z,result_arr[z]);
  }

	return result;
}

function factor(opts ,count,current) {
	if(1 == count) {
		return current;
	}

	var str = '';
	for(var i = count - 1;i > 0; i-- ) {
		str += current * opts.step+'*';
	}

	return eval( str + '1' );
}

;(function($) {
	/*
	 * 根据header创建目录内容
	 */
	function create_toc(opts) {
		$(opts.documment_selector).find(':header').each(function() {
			var level = parseInt(this.nodeName.substring(1), 10);

			_rename_header_content(opts,this,level);

			_add_header_node(opts,$(this));
		});//end each
	}

	/*
	 * 渲染ztree
	 */
	function render_with_ztree(opts) {
		var t = $(opts._zTree);
		t = $.fn.zTree.init(t,opts.ztreeSetting,opts._header_nodes).expandAll(opts.is_expand_all);
		// alert(opts._headers * 88);
		// $(opts._zTree).height(opts._headers  * 33 + 33);

		if(opts.is_posion_top == true){
			opts.ztreeStyle.top = '0px';

			if( opts.ztreeStyle.hasOwnProperty('bottom') )
				delete opts.ztreeStyle.bottom ;
		}else{
			opts.ztreeStyle.bottom = '0px';

			if( opts.ztreeStyle.hasOwnProperty('top') )
				delete opts.ztreeStyle.top;
		}

		$(opts._zTree).css(opts.ztreeStyle);
	}

	/*
	 * 将已有header编号，并重命名
	 */
	function _rename_header_content(opts ,header_obj ,level) {
		if(opts._headers.length == level) {
			opts._headers[level - 1]++;
		} else if(opts._headers.length > level) {
			opts._headers = opts._headers.slice(0, level);
			opts._headers[level - 1] ++;
		} else if(opts._headers.length < level) {
			for(var i = 0; i < (level - opts._headers.length); i++) {
			  // console.log('push 1');
			  opts._headers.push(1);
			}
		}

		if(opts.is_auto_number == true) {
			//另存为的文件里会有编号，所以有编号的就不再重新替换
			if($(header_obj).text().indexOf( opts._headers.join('.') ) != -1){

			}else{
				$(header_obj).text(opts._headers.join('.') + '. ' + $(header_obj).text());
			}
		}
	}

	/*
	 * 给ztree用的header_nodes增加数据
	 */
	function _add_header_node(opts ,header_obj) {
		var id  = encode_id_with_array(opts,opts._headers);
		var pid = get_parent_id_with_array(opts,opts._headers);

      	// 设置锚点id
		$(header_obj).attr('id',id);

		log($(header_obj).text());

		opts._header_offsets.push($(header_obj).offset().top - opts.highlight_offset);

		log('h offset ='+( $(header_obj).offset().top - opts.highlight_offset ) );

		opts._header_nodes.push({
			id:id,
			pId:pid ,
			name:$(header_obj).text()||'null',
			open:true,
			url:'#'+ id,
			target:'_self'
		});
	}

	/*
	 * 根据滚动确定当前位置，并更新ztree
	 */
	function bind_scroll_event_and_update_postion(opts) {
		var timeout;
	    var highlight_on_scroll = function(e) {
			if (timeout) {
				clearTimeout(timeout);
			}

			timeout = setTimeout(function() {
				var top = $(opts.scroll_selector).scrollTop(),highlighted;

				if(opts.debug) console.log('top='+top);

				for (var i = 0, c = opts._header_offsets.length; i < c; i++) {
					// fixed: top+5防止点击ztree的时候，出现向上抖动的情况
					if (opts._header_offsets[i] >= (top + 5) ) {
						console.log('opts._header_offsets['+ i +'] = '+opts._header_offsets[i]);
						$('a').removeClass('curSelectedNode');

						// 由于有root节点，所以i应该从1开始
				  		var obj = $('#tree_' + (i+1) + '_a').addClass('curSelectedNode');
						break;
					}
				}
			}, opts.refresh_scroll_time);
		};

	  if (opts.highlight_on_scroll) {
	    $(opts.scroll_selector).bind('scroll', highlight_on_scroll);
	    highlight_on_scroll();
	  }
	}

	/*
	 * 初始化
	 */
	function init_with_config(opts) {
		opts.highlight_offset = $(opts.documment_selector).offset().top;
	}

	/*
	 * 日志
	 */
	function log(str) {
		return;
		if($.fn.ztree_toc.defaults.debug == true) {
			console.log(str);
		}
	}

	$.fn.ztree_toc = function(options) {
		// 将defaults 和 options 参数合并到{}
		var opts = $.extend({},$.fn.ztree_toc.defaults,options);

		return this.each(function() {
			opts._zTree = $(this);

			// 初始化
			init_with_config(opts);

			// 创建table of content，获取元数据_headers
			create_toc(opts);

			// 根据_headers生成ztree
			render_with_ztree(opts);

			// 根据滚动确定当前位置，并更新ztree
		    bind_scroll_event_and_update_postion(opts);
		});
		// each end
	}

	//定义默认
	$.fn.ztree_toc.defaults = {
		_zTree: null,
		_headers: [],
		_header_offsets: [],
		_header_nodes: [{ id:1, pId:0, name:"Table of Content",open:true}],
		debug: true,
    scroll_selector: 'window',
		highlight_offset: 0,
		highlight_on_scroll: true,
		/*
		 * 计算滚动判断当前位置的时间，默认是50毫秒
		 */
		refresh_scroll_time: 50,
		documment_selector: 'body',
		/*
		 * ztree的位置，默认是在上部
		 */
		is_posion_top: true,
		/*
		 * 默认是否显示header编号
		 */
		is_auto_number: false,
		/*
		 * 默认是否展开全部
		 */
		is_expand_all: true,
		/*
		 * 是否对选中行，显示高亮效果
		 */
		is_highlight_selected_line: true,
		step: 100,
		ztreeStyle: {
			width:'260px',
			overflow: 'auto',
			position: 'fixed',
			'z-index': 2147483647,
			border: '0px none',
			left: '0px',
			bottom: '0px',
			// height:'100px'
		},
		ztreeSetting: {
			view: {
				dblClickExpand: false,
				showLine: true,
				showIcon: false,
				selectedMulti: false
			},
			data: {
				simpleData: {
					enable: true,
					idKey : "id",
					pIdKey: "pId",
					// rootPId: "0"
				}
			},
			callback: {
				beforeClick: function(treeId, treeNode) {
					$('a').removeClass('curSelectedNode');
					if(treeNode.id == 1){
						// TODO: when click root node
						console.log('click root table of content');
					}
					if($.fn.ztree_toc.defaults.is_highlight_selected_line == true) {
						$('#' + treeNode.id).css('color' ,'red').fadeOut("slow" ,function() {
						    // Animation complete.
							$(this).show().css('color','black');
						});
					}
				},
				onRightClick: function(event, treeId, treeNode) {
					if(treeNode.id == 1){
						// TODO: when right_click root node:table content
						console.log('right_click root table of content');
					}
				}
			}
		}
	};

})(jQuery);
<|endoftext|>


<commit_before>//
// SBON - JS library for working with SBON binary format.
// ---
// @copyright (c) 2017 Damian Bushong <katana@odios.us>
// @license MIT license
// @url <https://github.com/damianb/SBON>
//
/*jslint node: true, asi: true */
'use strict'

const ConsumableBuffer = require('ConsumableBuffer')
const ConsumableFile = require('ConsumableFile')
const bigInt = require('big-integer')

//
// SBON - provides a library of functions for reading/parsing SBON ("Starbound Object Notation").
//
// lovingly ported from blixt's py-starbound sbon.py module
// @url <https://github.com/blixt/py-starbound/blob/master/starbound/sbon.py>
// @license MIT license
//
// for good Reverse-Engineering documentation on the SBON format, reference:
// <https://github.com/blixt/py-starbound/blob/master/FORMATS.md#sbon>
//
module.exports = class SBON {
	/**
	 * Reads a variable integer from the provided ConsumableBuffer or ConsumableFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Number} - The javascript number form of the varint we just read.
	 */
	static async readVarInt(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readVarInt expects a ConsumableBuffer or ConsumableFile.')
		}

		let value = bigInt(0)
		while(true) {
			let byte = await sbuf.read(1)
			byte = bigInt(byte.readUIntBE(0, 1))
			if(byte.and(0b10000000).isZero()) {
				value = value.shiftLeft(7).or(byte)
				if(value.isZero()) { // no, stop giving us -0! STAHP!
					value = value.abs()
				}
				return value.toJSNumber()
			}
			value = value.shiftLeft(7).or(byte.and(0b01111111))
		}
	}

	/**
	 * Reads a *signed* variable integer from the provided ConsumableBuffer or ConsumableFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Number} - The javascript number form of the signed varint we just read.
	 */
	static async readVarIntSigned(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readVarIntSigned expects a ConsumableBuffer or ConsumableFile.')
		}

		let value = bigInt(await this.readVarInt(sbuf))
		if(!value.and(1).isZero()) {
			return value.shiftRight(1).times(-1).minus(1).toJSNumber()
		} else {
			return value.shiftRight(1).toJSNumber()
		}
	}

	/**
	 * Reads a series of bytes from the provided ConsumableBuffer or ConsumableFile.
	 * We expect that the first thing read will be a varint which will indicate how many bytes overall we will need to read.
	 * This is commonly used for a UTF-8 string, with a varint indicating how many bytes will compose the string.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Buffer} - A buffer instance containing the bytes read.
	 */
	static async readBytes(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readBytes expects a ConsumableBuffer or ConsumableFile.')
		}

		// starts with a varint to indicate the length of the byte series
		const length = await this.readVarInt(sbuf)
		if(length > 0) {
			return await sbuf.read(length)
		} else {
			return Buffer.alloc(0)
		}
	}

	/**
	 * Reads a series of bytes from the provided ConsumableBuffer or ConsumableFile and reencodes them into a string.
	 * Most of the work here is done in readBytes - we just transform the Buffer here into a UTF-8 stream after it's gotten our bytes.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:String} - A UTF-8 string.
	 */
	static async readString(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readString expects a ConsumableBuffer or ConsumableFile.')
		}

		return (await this.readBytes(sbuf)).toString('utf8')
	}

	/**
	 * Reads a dynamic-typed chunk of data from the provided ConsumableBuffer or ConsumableFile.
	 * Our first byte indicates the type, which then determines who will handle the rest.
	 * This farms out to the other SBON functions as necessary.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:mixed} - Too many potential return types to document. You'll get something - can't really tell you what, though.
	 */
	static async readDynamic(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readDynamic expects a ConsumableBuffer or ConsumableFile.')
		}

		// first byte of a dynamic type is always the type indicator
		const type = await sbuf.read(1)
		switch(type.readUIntBE(0, 1)) {
			case 1: // Nil-value
				return null
			case 2: // 64-bit float
				return (await sbuf.read(8)).readDoubleBE(0)
			case 3: // Boolean
				let byte = await sbuf.read(1)
				return (Buffer.compare(byte, Buffer.from([0x01])) === 0)
			case 4: // Signed varint
				return await this.readVarIntSigned(sbuf)
			case 5: // String
				return await this.readString(sbuf)
			case 6: // List
				return await this.readList(sbuf)
			case 7: // Map
				return await this.readMap(sbuf)
			default:
				throw new Error('Unknown dynamic type 0x' + type.toString('hex') + ' encountered in SBON.readDynamic')
		}
	}

	/**
	 * Reads a list from the provided ConsumableBuffer or ConsumableFile.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Array} - An Array used as a list.
	 */
	static async readList(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readList expects a ConsumableBuffer or ConsumableFile.')
		}

		// first chunk is a varint that indicates the length of the list (how many array entries)
		// all values are dynamic types
		const length = await this.readVarInt(sbuf)
		let value = [], i = length
		while(i--) {
			const listVal = await this.readDynamic(sbuf)
			value.push(listVal)
		}

		return value
	}

	/**
	 * Reads a map (which we use a generic Object to represent) from the provided ConsumableBuffer or ConsumableFile.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Object} - An Object used as a key-value map.
	 */
	static async readMap(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readMap expects a ConsumableBuffer or ConsumableFile.')
		}

		// first chunk is a varint that indicates the length of the map (how many key-value pairs)
		// keys are assumed strings, while values are dynamic types
		const length = await this.readVarInt(sbuf)
		let value = {}, i = length

		while(i--) {
			let key = await this.readString(sbuf)
			value[key] = await this.readDynamic(sbuf)
		}

		return value
	}
}<commit_msg>Stub out functions in the file.<commit_after>//
// SBON - JS library for working with SBON binary format.
// ---
// @copyright (c) 2017 Damian Bushong <katana@odios.us>
// @license MIT license
// @url <https://github.com/damianb/SBON>
//
/*jslint node: true, asi: true */
'use strict'

const ConsumableBuffer = require('ConsumableBuffer')
const ConsumableFile = require('ConsumableFile')
const ExpandingBuffer = require('ExpandingBuffer')
const ExpandingFile = require('ExpandingFile')
const bigInt = require('big-integer')

//
// SBON - provides a library of functions for reading/parsing SBON ("Starbound Object Notation").
//
// lovingly ported from blixt's py-starbound sbon.py module
// @url <https://github.com/blixt/py-starbound/blob/master/starbound/sbon.py>
// @license MIT license
//
// for good Reverse-Engineering documentation on the SBON format, reference:
// <https://github.com/blixt/py-starbound/blob/master/FORMATS.md#sbon>
//
module.exports = class SBON {
	/**
	 * Reads a variable integer from the provided ConsumableBuffer or ConsumableFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Number} - The javascript number form of the varint we just read.
	 */
	static async readVarInt(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readVarInt expects a ConsumableBuffer or ConsumableFile.')
		}

		let value = bigInt(0)
		while(true) {
			let byte = await sbuf.read(1)
			byte = bigInt(byte.readUIntBE(0, 1))
			if(byte.and(0b10000000).isZero()) {
				value = value.shiftLeft(7).or(byte)
				if(value.isZero()) { // no, stop giving us -0! STAHP!
					value = value.abs()
				}
				return value.toJSNumber()
			}
			value = value.shiftLeft(7).or(byte.and(0b01111111))
		}
	}

	/**
	 * Reads a *signed* variable integer from the provided ConsumableBuffer or ConsumableFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Number} - The javascript number form of the signed varint we just read.
	 */
	static async readVarIntSigned(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readVarIntSigned expects a ConsumableBuffer or ConsumableFile.')
		}

		let value = bigInt(await this.readVarInt(sbuf))
		if(!value.and(1).isZero()) {
			return value.shiftRight(1).times(-1).minus(1).toJSNumber()
		} else {
			return value.shiftRight(1).toJSNumber()
		}
	}

	/**
	 * Reads a series of bytes from the provided ConsumableBuffer or ConsumableFile.
	 * We expect that the first thing read will be a varint which will indicate how many bytes overall we will need to read.
	 * This is commonly used for a UTF-8 string, with a varint indicating how many bytes will compose the string.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Buffer} - A buffer instance containing the bytes read.
	 */
	static async readBytes(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readBytes expects a ConsumableBuffer or ConsumableFile.')
		}

		// starts with a varint to indicate the length of the byte series
		const length = await this.readVarInt(sbuf)
		if(length > 0) {
			return await sbuf.read(length)
		} else {
			return Buffer.alloc(0)
		}
	}

	/**
	 * Reads a series of bytes from the provided ConsumableBuffer or ConsumableFile and reencodes them into a string.
	 * Most of the work here is done in readBytes - we just transform the Buffer here into a UTF-8 stream after it's gotten our bytes.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:String} - A UTF-8 string.
	 */
	static async readString(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readString expects a ConsumableBuffer or ConsumableFile.')
		}

		return (await this.readBytes(sbuf)).toString('utf8')
	}

	/**
	 * Reads a dynamic-typed chunk of data from the provided ConsumableBuffer or ConsumableFile.
	 * Our first byte indicates the type, which then determines who will handle the rest.
	 * This farms out to the other SBON functions as necessary.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:mixed} - Too many potential return types to document. You'll get something - can't really tell you what, though.
	 */
	static async readDynamic(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readDynamic expects a ConsumableBuffer or ConsumableFile.')
		}

		// first byte of a dynamic type is always the type indicator
		const type = await sbuf.read(1)
		switch(type.readUIntBE(0, 1)) {
			case 1: // Nil-value
				return null
			case 2: // 64-bit float
				return (await sbuf.read(8)).readDoubleBE(0)
			case 3: // Boolean
				let byte = await sbuf.read(1)
				return (Buffer.compare(byte, Buffer.from([0x01])) === 0)
			case 4: // Signed varint
				return await this.readVarIntSigned(sbuf)
			case 5: // String
				return await this.readString(sbuf)
			case 6: // List
				return await this.readList(sbuf)
			case 7: // Map
				return await this.readMap(sbuf)
			default:
				throw new Error('Unknown dynamic type 0x' + type.toString('hex') + ' encountered in SBON.readDynamic')
		}
	}

	/**
	 * Reads a list from the provided ConsumableBuffer or ConsumableFile.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Array} - An Array used as a list.
	 */
	static async readList(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readList expects a ConsumableBuffer or ConsumableFile.')
		}

		// first chunk is a varint that indicates the length of the list (how many array entries)
		// all values are dynamic types
		const length = await this.readVarInt(sbuf)
		let value = [], i = length
		while(i--) {
			const listVal = await this.readDynamic(sbuf)
			value.push(listVal)
		}

		return value
	}

	/**
	 * Reads a map (which we use a generic Object to represent) from the provided ConsumableBuffer or ConsumableFile.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @return {Promise:Object} - An Object used as a key-value map.
	 */
	static async readMap(sbuf) {
		if(!(sbuf instanceof ConsumableBuffer || sbuf instanceof ConsumableFile)) {
			throw new TypeError('SBON.readMap expects a ConsumableBuffer or ConsumableFile.')
		}

		// first chunk is a varint that indicates the length of the map (how many key-value pairs)
		// keys are assumed strings, while values are dynamic types
		const length = await this.readVarInt(sbuf)
		let value = {}, i = length

		while(i--) {
			let key = await this.readString(sbuf)
			value[key] = await this.readDynamic(sbuf)
		}

		return value
	}

	/**
	 * Writes a variable integer to the provided ExpandingBuffer or ExpandingFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to write to.
	 * @param  {Number} value - The value to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeVarInt(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeVarInt expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

	/**
	 * Writes a *signed* variable integer to the provided ExpandingBuffer or ExpandingFile.
	 * Relies on bigInt for mathematical operations as we're performing mathematical operations beyond JS's native capabilities.
	 *
	 * See also: <https://en.wikipedia.org/wiki/Variable-length_quantity>
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to write to.
	 * @param  {Number} value - The value to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeVarIntSigned(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeVarIntSigned expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

	/**
	 * Writes an array of bytes to the provided ExpandingBuffer or ExpandingFile.
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to write to.
	 * @param  {Array|Buffer} value - The array of bytes or Buffer instance to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeBytes(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeBytes expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

	/**
	 * Reads a series of bytes from the provided ConsumableBuffer or ConsumableFile and reencodes them into a string.
	 * Most of the work here is done in readBytes - we just transform the Buffer here into a UTF-8 stream after it's gotten our bytes.
	 *
	 * @param  {ConsumableBuffer|ConsumableFile} sbuf - The stream to read from.
	 * @param  {String} value - The UTF-8 string to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeString(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeString expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

	/**
	 * Write a dynamically-typed chunk of data to the provided ExpandingBuffer or ExpandingFile.
	 * This farms out to the other SBON functions as necessary.
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to write to.
	 * @param  {mixed} value - The value we want to write.  Accepts too many different types to document.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeDynamic(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeDynamic expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

		/**
	 * Writes a list to the provided ExpandingBuffer or ExpandingFile.
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to read from.
	 * @param  {Array} value - The array we want to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeList(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeList expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}

	/**
	 * Writes an Object (also known as a map) to the provided ExpandingBuffer or ExpandingFile.
	 *
	 * @param  {ExpandingBuffer|ExpandingFile} sbuf - The stream to read from.
	 * @param  {Object} value - The object we want to write.
	 * @return {Promise:Number} - The return value of the sbuf.write() operation.
	 */
	static async writeMap(sbuf, value) {
		if(!(sbuf instanceof ExpandingBuffer || sbuf instanceof ExpandingFile)) {
			throw new TypeError('SBON.writeVarInt expects a ExpandingBuffer or ExpandingFile.')
		}

		// todo
	}
}<|endoftext|>


<commit_before>'use strict';

var vscode = require('vscode');
var Comb = require('csscomb');

/**
 * Check file extension
 *
 * @param  {String} ext
 */
var _testExtension = function(ext) {
	return /(css|less|sass|scss)/.test(ext);
};

/**
 * Attempt to parse the JSON data
 *
 * @param  {String} fileData
 */
var _parseJsonFile = function(fileData) {
	try {
		return JSON.parse(fileData);
	} catch (err) {
		vscode.window.showErrorMessage('Provided JSON file contains syntax errors. Used standard configuration!');
	}
};

/**
 * Initialization();
 *
 * @param  {Object} textEditor
 * @param  {Object} edit
 */
function Formatter(textEditor) {
	this.textEditor = textEditor;
}

/**
 * Run CSScomb
 *
 * @param  {Object} config
 */
Formatter.prototype._comb = function(config) {
	var document = this.textEditor.document;
	var targetText = document.getText();
	var lang = document._languageId;
	var comb = new Comb();
	comb.configure(config);

	if (_testExtension(lang)) {
		return comb.processString(targetText, { syntax: lang });
	}

	vscode.window.showWarningMessage('Cannot execute CSScomb because there is not style files.');
	return false;
};

/**
 * Modification (saving) of data in the editor
 *
 * @param  {String} combedStyles
 */
Formatter.prototype._modifyEditorText = function(combedStyles) {
	var document = this.textEditor.document;
	var lastLine = document.lineAt(document.lineCount - 1);
	var selectAll = new vscode.Range(0, 0, lastLine.lineNumber, lastLine.range.end.character);
	this.textEditor.edit(function(editBuilder) {
		editBuilder.replace(selectAll, combedStyles);
	});
};

/**
 * Lifecycle extensions
 */
Formatter.prototype.cssComb = function() {
	var _that = this;
	var preset = vscode.workspace.getConfiguration('csscomb').preset || 'csscomb';
	if (typeof preset === 'string') {
		preset = Comb.getConfig(preset);
	}

	return vscode.workspace.findFiles('**/*csscomb.json', '{**/node_modules/**,**/bower_components/**}', 1)
		// Get array of files contain `csscomb.json` in name
		.then(function(arrayOfFiles) {
			if (arrayOfFiles.length) {
				return arrayOfFiles[0];
			}
		})
		// Read the configuration file
		.then(function(configPath) {
			if (configPath) {
				return vscode.workspace.openTextDocument(configPath);
			}
		})
		// Attempt to parse the JSON data
		.then(function(fileData) {
			if (fileData) {
				return _parseJsonFile(fileData.getText());
			}
		})
		// Run CSScomb
		.then(function(config) {
			var combedStyles = (config) ? _that._comb(config) : _that._comb(preset);
			if (combedStyles) {
				return _that._modifyEditorText(combedStyles);
			}
		});
};

exports.Engine = Formatter;
<commit_msg>compatibility with VS Code v0.10.8<commit_after>'use strict';

var vscode = require('vscode');
var Comb = require('csscomb');

/**
 * Check file extension
 *
 * @param  {String} ext
 */
var _testExtension = function(ext) {
	return /(css|less|sass|scss)/.test(ext);
};

/**
 * Attempt to parse the JSON data
 *
 * @param  {String} fileData
 */
var _parseJsonFile = function(fileData) {
	try {
		return JSON.parse(fileData);
	} catch (err) {
		vscode.window.showErrorMessage('Provided JSON file contains syntax errors. Used standard configuration!');
	}
};

/**
 * Initialization();
 *
 * @param  {Object} textEditor
 * @param  {Object} edit
 */
function Formatter(textEditor) {
	this.textEditor = textEditor;
}

/**
 * Run CSScomb
 *
 * @param  {Object} config
 */
Formatter.prototype._comb = function(config) {
	var document = this.textEditor.document;
	var targetText = document.getText();
	var lang = document.languageId || document._languageId;
	var comb = new Comb();
	comb.configure(config);

	if (_testExtension(lang)) {
		return comb.processString(targetText, { syntax: lang });
	}

	vscode.window.showWarningMessage('Cannot execute CSScomb because there is not style files.');
	return false;
};

/**
 * Modification (saving) of data in the editor
 *
 * @param  {String} combedStyles
 */
Formatter.prototype._modifyEditorText = function(combedStyles) {
	var document = this.textEditor.document;
	var lastLine = document.lineAt(document.lineCount - 1);
	var selectAll = new vscode.Range(0, 0, lastLine.lineNumber, lastLine.range.end.character);
	this.textEditor.edit(function(editBuilder) {
		editBuilder.replace(selectAll, combedStyles);
	});
};

/**
 * Lifecycle extensions
 */
Formatter.prototype.cssComb = function() {
	var _that = this;
	var preset = vscode.workspace.getConfiguration('csscomb').preset || 'csscomb';
	if (typeof preset === 'string') {
		preset = Comb.getConfig(preset);
	}

	return vscode.workspace.findFiles('**/*csscomb.json', '{**/node_modules/**,**/bower_components/**}', 1)
		// Get array of files contain `csscomb.json` in name
		.then(function(arrayOfFiles) {
			if (arrayOfFiles.length) {
				return arrayOfFiles[0];
			}
		})
		// Read the configuration file
		.then(function(configPath) {
			if (configPath) {
				return vscode.workspace.openTextDocument(configPath);
			}
		})
		// Attempt to parse the JSON data
		.then(function(fileData) {
			if (fileData) {
				return _parseJsonFile(fileData.getText());
			}
		})
		// Run CSScomb
		.then(function(config) {
			var combedStyles = (config) ? _that._comb(config) : _that._comb(preset);
			if (combedStyles) {
				return _that._modifyEditorText(combedStyles);
			}
		});
};

exports.Engine = Formatter;
<|endoftext|>