function addProps(props, options) {
  if (!props) return '## No props'
  const keys = Object.keys(props).filter(key =>
    filterProps(key, props[key], options),
  )
  const filteredProps = keys.reduce(
    (last, key) => ({ ...last, [key]: props[key] }),
    {},
  )

  let output = '\n## Props\n'
  let isFlow = false
  const items = [
    TABLE_HEADERS,
    ...keys.map(key => {
      const prop = filteredProps[key]
      if (isFlowType(prop)) isFlow = true

      const row = [
        isFlowType(prop) ? key : getKey(key, getType(prop)),
        getTypeName(getType(prop)),
        getDefaultValue(prop),
        prop.required,
        prop.description,
      ]
      return row.map(rowValue => {
        if (typeof rowValue === 'string') {
          return rowValue.split('\n').join('<br>')
        }
        return rowValue
      })
    }),
  ]

  output += `${table(items)}\n`

  // Add subtypes
  if (!isFlow) {
    const subTypes = describeSubTypes(filteredProps)
    if (subTypes.length) {
      output += '\n## Complex Props\n'
      output += subTypes
    }
  }

  return output
}

function
addProps
(
props
,
options
)
{
if
(
!
props
)
return
'## No props'
const
keys
=
Object
.
keys
(
props
)
.
filter
(
key
=>
filterProps
(
key
,
props
[
key
]
,
options
)
,
)
const
filteredProps
=
keys
.
reduce
(
(
last
,
key
)
=>
(
{
...
last
,
[
key
]
:
props
[
key
]
}
)
,
{
}
,
)
let
output
=
'\n## Props\n'
\n
\n
let
isFlow
=
false
const
items
=
[
TABLE_HEADERS
,
...
keys
.
map
(
key
=>
{
const
prop
=
filteredProps
[
key
]
if
(
isFlowType
(
prop
)
)
isFlow
=
true
const
row
=
[
isFlowType
(
prop
)
key
:
getKey
(
key
,
getType
(
prop
)
)
,
getTypeName
(
getType
(
prop
)
)
,
getDefaultValue
(
prop
)
,
prop
.
required
,
prop
.
description
,
]
return
row
.
map
(
rowValue
=>
{
if
(
typeof
rowValue
===
'string'
)
{
return
rowValue
.
split
(
'\n'
)
.
\n
join
}
(
'<br>'
)
}
)
}
)
,
]
return
rowValue
}

Loop through all the top level props
@param props
@param options
@returns {string}


function debounce(quietMillis, fn, ctx ) {
    ctx = ctx || undefined;
    var timeout;
    return function () {
        var args = arguments;
        clearTimeout(timeout);
        timeout = setTimeout(function() {
            fn.apply(ctx, args);
        }, quietMillis);
    };
}

function debounce ( quietMillis , fn , ctx ) { ctx = ctx || undefined ; var timeout ; return function ( ) { var args = arguments ; clearTimeout ( timeout ) ; timeout = setTimeout ( function ( ) { fn . apply ( ctx , args ) ; } , quietMillis ) ; } ; }

Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
within the last quietMillis milliseconds.

@param quietMillis number of milliseconds to wait before invoking fn
@param fn function to be debounced
@param ctx object to be used as this reference within fn
@return debounced version of fn

Debounces a function . Returns a function that calls the original fn function only if no invocations have been made within the last quietMillis milliseconds .


function matroshka(fn) {
      var babushka = fn;
      Object.keys(process.namespaces).forEach(function (name) {
        babushka = process.namespaces[name].bind(babushka);
      });

      return babushka;
    }

function matroshka ( fn ) { var babushka = fn ; Object . keys ( process . namespaces ) . forEach ( function ( name ) { babushka = process . namespaces [ name ] . bind ( babushka ) ; } ) ; return babushka ; }


function findTagged(modelClass,tag){
    if(!modelClass || !modelClass.schema) return [];
    var cols = [];
    Object.keys(modelClass.schema.paths).forEach(function(path){
        var data = modelClass.schema.paths[path];
        if(data.options.tags && data.options.tags.indexOf(tag)>=0)
            cols.push(data);
    });
    return cols;
}

function findTagged ( modelClass , tag ) { if ( ! modelClass || ! modelClass . schema ) return [ ] ; var cols = [ ] ; Object . keys ( modelClass . schema . paths ) . forEach ( function ( path ) { var data = modelClass . schema . paths [ path ] ; if ( data . options . tags && data . options . tags . indexOf ( tag ) >= 0 ) cols . push ( data ) ; } ) ; return cols ; }

end directiveFunc get a list of fields with a specific tag


function error(msg) {
	if (exports.error)
		exports.error(msg);
	else
		console.log('Error: ' + msg);
}

function
error
(
msg
)
{
if
(
exports
.
error
)
exports
.
error
(
msg
)
;
else
console
.
log
(
'Error: '
+
msg
)
;
}


function call(name, isLong) {

	var obj = isLong ? long[name] : short[name];
	if (!obj)
		return error(`Unknown argument '${name}'`);

	if (n + obj.length > count)
		return error(`Too few arguments after '${name}'`);

	var arr = process.argv.slice(n, n + obj.length);
	n += obj.length;

	obj.callback(arr);
}

function call ( name , isLong ) { var obj = isLong ? long [ name ] : short [ name ] ; if ( ! obj ) return error ( ` ${ name } ` ) ; if ( n + obj . length > count ) return error ( ` ${ name } ` ) ; var arr = process . argv . slice ( n , n + obj . length ) ; n += obj . length ; obj . callback ( arr ) ; }


function findInputElement(templateElement) {
    return angular.element(templateElement.find('input')[0] || templateElement.find('select')[0] || templateElement.find('textarea')[0]);
  }

function findInputElement ( templateElement ) { return angular . element ( templateElement . find ( 'input' ) [ 0 ] || templateElement . find ( 'select' ) [ 0 ] || templateElement . find ( 'textarea' ) [ 0 ] ) ; }

Find the "input" element in the template.  It will be one of input, select or textarea. We need to ensure it is wrapped in jqLite\jQuery

Find the input element in the template . It will be one of input select or textarea . We need to ensure it is wrapped in jqLite \ jQuery


function getValidationMessageMap(originalElement) {
    // Find all the <validator> child elements and extract their (key, message) info
    var validationMessages = {};
    angular.forEach(originalElement.find('validator'), function(element) {
      // Wrap the element in jqLite/jQuery
      element = angular.element(element);
      // Store the message info to be provided to the scope later
      // The content of the validation element may include interpolation {{}}
      // so we will actually store a function created by the $interpolate service
      // To get the interpolated message we will call this function with the scope. e.g.
      //   var messageString = getMessage(scope);
      validationMessages[element.attr('key')] = $interpolate(element.text());
    });
    return validationMessages;
  }

function getValidationMessageMap ( originalElement ) { var validationMessages = { } ; angular . forEach ( originalElement . find ( 'validator' ) , function ( element ) { element = angular . element ( element ) ; validationMessages [ element . attr ( 'key' ) ] = $interpolate ( element . text ( ) ) ; } ) ; return validationMessages ; }

Search through the originalDirective's element for elements that contain information about how to map validation keys to messages

Search through the originalDirective s element for elements that contain information about how to map validation keys to messages


function registerClass(nameOrOpts, claz){
    var opts = typeof(nameOrOpts) == 'object'?nameOrOpts: {name: nameOrOpts};
    var className = opts.name;
    if(!className) throw "Missing module name: "+ className
    if(beans[className])
        logger.warn("Overriding existing bean: ", className);
    if(claz._angoosemeta && (claz._angoosemeta.baseClass == 'Service' || claz._angoosemeta.baseClass == 'Model') ){
        // already mixed
    }
    else{
        if(typeof(claz) === 'function' && claz.schema  && claz.modelName )
            opts.baseClass = 'Model';
        else if(claz instanceof getMongoose().Schema){
            opts.baseClass = 'Model';
            claz = getMongoose().model(className, claz);
        }
        else
            opts.baseClass = 'Service';
        angoose.Remotable.mixin(opts, claz);
    }
    _.extend(claz._angoosemeta, nameOrOpts);

    beans[className] = claz;
    //if(!nameOrOpts.isExtension)
        logger.debug("Registered module", claz._angoosemeta.baseClass, className);
    return claz;
    // if(claz._angoosemeta && (claz._angoosemeta.baseClass == 'Service' || claz._angoosemeta.baseClass == 'Model') ){
//
    // }
    // else{
        // throw "Invalid class: must be a Model or Service class: " + claz;
    // }
}

function
registerClass
(
nameOrOpts
,
claz
)
{
var
opts
=
typeof
(
nameOrOpts
)
==
'object'
nameOrOpts
:
{
name
:
nameOrOpts
}
;
var
className
=
opts
.
name
;
if
(
!
className
)
throw
"Missing module name: "
+
className
if
(
beans
[
className
]
)
logger
.
warn
(
"Overriding existing bean: "
,
className
)
;
if
(
claz
.
_angoosemeta
&&
(
claz
.
_angoosemeta
.
baseClass
==
'Service'
||
claz
.
_angoosemeta
.
baseClass
==
'Model'
)
)
{
}
else
{
if
(
typeof
(
claz
)
===
'function'
&&
claz
.
schema
&&
claz
.
modelName
)
opts
.
baseClass
=
'Model'
;
else
if
(
claz
instanceof
getMongoose
(
)
.
Schema
)
{
opts
.
baseClass
=
'Model'
;
claz
=
getMongoose
(
)
.
model
(
className
,
claz
)
;
}
else
opts
.
baseClass
=
'Service'
;
angoose
.
Remotable
.
mixin
(
opts
,
claz
)
;
}
_
.
extend
(
claz
.
_angoosemeta
,
nameOrOpts
)
;
beans
[
className
]
=
claz
;
logger
.
debug
(
"Registered module"
,
claz
.
_angoosemeta
.
baseClass
,
className
)
;
return
claz
;
}

register module with angoose so it knows to publish it


function config(path, val){
    if(!path) return options; /**@todo: probably a deep copy */
    if(!angoose.initialized && typeof(path) == 'string') throw "Cannot call config(" + path+") before angoose is intialized";
    //if(angoose.initialized && typeof(conf) == 'object') throw "Cannot config Angoose after startup";

    if(typeof (path) === 'string'){
         if(val === undefined)
            return toolbox.getter(options, path);
         toolbox.setter(options, path, val);
    }

    if(typeof(path) === 'object'){
        // deep merge
        options = toolbox.merge(options, path);

    }
}

function
config
(
path
,
val
)
{
if
(
!
path
)
return
options
;
if
(
!
angoose
.
initialized
&&
typeof
(
path
)
==
'string'
)
throw
"Cannot call config("
+
path
+
") before angoose is intialized"
;
if
(
typeof
(
path
)
===
'string'
)
{
if
(
val
===
undefined
)
return
toolbox
.
getter
(
options
,
path
)
;
toolbox
.
setter
(
options
,
path
,
val
)
;
}
if
(
typeof
(
path
)
===
'object'
)
{
options
=
toolbox
.
merge
(
options
,
path
)
;
}
}

Set or get configurations.

Usage:

config()    get the whole configuration object
config(object)    set the configuration by merging the configuration options
config(path)  get the configuration value at path.
config(path, val) set the value at path.


function connect (url, next) {
  log('connecting to %s', url);
  mongo.Db.connect(url, { db: { w: 1 }}, next);
}

function
connect
(
url
,
next
)
{
log
(
'connecting to %s'
,
url
)
;
mongo
.
Db
.
connect
(
url
,
{
db
:
{
w
:
1
}
}
,
next
)
;
}

Creates a connection to the given `url`.


function startShell (db, program, files) {
  var repl = global.repl = term(db);

  createContext(db, repl, function () {
    var code = program.eval;

    if (code) {
      executeJS(code);
      if (!program.shell) {
        repl.emit('exit');
        return;
      }
    }

    if (files.length) {
      executeFiles(files);
      printCloseMsg();
    }

    repl.prompt = prompt;
    repl.displayPrompt()
  });
}

function startShell ( db , program , files ) { var repl = global . repl = term ( db ) ; createContext ( db , repl , function ( ) { var code = program . eval ; if ( code ) { executeJS ( code ) ; if ( ! program . shell ) { repl . emit ( 'exit' ) ; return ; } } if ( files . length ) { executeFiles ( files ) ; printCloseMsg ( ) ; } repl . prompt = prompt ; repl . displayPrompt ( ) } ) ; }

Starts up a shell with the given context.

Starts up a shell with the given context .


function executeFiles (files) {
  var dir = process.cwd();
  files.forEach(function (file) {
    require(dir + '/' + file);
  });
}

function executeFiles ( files ) { var dir = process . cwd ( ) ; files . forEach ( function ( file ) { require ( dir + '/' + file ) ; } ) ; }

Execute the given `files` in the context shared
with the shell when started.

Execute the given files in the context shared with the shell when started .


