function valueParserNodesLength (length, operator = '===') {
    return t.binaryExpression(
        operator,
        valueParserASTNodesLength,
        t.numericLiteral(length)
    );
}

function valueParserNodesLength ( length , operator = '===' ) { return t . binaryExpression ( operator , valueParserASTNodesLength , t . numericLiteral ( length ) ) ; }

Test that the nodes from postcss-value-parser are a certain length. This
uses strict equality by default, but you can supply an alternate operator.

@private
@param  {number} length          The length to check
@param  {type} operator = '==='  The operator to use.
@return {Babel}                  The binary expression.
@example
const equality = valueParserNodesLength(5);
//=> valueParserAST.nodes.length === 5;

const lessThan = valueParserNodesLength(5, '<');
//=> valueParserAST.nodes.length < 5;

Test that the nodes from postcss - value - parser are a certain length . This uses strict equality by default but you can supply an alternate operator .


function sliceThen(file, offset, len) {
    var p = new Promise(function(_resolve) {
      fs.open(file, 'r', function(err, fd){
        if (err) {
          throw err;
        }

        var res = new Buffer(len);
        fs.read(fd, res, 0, len, offset, function(err, bytesRead, buffer){
          if (err) {
            throw err;
          }

          _resolve(buffer);
        });
      });
    });

    /**
     * Call proc with specified arguments prepending with sliced file/blob data (ArrayBuffer) been read.
     * @param the first argument is a function to be executed
     * @param other optional arguments are passed to the function following auto supplied input ArrayBuffer
     * @return a promise object which can be chained with further process through spread() method
     */
    p.exec = function(proc /*, args... */) {
      var args = Array.prototype.slice.call(arguments, 1);
      return p.then(function(data) {
          args.unshift(data);
          var ret = proc.apply(null, args);
          return resolve(ret !== UNDEFINED && ret._spreadus_ ? ret : [ret]);
      });
    };

    return p;
  }


function harvest(outcomes) {
    return Promise.settle(outcomes).then(function(results) {
      if (results.length === 0) {
        return reject("** NOT FOUND **");
      }

      var solved = [], failed = [];
      for (var i = 0; i < results.length; i++) {
        if (results[i].isResolved()) {
          solved.push(results[i].value());
        } else {
          failed.push(results[i].reason());
        }
      }
      return solved.length ? solved : failed;
    });
  }

function
harvest
(
outcomes
)
{
return
Promise
.
settle
(
outcomes
)
.
then
(
function
(
results
)
{
if
(
results
.
length
===
0
)
{
return
reject
(
"** NOT FOUND **"
)
;
}
var
solved
=
[
]
,
failed
=
[
]
;
for
(
var
i
=
0
;
i
<
results
.
length
;
i
++
)
{
if
(
results
[
i
]
.
isResolved
(
)
)
{
solved
.
push
(
results
[
i
]
.
value
(
)
)
;
}
else
{
failed
.
push
(
results
[
i
]
.
reason
(
)
)
;
}
}
return
solved
.
length
solved
:
failed
;
}
)
;
}

Harvest any resolved promises, if all failed then return reasons.

Harvest any resolved promises if all failed then return reasons .


function(keyAt) {
                var hi = (arr.length >> 1) - 1, lo = 0, i = (lo + hi) >> 1, val = arr[(i << 1) + 1];

                if (keyAt > arr[(hi << 1) + 1] || keyAt < 0) {
                  return;
                }

                while (true) {
                  if (hi - lo <= 1) {
                    if (i < hi) {
                      return {
                        block_no:     i,
                        comp_offset:  arr[i <<= 1],
                        comp_size:    arr[i + 2] - arr[i],
                        decomp_offset:arr[i + 1],
                        decomp_size:  arr[i + 3] - arr[i + 1]
                      };
                    } else {
                      return;
                    }
                  }

                  (keyAt < val)  ? hi = i : lo = i;
                  i = (lo + hi) >> 1;
                  val = arr[(i << 1) + 1];
                }
              }

function ( keyAt ) { var hi = ( arr . length >> 1 ) - 1 , lo = 0 , i = ( lo + hi ) >> 1 , val = arr [ ( i << 1 ) + 1 ] ; if ( keyAt > arr [ ( hi << 1 ) + 1 ] || keyAt < 0 ) { return ; } while ( true ) { if ( hi - lo <= 1 ) { if ( i < hi ) { return { block_no : i , comp_offset : arr [ i <<= 1 ] , comp_size : arr [ i + 2 ] - arr [ i ] , decomp_offset : arr [ i + 1 ] , decomp_size : arr [ i + 3 ] - arr [ i + 1 ] } ; } else { return ; } } ( keyAt < val ) ? hi = i : lo = i ; i = ( lo + hi ) >> 1 ; val = arr [ ( i << 1 ) + 1 ] ; } }

Given offset of a keyword after decompression, return a record block info containing it, else undefined if not found.

Given offset of a keyword after decompression return a record block info containing it else undefined if not found .


function(len) {
          len *= _bpu;
          var read = conseq(_decoder.decode(newUint8Array(buf, offset, len)), this.forward(len + _tail));
          return read;
        }

function ( len ) { len *= _bpu ; var read = conseq ( _decoder . decode ( newUint8Array ( buf , offset , len ) ) , this . forward ( len + _tail ) ) ; return read ; }

Read data to an Uint8Array and decode it to text with specified encoding. @param len length in basic unit, need to multiply byte per unit to get length in bytes NOTE: After decoding the text, it is need to forward extra "tail" bytes according to specified encoding.

Read data to an Uint8Array and decode it to text with specified encoding .


function(len) {
          return conseq(newUint8Array(buf, offset, len), this.forward(len === UNDEFINED ? buf.length - offset : len));
        }

function ( len ) { return conseq ( newUint8Array ( buf , offset , len ) , this . forward ( len === UNDEFINED ? buf . length - offset : len ) ) ; }

Read raw data as Uint8Array from current offset with specified length in bytes


function read_header_sect(input, len) {
      var scanner = Scanner(input),
          header_str = scanner.readUTF16(len).replace(/\0$/, ''); // need to remove tailing NUL

      // parse dictionary attributes
      var doc = new DOMParser().parseFromString(header_str,'text/xml');

      var elem = doc.getElementsByTagName('Dictionary')[0];
      if (!elem) {
        elem = doc.getElementsByTagName('Library_Data')[0];
      }

      // console.log(doc.getElementsByTagName('Dictionary')[0].attributes);

      // var xml = parseXml(header_str).querySelector('Dictionary, Library_Data').attributes;

      for (var i = 0, item; i < elem.attributes.length; i++) {
        item = elem.attributes[i];
        attrs[item.nodeName] = item.nodeValue;
      }

      attrs.Encrypted = parseInt(attrs.Encrypted, 10) || 0;

      config();
      return spreadus(len + 4, input);
    }

Read header section, parse dictionary attributes and config scanner according to engine version attribute.
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#header-section
@param input sliced file (start = 4, length = len + 48), header string + header section (max length 48)
@param len lenghth of header_str
@return [remained length of header section (header_str and checksum, = len + 4), original input]

Read header section parse dictionary attributes and config scanner according to engine version attribute .


function read_keyword_summary(input, offset) {
      var scanner = Scanner(input);
      scanner.forward(offset);
      return {
        num_blocks:           scanner.readNum(),
        num_entries:          scanner.readNum(),
        key_index_decomp_len: _v2 && scanner.readNum(),  // Ver >= 2.0 only
        key_index_comp_len:   scanner.readNum(),
        key_blocks_len:       scanner.readNum(),
        chksum:               scanner.checksum_v2(),
        // extra field
        len:                  scanner.offset() - offset,  // actual length of keyword section, varying with engine version attribute
      };
    }

Read keyword summary at the begining of keyword section.
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#keyword-section
@param input sliced file, same as input passed to read_header_sect()
@param offset start position of keyword section in sliced file, equals to length of header string plus checksum.\
@return keyword_sect object

