<commit_before>var clone = require('clone');
var each = require('each');
var svgAttributes = require('svg-attributes');

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

/**
 * Element Types
 */

var types = [
  'labels',
  'segments',
  'segments_front',
  'segment_labels',
  'segment_label_containers',
  'stops_merged',
  'stops_pattern',
  'places',
  'places_icon',
  'multipoints_merged',
  'multipoints_pattern'
];

/**
 * Add transform
 */

svgAttributes.push('transform');

/**
 * Expose `Styler`
 */

module.exports = Styler;

/**
 * Styler object
 */

function Styler(styles) {
  if (!(this instanceof Styler)) return new Styler(styles);

  // reset styles
  this.reset();

  // load styles
  if (styles) this.load(styles);
}

/**
 * Clear all current styles
 */

Styler.prototype.clear = function() {
  for (var i in types) {
    this[types[i]] = {};
  }
};

/**
 * Reset to the predefined styles
 */

Styler.prototype.reset = function() {
  for (var i in types) {
    var type = types[i];
    this[type] = clone(styles[type] || {});
  }
};

/**
 * Load rules
 *
 * @param {Object} a set of style rules
 */

Styler.prototype.load = function(styles) {
  var self = this;
  for (var i in types) {
    var type = types[i];
    if (styles[type]) {
      for (var key in styles[type]) {
        this[type][key] = (this[type][key] || []).concat(styles[type][key]);
      }
    }
  }
};

/**
 * Render pattern
 *
 * @param {Display} display
 * @param {Pattern} pattern
 */