function wrap (proto, name) {
  var old = proto[name];

  proto[name] = function () {
    if (global.repl) global.repl.bufferStart();
    var args = slice(arguments);
    var last = args[args.length-1];
    if ('function' == typeof last) {
      args[args.length-1] = function () {
        if (global.repl) global.repl.bufferEnd()
        if (p != last) console.log();
        last.apply(null, arguments)
        if (global.repl) {
          global.repl.displayPrompt();
          global.repl.moveCursorToEnd();
        }
      }
    } else {
      args.push(function () {
        if (global.repl) global.repl.bufferEnd()
        p.apply(null, arguments);
        if (global.repl) global.repl.moveCursorToEnd();
      });
    }
    old.apply(this, args);
  }

  if (old.help) {
    proto[name].help = old.help;
  }
}

function wrap ( proto , name ) { var old = proto [ name ] ; proto [ name ] = function ( ) { if ( global . repl ) global . repl . bufferStart ( ) ; var args = slice ( arguments ) ; var last = args [ args . length - 1 ] ; if ( 'function' == typeof last ) { args [ args . length - 1 ] = function ( ) { if ( global . repl ) global . repl . bufferEnd ( ) if ( p != last ) console . log ( ) ; last . apply ( null , arguments ) if ( global . repl ) { global . repl . displayPrompt ( ) ; global . repl . moveCursorToEnd ( ) ; } } } else { args . push ( function ( ) { if ( global . repl ) global . repl . bufferEnd ( ) p . apply ( null , arguments ) ; if ( global . repl ) global . repl . moveCursorToEnd ( ) ; } ) ; } old . apply ( this , args ) ; } if ( old . help ) { proto [ name ] . help = old . help ; } }


function handleError (err, cb) {
  if (err) {
    if (cb) {
      return process.nextTick(function(){
        cb(err);
      });
    }
    console.error(err);
  }
}

function handleError ( err , cb ) { if ( err ) { if ( cb ) { return process . nextTick ( function ( ) { cb ( err ) ; } ) ; } console . error ( err ) ; } }


function tablature(conf) {
  const {
    keys = [],
    data = [],
    headings = {},
    replacements = {},
    centerValues = [],
    centerHeadings = [],
  } = conf
  const [i] = data
  if (!i) return ''

  const cv = makeBinaryHash(centerValues)
  const hv = makeBinaryHash(centerHeadings)

  const k = Object.keys(i).reduce((acc, key) => {
    const h = headings[key]
    return {
      ...acc,
      [key]: h ? h.length : key.length, // initialise with titles lengths
    }
  }, {})

  const widths = data.reduce((dac, d) => {
    const res = Object.keys(d).reduce((acc, key) => {
      const maxLength = dac[key]
      const val = d[key]
      const r = getReplacement(replacements, key)
      const { length } = r(val)
      return {
        ...acc,
        [key]: Math.max(length, maxLength),
      }
    }, {})
    return res
  }, k)

  const kk = keys.reduce((acc, key) => {
    const h = headings[key]
    return {
      ...acc,
      [key]: h || key,
    }
  }, {})
  const hr = keys.reduce((acc, key) => {
    return {
      ...acc,
      [key]: heading,
    }
  }, {})
  const hl = getLine(keys, kk, widths, hr, hv)
  const rl = data.map((row) => {
    const line = getLine(keys, row, widths, replacements, cv)
    return line
  })
  return [
    hl,
    ...rl,
  ].join('\n')
}

function tablature ( conf ) { const { keys = [ ] , data = [ ] , headings = { } , replacements = { } , centerValues = [ ] , centerHeadings = [ ] , } = conf const [ i ] = data if ( ! i ) return '' const cv = makeBinaryHash ( centerValues ) const hv = makeBinaryHash ( centerHeadings ) const k = Object . keys ( i ) . reduce ( ( acc , key ) => { const h = headings [ key ] return { ... acc , [ key ] : h ? h . length : key . length , } } , { } ) const widths = data . reduce ( ( dac , d ) => { const res = Object . keys ( d ) . reduce ( ( acc , key ) => { const maxLength = dac [ key ] const val = d [ key ] const r = getReplacement ( replacements , key ) const { length } = r ( val ) return { ... acc , [ key ] : Math . max ( length , maxLength ) , } } , { } ) return res } , k ) const kk = keys . reduce ( ( acc , key ) => { const h = headings [ key ] return { ... acc , [ key ] : h || key , } } , { } ) const hr = keys . reduce ( ( acc , key ) => { return { ... acc , [ key ] : heading , } } , { } ) const hl = getLine ( keys , kk , widths , hr , hv ) const rl = data . map ( ( row ) => { const line = getLine ( keys , row , widths , replacements , cv ) return line } ) return [ hl , ... rl , ] . join ( '\n' ) }

Display values in a table.
@param {Config} conf Options for the program.
@param {Array<string>} conf.keys Keys to print as columns.
@param {Array<Object<string, string>>} conf.data The array of data items to prints as rows.
@param {Object<string, string>} [conf.headings] The display names for each column.
@param {Object.<string, Replacement>} [conf.replacements] The map of replacement functions which will run against data items.
@param {Array<string>} [conf.centerValues] Centre values of these column (use original keys, not headings).
@param {Array<string>} [conf.centerHeadings] Center headings of these column (use original keys, not headings).
@returns {string} A string which represents a table.


function _save() {
    if (db.source && db.write && writeOnChange) {
      var str = JSON.stringify(db.object);

      if (str !== db._checksum) {
        db._checksum = str;
        return db.write(db.source, db.object);
      }
    }
  }

function _save ( ) { if ( db . source && db . write && writeOnChange ) { var str = JSON . stringify ( db . object ) ; if ( str !== db . _checksum ) { db . _checksum = str ; return db . write ( db . source , db . object ) ; } } }

Return a promise or nothing in sync mode or if the database hasn't changed

Return a promise or nothing in sync mode or if the database hasn t changed


function Picklr (startDir, options) {
  options = options || {};

  let defaultExcludeDirsRe;
  if (/^\./.test(startDir)) {
    defaultExcludeDirsRe = /\/\.|node_modules/i;
  } else {
    defaultExcludeDirsRe = /^\.|\/\.|node_modules/i;
  }

  this.totalFileCount = 0;
  this.matchedFileCount = 0;
  this.startDir = startDir || '.';
  this.targetText = options.targetText || '';
  this.replacementText = options.replacementText || '';
  this.action = options.action || 'echo';
  this.includeExts = options.includeExts || ['.js'];
  this.excludeDirs = options.excludeDirsRe || defaultExcludeDirsRe;
  this.logger = options.logger || console.log;

  this.picklrActions = picklrActions;
}

function Picklr ( startDir , options ) { options = options || { } ; let defaultExcludeDirsRe ; if ( / ^\. / . test ( startDir ) ) { defaultExcludeDirsRe = / \/\.|node_modules / i ; } else { defaultExcludeDirsRe = / ^\.|\/\.|node_modules / i ; } this . totalFileCount = 0 ; this . matchedFileCount = 0 ; this . startDir = startDir || '.' ; this . targetText = options . targetText || '' ; this . replacementText = options . replacementText || '' ; this . action = options . action || 'echo' ; this . includeExts = options . includeExts || [ '.js' ] ; this . excludeDirs = options . excludeDirsRe || defaultExcludeDirsRe ; this . logger = options . logger || console . log ; this . picklrActions = picklrActions ; }


function (p) {
    fs.readdirSync(p).forEach(function (file) {
      const curPath = path.join(p, path.sep, file);
      const stats = fs.statSync(curPath);

      if (this.isDirectory(stats, curPath)) {
        this.recurseFiles(curPath);
      } else if (this.isFile(stats, curPath)) {
        this.picklrActions[this.action].call(this, curPath);
      }
    }, this);

    if (p === this.startDir) {
      this.logger('Total file count = ' + this.totalFileCount);
      if (this.action !== 'echo') {
        this.logger('Matched file count = ' + this.matchedFileCount);
      }
    }
  }

function
(
p
)
{
fs
.
readdirSync
(
p
)
.
forEach
(
function
(
file
)
{
const
curPath
=
path
.
join
(
p
,
path
.
sep
,
file
)
;
const
stats
=
fs
.
statSync
(
curPath
)
;
if
(
this
.
isDirectory
(
stats
,
curPath
)
)
{
this
.
recurseFiles
(
curPath
)
;
}
else
if
(
this
.
isFile
(
stats
,
curPath
)
)
{
this
.
picklrActions
[
this
.
action
]
.
call
(
this
,
curPath
)
;
}
}
,
this
)
;
if
(
p
===
this
.
startDir
)
{
this
.
logger
(
'Total file count = '
+
this
.
totalFileCount
)
;
if
(
this
.
action
!==
'echo'
)
{
this
.
logger
(
'Matched file count = '
+
this
.
matchedFileCount
)
;
}
}
}


function (stats, p) {
    let result = stats.isFile();

    if (result) {
      const ext = path.extname(p);
      result = this.includeExts.indexOf(ext) !== -1;
    }

    return result;
  }

function ( stats , p ) { let result = stats . isFile ( ) ; if ( result ) { const ext = path . extname ( p ) ; result = this . includeExts . indexOf ( ext ) !== - 1 ; } return result ; }

File type determination.

@private
@returns true if given path is a file.


function (stats, p) {
    let result = stats.isDirectory();

    if (result) {
      result = !this.excludeDirs.test(p);
    }

    return result;
  }

function ( stats , p ) { let result = stats . isDirectory ( ) ; if ( result ) { result = ! this . excludeDirs . test ( p ) ; } return result ; }

Directory type determination.

@private
@returns true if given path is a directory.


function processAllFiles (startDir, options) {
  const picklr = new Picklr(startDir, options);
  picklr.recurseFiles(startDir);
}

function processAllFiles ( startDir , options ) { const picklr = new Picklr ( startDir , options ) ; picklr . recurseFiles ( startDir ) ; }

Process all files under startDir using options.

Process all files under startDir using options .


function processFile (filePath, update) {
  let change, found = false;
  const lines = fs.readFileSync(filePath, { encoding: 'utf8' }).split('\n');

  for (let i = 0; i < lines.length; i++) {
    if (lines[i].indexOf(this.targetText) !== -1) {
      found = true;
      change = lines[i].replace(
        this.targetText, this.replacementText
      );
      if (update) {
        lines[i] = change;
      } else {
        // log the line that would be edited.
        this.logger('*** File:   ' + filePath);
        this.logger('@@@ Found:  ' + lines[i]);
        this.logger('--- Change: ' + change);
      }
      this.matchedFileCount++;
      break;
    }
  }

  if (!found && !update) {
    // log the file that would be omitted
    this.logger('*** Omitted: ' + filePath);
  }

  if (found && update) {
    fs.writeFileSync(filePath, lines.join('\n'), { encoding: 'utf8' });
    // log the updated file
    this.logger('@@@ Updated: ' + filePath);
  }

  this.totalFileCount++;
}

function
processFile
(
filePath
,
update
)
{
let
change
,
found
=
false
;
const
lines
=
fs
.
readFileSync
(
filePath
,
{
encoding
:
'utf8'
}
)
.
split
(
'\n'
)
;
\n
for
(
let
i
=
0
;
i
<
lines
.
length
;
i
++
)
{
if
(
lines
[
i
]
.
indexOf
(
this
.
targetText
)
!==
1
)
{
found
=
true
;
change
=
lines
[
i
]
.
replace
(
this
.
targetText
,
this
.
replacementText
)
;
if
(
update
)
{
lines
[
i
]
=
change
;
}
else
{
this
.
logger
(
'*** File:   '
+
filePath
)
;
this
.
logger
(
'@@@ Found:  '
+
lines
[
i
]
)
;
this
.
logger
(
'--- Change: '
+
change
)
;
}
this
.
matchedFileCount
++
;
break
;
}
}
if
(
!
found
&&
!
update
)
{
this
.
logger
(
'*** Omitted: '
+
filePath
)
;
}
if
(
found
&&
update
)
{
fs
.
writeFileSync
(
filePath
,
lines
.
join
(
'\n'
)
,
\n
)
;
{
encoding
:
'utf8'
}
}
}

Does the actual audit or update of a single file.

@private

Does the actual audit or update of a single file .