Read keyword summary at the begining of keyword section .


function read_keyword_index(input, keyword_summary) {
      var scanner = Scanner(input).readBlock(keyword_summary.key_index_comp_len, keyword_summary.key_index_decomp_len, _decryptors[1]),
          keyword_index = Array(keyword_summary.num_blocks),
          offset = 0;
      for (var i = 0, size; i < keyword_summary.num_blocks; i++) {
        keyword_index[i] = {
          num_entries: conseq(scanner.readNum(), size = scanner.readShort()),
// UNUSED, can be ignored
//          first_size:  size = scanner.readShort(),
          first_word:  conseq(scanner.readTextSized(size), size = scanner.readShort()),
// UNUSED, can be ignored
//          last_size:   size = scanner.readShort(),
          last_word:   scanner.readTextSized(size),
          comp_size:   size = scanner.readNum(),
          decomp_size: scanner.readNum(),
          // extra fields
          offset: offset,     // offset of the first byte for the target key block in mdx/mdd file
          index: i            // index of this key index, used to search previous/next block
        };
        offset += size;
      }
      return spreadus(keyword_summary, keyword_index);
    }

Read keyword index part of keyword section.
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#keyword-header-encryption
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#keyword-index
@param input sliced file, remained part of keyword section after keyword summary which can also be used to read following key blocks.
@param keyword_summary
@return [keyword_summary, array of keyword index]

Read keyword index part of keyword section .


function read_key_block(scanner, kdx) {
      var scanner = scanner.readBlock(kdx.comp_size, kdx.decomp_size);
      for (var i = 0; i < kdx.num_entries; i++) {
//        scanner.readNum(); scanner.readText();
        var kk = [scanner.readNum(), scanner.readText()];
      }
    }

Read keyword entries inside a keyword block and fill KEY_TABLE.
@param scanner scanner object to read key entries, which starts at begining of target key block
@param kdx corresponding keyword index object
NOTE: no need to read keyword block anymore, for debug only.

Read keyword entries inside a keyword block and fill KEY_TABLE .


function willScanKeyTable(slicedKeyBlock, num_entries, keyword_index, delay) {
      slicedKeyBlock.delay(delay).then(function (input) {
        var scanner = Scanner(input);
        for (var i = 0, size = keyword_index.length; i < size; i++) {
        // common.log('z',keyword_index[i]);
          read_key_block(scanner, keyword_index[i]);
        }
      });
    }

function
willScanKeyTable
(
slicedKeyBlock
,
num_entries
,
keyword_index
,
delay
)
{
slicedKeyBlock
.
delay
(
delay
)
.
then
(
function
(
input
)
{
var
scanner
=
Scanner
(
input
)
;
for
(
var
i
=
0
,
size
=
keyword_index
.
length
;
i
<
size
;
i
++
)
{
// common.log('z',keyword_index[i]);
read_key_block
(
scanner
,
keyword_index
[
i
]
)
;
}
}
)
;
}

Delay to scan key table, for debug onyl.
@param slicedKeyBlock a promise object which will resolve to an ArrayBuffer containing keyword blocks
sliced from mdx/mdd file.
@param num_entries number of keyword entries
@param keyword_index array of keyword index
@param delay time to delay for scanning key table

Delay to scan key table for debug onyl .


function read_record_summary(input, pos) {
      var scanner = Scanner(input),
          record_summary = {
            num_blocks:   scanner.readNum(),
            num_entries:  scanner.readNum(),
            index_len:    scanner.readNum(),
            blocks_len:   scanner.readNum(),
            // extra field
            len:          scanner.offset(),   // actual length of record section (excluding record block index), varying with engine version attribute
          };

      // start position of record block from head of mdx/mdd file
      record_summary.block_pos = pos + record_summary.index_len + record_summary.len;

      return record_summary;
    }

Read record summary at the begining of record section.
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#record-section
@param input sliced file, start = begining of record section, length = 32 (max length of record summary)
@param pos begining of record section
@returj record summary object

Read record summary at the begining of record section .


function read_record_block(input, record_summary) {
      var scanner = Scanner(input),
          size = record_summary.num_blocks,
          record_index = Array(size),
          p0 = record_summary.block_pos,
          p1 = 0;

      RECORD_BLOCK_TABLE.alloc(size + 1);
      for (var i = 0, rdx; i < size; i++) {
        record_index[i] = rdx = {
          comp_size:   scanner.readNum(),
          decomp_size: scanner.readNum()
        };
        RECORD_BLOCK_TABLE.put(p0, p1);
        p0 += rdx.comp_size;
        p1 += rdx.decomp_size;
      }
      RECORD_BLOCK_TABLE.put(p0, p1);
    }

function read_record_block ( input , record_summary ) { var scanner = Scanner ( input ) , size = record_summary . num_blocks , record_index = Array ( size ) , p0 = record_summary . block_pos , p1 = 0 ; RECORD_BLOCK_TABLE . alloc ( size + 1 ) ; for ( var i = 0 , rdx ; i < size ; i ++ ) { record_index [ i ] = rdx = { comp_size : scanner . readNum ( ) , decomp_size : scanner . readNum ( ) } ; RECORD_BLOCK_TABLE . put ( p0 , p1 ) ; p0 += rdx . comp_size ; p1 += rdx . decomp_size ; } RECORD_BLOCK_TABLE . put ( p0 , p1 ) ; }

Read record block index part in record section, and fill RECORD_BLOCK_TABLE
@see https://github.com/zhansliu/writemdict/blob/master/fileformat.md#record-section
@param input sliced file, start = begining of record block index, length = record_summary.index_len
@param record_summary record summary object

Read record block index part in record section and fill RECORD_BLOCK_TABLE


function read_definition(input, block, keyinfo) {
      var scanner = Scanner(input).readBlock(block.comp_size, block.decomp_size);
      scanner.forward(keyinfo.offset - block.decomp_offset);
      return scanner.readText();
    }

function read_definition ( input , block , keyinfo ) { var scanner = Scanner ( input ) . readBlock ( block . comp_size , block . decomp_size ) ; scanner . forward ( keyinfo . offset - block . decomp_offset ) ; return scanner . readText ( ) ; }

Read definition in text for given keyinfo object.
@param input record block sliced from the file
@param block record block index
@param keyinfo a object with property of record's offset and optional size for the given keyword
@return definition in text

Read definition in text for given keyinfo object .


function read_object(input, block, keyinfo) {
      if (input.byteLength > 0) {
        var scanner = Scanner(input).readBlock(block.comp_size, block.decomp_size);
        scanner.forward(keyinfo.offset - block.decomp_offset);
        return scanner.readRaw(keyinfo.size);
      } else {
        throw '* OUT OF FILE RANGE * ' + keyinfo + ' @offset=' + block.comp_offset;
      }
    }

function
read_object
(
input
,
block
,
keyinfo
)
{
if
(
input
.
byteLength
>
0
)
{
var
scanner
=
Scanner
(
input
)
.
readBlock
(
block
.
comp_size
,
block
.
decomp_size
)
;
scanner
.
forward
(
keyinfo
.
offset
block
.
decomp_offset
)
;
return
scanner
.
readRaw
(
keyinfo
.
size
)
;
}
else
{
throw
'* OUT OF FILE RANGE * '
+
keyinfo
+
' @offset='
+
block
.
comp_offset
;
}
}

Read content in ArrayBuffer for give keyinfo object
@param input record block sliced from the file
@param block record block index
@param keyinfo a object with property of record's offset and optional size for the given keyword
@return an ArrayBuffer containing resource of image/audio/css/font etc.


function findWord(keyinfo) {
      var block = RECORD_BLOCK_TABLE.find(keyinfo.offset);
      return _slice(block.comp_offset, block.comp_size)
                .exec(read_definition, block, keyinfo)
                  .spread(function (definition) { return resolve(followLink(definition, LOOKUP.mdx)); });
    }