Styler.prototype.renderSegment = function(display, segment) {
  this.applyAttrAndStyle(
    display,
    segment.lineGraph,
    this.segments
  );

  this.applyAttrAndStyle(
    display,
    segment.lineGraphFront,
    this.segments_front
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Point} Transitive Point object
 */

Styler.prototype.renderPoint = function(display, point) {
  if (point.getType() === 'STOP') this.renderStop(display, point);
  if (point.getType() === 'PLACE') this.renderPlace(display, point);
  if (point.getType() === 'MULTI') this.renderMultiPoint(display, point);
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Stop} Transitive Stop object
 */

Styler.prototype.renderStop = function(display, stop) {
  this.applyAttrAndStyle(
    display,
    stop.patternMarkers,
    this.stops_pattern
  );

  this.applyAttrAndStyle(
    display,
    stop.mergedMarker,
    this.stops_merged
  );

  this.applyAttrAndStyle(
    display,
    stop.svgGroup.selectAll('.transitive-stop-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Place} Transitive Place object
 */

Styler.prototype.renderPlace = function(display, place) {
  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-circle'),
    this.places
  );

  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-icon'),
    this.places_icon
  );

  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {MultiPoint} Transitive MultiPoint object
 */

Styler.prototype.renderMultiPoint = function(display, multipoint) {
  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multipoint-marker-pattern'),
    this.multipoints_pattern
  );

  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multipoint-marker-merged'),
    this.multipoints_merged
  );

  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multi-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Point} Transitive Point object
 */

Styler.prototype.renderPointLabel = function(display, point) {
  var pointType = point.getType().toLowerCase();

  this.applyAttrAndStyle(
    display,
    point.svgGroup.selectAll('.transitive-' + pointType + '-label'),
    this.labels
  );
};

Styler.prototype.renderSegmentLabel = function(display, segment) {
  this.applyAttrAndStyle(
    display,
    segment.label.svgGroup.selectAll('.transitive-segment-label-container'),
    this.segment_label_containers
  );
  this.applyAttrAndStyle(
    display,
    segment.label.svgGroup.selectAll('.transitive-segment-label'),
    this.segment_labels
  );
};

/**
 * Check if it's an attribute or a style and apply accordingly
 *
 * @param {Display} the Display object
 * @param {Object} a D3 list of elements
 * @param {Object} the list of attributes
 */

Styler.prototype.applyAttrAndStyle = function(display, elements, attributes) {
  for (var name in attributes) {
    var rules = attributes[name];
    var fn = svgAttributes.indexOf(name) === -1 ? 'style' : 'attr';

    this.applyRules(display, elements, name, rules, fn);
  }
};

/**
 * Apply style/attribute rules to a list of elements
 *
 * @param {Display} display object
 * @param {Object} elements
 * @param {String} rule name
 * @param {Array} rules
 * @param {String} style/attr
 */

Styler.prototype.applyRules = function(display, elements, name, rules, fn) {
  var self = this;
  elements[fn](name, function(data, index) {
    return self.compute(rules, display, data, index);
  });
};

/**
 * Compute a style rule based on the current display and data
 *
 * @param {Array} array of rules
 * @param {Object} the Display object
 * @param {Object} data associated with this object
 * @param {Number} index of this object
 */

Styler.prototype.compute = function(rules, display, data, index) {
  var computed, self = this;
  for (var i in rules) {
    var rule = rules[i];
    var val = isFunction(rule) ? rule.call(self, display, data, index, styles.utils) :
      rule;
    if (val !== undefined && val !== null) computed = val;
  }
  return computed;
};

/**
 * Is function?
 */

function isFunction(val) {
  return Object.prototype.toString.call(val) === '[object Function]';
}
<commit_msg>Rules dont have to be arrays<commit_after>var clone = require('clone');
var each = require('each');
var svgAttributes = require('svg-attributes');

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

/**
 * Element Types
 */

var types = [
  'labels',
  'segments',
  'segments_front',
  'segment_labels',
  'segment_label_containers',
  'stops_merged',
  'stops_pattern',
  'places',
  'places_icon',
  'multipoints_merged',
  'multipoints_pattern'
];

/**
 * Add transform
 */

svgAttributes.push('transform');

/**
 * Expose `Styler`
 */

module.exports = Styler;

/**
 * Styler object
 */

function Styler(styles) {
  if (!(this instanceof Styler)) return new Styler(styles);

  // reset styles
  this.reset();

  // load styles
  if (styles) this.load(styles);
}

/**
 * Clear all current styles
 */

Styler.prototype.clear = function() {
  for (var i in types) {
    this[types[i]] = {};
  }
};

/**
 * Reset to the predefined styles
 */

Styler.prototype.reset = function() {
  for (var i in types) {
    var type = types[i];
    this[type] = clone(styles[type] || {});
    for (var key in this[type]) {
      if (!Array.isArray(this[type][key])) this[type][key] = [this[type[key]]];
    }
  }
};

/**
 * Load rules
 *
 * @param {Object} a set of style rules
 */

Styler.prototype.load = function(styles) {
  var self = this;
  for (var i in types) {
    var type = types[i];
    if (styles[type]) {
      for (var key in styles[type]) {
        this[type][key] = (this[type][key] || []).concat(styles[type][key]);
      }
    }
  }
};

/**
 * Render pattern
 *
 * @param {Display} display
 * @param {Pattern} pattern
 */

Styler.prototype.renderSegment = function(display, segment) {
  this.applyAttrAndStyle(
    display,
    segment.lineGraph,
    this.segments
  );

  this.applyAttrAndStyle(
    display,
    segment.lineGraphFront,
    this.segments_front
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Point} Transitive Point object
 */

Styler.prototype.renderPoint = function(display, point) {
  if (point.getType() === 'STOP') this.renderStop(display, point);
  if (point.getType() === 'PLACE') this.renderPlace(display, point);
  if (point.getType() === 'MULTI') this.renderMultiPoint(display, point);
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Stop} Transitive Stop object
 */

Styler.prototype.renderStop = function(display, stop) {
  this.applyAttrAndStyle(
    display,
    stop.patternMarkers,
    this.stops_pattern
  );

  this.applyAttrAndStyle(
    display,
    stop.mergedMarker,
    this.stops_merged
  );

  this.applyAttrAndStyle(
    display,
    stop.svgGroup.selectAll('.transitive-stop-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Place} Transitive Place object
 */

Styler.prototype.renderPlace = function(display, place) {
  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-circle'),
    this.places
  );

  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-icon'),
    this.places_icon
  );

  this.applyAttrAndStyle(
    display,
    place.svgGroup.selectAll('.transitive-place-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {MultiPoint} Transitive MultiPoint object
 */

Styler.prototype.renderMultiPoint = function(display, multipoint) {
  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multipoint-marker-pattern'),
    this.multipoints_pattern
  );

  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multipoint-marker-merged'),
    this.multipoints_merged
  );

  this.applyAttrAndStyle(
    display,
    multipoint.svgGroup.selectAll('.transitive-multi-label'),
    this.labels
  );
};

/**
 * Render elements against these rules
 *
 * @param {Display} a D3 list of elements
 * @param {Point} Transitive Point object
 */

Styler.prototype.renderPointLabel = function(display, point) {
  var pointType = point.getType().toLowerCase();

  this.applyAttrAndStyle(
    display,
    point.svgGroup.selectAll('.transitive-' + pointType + '-label'),
    this.labels
  );
};

Styler.prototype.renderSegmentLabel = function(display, segment) {
  this.applyAttrAndStyle(
    display,
    segment.label.svgGroup.selectAll('.transitive-segment-label-container'),
    this.segment_label_containers
  );
  this.applyAttrAndStyle(
    display,
    segment.label.svgGroup.selectAll('.transitive-segment-label'),
    this.segment_labels
  );
};

/**
 * Check if it's an attribute or a style and apply accordingly
 *
 * @param {Display} the Display object
 * @param {Object} a D3 list of elements
 * @param {Object} the list of attributes
 */

Styler.prototype.applyAttrAndStyle = function(display, elements, attributes) {
  for (var name in attributes) {
    var rules = attributes[name];
    var fn = svgAttributes.indexOf(name) === -1 ? 'style' : 'attr';

    this.applyRules(display, elements, name, rules, fn);
  }
};

/**
 * Apply style/attribute rules to a list of elements
 *
 * @param {Display} display object
 * @param {Object} elements
 * @param {String} rule name
 * @param {Array} rules
 * @param {String} style/attr
 */

Styler.prototype.applyRules = function(display, elements, name, rules, fn) {
  var self = this;
  elements[fn](name, function(data, index) {
    return self.compute(rules, display, data, index);
  });
};

/**
 * Compute a style rule based on the current display and data
 *
 * @param {Array} array of rules
 * @param {Object} the Display object
 * @param {Object} data associated with this object
 * @param {Number} index of this object
 */

Styler.prototype.compute = function(rules, display, data, index) {
  var computed, self = this;
  for (var i in rules) {
    var rule = rules[i];
    var val = isFunction(rule) ? rule.call(self, display, data, index, styles.utils) :
      rule;
    if (val !== undefined && val !== null) computed = val;
  }
  return computed;
};

/**
 * Is function?
 */

function isFunction(val) {
  return Object.prototype.toString.call(val) === '[object Function]';
}
<|endoftext|>


<commit_before>class Subscription {
  constructor(client) {
    this.client = client
  }

  get(options) {
    return this.client._request({
      method: 'GET',
      path: '/email/public/v1/subscriptions/timeline',
      qs: options,
    })
  }

  subscribeToAll(email) {
    return this.client._request({
      method: 'PUT',
      path: `/email/public/v1/subscriptions/${email}`,
      body: {
        subscribed: true,
      },
    })
  }
}

module.exports = Subscription
<commit_msg>Update subscription.js<commit_after>class Subscription {
  constructor(client) {
    this.client = client
  }

  get(options) {
    return this.client._request({
      method: 'GET',
      path: '/email/public/v1/subscriptions/timeline',
      qs: options,
    })
  }

  unsubscribe(email) {
    return this.client._request({
      method: 'PUT',
      path: `/email/public/v1/subscriptions/${email}`,
      body: {
        unsubscribeFromAll: true
      },
    })
  }

  subscribeToAll(email) {
    return this.client._request({
      method: 'PUT',
      path: `/email/public/v1/subscriptions/${email}`,
      body: {
        subscribed: true,
      },
    })
  }
}

module.exports = Subscription
<|endoftext|>


<commit_before>'use strict';

const axios = require('axios');

const exp = {};
module.exports = exp;

// Authorization header
const config = {
    headers: {
        'Authorization': `SFAPI email=${process.env.SF_AUTH_EMAIL
        }&apikey=${process.env.SF_AUTH_API_KEY
        }&company_id=${process.env.SF_AUTH_COMPANY_ID
        }&module=${process.env.SF_AUTH_MODULE}`,
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    }
};

const debugLib = require('debug')('lib-SF');
const logERR = require('debug')('ERROR:lib-SF');
const logWARN = require('debug')('WARN:lib-SF');
const logINFO = require('debug')('INFO:lib-SF');

const mongoose = require('mongoose');

const Invoice = mongoose.models.Invoice;

exp.mapInvoiceToSFInvoice = function(i){
    if (!i) {
        logWARN("Invoice not provided");
        return null;
    }

    const sfi = {};
    sfi.Client = {
        name: i.billOrg.name,

        address: i.billAdr.addresLine1 + i.billAdr.addresLine2?', '+i.billAdr.addresLine2:'',
        city: i.billAdr.city,
        zip: i.billAdr.postCode,

        ico: i.billOrg.companyNo,
        dic: i.billOrg.taxNo,
        ic_dph: i.billOrg.VATNo,

        email: i.billContact.email,
        phone: i.billContact.phone,
        iban: i.billOrg.bankAccount,

        delivery_address: i.billAdr.addresLine1 + i.billAdr.addresLine2?', '+i.billAdr.addresLine2:'',
        delivery_city: i.billAdr.city,
        delivery_zip: i.billAdr.postCode,
        delivery_phone: i.billContact.phone,
    };

    sfi.Invoice = {
        name:`Registracia team ${i.team?i.team.name:'???'} faktura ${i.number}`,
        invoice_no_formatted: i.number,
        created:  i.issuedOn.toISOString().substr(0,10),
        due: i.duedOn.toISOString().substr(0,10),
        payment_type: 'transfer',
        paydate: i.paidOn.toISOString().substr(0,10),
        already_paid: i.paidOn?1:0,
        mark_sent: 1
    };

    sfi.InvoiceItem = i.items.map(itm => ({
        name: itm.text,
        description: itm.note,
        quantity: itm.qty,
        tax:0,
        unit_price: itm.unitPrice
    }));

    debugLib("mapped invoice %o",sfi);

    return sfi;

}

exp.postSFInvoice = async function (sfInvoice) {

    try {
        debugLib('Posting to SF invoice=%o',sfInvoice)
        const result = await axios.post(`${process.env.SF_API_URL}/invoices/create`, 'data=' + JSON.stringify(sfInvoice), config);
        debugLib('result=%o',result);

        if (result.status != 200) {
            logERR(`Failed posting invoice to Superfaktura. code=${result.status} text=${result.statusText}`);
            return false;
        }

        if (result.data.error) {
            logERR('Superfaktura reported error=%o', result.data.error_message);
            return false;
        }

        return true;

    } catch(err) {
        logERR(`Error posting invoice to Superfaktura err=${err}`);
    }

    return false;
}<commit_msg>fixing undef<commit_after>'use strict';

const axios = require('axios');

const exp = {};
module.exports = exp;

// Authorization header
const config = {
    headers: {
        'Authorization': `SFAPI email=${process.env.SF_AUTH_EMAIL
        }&apikey=${process.env.SF_AUTH_API_KEY
        }&company_id=${process.env.SF_AUTH_COMPANY_ID
        }&module=${process.env.SF_AUTH_MODULE}`,
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    }
};

const debugLib = require('debug')('lib-SF');
const logERR = require('debug')('ERROR:lib-SF');
const logWARN = require('debug')('WARN:lib-SF');
const logINFO = require('debug')('INFO:lib-SF');

const mongoose = require('mongoose');

const Invoice = mongoose.models.Invoice;

exp.mapInvoiceToSFInvoice = function(i){
    if (!i) {
        logWARN("Invoice not provided");
        return null;
    }

    const sfi = {};
    sfi.Client = {
        name: i.billOrg.name,

        address: i.billAdr.addresLine1 + i.billAdr.addresLine2?', '+i.billAdr.addresLine2:'',
        city: i.billAdr.city,
        zip: i.billAdr.postCode,

        ico: i.billOrg.companyNo,
        dic: i.billOrg.taxNo,
        ic_dph: i.billOrg.VATNo,

        email: i.billContact.email,
        phone: i.billContact.phone,
        iban: i.billOrg.bankAccount,

        delivery_address: i.billAdr.addresLine1 + i.billAdr.addresLine2?', '+i.billAdr.addresLine2:'',
        delivery_city: i.billAdr.city,
        delivery_zip: i.billAdr.postCode,
        delivery_phone: i.billContact.phone,
    };

    sfi.Invoice = {
        name:`Registracia team ${i.team?i.team.name:'???'} faktura ${i.number}`,
        invoice_no_formatted: i.number,
        created:  i.issuedOn && i.issuedOn.toISOString().substr(0,10),
        due: i.dueOn && i.dueOn.toISOString().substr(0,10),
        payment_type: 'transfer',
        paydate: i.paidOn && i.paidOn.toISOString().substr(0,10),
        already_paid: i.paidOn?1:0,
        mark_sent: 1
    };

    sfi.InvoiceItem = i.items.map(itm => ({
        name: itm.text,
        description: itm.note,
        quantity: itm.qty,
        tax:0,
        unit_price: itm.unitPrice
    }));

    debugLib("mapped invoice %o",sfi);

    return sfi;

}

exp.postSFInvoice = async function (sfInvoice) {

    try {
        debugLib('Posting to SF invoice=%o',sfInvoice)
        const result = await axios.post(`${process.env.SF_API_URL}/invoices/create`, 'data=' + JSON.stringify(sfInvoice), config);
        debugLib('result=%o',result);

        if (result.status != 200) {
            logERR(`Failed posting invoice to Superfaktura. code=${result.status} text=${result.statusText}`);
            return false;
        }

        if (result.data.error) {
            logERR('Superfaktura reported error=%o', result.data.error_message);
            return false;
        }

        return true;

    } catch(err) {
        logERR(`Error posting invoice to Superfaktura err=${err}`);
    }

    return false;
}<|endoftext|>


<commit_before>var fs = require('fs'),
    console = require('console'),
    util = require('util'),
    emitter = require('events').EventEmitter;

var open_tag = /^(?:\s*)?<(?=[^/])(")?([^"\s]+)(?:\s+([^"]*))?(")?>(?:\s*#.*)?$/;
var close_tag = /^(?:\s*)?<\/("?)?([^"]+)?(")?>(?:\s*#.*)?$/;
var include_tag = /^(?:\s*)?<<include\s+(\S+)\s*>>(?:\s*#.*)?$/;

var comment_open = /\/\*.*/;
var comment_close = /.*\*\//;
var sline_comment = /^(?:\s*)?#(?:.*)?$/;
// key-value pair where the value ends with the multi-line split marker
var key_value_ml = /^\s*([\w\d_]+)\s*(?:=\s*)?(.+?)\s*\\$/;
// non-multiline key-value pairs with or without trailing comments
var key_value_sl = /^\s*([^=\s]+)\s*(?:=)?\s*([^=#]+|"[^=#]")(?:\s*#.*)?$/;
var ml_continues = /^\s*(.+?)\s*\\$/;
var heredoc_open = /^(\S+?)\s+<<\s*(\S+?)\s*$/;

function tokenizer() {
  emitter.apply(this);
  this.buffer = [];
  this.cpos = 0;
  this.filename = "";
  this.events = [ 'tagopen', 'tagclose', 'keyvalue', 'end', 'includereq' ];
}

tokenizer.prototype = Object.create( emitter.prototype );
tokenizer.prototype.open = function( filename ) {
  if( filename == undefined )
    throw new Error("open called without a filename");

  var self = this;
  var tb;
  var inComment = false;

  self.filename = filename;

  tb = fs.readFileSync( self.filename, 'utf8' ).split('\n');

  tb.forEach( function( elem, index, arr ) {
    if( !/^\s+$/.test(elem) &&
        !elem == "" &&
        !sline_comment.test(elem) ) {
      if( !inComment && comment_open.test(elem) ) {
        inComment = true;
      } else if( inComment && comment_close.test(elem) ) {
        inComment = false;
      } else if( !inComment ) {
        self.buffer.push( elem );
      }
    }
  });
};

tokenizer.prototype.get_token = function() {
  var self = this;
  if( self.buffer.length == 0 )
    throw new Error("get_token called when a file has not be opened!");

  if( self.cpos >= self.buffer.length ) {
    return { 'type': 'end' };
  }

  var cl = self.buffer[self.cpos];
  var rv = {};

  if( include_tag.test(cl) ) {
    var match = cl.match(include_tag);
    rv['type'] = 'includereq';
    rv['pattern'] = match[1];
    self.cpos++;
    return rv;
  } else if( open_tag.test(cl) ) {
    var match = cl.match(open_tag);
    rv['type'] = 'tagopen';
    if( match[1] == '"' ) {
      if( match[3] != undefined )
        rv['tagname'] = [ match[2].trim(), match[3].trim() ].join(' ');
      else
        rv['tagname'] = match[2].trim();
    } else if( match[3] != undefined ) {
      rv['tagname'] = match[2].trim();
      rv['data'] = match[3].trim();
    } else {
      rv['tagname'] = match[2].trim();
    }
    self.cpos++;
    return rv;
  } else if( close_tag.test(cl) ) {
    var match = cl.match(close_tag);
    rv['type'] = 'tagclose';
    rv['tagname'] = match[2].trim();
    self.cpos++;
    return rv;
  } else if( heredoc_open.test(cl) ) {
    rv['type'] = 'keyvalue';
    var match = cl.match( heredoc_open );
    var key = match[1].trim();
    var endmark = match[2].trim();
    var temp = [];

    self.cpos++;

    while( self.buffer[self.cpos].trim() != endmark ) {
      temp.push( self.buffer[self.cpos] );
      self.cpos++;
    }
    self.cpos++;

    rv['data'] = { 'name': key, 'value': temp.join('\n') };
    return rv;
  } else if( key_value_ml.test(cl) ) {
    var match = cl.match(key_value_ml);
    var temp = [ match[2].trim() ];
    var key = match[1].trim();
    rv['type'] = 'keyvalue';
    self.cpos++;
    while( ml_continues.test(self.buffer[self.cpos]) ) {
      temp.push( self.buffer[self.cpos].trim() );
      self.cpos++;
    }
    // we need the next line after an escaped newline regardless
    temp.push( self.buffer[self.cpos].trim() );
    rv['data'] = { 'name': key, 'value': temp.join(' ') };
      self.cpos++;

    return rv;
  } else if( key_value_sl.test(cl) ) {
    var match = cl.match(key_value_sl);
    rv['type'] = 'keyvalue';
    rv['data'] = { 'name': match[1].trim(), 'value': match[2].trim() };
    self.cpos++;
    return rv;
  } else {
    if( self.cpos > self.buffer.length ) {
      rv['type'] = 'end';
      return rv;
    }
    throw new Error("unknown value in input: "+cl);
  }
};

tokenizer.prototype.next = function() {
  var self = this;

  var work = self.get_token();

  switch(work['type']) {
    case 'tagopen':
    var cbd = {};
    cbd['name'] = work['tagname'];
    if( work['data'] != undefined ) {
      cbd['specname'] = work['data'];
    }
    self.emit( 'tagopen', cbd );
    break;
    case 'tagclose':
    self.emit( 'tagclose', work['tagname'] );
    break;
    case 'keyvalue':
    self.emit( 'keyvalue', work['data'] );
    break;
    case 'end':
    self.emit( 'end' );
    break;
    case 'includereq':
    self.emit( 'includereq', work['pattern'] );
    break;
    default:
    throw new Error('unknown data returned from get_token!');
  }
};

module.exports = tokenizer;
<commit_msg>this was a tiny bit broken compared to Config::General when it comes to key->value pairs and what a valid key is when the pair is separated by an equals sign.<commit_after>var fs = require('fs'),
    console = require('console'),
    util = require('util'),
    emitter = require('events').EventEmitter;

var open_tag = /^(?:\s*)?<(?=[^/])(")?([^"\s]+)(?:\s+([^"]*))?(")?>(?:\s*#.*)?$/;
var close_tag = /^(?:\s*)?<\/("?)?([^"]+)?(")?>(?:\s*#.*)?$/;
var include_tag = /^(?:\s*)?<<include\s+(\S+)\s*>>(?:\s*#.*)?$/;

var comment_open = /\/\*.*/;
var comment_close = /.*\*\//;
var sline_comment = /^(?:\s*)?#(?:.*)?$/;
// key-value pair where the value ends with the multi-line split marker
var key_value_ml_s = /^\s*([^\s]+)\s+(.+?)\s*\\$/;
var key_value_ml_e = /^\s*([^=]+)\s*=\s*("?[^"]+"?)\s*\\$/;
// non-multiline key-value pairs with or without trailing comments
var key_value_sl_s = /^\s*([^\s]+)\s*([^=#]+|"[^=#]")(?:\s*#.*)?$/;
var key_value_sl_e = /^\s*([^=]+)\s*=\s*("?[^"]+"?)(?:\s*#.*)?$/;
var ml_continues = /^\s*(.+?)\s*\\$/;
var heredoc_open = /^(\S+?)\s+<<\s*(\S+?)\s*$/;

function tokenizer() {
  emitter.apply(this);
  this.buffer = [];
  this.cpos = 0;
  this.filename = "";
  this.events = [ 'tagopen', 'tagclose', 'keyvalue', 'end', 'includereq' ];
}

tokenizer.prototype = Object.create( emitter.prototype );
tokenizer.prototype.open = function( filename ) {
  if( filename == undefined )
    throw new Error("open called without a filename");

  var self = this;
  var tb;
  var inComment = false;

  self.filename = filename;

  tb = fs.readFileSync( self.filename, 'utf8' ).split('\n');

  tb.forEach( function( elem, index, arr ) {
    if( !/^\s+$/.test(elem) &&
        !elem == "" &&
        !sline_comment.test(elem) ) {
      if( !inComment && comment_open.test(elem) ) {
        inComment = true;
      } else if( inComment && comment_close.test(elem) ) {
        inComment = false;
      } else if( !inComment ) {
        self.buffer.push( elem );
      }
    }
  });
};

tokenizer.prototype.get_token = function() {
  var self = this;
  if( self.buffer.length == 0 )
    throw new Error("get_token called when a file has not be opened!");

  if( self.cpos >= self.buffer.length ) {
    return { 'type': 'end' };
  }

  var cl = self.buffer[self.cpos];
  var rv = {};

  if( include_tag.test(cl) ) {
    var match = cl.match(include_tag);
    rv['type'] = 'includereq';
    rv['pattern'] = match[1];
    self.cpos++;
    return rv;
  } else if( open_tag.test(cl) ) {
    var match = cl.match(open_tag);
    rv['type'] = 'tagopen';
    if( match[1] == '"' ) {
      if( match[3] != undefined )
        rv['tagname'] = [ match[2].trim(), match[3].trim() ].join(' ');
      else
        rv['tagname'] = match[2].trim();
    } else if( match[3] != undefined ) {
      rv['tagname'] = match[2].trim();
      rv['data'] = match[3].trim();
    } else {
      rv['tagname'] = match[2].trim();
    }
    self.cpos++;
    return rv;
  } else if( close_tag.test(cl) ) {
    var match = cl.match(close_tag);
    rv['type'] = 'tagclose';
    rv['tagname'] = match[2].trim();
    self.cpos++;
    return rv;
  } else if( heredoc_open.test(cl) ) {
    rv['type'] = 'keyvalue';
    var match = cl.match( heredoc_open );
    var key = match[1].trim();
    var endmark = match[2].trim();
    var temp = [];

    self.cpos++;

    while( self.buffer[self.cpos].trim() != endmark ) {
      temp.push( self.buffer[self.cpos] );
      self.cpos++;
    }
    self.cpos++;

    rv['data'] = { 'name': key, 'value': temp.join('\n') };
    return rv;
  } else if( key_value_ml_e.test(cl) ) {
    var match = cl.match(key_value_ml_e);
    var temp = [ match[2].trim() ];
    var key = match[1].trim();
    rv['type'] = 'keyvalue';
    self.cpos++;
    while( ml_continues.test(self.buffer[self.cpos]) ) {
      temp.push( self.buffer[self.cpos].trim() );
      self.cpos++;
    }
    // we need the next line after an escaped newline regardless
    temp.push( self.buffer[self.cpos].trim() );
    rv['data'] = { 'name': key, 'value': temp.join(' ') };
      self.cpos++;

    return rv;
  } else if( key_value_ml_s.test(cl) ) {
    var match = cl.match(key_value_ml_s);
    var temp = [ match[2].trim() ];
    var key = match[1].trim();
    rv['type'] = 'keyvalue';
    self.cpos++;
    while( ml_continues.test(self.buffer[self.cpos]) ) {
      temp.push( self.buffer[self.cpos].trim() );
      self.cpos++;
    }
    // we need the next line after an escaped newline regardless
    temp.push( self.buffer[self.cpos].trim() );
    rv['data'] = { 'name': key, 'value': temp.join(' ') };
      self.cpos++;

    return rv;
  } else if( key_value_sl_e.test(cl) ) {
    var match = cl.match(key_value_sl_e);
    rv['type'] = 'keyvalue';
    rv['data'] = { 'name': match[1].trim(), 'value': match[2].trim() };
    self.cpos++;
    return rv;
  } else if( key_value_sl_s.test(cl) ) {
    var match = cl.match(key_value_sl_s);
    rv['type'] = 'keyvalue';
    rv['data'] = { 'name': match[1].trim(), 'value': match[2].trim() };
    self.cpos++;
    return rv;
  } else {
    if( self.cpos > self.buffer.length ) {
      rv['type'] = 'end';
      return rv;
    }
    throw new Error("unknown value in input: "+cl);
  }
};

tokenizer.prototype.next = function() {
  var self = this;

  var work = self.get_token();

  switch(work['type']) {
    case 'tagopen':
    var cbd = {};
    cbd['name'] = work['tagname'];
    if( work['data'] != undefined ) {
      cbd['specname'] = work['data'];
    }
    self.emit( 'tagopen', cbd );
    break;
    case 'tagclose':
    self.emit( 'tagclose', work['tagname'] );
    break;
    case 'keyvalue':
    self.emit( 'keyvalue', work['data'] );
    break;
    case 'end':
    self.emit( 'end' );
    break;
    case 'includereq':
    self.emit( 'includereq', work['pattern'] );
    break;
    default:
    throw new Error('unknown data returned from get_token!');
  }
};

module.exports = tokenizer;
<|endoftext|>


<commit_before>var BufferedSender = function() {};
BufferedSender.prototype.send_constructor = function(sender) {
    var that = this;
    that.send_buffer = [];
    that.sender = sender;
};
BufferedSender.prototype.doSend = function(message) {
    var that = this;
    that.send_buffer.push(message);
    if (!that.send_stop) {
        that.send_schedule();
    }
};

// For polling transports in a situation when in the message callback,
// new message is being send. If the sending connection was started
// before receiving one, it is possible to saturate the network and
// timeout due to the lack of receiving socket. To avoid that we delay
// sending messages by some small time, in order to let receiving
// connection be started beforehand. This is only a halfmeasure and
// does not fix the big problem, but it does make the tests go more
// stable on slow networks.
BufferedSender.prototype.send_schedule_wait = function() {
    var that = this;
    var tref;
    that.send_stop = function() {
        that.send_stop = null;
        clearTimeout(tref);
    };
    tref = utils.delay(25, function() {
        that.send_stop = null;
        that.send_schedule();
    });
};

BufferedSender.prototype.send_schedule = function() {
    var that = this;
    if (that.send_buffer.length > 0) {
        var payload = '[' + that.send_buffer.join(',') + ']';
        that.send_stop = that.sender(that.trans_url,
                                     payload,
                                     function() {
                                         that.send_stop = null;
                                         that.send_schedule_wait();
                                     });
        that.send_buffer = [];
    }
};

BufferedSender.prototype.send_destructor = function() {
    var that = this;
    if (that._send_stop) {
        that._send_stop();
    }
    that._send_stop = null;
};

var jsonPGenericSender = function(url, payload, callback) {
    var that = this;
    if (!('_send_form' in that)) {
        var form = that._send_form = _document.createElement('form');
        var area = that._send_area = _document.createElement('textarea');
        area.name = 'd';
        form.style.display = 'none';
        form.style.position = 'absolute';
        form.method = 'POST';
        form.enctype = 'application/x-www-form-urlencoded';
        form.acceptCharset = "UTF-8";
        form.appendChild(area);
        _document.body.appendChild(form);
    }
    var form = that._send_form;
    var area = that._send_area;
    var id = 'a' + utils.random_string(8);
    form.target = id;
    form.action = url + '/jsonp_send?i=' + id;

    var iframe;
    try {
        // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
        iframe = _document.createElement('<iframe name="'+ id +'">');
    } catch(x) {
        iframe = _document.createElement('iframe');
        iframe.name = id;
    }
    iframe.id = id;
    form.appendChild(iframe);
    iframe.style.display = 'none';

    area.value = payload;
    form.submit();

    var completed = function(e) {
        if (!iframe.onerror) return;
        iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
        // Opera mini doesn't like if we GC iframe
        // immediately, thus this timeout.
        setTimeout(function() {
                       iframe.parentNode.removeChild(iframe);
                       iframe = null;
                   }, 500);
        area.value = null;
        callback();
    };
    iframe.onerror = iframe.onload = completed;
    iframe.onreadystatechange = function(e) {
        if (iframe.readyState == 'complete') completed();
    };
    return completed;
};

var ajaxSender = function(url, payload, callback) {
    var orsc = function (xhr, e, abort_reason) {
        if(xhr.readyState === 4 || abort_reason) {
            callback(xhr.status, abort_reason);
        }
    };
    return utils.createXHR('POST', url + '/xhr_send', payload, orsc);
};

var xdrSender = function(url, payload, callback) {
    var orsc = function (xhr, e, abort_reason) {
        if(xhr.readyState === 4 || abort_reason) {
            callback(xhr.status, abort_reason);
        }
    };
    var fun = window.XDomainRequest ? utils.createXDR : utils.createXHR;
    return fun('POST', url + '/xhr_send', payload, orsc);
};

<commit_msg>Utils.delay<commit_after>var BufferedSender = function() {};
BufferedSender.prototype.send_constructor = function(sender) {
    var that = this;
    that.send_buffer = [];
    that.sender = sender;
};
BufferedSender.prototype.doSend = function(message) {
    var that = this;
    that.send_buffer.push(message);
    if (!that.send_stop) {
        that.send_schedule();
    }
};

// For polling transports in a situation when in the message callback,
// new message is being send. If the sending connection was started
// before receiving one, it is possible to saturate the network and
// timeout due to the lack of receiving socket. To avoid that we delay
// sending messages by some small time, in order to let receiving
// connection be started beforehand. This is only a halfmeasure and
// does not fix the big problem, but it does make the tests go more
// stable on slow networks.
BufferedSender.prototype.send_schedule_wait = function() {
    var that = this;
    var tref;
    that.send_stop = function() {
        that.send_stop = null;
        clearTimeout(tref);
    };
    tref = utils.delay(25, function() {
        that.send_stop = null;
        that.send_schedule();
    });
};

BufferedSender.prototype.send_schedule = function() {
    var that = this;
    if (that.send_buffer.length > 0) {
        var payload = '[' + that.send_buffer.join(',') + ']';
        that.send_stop = that.sender(that.trans_url,
                                     payload,
                                     function() {
                                         that.send_stop = null;
                                         that.send_schedule_wait();
                                     });
        that.send_buffer = [];
    }
};

BufferedSender.prototype.send_destructor = function() {
    var that = this;
    if (that._send_stop) {
        that._send_stop();
    }
    that._send_stop = null;
};

var jsonPGenericSender = function(url, payload, callback) {
    var that = this;
    if (!('_send_form' in that)) {
        var form = that._send_form = _document.createElement('form');
        var area = that._send_area = _document.createElement('textarea');
        area.name = 'd';
        form.style.display = 'none';
        form.style.position = 'absolute';
        form.method = 'POST';
        form.enctype = 'application/x-www-form-urlencoded';
        form.acceptCharset = "UTF-8";
        form.appendChild(area);
        _document.body.appendChild(form);
    }
    var form = that._send_form;
    var area = that._send_area;
    var id = 'a' + utils.random_string(8);
    form.target = id;
    form.action = url + '/jsonp_send?i=' + id;

    var iframe;
    try {
        // ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
        iframe = _document.createElement('<iframe name="'+ id +'">');
    } catch(x) {
        iframe = _document.createElement('iframe');
        iframe.name = id;
    }
    iframe.id = id;
    form.appendChild(iframe);
    iframe.style.display = 'none';

    area.value = payload;
    form.submit();

    var completed = function(e) {
        if (!iframe.onerror) return;
        iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
        // Opera mini doesn't like if we GC iframe
        // immediately, thus this timeout.
        utils.delay(500, function() {
                       iframe.parentNode.removeChild(iframe);
                       iframe = null;
                   });
        area.value = null;
        callback();
    };
    iframe.onerror = iframe.onload = completed;
    iframe.onreadystatechange = function(e) {
        if (iframe.readyState == 'complete') completed();
    };
    return completed;
};

var ajaxSender = function(url, payload, callback) {
    var orsc = function (xhr, e, abort_reason) {
        if(xhr.readyState === 4 || abort_reason) {
            callback(xhr.status, abort_reason);
        }
    };
    return utils.createXHR('POST', url + '/xhr_send', payload, orsc);
};

var xdrSender = function(url, payload, callback) {
    var orsc = function (xhr, e, abort_reason) {
        if(xhr.readyState === 4 || abort_reason) {
            callback(xhr.status, abort_reason);
        }
    };
    var fun = window.XDomainRequest ? utils.createXDR : utils.createXHR;
    return fun('POST', url + '/xhr_send', payload, orsc);
};

<|endoftext|>


<commit_before>var util = require('./util'),
    AdapterError = require('./errors'),
    db = require('./db'),
    Transaction; // fn

/**
 * Sails Transaction allows you to pass specific sails actions through common database connection allowing you to
 * leverage mySQL transactions support.
 *
 * @constructor
 * @param {function} callback - receives `error`, `transaction`
 */
Transaction = function (callback) {
    /**
     * Store the transaction ID
     * @memberOf Transaction.prototype
     * @type {String}
     * @private
     *
     * @note usually _id is set by connect and removed by disconnect, however since for some actions, we need the ID
     * before we have connection, we initially set it to a value.
     */
    this._id = util.uid();

    /**
     * Store the connection associated with this transaction.
     * @memberOf Transaction.prototype
     * @type {mysql.Connection}
     *
     * @note Initialisation sets this to null. Need to .connect() to set these
     * @private
     */
    this._connection = null;

    /**
     * Store the name of the connection DB (in case multiple db is used)
     * @memberOf Transaction.prototype
     * @type {String}
     *
     * @note Initialisation sets this to null. Need to .connect() to set these
     * @private
     */
    this._connectionName = null;

    callback(null, this);
};

// Add static functions to the Transaction constructor.
util.extend(Transaction, /** @lends Transaction */ {
    /**
     * Stores all ongoing database connections.
     * @private
     *
     * @type {object<mysql~connection>}
     */
    connections: {},

    /**
     * Stores all database connection sources.
     * @private
     *
     * @type {object}
     */
    databases: {},

    /**
     * Start a new transaction.
     *
     * @param {function} callback - receives (`error`, `{Transaction#}`)
     */
    start: function (callback) {
        return (new Transaction(callback));
    },

    /**
     * For first run, the transactions environment needs to be setup. Without that, it is not possible to procure new
     * database connections.
     */
    setup: function (config) {
        // at this stage, the `db` variable should not exist. expecting fresh setup or post teardown setup.
        if (Transaction.databases[config.identity]) {
            // @todo - emit wrror event instead of console.log
            console.log('Warn: duplicate setup of connection found in Transactions.setup');
            this.teardown();
        }

        var _db;

        // clone the configuration
        config = util.clone(config);
        delete config.replication;

        // allow special transaction related config
        util.each(config, function (value, name, config) {
            if (!/^transaction.+/g.test(name)) { return; }

            // remove transaction config prefix
            var baseName = name.replace(/^transaction/g, '');
            baseName = baseName.charAt(0).toLowerCase() + baseName.slice(1);

            delete config[name];
            config[baseName] = value;
        });

        _db = db.createSource(config);

        // Save a few configurations
        _db && (_db.transactionConfig = {
            rollbackOnError: config.rollbackTransactionOnError
        });

        Transaction.databases[config.identity] = _db;
    },

    /**
     * This function needs to be called at the end of app-lifecycle to ensure all db connections are closed.
     */
    teardown: function () {
        // just to be sure! clear all items in the connections object. they should be cleared by now
        util.each(this.connections, function (value, prop, conns) {
            try {
                value.release();
            }
            catch (e) { } // nothing to do with error
            delete conns[prop];
        });

        // now execute end on the databases. will end pool if pool, or otherwise will execute whatever
        // `end` that has been exposed by db.js
        util.each(Transaction.databases, function (value, prop, databases) {
            value.end();
            databases[prop] = null;
        });
    },

    /**
     * Use this function to extract the underlying db connection from a transaction id.
     * @private
     *
     * @param {object|string} id
     * @returns {object} - mySQL connection object
     */
    retrieveConnection: function (id) {
        return id && (this.connections[id] || this.connections[id.transactionId]) || undefined;
    },

    /**
     * Update the internal cache to associate a connection with a particular transaction id
     * @private
     *
     * @param {mysql.Connection} connection
     * @param {string} uid
     * @param {Object} config
     */
    associateConnection: function (connection, uid, config) {
        if (!uid) {
            // @todo throw error if association ID is absent
        }

        if (!config) {
            // @todo throw error if configuration is absent
        }

        if (connection.transactionId && Transaction.connections[connection.transactionId]) {
            throw new AdapterError(AdapterError.TRANSACTION_CONNECTION_OVERLAP);
        }

        // save all much needed info with the connection itself. remember to delete during disassociation
        connection.transactionId = uid;
        connection.transactionConfig = config;

        Transaction.connections[connection.transactionId] = connection;
    },

    /**
     * Update internal cache to disassociate a connection from a transaction id
     * @private
     *
     * @param {mysql.Connection} connection
     */
    disassociateConnection: function (connection) {
        delete Transaction.connections[connection.transactionId];
        connection.transactionId = null;
        connection.transactionConfig = null;
    }
});

util.extend(Transaction.prototype, /** @lends Transaction.prototype */ {
    /**
     * Returns the transaction id associated with this transaction instance. If the transaction is not connected,
     * it creates a new ID and caches it if things are not connected
     *
     * @returns {string}
     */
    id: function () {
        var connection = this.connection();

        // if a connection is defined, get the ID from connection
        if (connection) {
            if (!connection.transactionId) {
                // @todo throw error if connection is associated but has no id. that would be weird.
            }

            return (this._id = connection.transactionId); // save it just in case, during return
        }

        // at this point if we do not have an id, we know that we will need to return a dummy one
        return this._id || (this._id = util.uid());
    },

    /**
     * Gets the instance of the db connection associated with this transaction. The connection object is sealed off
     * within the Transaction constructor to avoid any sort of integrity loss while the transaction or the actor is
     * moved along the codebase.
     *
     * @private
     * @returns {mysql.Connection}
     */
    connection: function () {
        return this._connection;
    },

    /**
     * Creates a connection if not already connected.
     *
     * @private
     * @returns {mysql.Connection}
     */
    connect: function (connectionName, callback) {
        var self = this,
            _db = Transaction.databases[connectionName],
            transactionId;

        // validate db setup prior to every connection. this ensures nothing goes forward post teardown
        if (!_db) {
            callback(new AdapterError(AdapterError.TRANSACTION_NOT_SETUP));
        }

        // validate connection name
        if (!connectionName) {
            callback(new AdapterError(AdapterError.TRANSACTION_NOT_IDENTIFIED));
        }

        // if this transaction is already connected, then continue
        if (self.connection()) {
            // @todo implement error check when multi-db conn is atempted
            // // callback with error if connection name and current connection mismatch
            // if (connectionName !== self.connection().identity) {
            //     callback(new AdapterError(AdapterError.TRANSACTION_MULTI_DB_CONNECTION_ATTEMPTED));
            // }

            callback(undefined, self.connection());
            return;
        }

        // at this point, it seems like thet connection has not been setup yet, so we setup one and then move forward
        transactionId = self.id(); // this will return and cache a new transaction ID if not already present

        // set the actual connection name
        self._connectionName = connectionName;

        _db.getConnection(function (error, conn) {
            if (!error) {
                self._connection = conn; // save reference
                Transaction.associateConnection(conn, transactionId, _db.transactionConfig); // @note disassociate on dc
            }

            callback(error, self._connection);
        });
    },

    /**
     * Clears the internal reference of the connection with this transaction
     *
     * @private
     */
    disconnect: function () {
        this._connection = null;
        this._id = null;
        this._connectionName = null;
    },

    /**
     * Start a new transaction.
     *
     * @param connectionName
     * @param callback
     */
    start: function (connectionName, callback) {
        var self = this,
            conn = self.connection();

        // if not yet connected, spawn new connection and initiate transaction
        if (!conn) {
            self.connect(connectionName, function (error, conn) {
                if (error) {
                    callback(error, conn);
                    return;
                }
                // now that we have the connection, we initiate transaction. note that this sql_start is part of the new
                // connection branch. it is always highly likely that this would be the program flow. in a very unlikely
                // case the alternate flow will kick in, which is the `conn.query` right after this if-block.
                conn.beginTransaction(function (error) {
                    callback(error, self);
                });
            });

            return; // do not proceed with sql_start if connection wasn't initially present.
        }

        // if transaction is attempted across multiple connections, return an error
        if (connectionName !== self._connectionName) {
            return callback(new AdapterError(AdapterError.TRANSACTION_MULTI_DB_CONNECTION_ATTEMPTED));
        }

        conn.beginTransaction(function (error) {
            // if callback mode is used, then execute it and send self as a parameter to match the new Constructor API.
            callback(error, self);
        });
    },

    /**
     * Use this function on the new instance of the transaction to mark a query as part of this transaction
     *
     * @param {*} query
     * @returns {*}
     */
    wrap: function (query) {
        return util.wrapquery(query, this.id());
    },

    /**
     * Commit the transaction
     * @param {function} callback - receives `error`
     */
    commit: function (callback) {
        var conn = this.connection();

        // prevent new transactions from using this connection.
        this.disconnect();

        // if commit was called with no active conn, it implies, no transact action
        // was called. as such it is an error.
        conn ? conn.commit(function (error) {
            // try releasing the connection.
            // if that fails then treat it as a major error.
            try {
                conn.release();
            }
            // if there was an error during release, set that as the main error.
            catch (err) {
                !error && (error = err);
            }

            // if failure to issue commit or release, then rollback
            if (error && conn.transactionConfig.rollbackOnError) {
                return conn.rollback(function () {
                    // disassociate the connection from transaction and execute callback
                    Transaction.disassociateConnection(conn);
                    callback && callback(error);
                });
            }

            // disassociate the connection from transaction and execute callback
            Transaction.disassociateConnection(conn);
            callback && callback(error);
        }) : (callback && callback(new AdapterError(AdapterError.TRANSACTION_UNINITIATED_COMM)));
    },

    /**
     * Rollback the transaction
     * @param {function} callback - receives `error`
     */
    rollback: function (callback) {
        var conn = this.connection();

        // prevent new transactions from using this connection.
        this.disconnect();

        // if commit was called with no active conn, it implies, no transact action
        // was called. as such it is an error.
        conn ? conn.rollback(function (error) {
            // try releasing the connection.
            // if that fails then treat it as a major error.
            try {
                conn.release();
            }
            // if there was an error during release, set that as the main error.
            catch (err) {
                !error && (error = err);
            }

            // disassociate the connection from transaction and execute callback
            Transaction.disassociateConnection(conn);
            callback && callback(error);
        }) : (callback && callback(new AdapterError(AdapterError.TRANSACTION_UNINITIATED_ROLL)));
    },

    toString: function () {
        return '[object Transaction:' + (this.connection() && this.connection().transactionId || 'disconnected') + ']';
    }
});

module.exports = Transaction;
<commit_msg>Fixed logical issue of disconnecting on commit / rollback error<commit_after>var util = require('./util'),
    AdapterError = require('./errors'),
    db = require('./db'),
    Transaction; // fn

/**
 * Sails Transaction allows you to pass specific sails actions through common database connection allowing you to
 * leverage mySQL transactions support.
 *
 * @constructor
 * @param {function} callback - receives `error`, `transaction`
 */
Transaction = function (callback) {
    /**
     * Store the transaction ID
     * @memberOf Transaction.prototype
     * @type {String}
     * @private
     *
     * @note usually _id is set by connect and removed by disconnect, however since for some actions, we need the ID
     * before we have connection, we initially set it to a value.
     */
    this._id = util.uid();

    /**
     * Store the connection associated with this transaction.
     * @memberOf Transaction.prototype
     * @type {mysql.Connection}
     *
     * @note Initialisation sets this to null. Need to .connect() to set these
     * @private
     */
    this._connection = null;

    /**
     * Store the name of the connection DB (in case multiple db is used)
     * @memberOf Transaction.prototype
     * @type {String}
     *
     * @note Initialisation sets this to null. Need to .connect() to set these
     * @private
     */
    this._connectionName = null;

    callback(null, this);
};

// Add static functions to the Transaction constructor.
util.extend(Transaction, /** @lends Transaction */ {
    /**
     * Stores all ongoing database connections.
     * @private
     *
     * @type {object<mysql~connection>}
     */
    connections: {},

    /**
     * Stores all database connection sources.
     * @private
     *
     * @type {object}
     */
    databases: {},

    /**
     * Start a new transaction.
     *
     * @param {function} callback - receives (`error`, `{Transaction#}`)
     */
    start: function (callback) {
        return (new Transaction(callback));
    },

    /**
     * For first run, the transactions environment needs to be setup. Without that, it is not possible to procure new
     * database connections.
     */
    setup: function (config) {
        // at this stage, the `db` variable should not exist. expecting fresh setup or post teardown setup.
        if (Transaction.databases[config.identity]) {
            // @todo - emit wrror event instead of console.log
            console.log('Warn: duplicate setup of connection found in Transactions.setup');
            this.teardown();
        }

        var _db;

        // clone the configuration
        config = util.clone(config);
        delete config.replication;

        // allow special transaction related config
        util.each(config, function (value, name, config) {
            if (!/^transaction.+/g.test(name)) { return; }

            // remove transaction config prefix
            var baseName = name.replace(/^transaction/g, '');
            baseName = baseName.charAt(0).toLowerCase() + baseName.slice(1);

            delete config[name];
            config[baseName] = value;
        });

        _db = db.createSource(config);

        // Save a few configurations
        _db && (_db.transactionConfig = {
            rollbackOnError: config.rollbackTransactionOnError
        });

        Transaction.databases[config.identity] = _db;
    },

    /**
     * This function needs to be called at the end of app-lifecycle to ensure all db connections are closed.
     */
    teardown: function () {
        // just to be sure! clear all items in the connections object. they should be cleared by now
        util.each(this.connections, function (value, prop, conns) {
            try {
                value.release();
            }
            catch (e) { } // nothing to do with error
            delete conns[prop];
        });

        // now execute end on the databases. will end pool if pool, or otherwise will execute whatever
        // `end` that has been exposed by db.js
        util.each(Transaction.databases, function (value, prop, databases) {
            value.end();
            databases[prop] = null;
        });
    },

    /**
     * Use this function to extract the underlying db connection from a transaction id.
     * @private
     *
     * @param {object|string} id
     * @returns {object} - mySQL connection object
     */
    retrieveConnection: function (id) {
        return id && (this.connections[id] || this.connections[id.transactionId]) || undefined;
    },

    /**
     * Update the internal cache to associate a connection with a particular transaction id
     * @private
     *
     * @param {mysql.Connection} connection
     * @param {string} uid
     * @param {Object} config
     */
    associateConnection: function (connection, uid, config) {
        if (!uid) {
            // @todo throw error if association ID is absent
        }

        if (!config) {
            // @todo throw error if configuration is absent
        }

        if (connection.transactionId && Transaction.connections[connection.transactionId]) {
            throw new AdapterError(AdapterError.TRANSACTION_CONNECTION_OVERLAP);
        }

        // save all much needed info with the connection itself. remember to delete during disassociation
        connection.transactionId = uid;
        connection.transactionConfig = config;

        Transaction.connections[connection.transactionId] = connection;
    },

    /**
     * Update internal cache to disassociate a connection from a transaction id
     * @private
     *
     * @param {mysql.Connection} connection
     */
    disassociateConnection: function (connection) {
        delete Transaction.connections[connection.transactionId];
        connection.transactionId = null;
        connection.transactionConfig = null;
    }
});

util.extend(Transaction.prototype, /** @lends Transaction.prototype */ {
    /**
     * Returns the transaction id associated with this transaction instance. If the transaction is not connected,
     * it creates a new ID and caches it if things are not connected
     *
     * @returns {string}
     */
    id: function () {
        var connection = this.connection();

        // if a connection is defined, get the ID from connection
        if (connection) {
            if (!connection.transactionId) {
                // @todo throw error if connection is associated but has no id. that would be weird.
            }

            return (this._id = connection.transactionId); // save it just in case, during return
        }

        // at this point if we do not have an id, we know that we will need to return a dummy one
        return this._id || (this._id = util.uid());
    },

    /**
     * Gets the instance of the db connection associated with this transaction. The connection object is sealed off
     * within the Transaction constructor to avoid any sort of integrity loss while the transaction or the actor is
     * moved along the codebase.
     *
     * @private
     * @returns {mysql.Connection}
     */
    connection: function () {
        return this._connection;
    },

    /**
     * Creates a connection if not already connected.
     *
     * @private
     * @returns {mysql.Connection}
     */
    connect: function (connectionName, callback) {
        var self = this,
            _db = Transaction.databases[connectionName],
            transactionId;

        // validate db setup prior to every connection. this ensures nothing goes forward post teardown
        if (!_db) {
            callback(new AdapterError(AdapterError.TRANSACTION_NOT_SETUP));
        }

        // validate connection name
        if (!connectionName) {
            callback(new AdapterError(AdapterError.TRANSACTION_NOT_IDENTIFIED));
        }

        // if this transaction is already connected, then continue
        if (self.connection()) {
            // @todo implement error check when multi-db conn is atempted
            // // callback with error if connection name and current connection mismatch
            // if (connectionName !== self.connection().identity) {
            //     callback(new AdapterError(AdapterError.TRANSACTION_MULTI_DB_CONNECTION_ATTEMPTED));
            // }

            callback(undefined, self.connection());
            return;
        }

        // at this point, it seems like thet connection has not been setup yet, so we setup one and then move forward
        transactionId = self.id(); // this will return and cache a new transaction ID if not already present

        // set the actual connection name
        self._connectionName = connectionName;

        _db.getConnection(function (error, conn) {
            if (!error) {
                self._connection = conn; // save reference
                Transaction.associateConnection(conn, transactionId, _db.transactionConfig); // @note disassociate on dc
            }

            callback(error, self._connection);
        });
    },

    /**
     * Clears the internal reference of the connection with this transaction
     *
     * @private
     */
    disconnect: function () {
        this._connection = null;
        this._id = null;
        this._connectionName = null;
    },

    /**
     * Start a new transaction.
     *
     * @param connectionName
     * @param callback
     */
    start: function (connectionName, callback) {
        var self = this,
            conn = self.connection();

        // if not yet connected, spawn new connection and initiate transaction
        if (!conn) {
            self.connect(connectionName, function (error, conn) {
                if (error) {
                    callback(error, conn);
                    return;
                }
                // now that we have the connection, we initiate transaction. note that this sql_start is part of the new
                // connection branch. it is always highly likely that this would be the program flow. in a very unlikely
                // case the alternate flow will kick in, which is the `conn.query` right after this if-block.
                conn.beginTransaction(function (error) {
                    callback(error, self);
                });
            });

            return; // do not proceed with sql_start if connection wasn't initially present.
        }

        // if transaction is attempted across multiple connections, return an error
        if (connectionName !== self._connectionName) {
            return callback(new AdapterError(AdapterError.TRANSACTION_MULTI_DB_CONNECTION_ATTEMPTED));
        }

        conn.beginTransaction(function (error) {
            // if callback mode is used, then execute it and send self as a parameter to match the new Constructor API.
            callback(error, self);
        });
    },

    /**
     * Use this function on the new instance of the transaction to mark a query as part of this transaction
     *
     * @param {*} query
     * @returns {*}
     */
    wrap: function (query) {
        return util.wrapquery(query, this.id());
    },

    /**
     * Commit the transaction
     * @param {function} callback - receives `error`
     */
    commit: function (callback) {
        var conn = this.connection();

        // if commit was called with no active conn, it implies, no transact action
        // was called. as such it is an error.
        if (!conn) {
            return callback && callback(new AdapterError(AdapterError.TRANSACTION_UNINITIATED_COMM));
        }

        // prevent new transactions from using this connection.
        this.disconnect();

        // we commit the connection and then release from hash
        conn.commit(function (error) {
            // try releasing the connection.
            // if that fails then treat it as a major error.
            try {
                conn.release();
            }
            // if there was an error during release, set that as the main error.
            catch (err) {
                !error && (error = err);
            }

            // if failure to issue commit or release, then rollback
            if (error && conn.transactionConfig.rollbackOnError) {
                return conn.rollback(function () {
                    // disassociate the connection from transaction and execute callback
                    Transaction.disassociateConnection(conn);
                    callback && callback(error);
                });
            }

            // disassociate the connection from transaction and execute callback
            Transaction.disassociateConnection(conn);
            callback && callback(error);
        });
    },

    /**
     * Rollback the transaction
     * @param {function} callback - receives `error`
     */
    rollback: function (callback) {
        var conn = this.connection();

        // if commit was called with no active conn, it implies, no transact action
        // was called. as such it is an error.
        if (!conn) {
            return callback && callback(new AdapterError(AdapterError.TRANSACTION_UNINITIATED_ROLL));
        }

        // prevent new transactions from using this connection.
        this.disconnect();

        conn.rollback(function (error) {
            // try releasing the connection.
            // if that fails then treat it as a major error.
            try {
                conn.release();
            }
            // if there was an error during release, set that as the main error.
            catch (err) {
                !error && (error = err);
            }

            // disassociate the connection from transaction and execute callback
            Transaction.disassociateConnection(conn);
            callback && callback(error);
        });
    },

    toString: function () {
        return '[object Transaction:' + (this.connection() && this.connection().transactionId || 'disconnected') + ']';
    }
});

module.exports = Transaction;
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var current_version = require('../version');
var transform_utils = require('../transform_utils');

var version_incrementer = transform_utils.version_incrementer;
var top_level_types = transform_utils.top_level_types;
var recursion_keys = transform_utils.recursion_keys;
var accumulatorFor = transform_utils.accumulatorFor;
var limitFields = transform_utils.limitFields;
var cleanFieldNames = transform_utils.cleanFieldNames;

// Tags in 0.5.7 were mostly undefined object. In 0.5.8 they have specified properties. Fields which
// match the new properties should be preserved, those that do not should be moved into additional_properties.
var convertTag = function convertTag(old_tag) {

  var additional_properties = _.has(old_tag, 'additional_properties') && _.isObject(old_tag.additional_properties) ?
      _.cloneDeep(old_tag.additional_properties) : {};

  var tag = _.transform(old_tag, function(result, value, key, object) {
    // Specced Tag fields for 0.5.8
    if (_.includes(['_id', 'text', 'description', 'slug'], key)) {
      result[key] = value;
    }
    else {
      // Example: .foo should become .additional_properties.foo
      // In the unlikely even that .additional_properties.foo already existed on the old object,
      // then this will overwrite it (but it will show up as .additional_properties.additional_properties.foo)
      additional_properties[key] = value;
      // 'tag' was in use in some places in lieu of text, so copy over if possible
      if (key === 'tag' && !_.has(object, 'text')) {
        result['text'] = value;
      }
    }
  }, {});

  if (_.size(additional_properties) > 0) {
    tag.additional_properties = additional_properties;
  }

  return tag;
};

// Move label from undefined object to new format
var convertLabel = function convertLabel(old_label) {

  // Force each label to have correct keys.
  var label = _.transform(old_label, function(result, value, key, object) {

    if (key !== 'additional_properties') {
      var label_item = limitFields(['text', 'url', 'display', 'additional_properties'], value);
      if (!_.has(label_item, 'text')) {
        label_item.text = '';
      }

      result[key] = label_item;
    }
    else {
      result[key] = value;
    }
  }, {});

  if (!_.has(label, 'basic')) {
    label.basic = {
      'text': ''
    };
  }

  // Rename invalid keys to valid names.
  return cleanFieldNames(label);

};

// Move source from undefined object to new format
var convertSource = function convertSource(old_source) {
  var source = limitFields(['source_id', 'source_type', 'name', 'system', 'additional_properties'], old_source);
  return source;
};

// Move comments from undefined object to new format
var convertComments = function convertComments(old_comments) {
  var comments = limitFields(['comments_period', 'allow_comments', 'display_comments', 'moderation_required'], old_comments);
  return comments;
};

// Convert a top-level ANS document and recur at known points
var convertDocument = function convertDocument(doc) {
  return _.transform(doc, function(result, value, key, object) {
    if (key === 'taxonomy') {
      var taxonomy = {};
      _.assign(taxonomy, value, { 'tags': _.map(value.tags, convertTag) });
      result[key] = taxonomy;
    }
    else if (key === 'label') {
      result[key] = convertLabel(value);
    }
    else if (key === 'source') {
      result[key] = convertSource(value);
    }
    else if (key === 'comments') {
      result[key] = convertComments(value);
    }
    else if (_.includes(recursion_keys, key)) {
      result[key] = convert(value);
    }
  }, doc);
};

// Generic recur-and-convert down object tree
var convert = function convert(ans) {
  if (!_.isObject(ans)) {
    return ans;
  }

  if (_.isArray(ans)) {
    return _.map(ans, convert);
  }

  if (_.has(ans, 'type') &&
      _.includes(top_level_types, ans.type)) {
    return convertDocument(ans);
  }

  return _.transform(ans, function(result, value, key, object) {
    if (key === 'additional_properties' || key === 'referent_properties') {
      result[key] = value;
    }
    else {
      result[key] = convert(value);
    }
  }, accumulatorFor(ans));
};

var upvert = function(input) {
  var output = version_incrementer('0.5.8')(input);

  return convertDocument(output);
};

module.exports = upvert;
<commit_msg>Allow additional_properties to be retained during upvert<commit_after>'use strict';

var _ = require('lodash');
var current_version = require('../version');
var transform_utils = require('../transform_utils');

var version_incrementer = transform_utils.version_incrementer;
var top_level_types = transform_utils.top_level_types;
var recursion_keys = transform_utils.recursion_keys;
var accumulatorFor = transform_utils.accumulatorFor;
var limitFields = transform_utils.limitFields;
var cleanFieldNames = transform_utils.cleanFieldNames;

// Tags in 0.5.7 were mostly undefined object. In 0.5.8 they have specified properties. Fields which
// match the new properties should be preserved, those that do not should be moved into additional_properties.
var convertTag = function convertTag(old_tag) {

  var additional_properties = _.has(old_tag, 'additional_properties') && _.isObject(old_tag.additional_properties) ?
      _.cloneDeep(old_tag.additional_properties) : {};

  var tag = _.transform(old_tag, function(result, value, key, object) {
    // Specced Tag fields for 0.5.8
    if (_.includes(['_id', 'text', 'description', 'slug'], key)) {
      result[key] = value;
    }
    else {
      // Example: .foo should become .additional_properties.foo
      // In the unlikely even that .additional_properties.foo already existed on the old object,
      // then this will overwrite it (but it will show up as .additional_properties.additional_properties.foo)
      additional_properties[key] = value;
      // 'tag' was in use in some places in lieu of text, so copy over if possible
      if (key === 'tag' && !_.has(object, 'text')) {
        result['text'] = value;
      }
    }
  }, {});

  if (_.size(additional_properties) > 0) {
    tag.additional_properties = additional_properties;
  }

  return tag;
};

// Move label from undefined object to new format
var convertLabel = function convertLabel(old_label) {

  // Force each label to have correct keys.
  var label = _.transform(old_label, function(result, value, key, object) {

    if (key !== 'additional_properties') {
      var label_item = limitFields(['text', 'url', 'display', 'additional_properties'], value);
      if (!_.has(label_item, 'text')) {
        label_item.text = '';
      }

      result[key] = label_item;
    }
    else {
      result[key] = value;
    }
  }, {});

  if (!_.has(label, 'basic')) {
    label.basic = {
      'text': ''
    };
  }

  // Rename invalid keys to valid names.
  return cleanFieldNames(label);

};

// Move source from undefined object to new format
var convertSource = function convertSource(old_source) {
  var source = limitFields(['source_id', 'source_type', 'name', 'system', 'additional_properties'], old_source);
  return source;
};

// Move comments from undefined object to new format
var convertComments = function convertComments(old_comments) {
  var comments = limitFields(['comments_period', 'allow_comments', 'display_comments', 'moderation_required',
                              'additional_properties'], old_comments);
  return comments;
};

// Convert a top-level ANS document and recur at known points
var convertDocument = function convertDocument(doc) {
  return _.transform(doc, function(result, value, key, object) {
    if (key === 'taxonomy') {
      var taxonomy = {};
      _.assign(taxonomy, value, { 'tags': _.map(value.tags, convertTag) });
      result[key] = taxonomy;
    }
    else if (key === 'label') {
      result[key] = convertLabel(value);
    }
    else if (key === 'source') {
      result[key] = convertSource(value);
    }
    else if (key === 'comments') {
      result[key] = convertComments(value);
    }
    else if (_.includes(recursion_keys, key)) {
      result[key] = convert(value);
    }
  }, doc);
};

// Generic recur-and-convert down object tree
var convert = function convert(ans) {
  if (!_.isObject(ans)) {
    return ans;
  }

  if (_.isArray(ans)) {
    return _.map(ans, convert);
  }

  if (_.has(ans, 'type') &&
      _.includes(top_level_types, ans.type)) {
    return convertDocument(ans);
  }

  return _.transform(ans, function(result, value, key, object) {
    if (key === 'additional_properties' || key === 'referent_properties') {
      result[key] = value;
    }
    else {
      result[key] = convert(value);
    }
  }, accumulatorFor(ans));
};

var upvert = function(input) {
  var output = version_incrementer('0.5.8')(input);

  return convertDocument(output);
};

module.exports = upvert;
<|endoftext|>


<commit_before>'use strict';

var registry = {};

module.exports = function(name, callback) {
  if (callback) {
    registry[name] = callback;
  } else if (typeof name === 'object') {
    for (var method in name) {
      registry[method] = name[method];
    }
  } else {
    return registry[name];
  }

  return registry;
};
<commit_msg>Validate name first<commit_after>'use strict';

var registry = {};

module.exports = function(name, callback) {
  if (callback) {
    registry[name] = callback;
  } else if (typeof name === 'object') {
    for (var method in name) {
      registry[method] = name[method];
    }
  } else if (name) {
    return registry[name];
  }

  return registry;
};
<|endoftext|>


<commit_before>// Copyright 2015 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

'use strict';
<commit_msg>Add TLS-based validation<commit_after>// Copyright 2015 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

'use strict';

var util   = require('./utils');
var crypto = require('./crypto-utils');
var dns    = require('native-dns');

// The fields that should be present in a completed challenge
const CHALLENGE_FIELDS = ['type', 'token', 'keyAuthorization'];

/**
 * A TLSSNI01Validator performs the client-side half of the ACME 'tls-sni-01'
 * validation.  Based on a challenge, it creates a sequence of hashes values and
 * responds in the correct way to TLS queries to server names based on those
 * hash values.
 */
class TLSSNI01Validator {
  /**
   * Create a DNS validation server.
   *
   * @param  {string}  domain    Domain name being validated
   * @param  {object}  challenge ACME challenge object being used for validation
   * @param  {integer} port      Port number on which to listen
   * @return {TLSSNI01Validator} The created server object
   * @throws {TypeError}         Invalid challenge
   */
  constructor(domain, challenge, port) {
    if (!util.fieldsPresent(CHALLENGE_FIELDS, challenge) ||
        (challenge.type !== 'tls-sni-01')) {
      throw new TypeError('Mal-formed challenge');
    }

    this.ready = crypto.generateKeyPair(2048)
    .then((keyPair) => {
      var privateKeyPEM = crypto.privateKeyToPem(keyPair.privateKey);
      var defaultCertPEM = crypto.selfSigned('acme.invalid', keyPair);

      var opts = {
        key:  privateKeyPEM,
        cert: defaultCertPEM
      };
      var closeImmediately = function(socket) { socket.end(); };
      this.server = tls.createServer(opts, closeImmediately);

      var n = challenge.n || 1;
      var z = challenge.keyAuthorization;
      for (var i=0; i<n; ++i) {
        // Z(i) = lowercase_hexadecimal(SHA256(Z(i-1)))
        z = crypto.sha256(new Buffer(z)).toString('hex').toLowerCase();
        var zName = z.substr(0, 32) + '.' + z.substr(32) + '.acme.invalid';

        var certPEM = crypto.selfSigned(zName, keyPair);
        this.server.addContext(zName, {
          key:  privateKeyPEM,
          cert: certPEM
        });
      }
    });
  }

  /**
   * Start the server
   *
   * @return {TLSSNI01Validator} Object instance
   */
  start() {
    this.server.listen(this.port);
    return this;
  }

  /**
   * Stop the server
   *
   * @return {TLSSNI01Validator} Object instance
   */
  stop() {
    this.server.close();
    return this;
  }
}

module.exports = TLSSNI01Validator;
<|endoftext|>


<commit_before>exports.createConfig = function(config) {
  return new Config(config);
}

function Config(config) {
  this.root = ".";
  this.viewDir = ".";
  this.reloadTemplates = false;
}

Config.prototype = {
  configure: function(config) {
    for (var key in config)
      if (config.hasOwnProperty(key)) {
        this[key] = config[key];
      }
  },

  set root(path) {
    if (/\.[^./]+$/.exec(path))
      this._root = node.path.dirname(path);
    else
      this._root = path;
  },

  get root() {
    return this._root;
  }
}
<commit_msg>Changed the Config system. Much more flexible and easier to use (hopefully).<commit_after>/**
 * Constructor for the Vroom.Config class. This class is responsible
 * for the configuration of the Vroom.Application.
 *
 * @param {Vroom.Application} application The application the config is for
 */
exports.Config = function Config(application) {
  this.application = application;

  this.root = ".";
  // this.viewDir = ".";
  // this.reloadTemplates = false;
}

var Conf = exports.Config;

Conf.options = [];

/**
 * Add a configurable option.
 *
 * @param {String} name The name of the option
 * @param {String} desc The description of the option
 * @param {Array} values Values the option can be set to
 */
Conf.addOption = function(name, desc, values) {
  Conf.options.push({
    name: name,
    desc: desc,
    values: values
  });
};

/**
 * Checks to see if a given option name actually exists.
 *
 * @param {String} name The name of the option to test for
 */
Conf.hasOption = function(name) {
  for (var i = 0; i < Conf.options.length; i++)
    if (Conf.options[i].name == name)
      return true;
  return false;
}

/**
 * Prints the options in a pretty human-readable format.
 */
Conf.printOptions = function() {
  var options = Conf.options;

  print("Configuration Options:\n");
  options.forEach(function(option) {
    print("\n  " + option.name);
    if (option.desc)
      print(" - " + option.desc);
    if (option.values)
      print("\n    " + "Values: " + option.values.join(" | "));
    print("\n")
  });
  print("\n");
}

Conf.addOption("root", "The filepath to use as the root of the application.", ["{String}"]);
Conf.addOption("logLevel", "Sets the log level.", ['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL']);

exports.Config.prototype = {
  /**
   * Used to set the configuration options.
   *
   * @example
   * app.config.use(function(c) {
   *   c['root'] = __filename;
   *   c['logLevel'] = "WARNa";
   * });
   *
   * @param {Function} callback The function that is used to configure the options
   */
  use: function(callback) {
    var obj = {};
    callback(obj);
    for (var k in obj)
      if (obj.hasOwnProperty(k)) {
        if (Vroom.Config.hasOption(k))
          this[k] = obj[k];
        else
          this.application.LOG.warn("Configuration property '" + k + "' is not defined.");
      }
  },

  /**
   * Sets the root path. If a filename is sent, it will be set to the
   * directory of the file.
   *
   * @param {String} path The directory path or file path
   */
  set root(path) {
    if (/\.[^./]+$/.exec(path))
      this._root = node.path.dirname(path);
    else
      this._root = path;
  },

  /**
   * Gets the root path.
   *
   * @returns {String} The root path
   */
  get root() {
    return this._root;
  },

  /**
   * Sets the applications LOG level.
   *
   * @param {String} level The log level to set to
   */
  set logLevel(level) {
    this.application.LOG.level = level;
  }
}
<|endoftext|>


<commit_before>var valueMask = {
    CreateWindow: {
        backgroundPixmap: 0x00000001,
        backgroundPixel : 0x00000002,
        borderPixmap    : 0x00000004,
        borderPixel     : 0x00000008,
        bitGrawity      : 0x00000010,
        winGravity      : 0x00000020,
        backingStore    : 0x00000040,
        backingPlanes   : 0x00000080,
        backingPixel    : 0x00000100,
        overrideRedirect: 0x00000200,
        saveUnder       : 0x00000400,
        eventMask       : 0x00000800,
      doNotPropagateMask: 0x00001000,
        colormap        : 0x00002000,
        cursor          : 0x00004000
    },
    CreateGC: {
          'function'    : 0x00000001, // TODO: alias? _function?
           planeMask    : 0x00000002,
           foreground   : 0x00000004,
           background   : 0x00000008,
           lineWidth    : 0x00000010,
           lineStyle    : 0x00000020,
           capStyle     : 0x00000040,
           joinStyle    : 0x00000080,
           fillStyle    : 0x00000100,
           fillRule     : 0x00000200,
           tile         : 0x00000400,
           stipple      : 0x00000800,
           tileStippleXOrigin: 0x00001000,
           tileStippleYOrigin: 0x00002000,
           font         : 0x00004000,
           subwindowMode: 0x00008000,
           graphicsExposures: 0x00010000,
           clipXOrigin  : 0x00020000,
           clipYOrigin  : 0x00040000,
           clipMask     : 0x00080000,
           dashOffset   : 0x00100000,
           dashes       : 0x00200000,
           arcMode      : 0x00400000
    }
};

var valueMaskName = {};
for (var req in valueMask) {
    var masks = valueMask[req];
    var names = valueMaskName[req] = {};
    for (var m in masks)
        names[masks[m]] = m;
}

function packValueMask(reqname, values)
{
    var bitmask = 0;
    var masksList = [];
    var reqValueMask = valueMask[reqname];
    var reqValueMaskName = valueMaskName[reqname];

    if (!reqValueMask)
        throw new Error(reqname + ': no value mask description');

    for (var v in values)
    {
        var valueBit = reqValueMask[v];
        if (!valueBit)
            throw new Error('CreateWindow: incorrect value param ' + v);
        masksList.push(valueBit);
        bitmask |= valueBit;
    }
    masksList.sort();
    var args = [];
    for (m in masksList)
    {
       valueName = reqValueMaskName[masksList[m]];
       args.push( values[valueName] );
    }
    return [bitmask, args]
}

/*

the way requests are described here

- outgoing request

   1) as function
   client.CreateWindow( params, params ) ->
       req = reqs.CreateWindow[0]( param, param );
       pack_stream.pack(req[0], req[1]);

   2) as array: [format, [opcode, request_length, additional known params]]

   client.MapWindow[0](id) ->
       req = reqs.MwpWindow;
       req[1].push(id);
       pack_stream.pack( req[0], req[1] );

- reply

*/

module.exports = {
   CreateWindow: [
       // create request packet - function OR format string
       function(id, parentId, x, y, width, height, borderWidth, class, visual, values) {

           // TODO: ??? there is depth field in xproto, but xlib just sets it to zero
           var depth = 0;

           var packetLength = 8 + (values ? Object.keys(values).length : 0);
           // TODO: should be CCSLLssSSSSLL - x,y are signed
           var format = 'CCSLLSSSSSSLL';

           // create bitmask
           var bitmask = 0;
           // TODO: slice from function arguments?
           var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, class, visual];

           // TODO: the code is a little bit mess
           // additional values need to be packed in the following way:
           // bitmask (bytes #24 to #31 in the packet) - 32 bit indicating what adittional arguments we supply
           // values list (bytes #32 .. #32+4*num_values) in order of corresponding bits

           // TODO: replace with packValueMask
           var masksList = [];
           for (var v in values)
           {
               var valueBit = valueMask['CreateWindow'][v];
               if (!valueBit)
               {
                   throw new Error('CreateWindow: incorrect value param ' + v);
               }
               masksList.push(valueBit);
               bitmask |= valueBit;
               format += 'L';
           }
           // values packed in order of corresponding bit
           masksList.sort();
           // set bits to indicate additional values we are sending in this request
           args.push(bitmask);
           // add values in the order of the bits
           // TODO: maybe it's better just to scan all 32 bits anstead of sorting parameters we are actually have?
           for (m in masksList)
           {
              valueName = valueMaskName['CreateWindow'][masksList[m]];
              args.push( values[valueName] );
           }
           return [format, args];
       }

   ],

   MapWindow: [
       // 8 - opcode, 2 - length
       [ 'CxSL', [8, 2] ]
   ],

   UnmapWindow: [
       [ 'CxSL', [10, 2] ]
   ],

   // opcode 55
   CreateGC: [
       function(cid, drawable, values) {
           var format = 'CxSLL';
           var packetLength = 8 + (values ? Object.keys(values).length : 0);
           var args = [55, packetLength, cid, drawable];
           var vals = packValueMask('CreateGC', values);
           args.push(vals[0]);     // values bitmask
           var valArr = vals[1];
           for (v in valArr)
           {
               format += 'L'; // TODO: we know format string length in advance and += inefficient for string
               args.push(valArr[v]);
           }
           return [format, args];
        }
   ]
}
<commit_msg>new V* stricter to variable names - class renamed to _class<commit_after>var valueMask = {
    CreateWindow: {
        backgroundPixmap: 0x00000001,
        backgroundPixel : 0x00000002,
        borderPixmap    : 0x00000004,
        borderPixel     : 0x00000008,
        bitGrawity      : 0x00000010,
        winGravity      : 0x00000020,
        backingStore    : 0x00000040,
        backingPlanes   : 0x00000080,
        backingPixel    : 0x00000100,
        overrideRedirect: 0x00000200,
        saveUnder       : 0x00000400,
        eventMask       : 0x00000800,
      doNotPropagateMask: 0x00001000,
        colormap        : 0x00002000,
        cursor          : 0x00004000
    },
    CreateGC: {
          'function'    : 0x00000001, // TODO: alias? _function?
           planeMask    : 0x00000002,
           foreground   : 0x00000004,
           background   : 0x00000008,
           lineWidth    : 0x00000010,
           lineStyle    : 0x00000020,
           capStyle     : 0x00000040,
           joinStyle    : 0x00000080,
           fillStyle    : 0x00000100,
           fillRule     : 0x00000200,
           tile         : 0x00000400,
           stipple      : 0x00000800,
           tileStippleXOrigin: 0x00001000,
           tileStippleYOrigin: 0x00002000,
           font         : 0x00004000,
           subwindowMode: 0x00008000,
           graphicsExposures: 0x00010000,
           clipXOrigin  : 0x00020000,
           clipYOrigin  : 0x00040000,
           clipMask     : 0x00080000,
           dashOffset   : 0x00100000,
           dashes       : 0x00200000,
           arcMode      : 0x00400000
    }
};

var valueMaskName = {};
for (var req in valueMask) {
    var masks = valueMask[req];
    var names = valueMaskName[req] = {};
    for (var m in masks)
        names[masks[m]] = m;
}

function packValueMask(reqname, values)
{
    var bitmask = 0;
    var masksList = [];
    var reqValueMask = valueMask[reqname];
    var reqValueMaskName = valueMaskName[reqname];

    if (!reqValueMask)
        throw new Error(reqname + ': no value mask description');

    for (var v in values)
    {
        var valueBit = reqValueMask[v];
        if (!valueBit)
            throw new Error('CreateWindow: incorrect value param ' + v);
        masksList.push(valueBit);
        bitmask |= valueBit;
    }
    masksList.sort();
    var args = [];
    for (m in masksList)
    {
       valueName = reqValueMaskName[masksList[m]];
       args.push( values[valueName] );
    }
    return [bitmask, args]
}

/*

the way requests are described here

- outgoing request

   1) as function
   client.CreateWindow( params, params ) ->
       req = reqs.CreateWindow[0]( param, param );
       pack_stream.pack(req[0], req[1]);

   2) as array: [format, [opcode, request_length, additional known params]]

   client.MapWindow[0](id) ->
       req = reqs.MwpWindow;
       req[1].push(id);
       pack_stream.pack( req[0], req[1] );

- reply

*/

module.exports = {
   CreateWindow: [
       // create request packet - function OR format string
       function(id, parentId, x, y, width, height, borderWidth, _class, visual, values) {
           console.log('CreateWindow called', id);

           // TODO: ??? there is depth field in xproto, but xlib just sets it to zero
           var depth = 0;

           var packetLength = 8 + (values ? Object.keys(values).length : 0);
           // TODO: should be CCSLLssSSSSLL - x,y are signed
           var format = 'CCSLLSSSSSSLL';

           // create bitmask
           var bitmask = 0;
           // TODO: slice from function arguments?
           var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual];

           // TODO: the code is a little bit mess
           // additional values need to be packed in the following way:
           // bitmask (bytes #24 to #31 in the packet) - 32 bit indicating what adittional arguments we supply
           // values list (bytes #32 .. #32+4*num_values) in order of corresponding bits

           // TODO: replace with packValueMask
           var masksList = [];
           for (var v in values)
           {
               var valueBit = valueMask['CreateWindow'][v];
               if (!valueBit)
               {
                   throw new Error('CreateWindow: incorrect value param ' + v);
               }
               masksList.push(valueBit);
               bitmask |= valueBit;
               format += 'L';
           }
           // values packed in order of corresponding bit
           masksList.sort();
           // set bits to indicate additional values we are sending in this request
           args.push(bitmask);
           // add values in the order of the bits
           // TODO: maybe it's better just to scan all 32 bits anstead of sorting parameters we are actually have?
           for (m in masksList)
           {
              valueName = valueMaskName['CreateWindow'][masksList[m]];
              args.push( values[valueName] );
           }
           return [format, args];
       }

   ],

   MapWindow: [
       // 8 - opcode, 2 - length
       [ 'CxSL', [8, 2] ]
   ],

   UnmapWindow: [
       [ 'CxSL', [10, 2] ]
   ],

   // opcode 55
   CreateGC: [
       function(cid, drawable, values) {
           var format = 'CxSLL';
           var packetLength = 8 + (values ? Object.keys(values).length : 0);
           var args = [55, packetLength, cid, drawable];
           var vals = packValueMask('CreateGC', values);
           args.push(vals[0]);     // values bitmask
           var valArr = vals[1];
           for (v in valArr)
           {
               format += 'L'; // TODO: we know format string length in advance and += inefficient for string
               args.push(valArr[v]);
           }
           return [format, args];
        }
   ]
}
<|endoftext|>