async function initHTTPServer({
  ENV = {},
  HOST = '127.0.0.1',
  PORT = 8080,
  MAX_HEADERS_COUNT = 800,
  KEEP_ALIVE_TIMEOUT = ms('5m'),
  TIMEOUT = ms('2m'),
  MAX_CONNECTIONS,
  httpRouter,
  log = noop,
}) {
  const sockets = ENV.DESTROY_SOCKETS ? new Set() : {}.undef;
  const httpServer = http.createServer(httpRouter);
  const listenPromise = new Promise(resolve => {
    httpServer.listen(PORT, HOST, () => {
      log('info', `HTTP Server listening at "http://${HOST}:${PORT}".`);
      resolve(httpServer);
    });
  });
  const errorPromise = new Promise((resolve, reject) => {
    httpServer.once('error', reject);
  });

  httpServer.timeout = TIMEOUT;
  httpServer.keepAliveTimeout = KEEP_ALIVE_TIMEOUT;
  httpServer.maxHeadersCount = MAX_HEADERS_COUNT;
  httpServer.maxConnections = MAX_CONNECTIONS;

  if ('undefined' !== typeof MAX_CONNECTIONS) {
    httpServer.maxConnections = MAX_CONNECTIONS;
  }

  if (ENV.DESTROY_SOCKETS) {
    httpServer.on('connection', socket => {
      sockets.add(socket);
      socket.on('close', () => {
        sockets.delete(socket);
      });
    });
  }

  return Promise.race([listenPromise, errorPromise]).then(() => ({
    service: httpServer,
    errorPromise,
    dispose: () =>
      new Promise((resolve, reject) => {
        log('debug', 'Closing HTTP server.');
        // Avoid to keepalive connections on shutdown
        httpServer.timeout = 1;
        httpServer.keepAliveTimeout = 1;
        httpServer.close(err => {
          if (err) {
            reject(err);
            return;
          }
          log('debug', 'HTTP server closed');
          resolve();
        });
        if (ENV.DESTROY_SOCKETS) {
          for (const socket of sockets.values()) {
            socket.destroy();
          }
        }
      }),
  }));
}

async
function
initHTTPServer
(
{
ENV
=
{
}
,
HOST
=
'127.0.0.1'
,
PORT
=
8080
,
MAX_HEADERS_COUNT
=
800
,
KEEP_ALIVE_TIMEOUT
=
ms
(
'5m'
)
,
TIMEOUT
=
ms
(
'2m'
)
,
MAX_CONNECTIONS
,
httpRouter
,
log
=
noop
,
}
)
{
const
sockets
=
ENV
.
DESTROY_SOCKETS
new
Set
(
)
:
{
}
.
undef
;
const
httpServer
=
http
.
createServer
(
httpRouter
)
;
const
listenPromise
=
new
Promise
(
resolve
=>
{
httpServer
.
listen
(
PORT
,
HOST
,
(
)
=>
{
log
(
'info'
,
`
${
HOST
}
${
PORT
}
`
)
;
resolve
(
httpServer
)
;
}
)
;
}
)
;
const
errorPromise
=
new
Promise
(
(
resolve
,
reject
)
=>
{
httpServer
.
once
(
'error'
,
reject
)
;
}
)
;
httpServer
.
timeout
=
TIMEOUT
;
httpServer
.
keepAliveTimeout
=
KEEP_ALIVE_TIMEOUT
;
httpServer
.
maxHeadersCount
=
MAX_HEADERS_COUNT
;
httpServer
.
maxConnections
=
MAX_CONNECTIONS
;
if
(
'undefined'
!==
typeof
MAX_CONNECTIONS
)
{
httpServer
.
maxConnections
=
MAX_CONNECTIONS
;
}
if
(
ENV
.
DESTROY_SOCKETS
)
{
httpServer
.
on
(
'connection'
,
socket
=>
{
sockets
.
add
(
socket
)
;
socket
.
on
(
'close'
,
(
)
=>
{
sockets
.
delete
(
socket
)
;
}
)
;
}
)
;
}
return
Promise
.
race
(
[
listenPromise
,
errorPromise
]
)
.
then
(
(
)
=>
(
{
service
:
httpServer
,
errorPromise
,
dispose
:
(
)
=>
new
Promise
(
(
resolve
,
reject
)
=>
{
log
(
'debug'
,
'Closing HTTP server.'
)
;
httpServer
.
timeout
=
1
;
httpServer
.
keepAliveTimeout
=
1
;
httpServer
.
close
(
err
=>
{
if
(
err
)
{
reject
(
err
)
;
return
;
}
log
(
'debug'
,
'HTTP server closed'
)
;
resolve
(
)
;
}
)
;
if
(
ENV
.
DESTROY_SOCKETS
)
{
for
(
const
socket
of
sockets
.
values
(
)
)
{
socket
.
destroy
(
)
;
}
}
}
)
,
}
)
)
;
}

Initialize an HTTP server
@param  {Object}   services
The services the server depends on
@param  {Object}   services.ENV
The process environment variables
@param  {Object}   services.HOST
The server host
@param  {Object}   services.PORT
The server port
@param  {Object}   services.MAX_HEADERS_COUNT
The https://nodejs.org/api/http.html#http_server_maxheaderscount
@param  {Object}   services.KEEP_ALIVE_TIMEOUT
See https://nodejs.org/api/http.html#http_server_keepalivetimeout
@param  {Object}   services.MAX_CONNECTIONS
See https://nodejs.org/api/net.html#net_server_maxconnections
@param  {Object}   services.TIMEOUT
See https://nodejs.org/api/http.html#http_server_timeout
@param  {Function} services.httpRouter
The function to run with the req/res tuple
@param  {Function} [services.log=noop]
A logging function
@return {Promise}
A promise of an object with a NodeJS HTTP server
in its `service` property.


function sortAndAddFirstElement(array, sortBy, element) {
    return _(array)
        .sortBy(sortBy)
        .unshift(element)
        .value();
}

function sortAndAddFirstElement ( array , sortBy , element ) { return _ ( array ) . sortBy ( sortBy ) . unshift ( element ) . value ( ) ; }

Sort an array by the name of existing property and add a first element into array

@customNeeds Sort array by name and add first element.
For e.g. user names - [ {name: 'All'}, {name: 'Aron'}, {name: 'Bob'} ]

@since 1.1.0
@category Array

@param {Array} array - The array to sort and add
@param {String} sortBy - Name of the property from an array by which array will be sorted
@param {*} element - Element which is added into an array

@returns {Array} Returns the new array

@example

famulus.sortAndAddFirstElement([{name:'Bob'}, {name:'Aron'}], 'name', {name:'All'})
// => [ {name:'All'}, {name:'Aron'}, {name:'Bob'} ]


function objectInterface(config) {
    return function(obj) {
        var result = {};

        for (var i = 0; i < config.length; i++) {
            var OR, NEXT, REAL;

            if ((OR = config[i].split('/')) && OR[1]) {
                result[OR[0]] = obj[OR[0]] || Function('return ' + OR[1])();
            }
            else if ((NEXT = config[i].split('|')) && NEXT[1]) {
                result[NEXT[0]] = Function('return ' + NEXT[1]).call(obj);
            }
            else if ((REAL = config[i].split(':')) && REAL[1]) {
                result[REAL[0]] = Function('return ' + REAL[1])();
            }
            else {
                result[config[i]] = obj[config[i]];
            }
        }

        return result;
    }
}

function
objectInterface
(
config
)
{
return
function
(
obj
)
{
var
result
=
{
}
;
for
(
var
i
=
0
;
i
<
config
.
length
;
i
++
)
{
var
OR
,
NEXT
,
REAL
;
if
(
(
OR
=
config
[
i
]
.
split
(
'/'
)
)
&&
OR
[
1
]
)
{
result
[
OR
[
0
]
]
=
obj
[
OR
[
0
]
]
||
Function
(
'return '
+
OR
[
1
]
)
(
)
;
}
else
if
(
(
NEXT
=
config
[
i
]
.
split
(
'|'
)
)
&&
NEXT
[
1
]
)
{
result
[
NEXT
[
0
]
]
=
Function
(
'return '
+
NEXT
[
1
]
)
.
call
(
obj
)
;
}
else
if
(
(
REAL
=
config
[
i
]
.
split
(
':'
)
)
&&
REAL
[
1
]
)
{
result
[
REAL
[
0
]
]
=
Function
(
'return '
+
REAL
[
1
]
)
(
)
;
}
else
{
result
[
config
[
i
]
]
=
obj
[
config
[
i
]
]
;
}
}
return
result
;
}
}

Interface for building an object by configuration

@customNeeds - have an interface for building an object based on configuration

@since 2.1.0
@category Object

@param {Array} config - Keys with configuration
[
'key/value' - "OR" if no value, set value after "/",
'key|this.firstName + " " + this.lastName' - set value from the expression after "|" which is bind to the passed object,
'key:new Date()' - set value from the expression after ":"
]

@returns {Function}

@example

var email = objectInterface(['body', 'count/1', 'sender|this.firstName + " " + this.lastName', 'isRead: false', 'created: new Date()'])
// => function

email({body: 'Hello world!', count: '', firstName: 'Vasyl', lastName: 'Stokolosa', another: ''})
// => {body: "Hello world!", count: 1, created: Mon Jul 09 2018 10:31:08, isRead: false, sender: "Vasyl Stokolosa"}


function httpTransaction(req, res) {
    let initializationPromise;

    /* Architecture Note #3.1: New Transaction
    The idea is to maintain a hash of each pending
     transaction. To do so, we create a transaction
     object that contains useful informations about
     the transaction and we store it into the
     `TRANSACTIONS` hash.

    Each transaction has a unique id that is either
     generated or picked up in the `Transaction-Id`
     request header. This allows to trace
     transactions end to end with that unique id.
    */
    return Promise.resolve().then(() => {
      const request = {
        url: req.url,
        method: req.method.toLowerCase(),
        headers: req.headers,
        body: req,
      };
      const transaction = {
        protocol: req.connection.encrypted ? 'https' : 'http',
        ip:
          (req.headers['x-forwarded-for'] || '').split(',')[0] ||
          req.connection.remoteAddress,
        startInBytes: req.socket.bytesRead,
        startOutBytes: req.socket.bytesWritten,
        startTime: time(),
        url: req.url,
        method: req.method,
        reqHeaders: req.headers,
        errored: false,
      };
      const delayPromise = delay.create(TIMEOUT);
      let id = req.headers['transaction-id'] || uniqueId();

      // Handle bad client transaction ids
      if (TRANSACTIONS[id]) {
        initializationPromise = Promise.reject(
          new HTTPError(400, 'E_TRANSACTION_ID_NOT_UNIQUE', id),
        );
        id = uniqueId();
      } else {
        initializationPromise = Promise.resolve();
      }

      transaction.id = id;
      TRANSACTIONS[id] = transaction;

      return [
        request,
        {
          id,
          start: startTransaction.bind(
            null,
            { id, req, res, delayPromise },
            initializationPromise,
          ),
          catch: catchTransaction.bind(null, { id, req, res }),
          end: endTransaction.bind(null, { id, req, res, delayPromise }),
        },
      ];
    });
  }

function httpTransaction ( req , res ) { let initializationPromise ; return Promise . resolve ( ) . then ( ( ) => { const request = { url : req . url , method : req . method . toLowerCase ( ) , headers : req . headers , body : req , } ; const transaction = { protocol : req . connection . encrypted ? 'https' : 'http' , ip : ( req . headers [ 'x-forwarded-for' ] || '' ) . split ( ',' ) [ 0 ] || req . connection . remoteAddress , startInBytes : req . socket . bytesRead , startOutBytes : req . socket . bytesWritten , startTime : time ( ) , url : req . url , method : req . method , reqHeaders : req . headers , errored : false , } ; const delayPromise = delay . create ( TIMEOUT ) ; let id = req . headers [ 'transaction-id' ] || uniqueId ( ) ; if ( TRANSACTIONS [ id ] ) { initializationPromise = Promise . reject ( new HTTPError ( 400 , 'E_TRANSACTION_ID_NOT_UNIQUE' , id ) , ) ; id = uniqueId ( ) ; } else { initializationPromise = Promise . resolve ( ) ; } transaction . id = id ; TRANSACTIONS [ id ] = transaction ; return [ request , { id , start : startTransaction . bind ( null , { id , req , res , delayPromise } , initializationPromise , ) , catch : catchTransaction . bind ( null , { id , req , res } ) , end : endTransaction . bind ( null , { id , req , res , delayPromise } ) , } , ] ; } ) ; }

Create a new HTTP transaction
@param  {HTTPRequest}  req
A raw NodeJS HTTP incoming message
@param  {HTTPResponse} res
A raw NodeJS HTTP response
@return {Array}
The normalized request and the HTTP
transaction created in an array.


function dateDifference(date1, date2, differenceType) {
    var diffMilliseconds = Math.abs(date1 - date2);

    switch(differenceType) {
        case 'days':
            return dates._getDaysDiff(diffMilliseconds);
        case 'hours':
            return dates._differenceInHours(diffMilliseconds);
        case 'minutes':
            return dates._differenceInMinutes(diffMilliseconds);
        case 'milliseconds':
            return diffMilliseconds;

        default:
            return {
                days: dates._getDaysDiff(diffMilliseconds),
                hours: dates._getHoursDiff(diffMilliseconds),
                minutes: dates._getMinutesDiff(diffMilliseconds),
                milliseconds: diffMilliseconds
            }
    }
}