function findWord ( keyinfo ) { var block = RECORD_BLOCK_TABLE . find ( keyinfo . offset ) ; return _slice ( block . comp_offset , block . comp_size ) . exec ( read_definition , block , keyinfo ) . spread ( function ( definition ) { return resolve ( followLink ( definition , LOOKUP . mdx ) ) ; } ) ; }

Find word definition for given keyinfo object.
@param keyinfo a object with property of record's offset and optional size for the given keyword
@return a promise object which will resolve to definition in text. Link to other keyword is followed to get actual definition.

Find word definition for given keyinfo object .


function reduce(arr, phrase) {
      var len = arr.length;
      if (len > 1) {
        len = len >> 1;
        return phrase > _adaptKey(arr[len - 1].last_word)
                  ? reduce(arr.slice(len), phrase)
                  : reduce(arr.slice(0, len), phrase);
      } else {
        return arr[0];
      }
    }

function reduce ( arr , phrase ) { var len = arr . length ; if ( len > 1 ) { len = len >> 1 ; return phrase > _adaptKey ( arr [ len - 1 ] . last_word ) ? reduce ( arr . slice ( len ) , phrase ) : reduce ( arr . slice ( 0 , len ) , phrase ) ; } else { return arr [ 0 ] ; } }

a oneway increased ticket used to cancel unfinished pattern match
Reduce the key index array to an element which contains or is the nearest one matching a given phrase.

a oneway increased ticket used to cancel unfinished pattern match Reduce the key index array to an element which contains or is the nearest one matching a given phrase .


function shrink(arr, phrase) {
      var len = arr.length, sub;
      if (len > 1) {
        len = len >> 1;
        var key = _adaptKey(arr[len]);
        if (phrase < key) {
          sub = arr.slice(0, len);
          sub.pos = arr.pos;
        } else {
          sub = arr.slice(len);
          sub.pos = (arr.pos || 0) + len;
        }
        return shrink(sub, phrase);
      } else {
        return (arr.pos || 0) + (phrase <= _adaptKey(arr[0]) ? 0 : 1);
      }
    }

function shrink ( arr , phrase ) { var len = arr . length , sub ; if ( len > 1 ) { len = len >> 1 ; var key = _adaptKey ( arr [ len ] ) ; if ( phrase < key ) { sub = arr . slice ( 0 , len ) ; sub . pos = arr . pos ; } else { sub = arr . slice ( len ) ; sub . pos = ( arr . pos || 0 ) + len ; } return shrink ( sub , phrase ) ; } else { return ( arr . pos || 0 ) + ( phrase <= _adaptKey ( arr [ 0 ] ) ? 0 : 1 ) ; } }

Reduce the array to index of an element which contains or is the nearest one matching a given phrase.

Reduce the array to index of an element which contains or is the nearest one matching a given phrase .


function seekVanguard(phrase) {
      phrase = _adaptKey(phrase);
      var kdx = reduce(KEY_INDEX, phrase);

      // look back for the first record block containing keyword for the specified phrase
      if (phrase <= _adaptKey(kdx.last_word)) {
        var index = kdx.index - 1, prev;
        while (prev = KEY_INDEX[index]) {
          if (_adaptKey(prev.last_word) !== _adaptKey(kdx.last_word)) {
            break;
          }
          kdx = prev;
          index--;
        }
      }

      return loadKeys(kdx).then(function (list) {
          var idx = shrink(list, phrase);
          // look back for the first matched keyword position
          while (idx > 0) {
            if (_adaptKey(list[--idx]) !== _adaptKey(phrase)) {
              idx++;
              break;
            }
          }
          return [kdx, Math.min(idx, list.length - 1), list];
        });
    }

Search for the first keyword match given phrase.

Search for the first keyword match given phrase .


function matchOffset(list, offset) {
      return list.some(function(el) { return el.offset === offset ? list = [el] : false; }) ? list : [];
    }

function matchOffset ( list , offset ) { return list . some ( function ( el ) { return el . offset === offset ? list = [ el ] : false ; } ) ? list : [ ] ; }

Match the first element in list with given offset.

Match the first element in list with given offset .


function isValidModifierKeyCombo(modifierKeys, e) {
        var modifierKeyNames = ['alt', 'ctrl', 'meta', 'shift'],
            numModKeys = modifierKeys.length,
            i,
            j,
            currModifierKey,
            isValid = true;

        // check that all required modifier keys were pressed
        for (i = 0; i < numModKeys; i += 1) {
            if (!e[modifierKeys[i]]) {
                isValid = false;
                break;
            }
        }

        // if the requirements were met, check for additional modifier keys
        if (isValid) {
            for (i = 0; i < modifierKeyNames.length; i += 1) {
                currModifierKey = modifierKeyNames[i] + 'Key';

                // if this key was pressed
                if (e[currModifierKey]) {
                    // if there are required keys, check whether the current key
                    // is required
                    if (numModKeys) {
                        isValid = false;

                        // if this is a required key, continue
                        for (j = 0; j < numModKeys; j += 1) {
                            if (currModifierKey === modifierKeys[j]) {
                                isValid = true;
                                break;
                            }
                        }
                    } else {
                        // no required keys, but one was pressed
                        isValid = false;
                    }
                }

                // an extra key was pressed, don't check anymore
                if (!isValid) {
                    break;
                }
            }
        }

        return isValid;
    }

Determines whether the specified modifier keys match the modifier keys
that were pressed.

@param  {string[]} modifierKeys  the modifier keys to check - ex: ['shiftKey']
@param  {Event}    e             the event object for the keydown event
@return {boolean}                whether modifierKeys are valid for the event

@method tabOverride.utils.isValidModifierKeyCombo

Determines whether the specified modifier keys match the modifier keys that were pressed .


function createKeyComboFunction(keyFunc, modifierKeys) {
        return function (keyCode, modifierKeyNames) {
            var i,
                keyCombo = '';

            if (arguments.length) {
                if (typeof keyCode === 'number') {
                    keyFunc(keyCode);

                    modifierKeys.length = 0; // clear the array

                    if (modifierKeyNames && modifierKeyNames.length) {
                        for (i = 0; i < modifierKeyNames.length; i += 1) {
                            modifierKeys.push(modifierKeyNames[i] + 'Key');
                        }
                    }
                }

                return this;
            }

            for (i = 0; i < modifierKeys.length; i += 1) {
                keyCombo += modifierKeys[i].slice(0, -3) + '+';
            }

            return keyCombo + keyFunc();
        };
    }

function
createKeyComboFunction
(
keyFunc
,
modifierKeys
)
{
return
function
(
keyCode
,
modifierKeyNames
)
{
var
i
,
keyCombo
=
''
;
if
(
arguments
.
length
)
{
if
(
typeof
keyCode
===
'number'
)
{
keyFunc
(
keyCode
)
;
modifierKeys
.
length
=
0
;
// clear the array
if
(
modifierKeyNames
&&
modifierKeyNames
.
length
)
{
for
(
i
=
0
;
i
<
modifierKeyNames
.
length
;
i
+=
1
)
{
modifierKeys
.
push
(
modifierKeyNames
[
i
]
+
'Key'
)
;
}
}
}
return
this
;
}
for
(
i
=
0
;
i
<
modifierKeys
.
length
;
i
+=
1
)
{
keyCombo
+=
modifierKeys
[
i
]
.
slice
(
0
,
3
)
+
'+'
;
}
return
keyCombo
+
keyFunc
(
)
;
}
;
}

Creates a function to get and set the specified key combination.

@param  {Function} keyFunc       getter/setter function for the key
@param  {string[]} modifierKeys  the array of modifier keys to manipulate
@return {Function}               a getter/setter function for the specified
key combination

@private

Creates a function to get and set the specified key combination .