function dateDifference ( date1 , date2 , differenceType ) { var diffMilliseconds = Math . abs ( date1 - date2 ) ; switch ( differenceType ) { case 'days' : return dates . _getDaysDiff ( diffMilliseconds ) ; case 'hours' : return dates . _differenceInHours ( diffMilliseconds ) ; case 'minutes' : return dates . _differenceInMinutes ( diffMilliseconds ) ; case 'milliseconds' : return diffMilliseconds ; default : return { days : dates . _getDaysDiff ( diffMilliseconds ) , hours : dates . _getHoursDiff ( diffMilliseconds ) , minutes : dates . _getMinutesDiff ( diffMilliseconds ) , milliseconds : diffMilliseconds } } }

Difference between dates which are passed, in formats 'milliseconds', 'days', 'hours', 'minutes'

@customNeeds -

@since 2.0.0
@category Date

@param {Date} date1 - The Date for compare
@param {Date} date2 - The Date for compare
@param {String} differenceType - [ 'days', 'hours', 'minutes', 'milliseconds', 'all' ]

@returns {Number|Object} Returns the numeric value or object depends on passed differenceType param

@example

famulus.dateDifference(new Date('06-20-2018'), new Date('06-26-2018'), 'days')
// => 6

famulus.dateDifference(new Date('06-20-2018'), new Date('06-26-2018'), 'hours')
// => 144

famulus.dateDifference(new Date('06-20-2018'), new Date('06-26-2018'), 'minutes')
// => 8640

famulus.dateDifference(new Date('06-26-2018'), new Date('06-20-2018'), 'milliseconds')
// => 518400000

famulus.dateDifference(new Date('06-26-2018 10:10'), new Date('06-20-2018 08:00'), 'all')
// => {days: 6, hours: 2, minutes: 10, milliseconds: 526200000}

Difference between dates which are passed in formats milliseconds days hours minutes


function initErrorHandler({
  ENV = {},
  DEBUG_NODE_ENVS = DEFAULT_DEBUG_NODE_ENVS,
  STRINGIFYERS = DEFAULT_STRINGIFYERS,
}) {
  return Promise.resolve(errorHandler);

  /**
   * Handle an HTTP transaction error and
   * map it to a serializable response
   * @param  {String}  transactionId
   * A raw NodeJS HTTP incoming message
   * @param  {Object} responseSpec
   * The response specification
   * @param  {HTTPError} err
   * The encountered error
   * @return {Promise}
   * A promise resolving when the operation
   *  completes
   */
  function errorHandler(transactionId, responseSpec, err) {
    return Promise.resolve().then(() => {
      const response = {};

      response.status = err.httpCode || 500;
      response.headers = Object.assign({}, err.headers || {}, {
        // Avoid caching errors
        'cache-control': 'private',
        // Fallback to the default stringifyer to always be
        // able to display errors
        'content-type':
          responseSpec &&
          responseSpec.contentTypes[0] &&
          STRINGIFYERS[responseSpec.contentTypes[0]]
            ? responseSpec.contentTypes[0]
            : Object.keys(STRINGIFYERS)[0],
      });

      response.body = {
        error: {
          code: err.code || 'E_UNEXPECTED',
          // Enjoy nerdy stuff:
          // https://en.wikipedia.org/wiki/Guru_Meditation
          guruMeditation: transactionId,
        },
      };

      if (ENV && DEBUG_NODE_ENVS.includes(ENV.NODE_ENV)) {
        response.body.error.stack = err.stack;
        response.body.error.params = err.params;
      }

      return response;
    });
  }
}

function initErrorHandler ( { ENV = { } , DEBUG_NODE_ENVS = DEFAULT_DEBUG_NODE_ENVS , STRINGIFYERS = DEFAULT_STRINGIFYERS , } ) { return Promise . resolve ( errorHandler ) ; function errorHandler ( transactionId , responseSpec , err ) { return Promise . resolve ( ) . then ( ( ) => { const response = { } ; response . status = err . httpCode || 500 ; response . headers = Object . assign ( { } , err . headers || { } , { 'cache-control' : 'private' , 'content-type' : responseSpec && responseSpec . contentTypes [ 0 ] && STRINGIFYERS [ responseSpec . contentTypes [ 0 ] ] ? responseSpec . contentTypes [ 0 ] : Object . keys ( STRINGIFYERS ) [ 0 ] , } ) ; response . body = { error : { code : err . code || 'E_UNEXPECTED' , guruMeditation : transactionId , } , } ; if ( ENV && DEBUG_NODE_ENVS . includes ( ENV . NODE_ENV ) ) { response . body . error . stack = err . stack ; response . body . error . params = err . params ; } return response ; } ) ; } }

Initialize an error handler for the
HTTP router
@param  {Object}   services
The services the server depends on
@param  {Object}   [services.ENV]
The services the server depends on
@param  {Array}   [services.DEBUG_NODE_ENVS]
The environnement that activate debugging
(prints stack trace in HTTP errors responses)
@param  {Object} [services.STRINGIFYERS]
The synchronous body stringifyers
@return {Promise}
A promise of a function to handle errors


function dateDifferenceFromNow(date, differenceType) {
    var now = new Date(),
        diffMilliseconds = Math.abs(date - now);

    switch(differenceType) {
        case 'days':
            return dates._getDaysDiff(diffMilliseconds);
        case 'hours':
            return dates._differenceInHours(diffMilliseconds);
        case 'minutes':
            return dates._differenceInMinutes(diffMilliseconds);
        case 'milliseconds':
            return diffMilliseconds;

        default:
            return {
                days: dates._getDaysDiff(diffMilliseconds),
                hours: dates._getHoursDiff(diffMilliseconds),
                minutes: dates._getMinutesDiff(diffMilliseconds),
                milliseconds: diffMilliseconds
            }
    }
}

function dateDifferenceFromNow ( date , differenceType ) { var now = new Date ( ) , diffMilliseconds = Math . abs ( date - now ) ; switch ( differenceType ) { case 'days' : return dates . _getDaysDiff ( diffMilliseconds ) ; case 'hours' : return dates . _differenceInHours ( diffMilliseconds ) ; case 'minutes' : return dates . _differenceInMinutes ( diffMilliseconds ) ; case 'milliseconds' : return diffMilliseconds ; default : return { days : dates . _getDaysDiff ( diffMilliseconds ) , hours : dates . _getHoursDiff ( diffMilliseconds ) , minutes : dates . _getMinutesDiff ( diffMilliseconds ) , milliseconds : diffMilliseconds } } }

Difference between now and date which is passed, in formats 'milliseconds', 'days', 'hours', 'minutes'

@customNeeds -

@since 2.0.0
@category Date

@param {Date} date - The Date to inspect
@param {String} differenceType - [ 'days', 'hours', 'minutes', 'milliseconds', 'all' ]

@returns {Number|Object} Returns the numeric value or object depends on passed differenceType param

@example
example result for now is new Date('12-26-2017')

famulus.dateDifferenceFromNow(new Date('12-20-2017'), 'milliseconds')
// => 555261242

famulus.dateDifferenceFromNow(new Date('12-20-2017'), 'days')
// => 6

famulus.dateDifferenceFromNow(new Date('12-20-2017'), 'hours')
// => 156

Difference between now and date which is passed in formats milliseconds days hours minutes


function consumePair(stream, close, open) {
	const start = stream.pos;
	if (stream.eat(close)) {
		while (!stream.sol()) {
			if (stream.eat(open)) {
				return true;
			}

			stream.pos--;
		}
	}

	stream.pos = start;
	return false;
}

function consumePair ( stream , close , open ) { const start = stream . pos ; if ( stream . eat ( close ) ) { while ( ! stream . sol ( ) ) { if ( stream . eat ( open ) ) { return true ; } stream . pos -- ; } } stream . pos = start ; return false ; }

Consumes full character pair, if possible
@param {StreamReader} stream
@param {Number} close
@param {Number} open
@return {Boolean}

Consumes full character pair if possible


function consumeArray(stream, arr) {
	const start = stream.pos;
	let consumed = false;

	for (let i = arr.length - 1; i >= 0 && !stream.sol(); i--) {
		if (!stream.eat(arr[i])) {
			break;
		}

		consumed = i === 0;
	}

	if (!consumed) {
		stream.pos = start;
	}

	return consumed;
}

function consumeArray ( stream , arr ) { const start = stream . pos ; let consumed = false ; for ( let i = arr . length - 1 ; i >= 0 && ! stream . sol ( ) ; i -- ) { if ( ! stream . eat ( arr [ i ] ) ) { break ; } consumed = i === 0 ; } if ( ! consumed ) { stream . pos = start ; } return consumed ; }

Consumes all character codes from given array, right-to-left, if possible
@param {StreamReader} stream
@param {Number[]} arr

Consumes all character codes from given array right - to - left if possible


function isIdent(c) {
	return c === COLON || c === DASH || isAlpha(c) || isNumber(c);
}

function isIdent ( c ) { return c === COLON || c === DASH || isAlpha ( c ) || isNumber ( c ) ; }

Check if given character code belongs to HTML identifier
@param  {Number}  c
@return {Boolean}


function onCycle(event) {
  if(objectPool.length == 0) {
    throw new Error('Pool ran out of objects');
  }
  console.log(String(event.target));
  initPool();
}

function
onCycle
(
event
)
{
if
(
objectPool
.
length
==
0
)
{
throw
new
Error
(
'Pool ran out of objects'
)
;
}
console
.
log
(
String
(
event
.
target
)
)
;
initPool
(
)
;
}


function json(file) {
  var filename = path.basename(file.path, path.extname(file.path)) + ".json";
  return optional(path.join(path.dirname(file.path), filename)) || {};
}

function json ( file ) { var filename = path . basename ( file . path , path . extname ( file . path ) ) + ".json" ; return optional ( path . join ( path . dirname ( file . path ) , filename ) ) || { } ; }

Load JSON data from a companion file and store in file data.

@param {Object} file Vinyl File object
@return JSON data

Load JSON data from a companion file and store in file data .


function (event) {
      if (event.name === 'goToLevel'
        && event.level !== self.level) {
        self.pushLevel(event.level);
      }
    }

function ( event ) { if ( event . name === 'goToLevel' && event . level !== self . level ) { self . pushLevel ( event . level ) ; } }

As the elevator's doors are currently opened
we push any user request to go to
a level on the level stack.

As the elevator s doors are currently opened we push any user request to go to a level on the level stack .


function (event) {
      if (event.name === 'goToLevel') {
        if (event.level === self.level) {
          this.transitionTo(open);
        } else {
          self.pushLevel(event.level);
          this.transitionTo(moving);
        }
      }
    }

function ( event ) { if ( event . name === 'goToLevel' ) { if ( event . level === self . level ) { this . transitionTo ( open ) ; } else { self . pushLevel ( event . level ) ; this . transitionTo ( moving ) ; } } }

When the elevator's doors are closed,
we wait for a request to move to another
level.

When the elevator s doors are closed we wait for a request to move to another level .


function decryptGCM(encryptedComponents, keyDerivationInfo) {
    // Extract the components
    const encryptedContent = encryptedComponents.content;
    const iv = new Buffer(encryptedComponents.iv, "hex");
    const { auth: tagHex, salt } = encryptedComponents;
    // Prepare tool
    const decryptTool = crypto.createDecipheriv(ENC_ALGORITHM_GCM, keyDerivationInfo.key, iv);
    // Add additional auth data
    decryptTool.setAAD(new Buffer(`${encryptedComponents.iv}${keyDerivationInfo.salt}`, "utf8"));
    // Set auth tag
    decryptTool.setAuthTag(new Buffer(tagHex, "hex"));
    // Perform decryption
    const decryptedText = decryptTool.update(encryptedContent, "base64", "utf8");
    return Promise.resolve(`${decryptedText}${decryptTool.final("utf8")}`);
}

function decryptGCM ( encryptedComponents , keyDerivationInfo ) { const encryptedContent = encryptedComponents . content ; const iv = new Buffer ( encryptedComponents . iv , "hex" ) ; const { auth : tagHex , salt } = encryptedComponents ; const decryptTool = crypto . createDecipheriv ( ENC_ALGORITHM_GCM , keyDerivationInfo . key , iv ) ; decryptTool . setAAD ( new Buffer ( ` ${ encryptedComponents . iv } ${ keyDerivationInfo . salt } ` , "utf8" ) ) ; decryptTool . setAuthTag ( new Buffer ( tagHex , "hex" ) ) ; const decryptedText = decryptTool . update ( encryptedContent , "base64" , "utf8" ) ; return Promise . resolve ( ` ${ decryptedText } ${ decryptTool . final ( "utf8" ) } ` ) ; }

Decrypt text using AES-GCM
@param {EncryptedComponents} encryptedComponents Encrypted components
@param {DerivedKeyInfo} keyDerivationInfo Key derivation information
@returns {Promise.<String>} A promise that resolves with the decrypted string