function overrideKeyDown(e) {
        e = e || event;

        // textarea elements can only contain text nodes which don't receive
        // keydown events, so the event target/srcElement will always be the
        // textarea element, however, prefer currentTarget in order to support
        // delegated events in compliant browsers
        var target = e.currentTarget || e.srcElement, // don't use the "this" keyword (doesn't work in old IE)
            key = e.keyCode, // the key code for the key that was pressed
            tab, // the string representing a tab
            tabLen, // the length of a tab
            text, // initial text in the textarea
            range, // the IE TextRange object
            tempRange, // used to calculate selection start and end positions in IE
            preNewlines, // the number of newline character sequences before the selection start (for IE)
            selNewlines, // the number of newline character sequences within the selection (for IE)
            initScrollTop, // initial scrollTop value used to fix scrolling in Firefox
            selStart, // the selection start position
            selEnd, // the selection end position
            sel, // the selected text
            startLine, // for multi-line selections, the first character position of the first line
            endLine, // for multi-line selections, the last character position of the last line
            numTabs, // the number of tabs inserted / removed in the selection
            startTab, // if a tab was removed from the start of the first line
            preTab, // if a tab was removed before the start of the selection
            whitespace, // the whitespace at the beginning of the first selected line
            whitespaceLen, // the length of the whitespace at the beginning of the first selected line
            CHARACTER = 'character'; // string constant used for the Range.move methods

        // don't do any unnecessary work
        if ((target.nodeName && target.nodeName.toLowerCase() !== 'textarea') ||
                (key !== tabKey && key !== untabKey && (key !== 13 || !autoIndent))) {
            return;
        }

        // initialize variables used for tab and enter keys
        inWhitespace = false; // this will be set to true if enter is pressed in the leading whitespace
        text = target.value;

        // this is really just for Firefox, but will be used by all browsers that support
        // selectionStart and selectionEnd - whenever the textarea value property is reset,
        // Firefox scrolls back to the top - this is used to set it back to the original value
        // scrollTop is nonstandard, but supported by all modern browsers
        initScrollTop = target.scrollTop;

        // get the text selection
        if (typeof target.selectionStart === 'number') {
            selStart = target.selectionStart;
            selEnd = target.selectionEnd;
            sel = text.slice(selStart, selEnd);

        } else if (document.selection) { // IE
            range = document.selection.createRange();
            sel = range.text;
            tempRange = range.duplicate();
            tempRange.moveToElementText(target);
            tempRange.setEndPoint('EndToEnd', range);
            selEnd = tempRange.text.length;
            selStart = selEnd - sel.length;

            // whenever the value of the textarea is changed, the range needs to be reset
            // IE <9 (and Opera) use both \r and \n for newlines - this adds an extra character
            // that needs to be accounted for when doing position calculations with ranges
            // these values are used to offset the selection start and end positions
            if (newlineLen > 1) {
                preNewlines = text.slice(0, selStart).split(newline).length - 1;
                selNewlines = sel.split(newline).length - 1;
            } else {
                preNewlines = selNewlines = 0;
            }
        } else {
            return; // cannot access textarea selection - do nothing
        }

        // tab / untab key - insert / remove tab
        if (key === tabKey || key === untabKey) {

            // initialize tab variables
            tab = aTab;
            tabLen = tab.length;
            numTabs = 0;
            startTab = 0;
            preTab = 0;

            // multi-line selection
            if (selStart !== selEnd && sel.indexOf('\n') !== -1) {
                // for multiple lines, only insert / remove tabs from the beginning of each line

                // find the start of the first selected line
                if (selStart === 0 || text.charAt(selStart - 1) === '\n') {
                    // the selection starts at the beginning of a line
                    startLine = selStart;
                } else {
                    // the selection starts after the beginning of a line
                    // set startLine to the beginning of the first partially selected line
                    // subtract 1 from selStart in case the cursor is at the newline character,
                    // for instance, if the very end of the previous line was selected
                    // add 1 to get the next character after the newline
                    // if there is none before the selection, lastIndexOf returns -1
                    // when 1 is added to that it becomes 0 and the first character is used
                    startLine = text.lastIndexOf('\n', selStart - 1) + 1;
                }

                // find the end of the last selected line
                if (selEnd === text.length || text.charAt(selEnd) === '\n') {
                    // the selection ends at the end of a line
                    endLine = selEnd;
                } else if (text.charAt(selEnd - 1) === '\n') {
                    // the selection ends at the start of a line, but no
                    // characters are selected - don't indent this line
                    endLine = selEnd - 1;
                } else {
                    // the selection ends before the end of a line
                    // set endLine to the end of the last partially selected line
                    endLine = text.indexOf('\n', selEnd);
                    if (endLine === -1) {
                        endLine = text.length;
                    }
                }

                // tab key combo - insert tabs
                if (tabKeyComboPressed(key, e)) {

                    numTabs = 1; // for the first tab

                    // insert tabs at the beginning of each line of the selection
                    target.value = text.slice(0, startLine) + tab +
                        text.slice(startLine, endLine).replace(/\n/g, function () {
                            numTabs += 1;
                            return '\n' + tab;
                        }) + text.slice(endLine);

                    // set start and end points
                    if (range) { // IE
                        range.collapse();
                        range.moveEnd(CHARACTER, selEnd + (numTabs * tabLen) - selNewlines - preNewlines);
                        range.moveStart(CHARACTER, selStart + tabLen - preNewlines);
                        range.select();
                    } else {
                        // the selection start is always moved by 1 character
                        target.selectionStart = selStart + tabLen;
                        // move the selection end over by the total number of tabs inserted
                        target.selectionEnd = selEnd + (numTabs * tabLen);
                        target.scrollTop = initScrollTop;
                    }
                } else if (untabKeyComboPressed(key, e)) {
                    // if the untab key combo was pressed, remove tabs instead of inserting them

                    if (text.slice(startLine).indexOf(tab) === 0) {
                        // is this tab part of the selection?
                        if (startLine === selStart) {
                            // it is, remove it
                            sel = sel.slice(tabLen);
                        } else {
                            // the tab comes before the selection
                            preTab = tabLen;
                        }
                        startTab = tabLen;
                    }

                    target.value = text.slice(0, startLine) + text.slice(startLine + preTab, selStart) +
                        sel.replace(new RegExp('\n' + tab, 'g'), function () {
                            numTabs += 1;
                            return '\n';
                        }) + text.slice(selEnd);

                    // set start and end points
                    if (range) { // IE
                        // setting end first makes calculations easier
                        range.collapse();
                        range.moveEnd(CHARACTER, selEnd - startTab - (numTabs * tabLen) - selNewlines - preNewlines);
                        range.moveStart(CHARACTER, selStart - preTab - preNewlines);
                        range.select();
                    } else {
                        // set start first for Opera
                        target.selectionStart = selStart - preTab; // preTab is 0 or tabLen
                        // move the selection end over by the total number of tabs removed
                        target.selectionEnd = selEnd - startTab - (numTabs * tabLen);
                    }
                } else {
                    return; // do nothing for invalid key combinations
                }

            } else { // single line selection

                // tab key combo - insert a tab
                if (tabKeyComboPressed(key, e)) {
                    if (range) { // IE
                        range.text = tab;
                        range.select();
                    } else {
                        target.value = text.slice(0, selStart) + tab + text.slice(selEnd);
                        target.selectionEnd = target.selectionStart = selStart + tabLen;
                        target.scrollTop = initScrollTop;
                    }
                } else if (untabKeyComboPressed(key, e)) {
                    // if the untab key combo was pressed, remove a tab instead of inserting one

                    // if the character before the selection is a tab, remove it
                    if (text.slice(selStart - tabLen).indexOf(tab) === 0) {
                        target.value = text.slice(0, selStart - tabLen) + text.slice(selStart);

                        // set start and end points
                        if (range) { // IE
                            // collapses range and moves it by -1 tab
                            range.move(CHARACTER, selStart - tabLen - preNewlines);
                            range.select();
                        } else {
                            target.selectionEnd = target.selectionStart = selStart - tabLen;
                            target.scrollTop = initScrollTop;
                        }
                    }
                } else {
                    return; // do nothing for invalid key combinations
                }
            }
        } else if (autoIndent) { // Enter key
            // insert a newline and copy the whitespace from the beginning of the line

            // find the start of the first selected line
            if (selStart === 0 || text.charAt(selStart - 1) === '\n') {
                // the selection starts at the beginning of a line
                // do nothing special
                inWhitespace = true;
                return;
            }

            // see explanation under "multi-line selection" above
            startLine = text.lastIndexOf('\n', selStart - 1) + 1;

            // find the end of the first selected line
            endLine = text.indexOf('\n', selStart);

            // if no newline is found, set endLine to the end of the text
            if (endLine === -1) {
                endLine = text.length;
            }

            // get the whitespace at the beginning of the first selected line (spaces and tabs only)
            whitespace = text.slice(startLine, endLine).match(/^[ \t]*/)[0];
            whitespaceLen = whitespace.length;

            // the cursor (selStart) is in the whitespace at beginning of the line
            // do nothing special
            if (selStart < startLine + whitespaceLen) {
                inWhitespace = true;
                return;
            }

            if (range) { // IE
                // insert the newline and whitespace
                range.text = '\n' + whitespace;
                range.select();
            } else {
                // insert the newline and whitespace
                target.value = text.slice(0, selStart) + '\n' + whitespace + text.slice(selEnd);
                // Opera uses \r\n for a newline, instead of \n,
                // so use newlineLen instead of a hard-coded value
                target.selectionEnd = target.selectionStart = selStart + newlineLen + whitespaceLen;
                target.scrollTop = initScrollTop;
            }
        }

        if (e.preventDefault) {
            e.preventDefault();
        } else {
            e.returnValue = false;
            return false;
        }
    }