function encryptCBC(text, keyDerivationInfo, iv) {
    return Promise.resolve().then(() => {
        const ivHex = iv.toString("hex");
        const encryptTool = crypto.createCipheriv(ENC_ALGORITHM_CBC, keyDerivationInfo.key, iv);
        const hmacTool = crypto.createHmac(HMAC_ALGORITHM, keyDerivationInfo.hmac);
        const { rounds } = keyDerivationInfo;
        // Perform encryption
        let encryptedContent = encryptTool.update(text, "utf8", "base64");
        encryptedContent += encryptTool.final("base64");
        // Generate hmac
        hmacTool.update(encryptedContent);
        hmacTool.update(ivHex);
        hmacTool.update(keyDerivationInfo.salt);
        const hmacHex = hmacTool.digest("hex");
        // Output encrypted components
        return {
            mode: "cbc",
            auth: hmacHex,
            iv: ivHex,
            salt: keyDerivationInfo.salt,
            rounds,
            content: encryptedContent
        };
    });
}

function encryptCBC ( text , keyDerivationInfo , iv ) { return Promise . resolve ( ) . then ( ( ) => { const ivHex = iv . toString ( "hex" ) ; const encryptTool = crypto . createCipheriv ( ENC_ALGORITHM_CBC , keyDerivationInfo . key , iv ) ; const hmacTool = crypto . createHmac ( HMAC_ALGORITHM , keyDerivationInfo . hmac ) ; const { rounds } = keyDerivationInfo ; let encryptedContent = encryptTool . update ( text , "utf8" , "base64" ) ; encryptedContent += encryptTool . final ( "base64" ) ; hmacTool . update ( encryptedContent ) ; hmacTool . update ( ivHex ) ; hmacTool . update ( keyDerivationInfo . salt ) ; const hmacHex = hmacTool . digest ( "hex" ) ; return { mode : "cbc" , auth : hmacHex , iv : ivHex , salt : keyDerivationInfo . salt , rounds , content : encryptedContent } ; } ) ; }

Encrypt text using AES-CBC
@param {String} text The text to encrypt
@param {DerivedKeyInfo} keyDerivationInfo Key derivation information
@param {Buffer} iv A buffer containing the IV
@returns {Promise.<EncryptedComponents>} A promise that resolves with encrypted components


function encryptGCM(text, keyDerivationInfo, iv) {
    return Promise.resolve().then(() => {
        const ivHex = iv.toString("hex");
        const { rounds } = keyDerivationInfo;
        const encryptTool = crypto.createCipheriv(ENC_ALGORITHM_GCM, keyDerivationInfo.key, iv);
        // Add additional auth data
        encryptTool.setAAD(new Buffer(`${ivHex}${keyDerivationInfo.salt}`, "utf8"));
        // Perform encryption
        let encryptedContent = encryptTool.update(text, "utf8", "base64");
        encryptedContent += encryptTool.final("base64");
        // Handle authentication
        const tag = encryptTool.getAuthTag();
        // Output encrypted components
        return {
            mode: "gcm",
            iv: ivHex,
            salt: keyDerivationInfo.salt,
            rounds,
            content: encryptedContent,
            auth: tag.toString("hex")
        };
    });
}

function encryptGCM ( text , keyDerivationInfo , iv ) { return Promise . resolve ( ) . then ( ( ) => { const ivHex = iv . toString ( "hex" ) ; const { rounds } = keyDerivationInfo ; const encryptTool = crypto . createCipheriv ( ENC_ALGORITHM_GCM , keyDerivationInfo . key , iv ) ; encryptTool . setAAD ( new Buffer ( ` ${ ivHex } ${ keyDerivationInfo . salt } ` , "utf8" ) ) ; let encryptedContent = encryptTool . update ( text , "utf8" , "base64" ) ; encryptedContent += encryptTool . final ( "base64" ) ; const tag = encryptTool . getAuthTag ( ) ; return { mode : "gcm" , iv : ivHex , salt : keyDerivationInfo . salt , rounds , content : encryptedContent , auth : tag . toString ( "hex" ) } ; } ) ; }

Encrypt text using AES-GCM
@param {String} text The text to encrypt
@param {DerivedKeyInfo} keyDerivationInfo Key derivation information
@param {Buffer} iv A buffer containing the IV
@returns {Promise.<EncryptedComponents>} A promise that resolves with encrypted components


function unpackEncryptedContent(encryptedContent) {
    const [content, iv, salt, auth, roundsRaw, methodRaw] = encryptedContent.split("$");
    // iocane was originally part of Buttercup's core package and used defaults from that originally.
    // There will be 4 components for pre 0.15.0 archives, and 5 in newer archives. The 5th component
    // is the pbkdf2 round count, which is optional:
    const rounds = roundsRaw ? parseInt(roundsRaw, 10) : PBKDF2_ROUND_DEFAULT;
    // Originally only "cbc" was supported, but GCM was added in version 1
    const method = methodRaw || "cbc";
    return {
        content,
        iv,
        salt,
        auth,
        rounds,
        method
    };
}

function unpackEncryptedContent ( encryptedContent ) { const [ content , iv , salt , auth , roundsRaw , methodRaw ] = encryptedContent . split ( "$" ) ; const rounds = roundsRaw ? parseInt ( roundsRaw , 10 ) : PBKDF2_ROUND_DEFAULT ; const method = methodRaw || "cbc" ; return { content , iv , salt , auth , rounds , method } ; }

Unpack encrypted content components from an encrypted string
@param {String} encryptedContent The encrypted string
@returns {EncryptedComponents} The extracted components
@throws {Error} Throws if the number of components is incorrect


function deriveFromPassword(pbkdf2Gen, password, salt, rounds, generateHMAC = true) {
    if (!password) {
        return Promise.reject(new Error("Failed deriving key: Password must be provided"));
    }
    if (!salt) {
        return Promise.reject(new Error("Failed deriving key: Salt must be provided"));
    }
    if (!rounds || rounds <= 0) {
        return Promise.reject(new Error("Failed deriving key: Rounds must be greater than 0"));
    }
    const bits = generateHMAC ? (PASSWORD_KEY_SIZE + HMAC_KEY_SIZE) * 8 : PASSWORD_KEY_SIZE * 8;
    return pbkdf2Gen(password, salt, rounds, bits)
        .then(derivedKeyData => derivedKeyData.toString("hex"))
        .then(function(derivedKeyHex) {
            const dkhLength = derivedKeyHex.length;
            const keyBuffer = generateHMAC
                ? new Buffer(derivedKeyHex.substr(0, dkhLength / 2), "hex")
                : new Buffer(derivedKeyHex, "hex");
            const output = {
                salt: salt,
                key: keyBuffer,
                rounds: rounds
            };
            if (generateHMAC) {
                output.hmac = new Buffer(derivedKeyHex.substr(dkhLength / 2, dkhLength / 2), "hex");
            }
            return output;
        });
}

Derived key info
@typedef DerivedKeyInfo
@property {String} salt - The salt used
@property {Buffer} key - The derived key
@property {Buffer} hmac - The HMAC
@property {Number} rounds - The number of rounds used

Derive a key from a password
@param {Function} pbkdf2Gen The generator method
@param {String} password The password to derive from
@param {String} salt The salt (Optional)
@param {Number} rounds The number of iterations
@param {Boolean=} generateHMAC Enable HMAC key generation
@throws {Error} Rejects if no password is provided
@throws {Error} Rejects if no salt is provided
@throws {Error} Rejects if no rounds are provided
@returns {Promise.<DerivedKeyInfo>} A promise that resolves with an object (DerivedKeyInfo)


function pbkdf2(password, salt, rounds, bits) {
    return new Promise((resolve, reject) => {
        deriveKey(password, salt, rounds, bits / 8, DERIVED_KEY_ALGORITHM, (err, key) => {
            if (err) {
                return reject(err);
            }
            return resolve(key);
        });
    });
}

function pbkdf2 ( password , salt , rounds , bits ) { return new Promise ( ( resolve , reject ) => { deriveKey ( password , salt , rounds , bits / 8 , DERIVED_KEY_ALGORITHM , ( err , key ) => { if ( err ) { return reject ( err ) ; } return resolve ( key ) ; } ) ; } ) ; }

The default PBKDF2 function
@param {String} password The password to use
@param {String} salt The salt to use
@param {Number} rounds The number of iterations
@param {Number} bits The size of the key to generate, in bits
@returns {Promise.<Buffer>} A Promise that resolves with the hash


function createEncodeStream(schema) {
  const stream = new BinaryStream({
    readableObjectMode: false,
    writableObjectMode: true,
    transform: transformEncode,
  });

  stream[kschema] = schema;
  return stream;
}

function createEncodeStream ( schema ) { const stream = new BinaryStream ( { readableObjectMode : false , writableObjectMode : true , transform : transformEncode , } ) ; stream [ kschema ] = schema ; return stream ; }

Create transform stream to encode objects into Buffer.
@param {Object} [schema]
@returns {EncodeStream}

Create transform stream to encode objects into Buffer .


function createDecodeStream(bufOrSchema) {
  let schema = null;
  const isBuffer = Buffer.isBuffer(bufOrSchema);

  if (!isBuffer) {
    schema = bufOrSchema;
  }

  const stream = new BinaryStream({
    transform: transformDecode,
    readableObjectMode: true,
    writableObjectMode: false,
  });

  stream[kschema] = schema;

  if (isBuffer) {
    stream.append(bufOrSchema);
  }

  return stream;
}

function createDecodeStream ( bufOrSchema ) { let schema = null ; const isBuffer = Buffer . isBuffer ( bufOrSchema ) ; if ( ! isBuffer ) { schema = bufOrSchema ; } const stream = new BinaryStream ( { transform : transformDecode , readableObjectMode : true , writableObjectMode : false , } ) ; stream [ kschema ] = schema ; if ( isBuffer ) { stream . append ( bufOrSchema ) ; } return stream ; }

Create transform stream to decode binary data into object.
@param {Buffer|Object} [bufOrSchema]
@returns {DecodeStream}

Create transform stream to decode binary data into object .


function erdosRenyi(GraphClass, options) {
  if (!isGraphConstructor(GraphClass))
    throw new Error('graphology-generators/random/erdos-renyi: invalid Graph constructor.');

  var order = options.order,
      probability = options.probability,
      rng = options.rng || Math.random;

  var graph = new GraphClass();

  // If user gave a size, we need to compute probability
  if (typeof options.approximateSize === 'number') {
    var densityFunction = density[graph.type + 'Density'];
    probability = densityFunction(order, options.approximateSize);
  }

  if (typeof order !== 'number' || order <= 0)
    throw new Error('graphology-generators/random/erdos-renyi: invalid `order`. Should be a positive number.');

  if (typeof probability !== 'number' || probability < 0 || probability > 1)
    throw new Error('graphology-generators/random/erdos-renyi: invalid `probability`. Should be a number between 0 and 1. Or maybe you gave an `approximateSize` exceeding the graph\'s density.');

  if (typeof rng !== 'function')
    throw new Error('graphology-generators/random/erdos-renyi: invalid `rng`. Should be a function.');

  for (var i = 0; i < order; i++)
    graph.addNode(i);

  if (probability <= 0)
    return graph;

  if (order > 1) {
    var iterator = combinations(range(order), 2),
        path,
        step;

    while ((step = iterator.next(), !step.done)) {
      path = step.value;

      if (graph.type !== 'directed') {
        if (rng() < probability)
          graph.addUndirectedEdge(path[0], path[1]);
      }

      if (graph.type !== 'undirected') {

        if (rng() < probability)
          graph.addDirectedEdge(path[0], path[1]);

        if (rng() < probability)
          graph.addDirectedEdge(path[1], path[0]);
      }
    }
  }

  return graph;
}

Generates a binomial graph graph with n nodes.

@param  {Class}    GraphClass    - The Graph Class to instantiate.
@param  {object}   options       - Options:
@param  {number}     order       - Number of nodes in the graph.
@param  {number}     probability - Probability for edge creation.
@param  {function}   rng         - Custom RNG function.
@return {Graph}

Generates a binomial graph graph with n nodes .


function erdosRenyiSparse(GraphClass, options) {
  if (!isGraphConstructor(GraphClass))
    throw new Error('graphology-generators/random/erdos-renyi: invalid Graph constructor.');

  var order = options.order,
      probability = options.probability,
      rng = options.rng || Math.random;

  var graph = new GraphClass();

  // If user gave a size, we need to compute probability
  if (typeof options.approximateSize === 'number') {
    var densityFunction = density[graph.type + 'Density'];
    probability = densityFunction(order, options.approximateSize);
  }

  if (typeof order !== 'number' || order <= 0)
    throw new Error('graphology-generators/random/erdos-renyi: invalid `order`. Should be a positive number.');

  if (typeof probability !== 'number' || probability < 0 || probability > 1)
    throw new Error('graphology-generators/random/erdos-renyi: invalid `probability`. Should be a number between 0 and 1. Or maybe you gave an `approximateSize` exceeding the graph\'s density.');

  if (typeof rng !== 'function')
    throw new Error('graphology-generators/random/erdos-renyi: invalid `rng`. Should be a function.');

  for (var i = 0; i < order; i++)
    graph.addNode(i);

  if (probability <= 0)
    return graph;

  var w = -1,
      lp = Math.log(1 - probability),
      lr,
      v;

  if (graph.type !== 'undirected') {
    v = 0;

    while (v < order) {
      lr = Math.log(1 - rng());
      w += 1 + ((lr / lp) | 0);

      // Avoiding self loops
      if (v === w) {
        w++;
      }

      while (v < order && order <= w) {
        w -= order;
        v++;

        // Avoiding self loops
        if (v === w)
          w++;
      }

      if (v < order)
        graph.addDirectedEdge(v, w);
    }
  }

  w = -1;

  if (graph.type !== 'directed') {
    v = 1;

    while (v < order) {
      lr = Math.log(1 - rng());

      w += 1 + ((lr / lp) | 0);

      while (w >= v && v < order) {
        w -= v;
        v++;
      }

      if (v < order)
        graph.addUndirectedEdge(v, w);
    }
  }

  return graph;
}