// delegated events in compliant browsers

// tab / untab key - insert / remove tab

// find the end of the last selected line

// do nothing for invalid key combinations

// collapses range and moves it by -1 tab

// find the end of the first selected line

Event handler to insert or remove tabs and newlines on the keydown event
for the tab or enter key.

@param {Event} e  the event object

@method tabOverride.handlers.keydown

Event handler to insert or remove tabs and newlines on the keydown event for the tab or enter key .


function overrideKeyPress(e) {
        e = e || event;

        var key = e.keyCode;

        if (tabKeyComboPressed(key, e) || untabKeyComboPressed(key, e) ||
                (key === 13 && autoIndent && !inWhitespace)) {

            if (e.preventDefault) {
                e.preventDefault();
            } else {
                e.returnValue = false;
                return false;
            }
        }
    }

function overrideKeyPress ( e ) { e = e || event ; var key = e . keyCode ; if ( tabKeyComboPressed ( key , e ) || untabKeyComboPressed ( key , e ) || ( key === 13 && autoIndent && ! inWhitespace ) ) { if ( e . preventDefault ) { e . preventDefault ( ) ; } else { e . returnValue = false ; return false ; } } }

Event handler to prevent the default action for the keypress event when
tab or enter is pressed. Opera and Firefox also fire a keypress event
when the tab or enter key is pressed. Opera requires that the default
action be prevented on this event or the textarea will lose focus.

@param {Event} e  the event object

@method tabOverride.handlers.keypress

Event handler to prevent the default action for the keypress event when tab or enter is pressed . Opera and Firefox also fire a keypress event when the tab or enter key is pressed . Opera requires that the default action be prevented on this event or the textarea will lose focus .


function executeExtensions(hook, args) {
        var i,
            extensions = hooks[hook] || [],
            len = extensions.length;

        for (i = 0; i < len; i += 1) {
            extensions[i].apply(null, args);
        }
    }

function executeExtensions ( hook , args ) { var i , extensions = hooks [ hook ] || [ ] , len = extensions . length ; for ( i = 0 ; i < len ; i += 1 ) { extensions [ i ] . apply ( null , args ) ; } }

Executes all registered extension functions for the specified hook.

@param {string} hook    the name of the hook for which the extensions are registered
@param {Array}  [args]  the arguments to pass to the extension

@method tabOverride.utils.executeExtensions

Executes all registered extension functions for the specified hook .


function(imapMessage) {
    var deferred = Q.defer();
    var message = new Message();

    imapMessage.on('body', function(stream, info) {
        var buffer = '';

        stream.on('data', function(chunk) {
            buffer += chunk.toString('utf8');
        });

        stream.on('end', function() {
            if (info.which === 'TEXT') {
                message.body = buffer;
            } else {
                message.headers = Imap.parseHeader(buffer);
            }
        });
    });

    imapMessage.on('attributes', function(attrs) {
        message.attributes = attrs;
    });

    imapMessage.on('end', function() {
        deferred.resolve(message);
    });

    return deferred.promise;
}

function ( imapMessage ) { var deferred = Q . defer ( ) ; var message = new Message ( ) ; imapMessage . on ( 'body' , function ( stream , info ) { var buffer = '' ; stream . on ( 'data' , function ( chunk ) { buffer += chunk . toString ( 'utf8' ) ; } ) ; stream . on ( 'end' , function ( ) { if ( info . which === 'TEXT' ) { message . body = buffer ; } else { message . headers = Imap . parseHeader ( buffer ) ; } } ) ; } ) ; imapMessage . on ( 'attributes' , function ( attrs ) { message . attributes = attrs ; } ) ; imapMessage . on ( 'end' , function ( ) { deferred . resolve ( message ) ; } ) ; return deferred . promise ; }

Helper function that asynchronously converts ImapMessage instance
to instance of Message class.

@param  {ImapMessage} imapMessage    Instance of ImapMessage class obtained from Imap server call
@return {Promise}                    Promise resolved with instance of Message class

Helper function that asynchronously converts ImapMessage instance to instance of Message class .


function GPT( options ) {

  if( !(this instanceof GPT) ) {
    return new GPT( options )
  }

  options = options != null ? options : {}

  /** @type {Number} Storage device's block size in bytes */
  this.blockSize = options.blockSize || 512

  /** @type {String} GUID of the GUID Partition Table */
  this.guid = options.guid || GPT.GUID.ZERO
  /** @type {Number} GPT format revision (?) */
  this.revision = options.revision || 0
  /** @type {Number} Size of the GPT header in bytes */
  this.headerSize = options.headerSize || GPT.HEADER_SIZE
  /** @type {Number} GPT header's CRC32 checksum */
  this.headerChecksum = 0

  /** @type {Number} Logical block address of *this* GPT */
  this.currentLBA = options.currentLBA || 1
  /** @type {Number} Logical block address of the secondary GPT */
  this.backupLBA = options.backupLBA || 0
  /** @type {Number} Address of the first user-space usable logical block */
  this.firstLBA = options.firstLBA || 34
  /** @type {Number} Address of the last user-space usable logical block */
  this.lastLBA = options.lastLBA || 0

  /** @type {Number} LBA of partition table */
  this.tableOffset = options.tableOffset || GPT.TABLE_OFFSET
  /** @type {Number} Number of partition table entries */
  this.entries = options.entries || GPT.TABLE_ENTRIES
  /** @type {Number} Partition entry's size in bytes */
  this.entrySize = options.entrySize || GPT.TABLE_ENTRY_SIZE
  /** @type {Number} Partition table's CRC32 checksum */
  this.tableChecksum = 0

  // Array of partition entries
  this.partitions = []

}

GUID Partition Table
@constructor
@param {Object} [options]
@param {Number} [options.blockSize=512]
@returns {GPT}


function readBackupGPT(primaryGPT) {

  var backupGPT = new GPT({ blockSize: primaryGPT.blockSize })
  var buffer = Buffer.alloc( 33 * primaryGPT.blockSize )
  var offset = ( ( primaryGPT.backupLBA - 32 ) * blockSize )

  fs.readSync( fd, buffer, 0, buffer.length, offset )
  backupGPT.parseBackup( buffer )

  return backupGPT

}