Generates a binomial graph graph with n nodes using a faster algorithm
for sparse graphs.

@param  {Class}    GraphClass    - The Graph Class to instantiate.
@param  {object}   options       - Options:
@param  {number}     order       - Number of nodes in the graph.
@param  {number}     probability - Probability for edge creation.
@param  {function}   rng         - Custom RNG function.
@return {Graph}

Generates a binomial graph graph with n nodes using a faster algorithm for sparse graphs .


function single_curve(d, ctx) {

        var centroids = compute_centroids(d);
        var cps = compute_control_points(centroids);

        ctx.moveTo(cps[0].e(1), cps[0].e(2));
        for (var i = 1; i < cps.length; i += 3) {
            if (__.showControlPoints) {
                for (var j = 0; j < 3; j++) {
                    ctx.fillRect(cps[i+j].e(1), cps[i+j].e(2), 2, 2);
                }
            }
            ctx.bezierCurveTo(cps[i].e(1), cps[i].e(2), cps[i+1].e(1), cps[i+1].e(2), cps[i+2].e(1), cps[i+2].e(2));
        }
    }

function single_curve ( d , ctx ) { var centroids = compute_centroids ( d ) ; var cps = compute_control_points ( centroids ) ; ctx . moveTo ( cps [ 0 ] . e ( 1 ) , cps [ 0 ] . e ( 2 ) ) ; for ( var i = 1 ; i < cps . length ; i += 3 ) { if ( __ . showControlPoints ) { for ( var j = 0 ; j < 3 ; j ++ ) { ctx . fillRect ( cps [ i + j ] . e ( 1 ) , cps [ i + j ] . e ( 2 ) , 2 , 2 ) ; } } ctx . bezierCurveTo ( cps [ i ] . e ( 1 ) , cps [ i ] . e ( 2 ) , cps [ i + 1 ] . e ( 1 ) , cps [ i + 1 ] . e ( 2 ) , cps [ i + 2 ] . e ( 1 ) , cps [ i + 2 ] . e ( 2 ) ) ; } }


function color_path(d, ctx) {
        ctx.beginPath();
        if ((__.bundleDimension !== null && __.bundlingStrength > 0) || __.smoothness > 0) {
            single_curve(d, ctx);
        } else {
            single_path(d, ctx);
        }
        ctx.stroke();
    }

function color_path ( d , ctx ) { ctx . beginPath ( ) ; if ( ( __ . bundleDimension !== null && __ . bundlingStrength > 0 ) || __ . smoothness > 0 ) { single_curve ( d , ctx ) ; } else { single_path ( d , ctx ) ; } ctx . stroke ( ) ; }


function paths(data, ctx) {
        ctx.clearRect(-1, -1, w() + 2, h() + 2);
        ctx.beginPath();
        data.forEach(function(d) {
            if ((__.bundleDimension !== null && __.bundlingStrength > 0) || __.smoothness > 0) {
                single_curve(d, ctx);
            } else {
                single_path(d, ctx);
            }
        });
        ctx.stroke();
    }

function paths ( data , ctx ) { ctx . clearRect ( - 1 , - 1 , w ( ) + 2 , h ( ) + 2 ) ; ctx . beginPath ( ) ; data . forEach ( function ( d ) { if ( ( __ . bundleDimension !== null && __ . bundlingStrength > 0 ) || __ . smoothness > 0 ) { single_curve ( d , ctx ) ; } else { single_path ( d , ctx ) ; } } ) ; ctx . stroke ( ) ; }


function brushUpdated(newSelection) {
        __.brushed = newSelection;
        events.brush.call(pc,__.brushed);
        pc.renderBrushed();
    }

function brushUpdated ( newSelection ) { __ . brushed = newSelection ; events . brush . call ( pc , __ . brushed ) ; pc . renderBrushed ( ) ; }

This function can be used for 'live' updates of brushes. That is, during the specification of a brush, this method can be called to update the view.  @param newSelection - The new set of data items that is currently contained by the brushes

This function can be used for live updates of brushes . That is during the specification of a brush this method can be called to update the view .


function selected() {
            var actives = d3.keys(__.dimensions).filter(is_brushed),
                extents = actives.map(function(p) { return brushes[p].extent(); });

            // We don't want to return the full data set when there are no axes brushed.
            // Actually, when there are no axes brushed, by definition, no items are
            // selected. So, let's avoid the filtering and just return false.
            //if (actives.length === 0) return false;

            // Resolves broken examples for now. They expect to get the full dataset back from empty brushes
            if (actives.length === 0) return __.data;

            // test if within range
            var within = {
                "date": function(d,p,dimension) {
                    if (typeof __.dimensions[p].yscale.rangePoints === "function") { // if it is ordinal
                        return extents[dimension][0] <= __.dimensions[p].yscale(d[p]) && __.dimensions[p].yscale(d[p]) <= extents[dimension][1]
                    } else {
                        return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1]
                    }
                },
                "number": function(d,p,dimension) {
                    if (typeof __.dimensions[p].yscale.rangePoints === "function") { // if it is ordinal
                        return extents[dimension][0] <= __.dimensions[p].yscale(d[p]) && __.dimensions[p].yscale(d[p]) <= extents[dimension][1]
                    } else {
                        return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1]
                    }
                },
                "string": function(d,p,dimension) {
                    return extents[dimension][0] <= __.dimensions[p].yscale(d[p]) && __.dimensions[p].yscale(d[p]) <= extents[dimension][1]
                }
            };

            return __.data
                .filter(function(d) {
                    switch(brush.predicate) {
                        case "AND":
                            return actives.every(function(p, dimension) {
                                return within[__.dimensions[p].type](d,p,dimension);
                            });
                        case "OR":
                            return actives.some(function(p, dimension) {
                                return within[__.dimensions[p].type](d,p,dimension);
                            });
                        default:
                            throw new Error("Unknown brush predicate " + __.brushPredicate);
                    }
                });
        }

function
selected
(
)
{
var
actives
=
d3
.
keys
(
__
.
dimensions
)
.
filter
(
is_brushed
)
,
extents
=
actives
.
map
(
function
(
p
)
{
return
brushes
[
p
]
.
extent
(
)
;
}
)
;
if
(
actives
.
length
===
0
)
return
__
.
data
;
var
within
=
{
"date"
:
function
(
d
,
p
,
dimension
)
{
if
(
typeof
__
.
dimensions
[
p
]
.
yscale
.
rangePoints
===
"function"
)
{
return
extents
[
dimension
]
[
0
]
<=
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
&&
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
<=
extents
[
dimension
]
[
1
]
}
else
{
return
extents
[
dimension
]
[
0
]
<=
d
[
p
]
&&
d
[
p
]
<=
extents
[
dimension
]
[
1
]
}
}
,
"number"
:
function
(
d
,
p
,
dimension
)
{
if
(
typeof
__
.
dimensions
[
p
]
.
yscale
.
rangePoints
===
"function"
)
{
return
extents
[
dimension
]
[
0
]
<=
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
&&
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
<=
extents
[
dimension
]
[
1
]
}
else
{
return
extents
[
dimension
]
[
0
]
<=
d
[
p
]
&&
d
[
p
]
<=
extents
[
dimension
]
[
1
]
}
}
,
"string"
:
function
(
d
,
p
,
dimension
)
{
return
extents
[
dimension
]
[
0
]
<=
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
&&
__
.
dimensions
[
p
]
.
yscale
(
d
[
p
]
)
<=
extents
[
dimension
]
[
1
]
}
}
;
return
__
.
data
.
filter
(
function
(
d
)
{
switch
(
brush
.
predicate
)
{
case
"AND"
:
return
actives
.
every
(
function
(
p
,
dimension
)
{
return
within
[
__
.
dimensions
[
p
]
.
type
]
(
d
,
p
,
dimension
)
;
}
)
;
case
"OR"
:
return
actives
.
some
(
function
(
p
,
dimension
)
{
return
within
[
__
.
dimensions
[
p
]
.
type
]
(
d
,
p
,
dimension
)
;
}
)
;
default
:
throw
new
Error
(
"Unknown brush predicate "
+
__
.
brushPredicate
)
;
}
}
)
;
}


function consecutive(first, second) {
                    var length = d3.keys(__.dimensions).length;
                    return d3.keys(__.dimensions).some(function(d, i) {
                        return (d === first)
                            ? i + i < length && __.dimensions[i + 1] === second
                            : false;
                    });
                }

function consecutive ( first , second ) { var length = d3 . keys ( __ . dimensions ) . length ; return d3 . keys ( __ . dimensions ) . some ( function ( d , i ) { return ( d === first ) ? i + i < length && __ . dimensions [ i + 1 ] === second : false ; } ) ; }

Checks if the first dimension is directly left of the second dimension.

Checks if the first dimension is directly left of the second dimension .


function convertProperty(originalKey, originalValue, isRtl) {
  const key = getPropertyDoppelganger(originalKey, isRtl)
  const value = getValueDoppelganger(key, originalValue, isRtl)
  return {key, value}
}

function convertProperty ( originalKey , originalValue , isRtl ) { const key = getPropertyDoppelganger ( originalKey , isRtl ) const value = getValueDoppelganger ( key , originalValue , isRtl ) return { key , value } }

Logically converts a property and its value based on the flow direction context
@param {String} originalKey the original property key
@param {Number|String|Object} originalValue the original css property value
@param {Boolean} isRtl Should conversion happen in RTL context?
@return {Object} the new {key, value} pair


function getPropertyDoppelganger(property, isRtl) {
  const convertedProperty = isRtl
    ? propertiesToConvert.rtl[property]
    : propertiesToConvert.ltr[property]

  return convertedProperty || property
}

function getPropertyDoppelganger ( property , isRtl ) { const convertedProperty = isRtl ? propertiesToConvert . rtl [ property ] : propertiesToConvert . ltr [ property ] return convertedProperty || property }

Logically gets the direction of the given property based on the flow direction context
@param {String} property the name of the property
@param {Boolean} isRtl Should conversion happen in RTL context?
@return {String} the name of the RTL property


function ReadFileCache(sourceDir, charset) {
    assert.ok(this instanceof ReadFileCache);
    assert.strictEqual(typeof sourceDir, "string");

    this.charset = charset;

    EventEmitter.call(this);

    Object.defineProperties(this, {
        sourceDir: { value: sourceDir },
        sourceCache: { value: {} }
    });
}

function ReadFileCache ( sourceDir , charset ) { assert . ok ( this instanceof ReadFileCache ) ; assert . strictEqual ( typeof sourceDir , "string" ) ; this . charset = charset ; EventEmitter . call ( this ) ; Object . defineProperties ( this , { sourceDir : { value : sourceDir } , sourceCache : { value : { } } } ) ; }

ReadFileCache is an EventEmitter subclass that caches file contents in
memory so that subsequent calls to readFileP return the same contents,
regardless of any changes in the underlying file.

ReadFileCache is an EventEmitter subclass that caches file contents in memory so that subsequent calls to readFileP return the same contents regardless of any changes in the underlying file .


function done(err, resource) {
            totalRequestElapsed += ((new Date().getTime()) - started);
            ++totalRequests;
            stats.avgFetchTime = parseInt(totalRequestElapsed / totalRequests);
            if (err || verbose) util.log('cache|execute|done|err='+err+'|result='+(resource ? 'found':'null'));
            if (err) {
                ++stats.failed;
            }
            if (!err && defaultCacheTTL) {    // ttl ===  0 --> expire imediatly.
                if (stats.inCache >= defaultCacheSize) {
                    weedOutCache();
                }
                var now = new Date().getTime();
                resourceCache[key] = {
                    'key'   : key,
                    'epoch' : now,
                    'access': now,
                    'expire': defaultCacheTTL,
                    'hits'  : 0,
                    'data'  : resource
                };
                ++stats.inCache;
            }

            var pendingRequests = requestQueue[key];
            delete requestQueue[key];
            for (var i = 0, size = pendingRequests.length ; i < size ; ++i) {
                if (debug) util.log('cache|calling='+i+'|err='+err+'|resource='+(resource ? 'found':'null'));
                if (!err && defaultCacheTTL) {
                    ++resourceCache[key].hits;
                }
                pendingRequests[i].call(this, err, resource, resourceCache[key]);
                --stats.waiting;
            }
            --stats.fetching;
            if (stats.fetching === 0 && stats.waiting === 0) {
                self.emit('stats', stats);
            } else {
                bufferedEmitter.call(self, 'stats', stats);
            }
        }

function done ( err , resource ) { totalRequestElapsed += ( ( new Date ( ) . getTime ( ) ) - started ) ; ++ totalRequests ; stats . avgFetchTime = parseInt ( totalRequestElapsed / totalRequests ) ; if ( err || verbose ) util . log ( 'cache|execute|done|err=' + err + '|result=' + ( resource ? 'found' : 'null' ) ) ; if ( err ) { ++ stats . failed ; } if ( ! err && defaultCacheTTL ) { if ( stats . inCache >= defaultCacheSize ) { weedOutCache ( ) ; } var now = new Date ( ) . getTime ( ) ; resourceCache [ key ] = { 'key' : key , 'epoch' : now , 'access' : now , 'expire' : defaultCacheTTL , 'hits' : 0 , 'data' : resource } ; ++ stats . inCache ; } var pendingRequests = requestQueue [ key ] ; delete requestQueue [ key ] ; for ( var i = 0 , size = pendingRequests . length ; i < size ; ++ i ) { if ( debug ) util . log ( 'cache|calling=' + i + '|err=' + err + '|resource=' + ( resource ? 'found' : 'null' ) ) ; if ( ! err && defaultCacheTTL ) { ++ resourceCache [ key ] . hits ; } pendingRequests [ i ] . call ( this , err , resource , resourceCache [ key ] ) ; -- stats . waiting ; } -- stats . fetching ; if ( stats . fetching === 0 && stats . waiting === 0 ) { self . emit ( 'stats' , stats ) ; } else { bufferedEmitter . call ( self , 'stats' , stats ) ; } }

Fetch the resource and call 'done' when it is fetched

Fetch the resource and call done when it is fetched


function(options) {
  options = (options||{});
  this.agent = options.agent;
  this.defaults = options.defaults||{};
  this.log = options.logger||(new Ax({ level: "info" }));
  this._sharedCookieJar = new CookieJar();
  this.logCurl = options.logCurl || false;
}

function ( options ) { options = ( options || { } ) ; this . agent = options . agent ; this . defaults = options . defaults || { } ; this . log = options . logger || ( new Ax ( { level : "info" } ) ) ; this . _sharedCookieJar = new CookieJar ( ) ; this . logCurl = options . logCurl || false ; }

Shred takes some options, including a logger and request defaults.

Shred takes some options including a logger and request defaults .


function(level,message) {
  var debug = (level=="debug"||level=="error");
  if (!message) { return message.toString(); }
  if (typeof(message) == "object") {
    if (message instanceof Error && debug) {
      return message.stack;
    } else {
      return inspect(message);
    }
  } else {
    return message.toString();
  }
}

function ( level , message ) { var debug = ( level == "debug" || level == "error" ) ; if ( ! message ) { return message . toString ( ) ; } if ( typeof ( message ) == "object" ) { if ( message instanceof Error && debug ) { return message . stack ; } else { return inspect ( message ) ; } } else { return message . toString ( ) ; } }

this is a quick-and-dirty logger. there are other nicer loggers out there but the ones i found were also somewhat involved. this one has a Ruby logger type interface  we can easily replace this, provide the info, debug, etc. methods are the same. or, we can change Haiku to use a more standard node.js interface

this is a quick - and - dirty logger . there are other nicer loggers out there but the ones i found were also somewhat involved . this one has a Ruby logger type interface we can easily replace this provide the info debug etc . methods are the same . or we can change Haiku to use a more standard node . js interface


function(options) {
  this.log = options.logger;
  this.cookieJar = options.cookieJar;
  this.encoding = options.encoding;
  this.logCurl = options.logCurl;
  processOptions(this,options||{});
  createRequest(this);
}

function ( options ) { this . log = options . logger ; this . cookieJar = options . cookieJar ; this . encoding = options . encoding ; this . logCurl = options . logCurl ; processOptions ( this , options || { } ) ; createRequest ( this ) ; }

The Shred object itself constructs the `Request` object. You should rarely need to do this directly.

The Shred object itself constructs the Request object . You should rarely need to do this directly .


function(request,options) {

  request.log.debug("Processing request options ..");

  // We'll use `request.emitter` to manage the `on` event handlers.
  request.emitter = (new Emitter);

  request.agent = options.agent;

  // Set up the handlers ...
  if (options.on) {
    for (var key in options.on) {
      if (options.on.hasOwnProperty(key)) {
        request.emitter.on(key, options.on[key]);
      }
    }
  }

  // Make sure we were give a URL or a host
  if (!options.url && !options.host) {
    request.emitter.emit("request_error",
        new Error("No url or url options (host, port, etc.)"));
    return;
  }

  // Allow for the [use of a proxy](http://www.jmarshall.com/easy/http/#proxies).

  if (options.url) {
    if (options.proxy) {
      request.url = options.proxy;
      request.path = options.url;
    } else {
      request.url = options.url;
    }
  }

  // Set the remaining options.
  request.query = options.query||options.parameters||request.query ;
  request.method = options.method;
  request.setHeader("user-agent",options.agent||"Shred");
  request.setHeaders(options.headers);

  if (request.cookieJar) {
    var cookies = request.cookieJar.getCookies( CookieAccessInfo( request.host, request.path ) );
    if (cookies.length) {
      var cookieString = request.getHeader('cookie')||'';
      for (var cookieIndex = 0; cookieIndex < cookies.length; ++cookieIndex) {
          if ( cookieString.length && cookieString[ cookieString.length - 1 ] != ';' )
          {
              cookieString += ';';
          }
          cookieString += cookies[ cookieIndex ].name + '=' + cookies[ cookieIndex ].value + ';';
      }
      request.setHeader("cookie", cookieString);
    }
  }

  // The content entity can be set either using the `body` or `content` attributes.
  if (options.body||options.content) {
    request.content = options.body||options.content;
  }
  request.timeout = options.timeout;

}

`processOptions` is called from the constructor to handle all the work associated with making sure we do our best to ensure we have a valid request.

processOptions is called from the constructor to handle all the work associated with making sure we do our best to ensure we have a valid request .


function(event) {
        var emitter = request.emitter;
        var textStatus = STATUS_CODES[response.status] ? STATUS_CODES[response.status].toLowerCase() : null;
        if (emitter.listeners(response.status).length > 0 || emitter.listeners(textStatus).length > 0) {
          emitter.emit(response.status, response);
          emitter.emit(textStatus, response);
        } else {
          if (emitter.listeners(event).length>0) {
            emitter.emit(event, response);
          } else if (!response.isRedirect) {
            emitter.emit("response", response);
            //console.warn("Request has no event listener for status code " + response.status);
          }
        }
      }

function ( event ) { var emitter = request . emitter ; var textStatus = STATUS_CODES [ response . status ] ? STATUS_CODES [ response . status ] . toLowerCase ( ) : null ; if ( emitter . listeners ( response . status ) . length > 0 || emitter . listeners ( textStatus ) . length > 0 ) { emitter . emit ( response . status , response ) ; emitter . emit ( textStatus , response ) ; } else { if ( emitter . listeners ( event ) . length > 0 ) { emitter . emit ( event , response ) ; } else if ( ! response . isRedirect ) { emitter . emit ( "response" , response ) ; } } }

Set up some event magic. The precedence is given first to status-specific handlers, then to responses for a given event, and then finally to the more general `response` handler. In the last case, we need to first make sure we're not dealing with a a redirect.

Set up some event magic . The precedence is given first to status - specific handlers then to responses for a given event and then finally to the more general response handler . In the last case we need to first make sure we re not dealing with a a redirect .


function (req) {
  var headers = req.getHeaders();
  var headerString = "";

  for (var key in headers) {
    headerString += '-H "' + key + ": " + headers[key] + '" ';
  }

  var bodyString = ""

  if (req.content) {
    bodyString += "-d '" + req.content.body + "' ";
  }

  var query = req.query ? '?' + req.query : "";

  console.log("curl " +
    "-X " + req.method.toUpperCase() + " " +
    req.scheme + "://" + req.host + ":" + req.port + req.path + query + " " +
    headerString +
    bodyString
  );
}

function
(
req
)
{
var
headers
=
req
.
getHeaders
(
)
;
var
headerString
=
""
;
for
(
var
key
in
headers
)
{
headerString
+=
'-H "'
+
key
+
": "
+
headers
[
key
]
+
'" '
;
}
var
bodyString
=
""
if
(
req
.
content
)
{
bodyString
+=
"-d '"
+
req
.
content
.
body
+
"' "
;
}
var
query
=
req
.
query
'?'
+
req
.
query
:
""
;
console
.
log
(
"curl "
+
"-X "
+
req
.
method
.
toUpperCase
(
)
+
" "
+
req
.
scheme
+
"://"
+
req
.
host
+
":"
+
req
.
port
+
req
.
path
+
query
+
" "
+
headerString
+
bodyString
)
;
}


function(raw, request, callback) {
  var response = this;
  this._raw = raw;

  // The `._setHeaders` method is "private"; you can't otherwise set headers on
  // the response.
  this._setHeaders.call(this,raw.headers);

  // store any cookies
  if (request.cookieJar && this.getHeader('set-cookie')) {
    var cookieStrings = this.getHeader('set-cookie');
    var cookieObjs = []
      , cookie;

    for (var i = 0; i < cookieStrings.length; i++) {
      var cookieString = cookieStrings[i];
      if (!cookieString) {
        continue;
      }

      if (!cookieString.match(/domain\=/i)) {
        cookieString += '; domain=' + request.host;
      }

      if (!cookieString.match(/path\=/i)) {
        cookieString += '; path=' + request.path;
      }

      try {
        cookie = new Cookie(cookieString);
        if (cookie) {
          cookieObjs.push(cookie);
        }
      } catch (e) {
        console.warn("Tried to set bad cookie: " + cookieString);
      }
    }

    request.cookieJar.setCookies(cookieObjs);
  }

  this.request = request;
  this.client = request.client;
  this.log = this.request.log;

  // Stream the response content entity and fire the callback when we're done.
  // Store the incoming data in a array of Buffers which we concatinate into one
  // buffer at the end.  We need to use buffers instead of strings here in order
  // to preserve binary data.
  var chunkBuffers = [];
  var dataLength = 0;
  raw.on("data", function(chunk) {
    chunkBuffers.push(chunk);
    dataLength += chunk.length;
  });
  raw.on("end", function() {
    var body;
    if (typeof Buffer === 'undefined') {
      // Just concatinate into a string
      body = chunkBuffers.join('');
    } else {
      // Initialize new buffer and add the chunks one-at-a-time.
      body = new Buffer(dataLength);
      for (var i = 0, pos = 0; i < chunkBuffers.length; i++) {
        chunkBuffers[i].copy(body, pos);
        pos += chunkBuffers[i].length;
      }
    }

    var setBodyAndFinish = function (body) {
      response._body = new Content({
        body: body,
        type: response.getHeader("Content-Type")
      });
      callback(response);
    }

    if (zlib && response.getHeader("Content-Encoding") === 'gzip'){
      zlib.gunzip(body, function (err, gunzippedBody) {
        if (Iconv && response.request.encoding){
          body = Iconv.fromEncoding(gunzippedBody,response.request.encoding);
        } else {
          body = gunzippedBody.toString();
        }
        setBodyAndFinish(body);
      })
    }
    else{
       if (response.request.encoding){
            body = Iconv.fromEncoding(body,response.request.encoding);
        }
      setBodyAndFinish(body);
    }
  });
}