function readBackupGPT ( primaryGPT ) { var backupGPT = new GPT ( { blockSize : primaryGPT . blockSize } ) var buffer = Buffer . alloc ( 33 * primaryGPT . blockSize ) var offset = ( ( primaryGPT . backupLBA - 32 ) * blockSize ) fs . readSync ( fd , buffer , 0 , buffer . length , offset ) backupGPT . parseBackup ( buffer ) return backupGPT }


function stopcock(fn, options) {
  options = Object.assign(
    {
      queueSize: Math.pow(2, 32) - 1,
      bucketSize: 40,
      interval: 1000,
      limit: 2
    },
    options
  );

  const bucket = new TokenBucket(options);
  const queue = [];
  let timer = null;

  function shift() {
    clearTimeout(timer);
    while (queue.length) {
      const delay = bucket.consume();

      if (delay > 0) {
        timer = setTimeout(shift, delay);
        break;
      }

      const data = queue.shift();
      data[2](fn.apply(data[0], data[1]));
    }
  }

  function limiter() {
    const args = arguments;

    return new Promise((resolve, reject) => {
      if (queue.length === options.queueSize) {
        return reject(new Error('Queue is full'));
      }

      queue.push([this, args, resolve]);
      shift();
    });
  }

  Object.defineProperty(limiter, 'size', { get: () => queue.length });

  return limiter;
}

function
stopcock
(
fn
,
options
)
{
options
=
Object
.
assign
(
{
queueSize
:
Math
.
pow
(
2
,
32
)
1
,
bucketSize
:
40
,
interval
:
1000
,
limit
:
2
}
,
options
)
;
const
bucket
=
new
TokenBucket
(
options
)
;
const
queue
=
[
]
;
let
timer
=
;
function
shift
(
)
{
clearTimeout
(
timer
)
;
while
(
queue
.
length
)
{
const
delay
=
bucket
.
consume
(
)
;
if
(
delay
>
0
)
{
timer
=
setTimeout
(
shift
,
delay
)
;
break
;
}
const
data
=
queue
.
shift
(
)
;
data
[
2
]
(
fn
.
apply
(
data
[
0
]
,
data
[
1
]
)
)
;
}
}
function
limiter
(
)
{
const
args
=
arguments
;
return
new
Promise
(
(
resolve
,
reject
)
=>
{
if
(
queue
.
length
===
options
.
queueSize
)
{
return
reject
(
new
Error
(
'Queue is full'
)
)
;
}
queue
.
push
(
[
this
,
args
,
resolve
]
)
;
shift
(
)
;
}
)
;
}
Object
.
defineProperty
(
limiter
,
'size'
,
{
get
:
(
)
=>
queue
.
length
}
)
;
return
limiter
;
}

Limit the execution rate of a function using a leaky bucket algorithm.

@param {Function} fn The function to rate limit calls to
@param {Object} options Options object
@param {Number} options.limit The number of allowed calls per `interval`
@param {Number} options.interval The timespan where `limit` is calculated
@param {Number} options.queueSize The maximum size of the queue
@param {Number} options.bucketSize The capacity of the bucket
@return {Function}
@public

Limit the execution rate of a function using a leaky bucket algorithm .


function formatQuantity(value, encode, pad) {
  if (['string', 'number', 'object'].indexOf(typeof value) === -1 || value === null) {
    return value;
  }

  const numberValue = numberToBN(value);
  const numPadding = numberValue.lt(ten) && pad === true && !numberValue.isZero() ? '0' : '';

  if (numberToBN(value).isNeg()) { throw new Error(`[ethjs-format] while formatting quantity '${numberValue.toString(10)}', invalid negative number. Number must be positive or zero.`); }

  return encode ? `0x${numPadding}${numberValue.toString(16)}` : numberValue;
}

function formatQuantity ( value , encode , pad ) { if ( [ 'string' , 'number' , 'object' ] . indexOf ( typeof value ) === - 1 || value === null ) { return value ; } const numberValue = numberToBN ( value ) ; const numPadding = numberValue . lt ( ten ) && pad === true && ! numberValue . isZero ( ) ? '0' : '' ; if ( numberToBN ( value ) . isNeg ( ) ) { throw new Error ( ` ${ numberValue . toString ( 10 ) } ` ) ; } return encode ? ` ${ numPadding } ${ numberValue . toString ( 16 ) } ` : numberValue ; }

Format quantity values, either encode to hex or decode to BigNumber
should intake null, stringNumber, number, BN

@method formatQuantity
@param {String|BigNumber|Number} value quantity or tag to convert
@param {Boolean} encode to hex or decode to BigNumber
@returns {Optional} output to BigNumber or string
@throws error if value is a float

Format quantity values either encode to hex or decode to BigNumber should intake null stringNumber number BN


function formatQuantityOrTag(value, encode) {
  var output = value; // eslint-disable-line

  // if the value is a tag, bypass
  if (schema.tags.indexOf(value) === -1) {
    output = formatQuantity(value, encode);
  }

  return output;
}

function
formatQuantityOrTag
(
value
,
encode
)
{
var
output
=
value
;
// eslint-disable-line
// if the value is a tag, bypass
if
(
schema
.
tags
.
indexOf
(
value
)
===
1
)
{
output
=
formatQuantity
(
value
,
encode
)
;
}
return
output
;
}

Format quantity or tag, if tag bypass return, else format quantity
should intake null, stringNumber, number, BN, string tag

@method formatQuantityOrTag
@param {String|BigNumber|Number} value quantity or tag to convert
@param {Boolean} encode encode the number to hex or decode to BigNumber
@returns {Object|String} output to BigNumber or string
@throws error if value is a float

Format quantity or tag if tag bypass return else format quantity should intake null stringNumber number BN string tag


function formatData(value, byteLength) {
  var output = value; // eslint-disable-line
  var outputByteLength = 0; // eslint-disable-line

  // prefix only under strict conditions, else bypass
  if (typeof value === 'string') {
    output = `0x${padToEven(stripHexPrefix(value))}`;
    outputByteLength = getBinarySize(output);
  }

  // format double padded zeros.
  if (output === '0x00') { output = '0x0'; }

  // throw if bytelength is not correct
  if (typeof byteLength === 'number' && value !== null && output !== '0x' && output !== '0x0' // support empty values
    && (!/^[0-9A-Fa-f]+$/.test(stripHexPrefix(output)) || outputByteLength !== 2 + byteLength * 2)) {
    throw new Error(`[ethjs-format] hex string '${output}' must be an alphanumeric ${2 + byteLength * 2} utf8 byte hex (chars: a-fA-F) string, is ${outputByteLength} bytes`);
  }

  return output;
}

FormatData under strict conditions hex prefix

@method formatData
@param {String} value the bytes data to be formatted
@param {Number} byteLength the required byte length (usually 20 or 32)
@returns {String} output output formatted data
@throws error if minimum length isnt met


function formatObject(formatter, value, encode) {
  var output = Object.assign({}, value); // eslint-disable-line
  var formatObject = null; // eslint-disable-line

  // if the object is a string flag, then retreive the object
  if (typeof formatter === 'string') {
    if (formatter === 'Boolean|EthSyncing') {
      formatObject = Object.assign({}, schema.objects.EthSyncing);
    } else if (formatter === 'DATA|Transaction') {
      formatObject = Object.assign({}, schema.objects.Transaction);
    } else {
      formatObject = Object.assign({}, schema.objects[formatter]);
    }
  }

  // check if all required data keys are fulfilled
  if (!arrayContainsArray(Object.keys(value), formatObject.__required)) { // eslint-disable-line
    throw new Error(`[ethjs-format] object ${JSON.stringify(value)} must contain properties: ${formatObject.__required.join(', ')}`); // eslint-disable-line
  }

  // assume formatObject is an object, go through keys and format each
  Object.keys(formatObject).forEach((valueKey) => {
    if (valueKey !== '__required' && typeof value[valueKey] !== 'undefined') {
      output[valueKey] = format(formatObject[valueKey], value[valueKey], encode);
    }
  });

  return output;
}