function
(
raw
,
request
,
callback
)
{
var
response
=
this
;
this
.
_raw
=
raw
;
this
.
_setHeaders
.
call
(
this
,
raw
.
headers
)
;
if
(
request
.
cookieJar
&&
this
.
getHeader
(
'set-cookie'
)
)
{
var
cookieStrings
=
this
.
getHeader
(
'set-cookie'
)
;
var
cookieObjs
=
[
]
,
cookie
;
for
(
var
i
=
0
;
i
<
cookieStrings
.
length
;
i
++
)
{
var
cookieString
=
cookieStrings
[
i
]
;
if
(
!
cookieString
)
{
continue
;
}
if
(
!
cookieString
.
match
(
/
domain\=
/
i
)
)
{
cookieString
+=
'; domain='
+
request
.
host
;
}
if
(
!
cookieString
.
match
(
/
path\=
/
i
)
)
{
cookieString
+=
'; path='
+
request
.
path
;
}
try
{
cookie
=
new
Cookie
(
cookieString
)
;
if
(
cookie
)
{
cookieObjs
.
push
(
cookie
)
;
}
}
catch
(
e
)
{
console
.
warn
(
"Tried to set bad cookie: "
+
cookieString
)
;
}
}
request
.
cookieJar
.
setCookies
(
cookieObjs
)
;
}
this
.
request
=
request
;
this
.
client
=
request
.
client
;
this
.
log
=
this
.
request
.
log
;
var
chunkBuffers
=
[
]
;
var
dataLength
=
0
;
raw
.
on
(
"data"
,
function
(
chunk
)
{
chunkBuffers
.
push
(
chunk
)
;
dataLength
+=
chunk
.
length
;
}
)
;
raw
.
on
(
"end"
,
function
(
)
{
var
body
;
if
(
typeof
Buffer
===
'undefined'
)
{
body
=
chunkBuffers
.
join
(
''
)
;
}
else
{
body
=
new
Buffer
(
dataLength
)
;
for
(
var
i
=
0
,
pos
=
0
;
i
<
chunkBuffers
.
length
;
i
++
)
{
chunkBuffers
[
i
]
.
copy
(
body
,
pos
)
;
pos
+=
chunkBuffers
[
i
]
.
length
;
}
}
var
setBodyAndFinish
=
function
(
body
)
{
response
.
_body
=
new
Content
(
{
body
:
body
,
type
:
response
.
getHeader
(
"Content-Type"
)
}
)
;
callback
(
response
)
;
}
if
(
zlib
&&
response
.
getHeader
(
"Content-Encoding"
)
===
'gzip'
)
{
zlib
.
gunzip
(
body
,
function
(
err
,
gunzippedBody
)
{
if
(
Iconv
&&
response
.
request
.
encoding
)
{
body
=
Iconv
.
fromEncoding
(
gunzippedBody
,
response
.
request
.
encoding
)
;
}
else
{
body
=
gunzippedBody
.
toString
(
)
;
}
setBodyAndFinish
(
body
)
;
}
)
}
else
{
if
(
response
.
request
.
encoding
)
{
body
=
Iconv
.
fromEncoding
(
body
,
response
.
request
.
encoding
)
;
}
setBodyAndFinish
(
body
)
;
}
}
)
;
}

Construct a `Response` object. You should never have to do this directly. The `Request` object handles this, getting the raw response object and passing it in here, along with the request. The callback allows us to stream the response and then use the callback to let the request know when it's ready.

Construct a Response object . You should never have to do this directly . The Request object handles this getting the raw response object and passing it in here along with the request . The callback allows us to stream the response and then use the callback to let the request know when it s ready .


function(constructor) {
    constructor.prototype.getHeader = function(name) { return getHeader(this,name); };
    constructor.prototype.getHeaders = function() { return getHeaders(this,arguments); };
  }

function ( constructor ) { constructor . prototype . getHeader = function ( name ) { return getHeader ( this , name ) ; } ; constructor . prototype . getHeaders = function ( ) { return getHeaders ( this , arguments ) ; } ; }


function(constructor) {
    constructor.prototype._setHeader = function(key,value) { return setHeader(this,key,value); };
    constructor.prototype._setHeaders = function(hash) { return setHeaders(this,hash); };
  }

function ( constructor ) { constructor . prototype . _setHeader = function ( key , value ) { return setHeader ( this , key , value ) ; } ; constructor . prototype . _setHeaders = function ( hash ) { return setHeaders ( this , hash ) ; } ; }


function(constructor) {
    constructor.prototype.setHeader = function(key,value) { return setHeader(this,key,value); };
    constructor.prototype.setHeaders = function(hash) { return setHeaders(this,hash); };
  }

function ( constructor ) { constructor . prototype . setHeader = function ( key , value ) { return setHeader ( this , key , value ) ; } ; constructor . prototype . setHeaders = function ( hash ) { return setHeaders ( this , hash ) ; } ; }


function(constructor) {
    constructor.prototype.getHeader = function(name) { return getHeader(this,name); };
    constructor.prototype.getHeaders = function() { return getHeaders(this,arguments); };
    constructor.prototype.setHeader = function(key,value) { return setHeader(this,key,value); };
    constructor.prototype.setHeaders = function(hash) { return setHeaders(this,hash); };
  }

function ( constructor ) { constructor . prototype . getHeader = function ( name ) { return getHeader ( this , name ) ; } ; constructor . prototype . getHeaders = function ( ) { return getHeaders ( this , arguments ) ; } ; constructor . prototype . setHeader = function ( key , value ) { return setHeader ( this , key , value ) ; } ; constructor . prototype . setHeaders = function ( hash ) { return setHeaders ( this , hash ) ; } ; }


function(encoding) {
        var enc = encoding || "utf8";
        var codecOptions = undefined;
        while (1) {
            if (getType(enc) === "String")
                enc = enc.replace(/[- ]/g, "").toLowerCase();
            var codec = iconv.encodings[enc];
            var type = getType(codec);
            if (type === "String") {
                // Link to other encoding.
                codecOptions = {originalEncoding: enc};
                enc = codec;
            }
            else if (type === "Object" && codec.type != undefined) {
                // Options for other encoding.
                codecOptions = codec;
                enc = codec.type;
            }
            else if (type === "Function")
                // Codec itself.
                return codec(codecOptions);
            else
                throw new Error("Encoding not recognized: '" + encoding + "' (searched as: '"+enc+"')");
        }
    }

function
(
encoding
)
{
var
enc
=
encoding
||
"utf8"
;
var
codecOptions
=
undefined
;
while
(
1
)
{
if
(
getType
(
enc
)
===
"String"
)
enc
=
enc
.
replace
(
/
[- ]
/
g
,
""
)
.
toLowerCase
(
)
;
var
codec
=
iconv
.
encodings
[
enc
]
;
var
type
=
getType
(
codec
)
;
if
(
type
===
"String"
)
{
codecOptions
=
{
originalEncoding
:
enc
}
;
enc
=
codec
;
}
else
if
(
type
===
"Object"
&&
codec
.
type
!=
undefined
)
{
codecOptions
=
codec
;
enc
=
codec
.
type
;
}
else
if
(
type
===
"Function"
)
return
codec
(
codecOptions
)
;
else
throw
new
Error
(
"Encoding not recognized: '"
+
encoding
+
"' (searched as: '"
+
enc
+
"')"
)
;
}
}


function(options) {
            // Prepare chars if needed
            if (!options.chars || (options.chars.length !== 128 && options.chars.length !== 256))
                throw new Error("Encoding '"+options.type+"' has incorrect 'chars' (must be of len 128 or 256)");

            if (options.chars.length === 128)
                options.chars = asciiString + options.chars;

            if (!options.charsBuf) {
                options.charsBuf = new Buffer(options.chars, 'ucs2');
            }

            if (!options.revCharsBuf) {
                options.revCharsBuf = new Buffer(65536);
                var defChar = iconv.defaultCharSingleByte.charCodeAt(0);
                for (var i = 0; i < options.revCharsBuf.length; i++)
                    options.revCharsBuf[i] = defChar;
                for (var i = 0; i < options.chars.length; i++)
                    options.revCharsBuf[options.chars.charCodeAt(i)] = i;
            }

            return {
                toEncoding: function(str) {
                    str = ensureString(str);

                    var buf = new Buffer(str.length);
                    var revCharsBuf = options.revCharsBuf;
                    for (var i = 0; i < str.length; i++)
                        buf[i] = revCharsBuf[str.charCodeAt(i)];

                    return buf;
                },
                fromEncoding: function(buf) {
                    buf = ensureBuffer(buf);

                    // Strings are immutable in JS -> we use ucs2 buffer to speed up computations.
                    var charsBuf = options.charsBuf;
                    var newBuf = new Buffer(buf.length*2);
                    var idx1 = 0, idx2 = 0;
                    for (var i = 0, _len = buf.length; i < _len; i++) {
                        idx1 = buf[i]*2; idx2 = i*2;
                        newBuf[idx2] = charsBuf[idx1];
                        newBuf[idx2+1] = charsBuf[idx1+1];
                    }
                    return newBuf.toString('ucs2');
                }
            };
        }


function(options) {
            var table = options.table, key, revCharsTable = options.revCharsTable;
            if (!table) {
                throw new Error("Encoding '" + options.type +"' has incorect 'table' option");
            }
            if(!revCharsTable) {
                revCharsTable = options.revCharsTable = {};
                for (key in table) {
                    revCharsTable[table[key]] = parseInt(key);
                }
            }

            return {
                toEncoding: function(str) {
                    str = ensureString(str);
                    var strLen = str.length;
                    var bufLen = strLen;
                    for (var i = 0; i < strLen; i++)
                        if (str.charCodeAt(i) >> 7)
                            bufLen++;

                    var newBuf = new Buffer(bufLen), gbkcode, unicode,
                        defaultChar = revCharsTable[iconv.defaultCharUnicode.charCodeAt(0)];

                    for (var i = 0, j = 0; i < strLen; i++) {
                        unicode = str.charCodeAt(i);
                        if (unicode >> 7) {
                            gbkcode = revCharsTable[unicode] || defaultChar;
                            newBuf[j++] = gbkcode >> 8; //high byte;
                            newBuf[j++] = gbkcode & 0xFF; //low byte
                        } else {//ascii
                            newBuf[j++] = unicode;
                        }
                    }
                    return newBuf;
                },
                fromEncoding: function(buf) {
                    buf = ensureBuffer(buf);
                    var bufLen = buf.length, strLen = 0;
                    for (var i = 0; i < bufLen; i++) {
                        strLen++;
                        if (buf[i] & 0x80) //the high bit is 1, so this byte is gbkcode's high byte.skip next byte
                            i++;
                    }
                    var newBuf = new Buffer(strLen*2), unicode, gbkcode,
                        defaultChar = iconv.defaultCharUnicode.charCodeAt(0);

                    for (var i = 0, j = 0; i < bufLen; i++, j+=2) {
                        gbkcode = buf[i];
                        if (gbkcode & 0x80) {
                            gbkcode = (gbkcode << 8) + buf[++i];
                            unicode = table[gbkcode] || defaultChar;
                        } else {
                            unicode = gbkcode;
                        }
                        newBuf[j] = unicode & 0xFF; //low byte
                        newBuf[j+1] = unicode >> 8; //high byte
                    }
                    return newBuf.toString('ucs2');
                }
            }
        }

function
(
options
)
{
var
table
=
options
.
table
,
key
,
revCharsTable
=
options
.
revCharsTable
;
if
(
!
table
)
{
throw
new
Error
(
"Encoding '"
+
options
.
type
+
"' has incorect 'table' option"
)
;
}
if
(
!
revCharsTable
)
{
revCharsTable
=
options
.
revCharsTable
=
{
}
;
for
(
key
in
table
)
{
revCharsTable
[
table
[
key
]
]
=
parseInt
(
key
)
;
}
}
return
{
toEncoding
:
function
(
str
)
{
str
=
ensureString
(
str
)
;
var
strLen
=
str
.
length
;
var
bufLen
=
strLen
;
for
(
var
i
=
0
;
i
<
strLen
;
i
++
)
if
(
str
.
charCodeAt
(
i
)
>>
7
)
bufLen
++
;
var
newBuf
=
new
Buffer
(
bufLen
)
,
gbkcode
,
unicode
,
defaultChar
=
revCharsTable
[
iconv
.
defaultCharUnicode
.
charCodeAt
(
0
)
]
;
for
(
var
i
=
0
,
j
=
0
;
i
<
strLen
;
i
++
)
{
unicode
=
str
.
charCodeAt
(
i
)
;
if
(
unicode
>>
7
)
{
gbkcode
=
revCharsTable
[
unicode
]
||
defaultChar
;
newBuf
[
j
++
]
=
gbkcode
>>
8
;
newBuf
[
j
++
]
=
gbkcode
&
0xFF
;
}
else
{
newBuf
[
j
++
]
=
unicode
;
}
}
return
newBuf
;
}
,
fromEncoding
:
function
(
buf
)
{
buf
=
ensureBuffer
(
buf
)
;
var
bufLen
=
buf
.
length
,
strLen
=
0
;
for
(
var
i
=
0
;
i
<
bufLen
;
i
++
)
{
strLen
++
;
if
(
buf
[
i
]
&
0x80
)
i
++
;
}
var
newBuf
=
new
Buffer
(
strLen
*
2
)
,
unicode
,
gbkcode
,
defaultChar
=
iconv
.
defaultCharUnicode
.
charCodeAt
(
0
)
;
for
(
var
i
=
0
,
j
=
0
;
i
<
bufLen
;
i
++
,
j
+=
2
)
{
gbkcode
=
buf
[
i
]
;
if
(
gbkcode
&
0x80
)
{
gbkcode
=
(
gbkcode
<<
8
)
+
buf
[
++
i
]
;
unicode
=
table
[
gbkcode
]
||
defaultChar
;
}
else
{
unicode
=
gbkcode
;
}
newBuf
[
j
]
=
unicode
&
0xFF
;
newBuf
[
j
+
1
]
=
unicode
>>
8
;
}
return
newBuf
.
toString
(
'ucs2'
)
;
}
}
}