Format object, even with random RPC caviets

@method formatObject
@param {String|Array} formatter the unit to convert to, default ether
@param {Object} value the object value
@param {Boolean} encode encode to hex or decode to BigNumber
@returns {Object} output object
@throws error if value is a float

Format object even with random RPC caviets


function format(formatter, value, encode, lengthRequirement) {
  var output = value; // eslint-disable-line

  // if formatter is quantity or quantity or tag
  if (formatter === 'Q') {
    output = formatQuantity(value, encode);
  } else if (formatter === 'QP') {
    output = formatQuantity(value, encode, true);
  } else if (formatter === 'Q|T') {
    output = formatQuantityOrTag(value, encode);
  } else if (formatter === 'D') {
    output = formatData(value); // dont format data flagged objects like compiler output
  } else if (formatter === 'D20') {
    output = formatData(value, 20); // dont format data flagged objects like compiler output
  } else if (formatter === 'D32') {
    output = formatData(value, 32); // dont format data flagged objects like compiler output
  } else {
    // if value is an object or array
    if (typeof value === 'object'
      && value !== null
      && Array.isArray(value) === false) {
      output = formatObject(formatter, value, encode);
    } else if (Array.isArray(value)) {
      output = formatArray(formatter, value, encode, lengthRequirement);
    }
  }

  return output;
}

Format various kinds of data to RPC spec or into digestable JS objects

@method format
@param {String|Array} formatter the data formatter
@param {String|Array|Object|Null|Number} value the data value input
@param {Boolean} encode encode to hex or decode to BigNumbers, Strings, Booleans, Null
@param {Number} lengthRequirement the minimum data length requirement
@throws error if minimum length isnt met


function formatInputs(method, inputs) {
  return format(schema.methods[method][0], inputs, true, schema.methods[method][2]);
}

function formatInputs ( method , inputs ) { return format ( schema . methods [ method ] [ 0 ] , inputs , true , schema . methods [ method ] [ 2 ] ) ; }

Format RPC inputs generally to the node or TestRPC

@method formatInputs
@param {Object} method the data formatter
@param {Array} inputs the data inputs
@returns {Array} output the formatted inputs array
@throws error if minimum length isnt met


function (files) {
        if (!_.isArray(files)) {
            throw new Error('Arguments to config-helper.mergeConfig should be an array');
        }

        var appConfig = {};
        files.forEach(function (filePath) {
            if (gruntFile.exists(filePath)) {
                var fileConfig = gruntFile.readYAML(filePath);
                // Use lodash to do a 'deep merge' which only overwrites the properties
                // specified in previous config files, without wiping out their child properties.
                _.merge(appConfig, fileConfig);
            }
        });

        return appConfig;
    }

Returns a merged set of yaml files
@param {array} files - array of file paths to merge together into one object.
@return {object} Merged javascript object containing converted data from the merged yaml files


function parseProperties(node) {
    consume(); // '('

    while(true) {
      clear();
      /**
       * Properties always have to start with '.' or ':'
       * o(.x, :y) matches an object with at least an owned property
       * 'x' and a owned or inherited property 'y'.
       */
      if(peek() === '.') {
        parseProperty(node,false);  // own property
      } else if(peek() === ':') {
        parseProperty(node,true);   // prototype property
      } else {
        unexpectedTokenException('. or :');
      }
      clear();

      if(peek() !== ',') {
        break;
      }
      consume(); // ','
    }
  }

Parse the property list of an object pattern.

Parse the property list of an object pattern .


function extractStringLiteral() {
    var literal = [], enclosing = next();

    if(!(enclosing === '"' || enclosing === "'")) {
      throw "Unexpected token at index " + index +
        " expected 'string' but found " + enclosing;
    }

    while(hasNext() && peek() !== enclosing) {
      literal[literal.length] = next();
    }

    consume(); // ' or "
    return literal.join('');
  }

function
extractStringLiteral
(
)
{
var
literal
=
[
]
,
enclosing
=
next
(
)
;
if
(
!
(
enclosing
===
'"'
||
enclosing
===
"'"
)
)
{
throw
"Unexpected token at index "
+
index
+
" expected 'string' but found "
+
enclosing
;
}
while
(
hasNext
(
)
&&
peek
(
)
!==
enclosing
)
{
literal
[
literal
.
length
]
=
next
(
)
;
}
consume
(
)
;
// ' or "
return
literal
.
join
(
''
)
;
}


function parseStringLiteral(AST) {
    if(peek() === '/') {
      newNode(extractRegex(), newNode('r=', AST).nodes);
    } else {
      newNode(extractStringLiteral(), newNode('=', AST).nodes);
    }
  }

function parseStringLiteral ( AST ) { if ( peek ( ) === '/' ) { newNode ( extractRegex ( ) , newNode ( 'r=' , AST ) . nodes ) ; } else { newNode ( extractStringLiteral ( ) , newNode ( '=' , AST ) . nodes ) ; } }

A string literal list may contain strings or regular expressions.

A string literal list may contain strings or regular expressions .


function parseNumericLiteral(AST) {
    var literal = [], value;

    while(hasNext() && validNum(peek())) {
      literal[literal.length] = next();
    }

    value = parseFloat(literal.join(''));

    /**
     * Thanks to CMS's answer on StackOverflow:
     * http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
     */
    if(!isNaN(value) && isFinite(value)) {
      newNode(value, newNode('=', AST).nodes);
    } else {
        unexpectedTokenException('numeric');
    }
  }

Parse numeric literals like 1, 1.05, .05, 8e5...


function stage1(AST) {
    if(hasNext()) {
      switch (peek()) {
        case 'a':
          parseArray(AST);
          break;
        case 'o':
          parseObject(AST);
          break;
        default:
          if (/[nsSbfdr_]/.test(peek())) {
            parseGeneric(AST,peek());
          } else {
            unexpectedTokenException('one of (a,o,n,s,S,b,f,d,r,_)');
          }
      }
    }
    return AST;
  }

function
stage1
(
AST
)
{
if
(
hasNext
(
)
)
{
switch
(
peek
(
)
)
{
case
'a'
:
parseArray
(
AST
)
;
break
;
case
'o'
:
parseObject
(
AST
)
;
break
;
default
:
if
(
/
[nsSbfdr_]
/
.
test
(
peek
(
)
)
)
{
parseGeneric
(
AST
,
peek
(
)
)
;
}
else
{
unexpectedTokenException
(
'one of (a,o,n,s,S,b,f,d,r,_)'
)
;
}
}
}
return
AST
;
}


function curry(fun, args) {
    return function (x) {
      return fun.apply(bindingContext, args.concat([x]));
    };
  }

function curry ( fun , args ) { return function ( x ) { return fun . apply ( bindingContext , args . concat ( [ x ] ) ) ; } ; }

curry takes a function, and a partial list of arguments and returns
a function that can be executed with the rest of the arguments.

--> var max = curry(Math.max, [2,5]);
--> max(4);
--> 5

curry takes a function and a partial list of arguments and returns a function that can be executed with the rest of the arguments .


function matchArray(m,a) {
    var from = 0, rest = false, restBindingResult, index, matcher, item,
    matchResult, restOfArray = [], i, result = {
      result: false,
      param: a
    };

    // If this isn't an array then it can't match
    if (!is(a, '[object Array]')) {
      return result;
    }

    // If there are more matchers than array elements it also can't match unless the
    // last matcher is a rest matcher
    if (m.length > a.length && !m[m.length - 1].name) {
      return result;
    }

    /**
     * If there are no predicates at all, this matches because it is
     * already ensured that argument a is an array.
     */
    if(m.length === 0) {
      result.result = true;
      return result;
    }

    for(index=0;index<a.length;index++) {
      matcher = m[index];
      item = a[index];

      if(!matcher) {
        return result;
      }

      matchResult = matcher(item);
      if(!matchResult.result) {
        return result;
      }

      /**
       * If the rest of an array is matched, the predicate will
       * return an object that has a'rest' parameter. We can't
       * recognize the rest predicate by it's function name, because
       * it might be hidden behind a 'bind' call.
       */
      if(matchResult.rest) {
        restBindingResult = matchResult;
        from = index;
        rest = true;
        break;
      }
    }

    if(rest && restBindingResult.this_binding) {
      for(i = from; i < a.length; i++) {
        restOfArray[restOfArray.length] = a[i];
      }
      bindingContext[restBindingResult.this_binding] = restOfArray;
    }

    result.result = true;
    return result;
  }

m is an array of predicates, a is the array to match

m is an array of predicates a is the array to match


function compileNode(ast) {
    var result = [], index, node, matcher;

    for(index=0;index<ast.length;index++) {
      node = ast[index];

      switch(node.type) {
        case 'a':
          matcher = curry(matchArray, [compileNode(node.nodes)]);
          break;
        case 'o':
          matcher = curry(matchObject, [compileNode(node.nodes)]);
          break;
        case '.':
          matcher = curry(hasProperty, [compileNode(node.nodes), node.name ]);
          break;
        case ':':
          matcher = curry(hasPrototypeProperty, [compileNode(node.nodes), node.name ]);
          break;
        case '=':
          matcher = curry(equals, [node.nodes[0].type]);
          break;
        case 'd=':
          matcher = curry(equalsDate, [node.nodes[0].type]);
          break;
        case 'r=':
          matcher = curry(matchesRegex, [node.nodes[0].type]);
          break;
        case '||':
          matcher = curry(or, [compileNode(node.nodes)]);
          break;
        case 'n':
          matcher = curry(matchType, ['number']);
          break;
        case 's':
          matcher = curry(matchType, ['string']);
          break;
        case 'S':
          matcher = matchNonBlankString;
          break;
        case 'b':
          matcher = curry(matchType, ['boolean']);
          break;
        case 'f':
          matcher = curry(matchType, ['function']);
          break;
        case '_':
          matcher = any;
          break;
        case '|':
          matcher = rest;
          break;
        case '()':
          matcher = matchEmptyArray;
          break;
        case 'd':
          matcher = curry(matchInstanceOf, ['[object Date]']);
          break;
        case 'r':
          matcher = curry(matchInstanceOf, ['[object RegExp]']);
          break;
        default:
          throw "Unknown AST entity: " + node.type;
      }

      // Bind requested. Wrap the matcher function with a call to bind.
      if (node.binding) {
        matcher = curry(bind, [node.binding, matcher]);
      }

      result[result.length] = matcher;
    }
    return result;
  }


function getName(tag) {
	return tag.name ? tag.name.value.toLowerCase() : `#${tag.type}`;
}

function getName ( tag ) { return tag . name ? tag . name . value . toLowerCase ( ) : ` ${ tag . type } ` ; }

Returns name of given matched token
@param  {Token} tag
@return {String}


function eatAttributeValue(stream) {
	const start = stream.pos;
	if (eatQuoted(stream)) {
		// Should return token that points to unquoted value.
		// Use stream readers’ public API to traverse instead of direct
		// manipulation
		const current = stream.pos;
		let valueStart, valueEnd;

		stream.pos = start;
		stream.next();
		valueStart = stream.start = stream.pos;

		stream.pos = current;
		stream.backUp(1);
		valueEnd = stream.pos;

		const result = token(stream, valueStart, valueEnd);
		stream.pos = current;
		return result;
	}

	return eatPaired(stream) || eatUnquoted(stream);
}

Consumes attribute value from given location
@param  {StreamReader} stream
@return {Token}


function isUnquoted(code) {
	return !isNaN(code) && !isQuote(code) && !isSpace(code) && !isTerminator(code);
}

function isUnquoted ( code ) { return ! isNaN ( code ) && ! isQuote ( code ) && ! isSpace ( code ) && ! isTerminator ( code ) ; }

Check if given character code is valid unquoted value
@param  {Number}  code
@return {Boolean}


function setDefault(obj, key, val) {
  if (_.isUndefined(obj[key])) {
    obj[key] = val;
    return val;
  }
  return obj[key];
}

function setDefault ( obj , key , val ) { if ( _ . isUndefined ( obj [ key ] ) ) { obj [ key ] = val ; return val ; } return obj [ key ] ; }

If given key is set in the object it returns the associated value, otherwise it sets the value to val and returns it.

If given key is set in the object it returns the associated value otherwise it sets the value to val and returns it .


function getXml(path, finish) {
  fs.readFile(path, function(err, data) {
      if (err) throw err;
      xmlParser.parseString(data, function (err, result) {
        if (err) throw err;
        finish(result);
      });
  });
}

function getXml ( path , finish ) { fs . readFile ( path , function ( err , data ) { if ( err ) throw err ; xmlParser . parseString ( data , function ( err , result ) { if ( err ) throw err ; finish ( result ) ; } ) ; } ) ; }

Read and Parse XML file from given path, pass result to finish Any error that occurs is simpy thrown.

Read and Parse XML file from given path pass result to finish Any error that occurs is simpy thrown .


function appendUISource(client){
    angoose.getLogger('angoose').debug("Appending angoose-ui sources");
//    client.source += " \n;console.log('####################----------- angoose-ui -----------##############');\n";
    var output="";
    output += readFile(path.resolve(__dirname, 'angular-modules.js'));
    output += concatFilesInDirectory(['services',  'controllers', 'directives', 'filters']); //'directives',
    output +=  concatTemplates();
    client.source+="\n\n" + output;
}

append angoose-ui sources @todo: call grunt task api to concat/minify the source & templates


function error(msg, addHint) {
	console.log('\x1b[31m');
	console.log('The compiler has stopped on an error')
	console.log(`\x1b[1;31mError: ${msg}\x1b[0m`);

	if (addHint)
		console.log(`\nPlease use -h to show the usage`);

	process.exit(1);
}

function
error
(
msg
,
addHint
)
{
console
.
log
(
'\x1b[31m'
)
;
console
.
log
(
'The compiler has stopped on an error'
)
console
.
log
(
`
\x1b
${
msg
}
\x1b
`
)
;
if
(
addHint
)
console
.
log
(
`
\n
`
)
;
process
.
exit
(
1
)
;
}


function compile(modelName, schema, dependencies) {
        logger.trace("Compiling schema ", modelName)
        var model = function AngooseModule(data) {
            //@todo proper clone
            for (var i in data) {
                this[i] = data[i];
            }
        };

        model.toString = function() {
            return "PROXY: function " + modelName + "()";
        }
        // static methods
        for (var name in schema.statics) {
            model[name] = createProxy(model, name, schema.statics[name], 'static');
        }
        for (var name in schema.methods) {
            model.prototype[name] = createProxy(model, name, schema.methods[name], 'instance');
        }

        //model.angoose$ = staticInvoker;
        model.dependencies$ = dependencies;
        model.schema = schema;
        //model.prototype.angoose$ = instanceInvoker;
        //model.prototype.classname$ = modelName;
        //model.prototype.schema$ = schema;
        model.prototype.get = getter;
        model.prototype.set = setter;
        model.modelName = modelName; // this is to be compatible with backend mongoose
        model.name = modelName;

        // merge data into this instance
        model.prototype.mergeData = function(source) {
            if ( typeof source != "object")
                throw "Invalid source object, must be an model instance";
            //@todo: proper implementation
            for (var i in source) {
                this[i] = source[i];
            }
        }
        AngooseClient.models = AngooseClient.models || {};
        AngooseClient.models[modelName] = model;
        return model;
    }

compile the model based on the server side schema


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'
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
}

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;
  }

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;
    // }
}

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);

    }
}

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
,
// 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'
)
}

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'
)
;
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
++
;
}

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();
          }
        }
      }),
  }));
}

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 }),
        },
      ];
    });
  }

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.