function parse_status_block(block) {
    var match;

    var parsed = {};
    if ((match = block.match(/bssid=([A-Fa-f0-9:]{17})/))) {
        parsed.bssid = match[1].toLowerCase();
    }

    if ((match = block.match(/freq=([0-9]+)/))) {
        parsed.frequency = parseInt(match[1], 10);
    }

    if ((match = block.match(/mode=([^\s]+)/))) {
        parsed.mode = match[1];
    }

    if ((match = block.match(/key_mgmt=([^\s]+)/))) {
        parsed.key_mgmt = match[1].toLowerCase();
    }

    if ((match = block.match(/[^b]ssid=([^\n]+)/))) {
        parsed.ssid = match[1];
    }

    if ((match = block.match(/[^b]pairwise_cipher=([^\n]+)/))) {
        parsed.pairwise_cipher = match[1];
    }

    if ((match = block.match(/[^b]group_cipher=([^\n]+)/))) {
        parsed.group_cipher = match[1];
    }

    if ((match =  block.match(/p2p_device_address=([A-Fa-f0-9:]{17})/))) {
        parsed.p2p_device_address = match[1];
    }

    if ((match = block.match(/wpa_state=([^\s]+)/))) {
        parsed.wpa_state = match[1];
    }

    if ((match = block.match(/ip_address=([^\n]+)/))) {
        parsed.ip = match[1];
    }

    if ((match = block.match(/[^_]address=([A-Fa-f0-9:]{17})/))) {
        parsed.mac = match[1].toLowerCase();
    }

    if ((match = block.match(/uuid=([^\n]+)/))) {
        parsed.uuid = match[1];
    }

    if ((match = block.match(/[^s]id=([0-9]+)/))) {
        parsed.id = parseInt(match[1], 10);
    }

    return parsed;
}

function parse_status_block ( block ) { var match ; var parsed = { } ; if ( ( match = block . match ( / bssid=([A-Fa-f0-9:]{17}) / ) ) ) { parsed . bssid = match [ 1 ] . toLowerCase ( ) ; } if ( ( match = block . match ( / freq=([0-9]+) / ) ) ) { parsed . frequency = parseInt ( match [ 1 ] , 10 ) ; } if ( ( match = block . match ( / mode=([^\s]+) / ) ) ) { parsed . mode = match [ 1 ] ; } if ( ( match = block . match ( / key_mgmt=([^\s]+) / ) ) ) { parsed . key_mgmt = match [ 1 ] . toLowerCase ( ) ; } if ( ( match = block . match ( / [^b]ssid=([^\n]+) / ) ) ) { parsed . ssid = match [ 1 ] ; } if ( ( match = block . match ( / [^b]pairwise_cipher=([^\n]+) / ) ) ) { parsed . pairwise_cipher = match [ 1 ] ; } if ( ( match = block . match ( / [^b]group_cipher=([^\n]+) / ) ) ) { parsed . group_cipher = match [ 1 ] ; } if ( ( match = block . match ( / p2p_device_address=([A-Fa-f0-9:]{17}) / ) ) ) { parsed . p2p_device_address = match [ 1 ] ; } if ( ( match = block . match ( / wpa_state=([^\s]+) / ) ) ) { parsed . wpa_state = match [ 1 ] ; } if ( ( match = block . match ( / ip_address=([^\n]+) / ) ) ) { parsed . ip = match [ 1 ] ; } if ( ( match = block . match ( / [^_]address=([A-Fa-f0-9:]{17}) / ) ) ) { parsed . mac = match [ 1 ] . toLowerCase ( ) ; } if ( ( match = block . match ( / uuid=([^\n]+) / ) ) ) { parsed . uuid = match [ 1 ] ; } if ( ( match = block . match ( / [^s]id=([0-9]+) / ) ) ) { parsed . id = parseInt ( match [ 1 ] , 10 ) ; } return parsed ; }

Parses the status for a wpa network interface.

@private
@static
@category wpa_cli
@param {string} block The section of stdout for the interface.
@returns {object} The parsed wpa status.

Parses the status for a wpa network interface .


function parse_command_interface(callback) {
    return function(error, stdout, stderr) {
        if (error) {
            callback(error);
        } else {
            var output = parse_command_block(stdout.trim());
            if (output.result === 'FAIL') {
                callback(new Error(output.result));
            } else {
                callback(error, parse_command_block(stdout.trim()));
            }
        }
    };
}

function parse_command_interface ( callback ) { return function ( error , stdout , stderr ) { if ( error ) { callback ( error ) ; } else { var output = parse_command_block ( stdout . trim ( ) ) ; if ( output . result === 'FAIL' ) { callback ( new Error ( output . result ) ) ; } else { callback ( error , parse_command_block ( stdout . trim ( ) ) ) ; } } } ; }

Parses the result for a wpa command over an interface.

@private
@static
@category wpa_cli
@param {function} callback The callback function.

Parses the result for a wpa command over an interface .


function parse_scan_results(block) {
    var match;
    var results = [];
    var lines;

    lines = block.split('\n').map(function(item) { return item + "\n"; });
    lines.forEach(function(entry){
        var parsed = {};
        if ((match = entry.match(/([A-Fa-f0-9:]{17})\t/))) {
            parsed.bssid = match[1].toLowerCase();
        }

        if ((match = entry.match(/\t([\d]+)\t+/))) {
            parsed.frequency = parseInt(match[1], 10);
        }

        if ((match = entry.match(/([-][0-9]+)\t/))) {
            parsed.signalLevel = parseInt(match[1], 10);
        }

        if ((match = entry.match(/\t(\[.+\])\t/))) {
            parsed.flags = match[1];
        }

        if ((match = entry.match(/\t([^\t]{1,32}(?=\n))/))) {
            parsed.ssid = match[1];
        }

        if(!(Object.keys(parsed).length === 0 && parsed.constructor === Object)){
            results.push(parsed);
        }
    });

    return results;
}

function parse_scan_results ( block ) { var match ; var results = [ ] ; var lines ; lines = block . split ( '\n' ) . map ( function ( item ) { return item + "\n" ; } ) ; lines . forEach ( function ( entry ) { var parsed = { } ; if ( ( match = entry . match ( / ([A-Fa-f0-9:]{17})\t / ) ) ) { parsed . bssid = match [ 1 ] . toLowerCase ( ) ; } if ( ( match = entry . match ( / \t([\d]+)\t+ / ) ) ) { parsed . frequency = parseInt ( match [ 1 ] , 10 ) ; } if ( ( match = entry . match ( / ([-][0-9]+)\t / ) ) ) { parsed . signalLevel = parseInt ( match [ 1 ] , 10 ) ; } if ( ( match = entry . match ( / \t(\[.+\])\t / ) ) ) { parsed . flags = match [ 1 ] ; } if ( ( match = entry . match ( / \t([^\t]{1,32}(?=\n)) / ) ) ) { parsed . ssid = match [ 1 ] ; } if ( ! ( Object . keys ( parsed ) . length === 0 && parsed . constructor === Object ) ) { results . push ( parsed ) ; } } ) ; return results ; }

Parses the results of a scan_result request.

@private
@static
@category wpa_cli
@param {string} block The section of stdout for the interface.
@returns {object} The parsed scan results.

Parses the results of a scan_result request .


function parse_scan_results_interface(callback) {
    return function(error, stdout, stderr) {
        if (error) {
            callback(error);
        } else {
            callback(error, parse_scan_results(stdout.trim()));
        }
    };
}

function parse_scan_results_interface ( callback ) { return function ( error , stdout , stderr ) { if ( error ) { callback ( error ) ; } else { callback ( error , parse_scan_results ( stdout . trim ( ) ) ) ; } } ; }

Parses the status for a scan_results request.

@private
@static
@category wpa_cli
@param {function} callback The callback function.

Parses the status for a scan_results request .


function parse_status_block(block) {
  var match;

  var parsed = {
    interface: block.match(/^([^\s]+)/)[1]
  };

  if ((match = block.match(/Link encap:\s*([^\s]+)/))) {
    parsed.link = match[1].toLowerCase();
  }

  if ((match = block.match(/HWaddr\s+([^\s]+)/))) {
    parsed.address = match[1].toLowerCase();
  }

  if ((match = block.match(/inet6\s+addr:\s*([^\s]+)/))) {
    parsed.ipv6_address = match[1];
  }

  if ((match = block.match(/inet\s+addr:\s*([^\s]+)/))) {
    parsed.ipv4_address = match[1];
  }

  if ((match = block.match(/Bcast:\s*([^\s]+)/))) {
    parsed.ipv4_broadcast = match[1];
  }

  if ((match = block.match(/Mask:\s*([^\s]+)/))) {
    parsed.ipv4_subnet_mask = match[1];
  }

  if ((match = block.match(/UP/))) {
    parsed.up = true;
  }

  if ((match = block.match(/BROADCAST/))) {
    parsed.broadcast = true;
  }

  if ((match = block.match(/RUNNING/))) {
    parsed.running = true;
  }

  if ((match = block.match(/MULTICAST/))) {
    parsed.multicast = true;
  }

  if ((match = block.match(/LOOPBACK/))) {
    parsed.loopback = true;
  }

  return parsed;
}

function
parse_status_block
(
block
)
{
var
match
;
var
parsed
=
{
interface
:
block
.
match
(
/
^([^\s]+)
/
)
[
1
]
}
;
if
(
(
match
=
block
.
match
(
/
Link encap:\s*([^\s]+)
/
)
)
)
{
parsed
.
link
=
match
[
1
]
.
toLowerCase
(
)
;
}
if
(
(
match
=
block
.
match
(
/
HWaddr\s+([^\s]+)
/
)
)
)
{
parsed
.
address
=
match
[
1
]
.
toLowerCase
(
)
;
}
if
(
(
match
=
block
.
match
(
/
inet6\s+addr:\s*([^\s]+)
/
)
)
)
{
parsed
.
ipv6_address
=
match
[
1
]
;
}
if
(
(
match
=
block
.
match
(
/
inet\s+addr:\s*([^\s]+)
/
)
)
)
{
parsed
.
ipv4_address
=
match
[
1
]
;
}
if
(
(
match
=
block
.
match
(
/
Bcast:\s*([^\s]+)
/
)
)
)
{
parsed
.
ipv4_broadcast
=
match
[
1
]
;
}
if
(
(
match
=
block
.
match
(
/
Mask:\s*([^\s]+)
/
)
)
)
{
parsed
.
ipv4_subnet_mask
=
match
[
1
]
;
}
if
(
(
match
=
block
.
match
(
/
UP
/
)
)
)
{
parsed
.
up
=
true
;
}
if
(
(
match
=
block
.
match
(
/
BROADCAST
/
)
)
)
{
parsed
.
broadcast
=
true
;
}
if
(
(
match
=
block
.
match
(
/
RUNNING
/
)
)
)
{
parsed
.
running
=
true
;
}
if
(
(
match
=
block
.
match
(
/
MULTICAST
/
)
)
)
{
parsed
.
multicast
=
true
;
}
if
(
(
match
=
block
.
match
(
/
LOOPBACK
/
)
)
)
{
parsed
.
loopback
=
true
;
}
return
parsed
;
}

Parses the status for a single network interface.

@private
@static
@category ifconfig
@param {string} block The section of stdout for the interface.
@returns {object} The parsed network interface status.

Parses the status for a single network interface .


function parse_status(callback) {
  return function(error, stdout, stderr) {
    if (error) callback(error);
    else callback(error,
      stdout.trim().split('\n\n').map(parse_status_block));
  };
}

function parse_status ( callback ) { return function ( error , stdout , stderr ) { if ( error ) callback ( error ) ; else callback ( error , stdout . trim ( ) . split ( '\n\n' ) . map ( parse_status_block ) ) ; } ; }

Parses the status for all network interfaces.

@private
@static
@category ifconfig
@param {function} callback The callback function.

Parses the status for all network interfaces .


function expand_r(options, lines, prefix) {
  Object.getOwnPropertyNames(options).forEach(function(key) {
    var full = prefix.concat(key);
    var value = options[key];

    if (Array.isArray(value)) {
      value.forEach(function(val) {
        lines.push(full.concat(val).join(' '));
      });
    }
    else if (typeof(value) == 'object') {
      expand_r(value, lines, full);
    }
    else {
      lines.push(full.concat(value).join(' '));
    }
  });
}

function
expand_r
(
options
,
lines
,
prefix
)
{
Object
.
getOwnPropertyNames
(
options
)
.
forEach
(
function
(
key
)
{
var
full
=
prefix
.
concat
(
key
)
;
var
value
=
options
[
key
]
;
if
(
Array
.
isArray
(
value
)
)
{
value
.
forEach
(
function
(
val
)
{
lines
.
push
(
full
.
concat
(
val
)
.
join
(
' '
)
)
;
}
)
;
}
else
if
(
typeof
(
value
)
==
'object'
)
{
expand_r
(
value
,
lines
,
full
)
;
}
else
{
lines
.
push
(
full
.
concat
(
value
)
.
join
(
' '
)
)
;
}
}
)
;
}

Recursively expand `options` into `lines` with a `prefix`.

@private
@static
@category udhcpd
@param {object} options The dhcp server configuration.
@param {array} lines The lines of the configuration file.
@param {array) prefix The key prefix.

Recursively expand options into lines with a prefix .


function parse_status_block(block) {
  var match;

  // Skip out of the block is invalid
  if (!block) return;

  var parsed = {
    interface: block.match(/^([^\s]+)/)[1]
  };

  if ((match = block.match(/Access Point:\s*([A-Fa-f0-9:]{17})/))) {
    parsed.access_point = match[1].toLowerCase();
  }

  if ((match = block.match(/Frequency[:|=]\s*([0-9\.]+)/))) {
    parsed.frequency = parseFloat(match[1]);
  }

  if ((match = block.match(/IEEE\s*([^\s]+)/))) {
    parsed.ieee = match[1].toLowerCase();
  }

  if ((match = block.match(/Mode[:|=]\s*([^\s]+)/))) {
    parsed.mode = match[1].toLowerCase();
  }

  if ((match = block.match(/Noise level[:|=]\s*(-?[0-9]+)/))) {
    parsed.noise = parseInt(match[1], 10);
  }

  if ((match = block.match(/Link Quality[:|=]\s*([0-9]+)/))) {
    parsed.quality = parseInt(match[1], 10);
  }

  if ((match = block.match(/Sensitivity[:|=]\s*([0-9]+)/))) {
    parsed.sensitivity = parseInt(match[1], 10);
  }

  if ((match = block.match(/Signal level[:|=]\s*(-?[0-9]+)/))) {
    parsed.signal = parseInt(match[1], 10);
  }

  if ((match = block.match(/ESSID[:|=]\s*"([^"]+)"/))) {
    parsed.ssid = match[1];
  }

  if ((match = block.match(/unassociated/))) {
    parsed.unassociated = true;
  }

  return parsed;
}

function
parse_status_block
(
block
)
{
var
match
;
// Skip out of the block is invalid
if
(
!
block
)
return
;
var
parsed
=
{
interface
:
block
.
match
(
/
^([^\s]+)
/
)
[
1
]
}
;
if
(
(
match
=
block
.
match
(
/
Access Point:\s*([A-Fa-f0-9:]{17})
/
)
)
)
{
parsed
.
access_point
=
match
[
1
]
.
toLowerCase
(
)
;
}
if
(
(
match
=
block
.
match
(
/
Frequency[:|=]\s*([0-9\.]+)
/
)
)
)
{
parsed
.
frequency
=
parseFloat
(
match
[
1
]
)
;
}
if
(
(
match
=
block
.
match
(
/
IEEE\s*([^\s]+)
/
)
)
)
{
parsed
.
ieee
=
match
[
1
]
.
toLowerCase
(
)
;
}
if
(
(
match
=
block
.
match
(
/
Mode[:|=]\s*([^\s]+)
/
)
)
)
{
parsed
.
mode
=
match
[
1
]
.
toLowerCase
(
)
;
}
if
(
(
match
=
block
.
match
(
/
Noise level[:|=]\s*(-?[0-9]+)
/
)
)
)
{
parsed
.
noise
=
parseInt
(
match
[
1
]
,
10
)
;
}
if
(
(
match
=
block
.
match
(
/
Link Quality[:|=]\s*([0-9]+)
/
)
)
)
{
parsed
.
quality
=
parseInt
(
match
[
1
]
,
10
)
;
}
if
(
(
match
=
block
.
match
(
/
Sensitivity[:|=]\s*([0-9]+)
/
)
)
)
{
parsed
.
sensitivity
=
parseInt
(
match
[
1
]
,
10
)
;
}
if
(
(
match
=
block
.
match
(
/
Signal level[:|=]\s*(-?[0-9]+)
/
)
)
)
{
parsed
.
signal
=
parseInt
(
match
[
1
]
,
10
)
;
}
if
(
(
match
=
block
.
match
(
/
ESSID[:|=]\s*"([^"]+)"
/
)
)
)
{
parsed
.
ssid
=
match
[
1
]
;
}
if
(
(
match
=
block
.
match
(
/
unassociated
/
)
)
)
{
parsed
.
unassociated
=
true
;
}
return
parsed
;
}

Parses the status for a single wireless network interface.

@private
@static
@category iwconfig
@param {string} block The section of stdout for the interface.
@returns {object} The parsed wireless network interface status.

Parses the status for a single wireless network interface .


function parse_scan(show_hidden, callback) {
  return function(error, stdout, stderr) {
    if (error) callback(error);
    else
      if (show_hidden) {
        callback(error, stdout
        .split(/Cell [0-9]+ -/)
        .map(parse_cell)
        .filter(has_keys)
        .sort(by_signal));
    } else {
        callback(error, stdout
        .split(/Cell [0-9]+ -/)
        .map(parse_cell)
        .filter(has_ssid)
        .sort(by_signal));
    }
  };
}

function
parse_scan
(
show_hidden
,
callback
)
{
return
function
(
error
,
stdout
,
stderr
)
{
if
(
error
)
callback
(
error
)
;
else
if
(
show_hidden
)
{
callback
(
error
,
stdout
.
split
(
/
Cell [0-9]+ -
/
)
.
map
(
parse_cell
)
.
filter
(
has_keys
)
.
sort
(
by_signal
)
)
;
}
else
{
callback
(
error
,
stdout
.
split
(
/
Cell [0-9]+ -
/
)
.
map
(
parse_cell
)
.
filter
(
has_ssid
)
.
sort
(
by_signal
)
)
;
}
}
;
}

Parses all scanned wireless network cells.

@private
@static
@category iwlist
@param {function} callback The callback function.

Parses all scanned wireless network cells .


function createItemContent(cfg, item) {
  var data = item.children || cfg.data;
  var frag = document.createDocumentFragment();
  var label = _.el('span');
  var iconPrepend = _.el('i');
  var iconAppend = _.el('i');
  var prependClasses = ['fa'];
  var appendClasses = ['fa'];

  // prepended icon
  if (data) {
    prependClasses.push('fa-folder');
  } else if (item.type === 'github-url') {
    prependClasses.push('fa-github');
  } else {
    prependClasses.push('fa-file-o');
  }
  _.addClass(iconPrepend, prependClasses);

  // text label
  _.append(label, [iconPrepend, _.text(item.label)]);
  frag.appendChild(label);

  // appended icon
  if (data) {
    appendClasses.push('fa-caret-right');
  } else if ('url' in item) {
    appendClasses.push('fa-external-link');
  }
  _.addClass(iconAppend, appendClasses);
  frag.appendChild(iconAppend);

  return frag;
}

function
createItemContent
(
cfg
,
item
)
{
var
data
=
item
.
children
||
cfg
.
data
;
var
frag
=
document
.
createDocumentFragment
(
)
;
var
label
=
_
.
el
(
'span'
)
;
var
iconPrepend
=
_
.
el
(
'i'
)
;
var
iconAppend
=
_
.
el
(
'i'
)
;
var
prependClasses
=
[
'fa'
]
;
var
appendClasses
=
[
'fa'
]
;
// prepended icon
if
(
data
)
{
prependClasses
.
push
(
'fa-folder'
)
;
}
else
if
(
item
.
type
===
'github-url'
)
{
prependClasses
.
push
(
'fa-github'
)
;
}
else
{
prependClasses
.
push
(
'fa-file-o'
)
;
}
_
.
addClass
(
iconPrepend
,
prependClasses
)
;
// text label
_
.
append
(
label
,
[
iconPrepend
,
_
.
text
(
item
.
label
)
]
)
;
frag
.
appendChild
(
label
)
;
// appended icon
if
(
data
)
{
appendClasses
.
push
(
'fa-caret-right'
)
;
}
else
if
(
'url'
in
item
)
{
appendClasses
.
push
(
'fa-external-link'
)
;
}
_
.
addClass
(
iconAppend
,
appendClasses
)
;
frag
.
appendChild
(
iconAppend
)
;
return
frag
;
}

how each item in a column should be rendered


function closest(element, test) {
  var el = element;

  while (el) {
    if (test(el)) {
      return el;
    }
    el = el.parentNode;
  }

  return null;
}

function closest ( element , test ) { var el = element ; while ( el ) { if ( test ( el ) ) { return el ; } el = el . parentNode ; } return null ; }

Find first element that tests true, starting with the element itself
and traversing up through its ancestors
@param  {Element} element
@param  {Function} test fn - return true when element located
@return {Element}

Find first element that tests true starting with the element itself and traversing up through its ancestors


function addClass(element, className) {
  var classNames = className;

  function _addClass(el, cn) {
    if (!el.className) {
      el.className = cn;
    } else if (!hasClass(el, cn)) {
      if (el.classList) {
        el.classList.add(cn);
      } else {
        el.className += ' ' + cn;
      }
    }
  }

  if (!isArray(className)) {
    classNames = className.trim().split(/\s+/);
  }
  classNames.forEach(_addClass.bind(null, element));

  return element;
}

function
addClass
(
element
,
className
)
{
var
classNames
=
className
;
function
_addClass
(
el
,
cn
)
{
if
(
!
el
.
className
)
{
el
.
className
=
cn
;
}
else
if
(
!
hasClass
(
el
,
cn
)
)
{
if
(
el
.
classList
)
{
el
.
classList
.
add
(
cn
)
;
}
else
{
el
.
className
+=
' '
+
cn
;
}
}
}
if
(
!
isArray
(
className
)
)
{
classNames
=
className
.
trim
(
)
.
split
(
/
\s+
/
)
;
}
classNames
.
forEach
(
_addClass
.
bind
(
,
element
)
)
;
return
element
;
}

Add one or more classnames to an element
@param {Element} element
@param {Array.<string>|String} array of classnames or string with
classnames separated by whitespace
@return {Element}


function removeClass(element, className) {
  var classNames = className;

  function _removeClass(el, cn) {
    var classRegex;
    if (el.classList) {
      el.classList.remove(cn);
    } else {
      classRegex = new RegExp('(?:^|\\s)' + cn + '(?!\\S)', 'g');
      el.className = el.className.replace(classRegex, '').trim();
    }
  }

  if (!isArray(className)) {
    classNames = className.trim().split(/\s+/);
  }
  classNames.forEach(_removeClass.bind(null, element));

  return element;
}

function removeClass ( element , className ) { var classNames = className ; function _removeClass ( el , cn ) { var classRegex ; if ( el . classList ) { el . classList . remove ( cn ) ; } else { classRegex = new RegExp ( '(?:^|\\s)' + cn + '(?!\\S)' , 'g' ) ; el . className = el . className . replace ( classRegex , '' ) . trim ( ) ; } } if ( ! isArray ( className ) ) { classNames = className . trim ( ) . split ( / \s+ / ) ; } classNames . forEach ( _removeClass . bind ( null , element ) ) ; return element ; }

Remove a class from an element
@param  {Element} element
@param  {Array.<string>|String} array of classnames or string with
@return {Element}


function hasClass(element, className) {
  if (!element || !('className' in element)) {
    return false;
  }

  return element.className.split(/\s+/).indexOf(className) !== -1;
}

function hasClass ( element , className ) { if ( ! element || ! ( 'className' in element ) ) { return false ; } return element . className . split ( / \s+ / ) . indexOf ( className ) !== - 1 ; }

Check if element has a class
@param  {Element}  element
@param  {String}  className
@return {boolean}


function nextSiblings(element) {
  var next = element.nextSibling;
  var siblings = [];

  while (next) {
    siblings.push(next);
    next = next.nextSibling;
  }

  return siblings;
}

function nextSiblings ( element ) { var next = element . nextSibling ; var siblings = [ ] ; while ( next ) { siblings . push ( next ) ; next = next . nextSibling ; } return siblings ; }

Return all next siblings
@param  {Element} element
@return {Array.<element>}


function previousSiblings(element) {
  var prev = element.previousSibling;
  var siblings = [];

  while (prev) {
    siblings.push(prev);
    prev = prev.previousSibling;
  }

  return siblings;
}

function previousSiblings ( element ) { var prev = element . previousSibling ; var siblings = [ ] ; while ( prev ) { siblings . push ( prev ) ; prev = prev . previousSibling ; } return siblings ; }

Return all prev siblings
@param  {Element} element
@return {Array.<element>}


function uniqueCountryData(data, type, parent) {
  var hash = data.reduce(function each(prev, curr) {
    if (!(curr[type] in prev)) {
      if (parent) {
        if (parent.label === curr[parent.type]) {
          prev[curr[type]] = curr;
        }
      } else if (curr[type]) {
        prev[curr[type]] = curr;
      }
    }

    return prev;
  }, {});

  return Object.keys(hash).map(function each(item) {
    return extend(hash[item], {
      label: item,
      type: type === 'name' ? 'country' : type
    });
  });
}

function uniqueCountryData ( data , type , parent ) { var hash = data . reduce ( function each ( prev , curr ) { if ( ! ( curr [ type ] in prev ) ) { if ( parent ) { if ( parent . label === curr [ parent . type ] ) { prev [ curr [ type ] ] = curr ; } } else if ( curr [ type ] ) { prev [ curr [ type ] ] = curr ; } } return prev ; } , { } ) ; return Object . keys ( hash ) . map ( function each ( item ) { return extend ( hash [ item ] , { label : item , type : type === 'name' ? 'country' : type } ) ; } ) ; }


function (el) {
  var className = el.className
  var listClass = className.split(' ')
  this.classList = listClass
  this.el = el
}

function
(
el
)
{
var
className
=
el
.
className
var
listClass
=
className
.
split
(
' '
)
this
.
classList
=
listClass
this
.
el
=
el
}

new object function for unsupport classList


function (el) {
  this.el = el
  if(typeof el.classList !== 'undefined') {
    // if classList support
    this.old = false
  } else {
    // browser class unsupport classList
    this.classList = new nativeClasList(el)
    this.old = true
  }
}

function
(
el
)
{
this
.
el
=
el
if
(
typeof
el
.
classList
!==
'undefined'
)
{
// if classList support
this
.
old
=
false
}
else
{
// browser class unsupport classList
this
.
classList
=
new
nativeClasList
(
el
)
this
.
old
=
true
}
}


function (obj, src) {
  var result = false
  var key
  for (key in obj) {
    if (obj.hasOwnProperty(key) && key === src) result = true
  }
  return result
}

function ( obj , src ) { var result = false var key for ( key in obj ) { if ( obj . hasOwnProperty ( key ) && key === src ) result = true } return result }

return boolen
- check if key has in object


function (v) {
  var result = 0
  var key
  for (key in v) {
      v.hasOwnProperty(key) && result++
  }
  return result
}

function ( v ) { var result = 0 var key for ( key in v ) { v . hasOwnProperty ( key ) && result ++ } return result }


function (el, check) {
  var cls = el.classList
  var size = cls.length
  var result = false
  var i = 0
  for (i; i < size; i++) {
    if (cls[i].toString() === check) result = true
  }
  return result
}

function ( el , check ) { var cls = el . classList var size = cls . length var result = false var i = 0 for ( i ; i < size ; i ++ ) { if ( cls [ i ] . toString ( ) === check ) result = true } return result }


function () {
			var self = this;
			console.log('starting capture...');
			var req = get_req();
			req.onreadystatechange = function start_capture_response () {
				if (req.readyState === 4) {
					if (req.status == 200) {
						console.log('started.');
						jQuery("#start").hide();
						jQuery("#stop").show();
					  htracr.ui.pulse_logo();
					} else {
						var error = eval("(" + req.responseText + ")");
						alert("Sorry, I can't start the sniffer; it says \"" +
						  error.message + "\"."
						);
						console.log("start problem: " + error);
					}
				}
			};
			req.open("POST", "/start", true);
			req.send("");
			return false;
		}


function () {
			var self = this;
			console.log('stopping capture...');
			var req = get_req();
			req.onreadystatechange = function stop_capture_response () {
				if (req.readyState === 4) {
					self.update_state();
					console.log('stopped.');
					jQuery("#stop").hide();
					jQuery("#start").show();
          htracr.ui.unpulse_logo(true);
				}
			};
			req.open("POST", "/stop", true);
			req.send("");
			return false;
		}

function
(
)
{
var
self
=
this
;
console
.
log
(
'stopping capture...'
)
;
var
req
=
get_req
(
)
;
req
.
onreadystatechange
=
function
stop_capture_response
(
)
{
if
(
req
.
readyState
===
4
)
{
self
.
update_state
(
)
;
console
.
log
(
'stopped.'
)
;
jQuery
(
"#stop"
)
.
hide
(
)
;
jQuery
(
"#start"
)
.
show
(
)
;
htracr
.
ui
.
unpulse_logo
(
true
)
;
}
}
;
req
.
open
(
"POST"
,
"/stop"
,
true
)
;
req
.
send
(
""
)
;
return
false
;
}


function () {
			var self = this;
			console.log('updating...');
			var req = get_req();
			req.onreadystatechange = function update_state_response () {
				if (req.readyState === 4) {
					if (req.status === 200) {
						var capture = JSON.parse(req.responseText);
						if (capture.error) {
							alert(capture.error.message);
						}
						htracr.ui.update(capture);
						console.log('updated.');
					} else {
					  console.log('no updates.');
					}
				}
			};
			req.open("GET", "/conns", true);
			req.send("");
			return false;
		}

function
(
)
{
var
self
=
this
;
console
.
log
(
'updating...'
)
;
var
req
=
get_req
(
)
;
req
.
onreadystatechange
=
function
update_state_response
(
)
{
if
(
req
.
readyState
===
4
)
{
if
(
req
.
status
===
200
)
{
var
capture
=
JSON
.
parse
(
req
.
responseText
)
;
if
(
capture
.
error
)
{
alert
(
capture
.
error
.
message
)
;
}
htracr
.
ui
.
update
(
capture
)
;
console
.
log
(
'updated.'
)
;
}
else
{
console
.
log
(
'no updates.'
)
;
}
}
}
;
req
.
open
(
"GET"
,
"/conns"
,
true
)
;
req
.
send
(
""
)
;
return
false
;
}

get the latest capture info from the server


function () {
			var self = this;
			console.log('clearing...');
			var req = get_req();
			req.onreadystatechange = function clear_state_response () {
				if (req.readyState === 4) {
					htracr.ui.clear();
				}
			};
			req.open("POST", "/clear", true);
			req.send("");
			return false;
		}

function ( ) { var self = this ; console . log ( 'clearing...' ) ; var req = get_req ( ) ; req . onreadystatechange = function clear_state_response ( ) { if ( req . readyState === 4 ) { htracr . ui . clear ( ) ; } } ; req . open ( "POST" , "/clear" , true ) ; req . send ( "" ) ; return false ; }


function get_req () {
		var self = this;
		var req;
		if (window.XMLHttpRequest) {
			try {
				req = new XMLHttpRequest();
			} catch(e1) {
				req = false;
			}
		} else if (window.ActiveXObject) {
			try {
				req = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e2) {
				req = false;
			}
		}
		return req;
	}

function get_req ( ) { var self = this ; var req ; if ( window . XMLHttpRequest ) { try { req = new XMLHttpRequest ( ) ; } catch ( e1 ) { req = false ; } } else if ( window . ActiveXObject ) { try { req = new ActiveXObject ( "Microsoft.XMLHTTP" ) ; } catch ( e2 ) { req = false ; } } return req ; }


function (capture) {
      var self = this;
      self.clear();
      self.capture = capture;
      self.capture_idx = index_capture(capture);
      self.render();
    }

function ( capture ) { var self = this ; self . clear ( ) ; self . capture = capture ; self . capture_idx = index_capture ( capture ) ; self . render ( ) ; }

update with new capture data and re-render

update with new capture data and re - render


function () {
      var self = this;

      self.clear_ui();
      self.resize();
      self.draw_scale();

      self.capture_idx.servers.forEach(function (bundle) {
        var server_name = bundle[0];
        var conn_ids = bundle[1];
        var i;
        self.y += self.server_pad;
        self.draw_server_label(server_name);
        self.y += self.server_pad;
        conn_ids.forEach(function (conn_id) {
          var conn = self.capture.sessions[server_name][conn_id];
          htracr.connection(conn).draw(
            di, [server_name, conn_id, undefined, 0]);
          i = 0;
          conn.http_reqs.forEach(function (http_req) {
            var msg = htracr.http_msg(http_req);
            msg.kind = "req";
            msg.draw(di, [server_name, conn_id, 'http_reqs', i]);
            i += 1;
          });
          i = 0;
          conn.http_ress.forEach(function (http_req) {
            var msg = htracr.http_msg(http_req);
            msg.kind = "res";
            msg.draw(di, [server_name, conn_id, 'http_ress', i]);
            i += 1;
          });
          i = 0;
          conn.packets.forEach(function (packet) {
            var pkt = htracr.packet(packet);
            pkt.draw(di, [server_name, conn_id, 'packets', i]);
            i += 1;
          });
          self.y += self.conn_pad;
        });

        self.draw_referers();
        self.draw_locations();
      });
    }

function ( ) { var self = this ; self . clear_ui ( ) ; self . resize ( ) ; self . draw_scale ( ) ; self . capture_idx . servers . forEach ( function ( bundle ) { var server_name = bundle [ 0 ] ; var conn_ids = bundle [ 1 ] ; var i ; self . y += self . server_pad ; self . draw_server_label ( server_name ) ; self . y += self . server_pad ; conn_ids . forEach ( function ( conn_id ) { var conn = self . capture . sessions [ server_name ] [ conn_id ] ; htracr . connection ( conn ) . draw ( di , [ server_name , conn_id , undefined , 0 ] ) ; i = 0 ; conn . http_reqs . forEach ( function ( http_req ) { var msg = htracr . http_msg ( http_req ) ; msg . kind = "req" ; msg . draw ( di , [ server_name , conn_id , 'http_reqs' , i ] ) ; i += 1 ; } ) ; i = 0 ; conn . http_ress . forEach ( function ( http_req ) { var msg = htracr . http_msg ( http_req ) ; msg . kind = "res" ; msg . draw ( di , [ server_name , conn_id , 'http_ress' , i ] ) ; i += 1 ; } ) ; i = 0 ; conn . packets . forEach ( function ( packet ) { var pkt = htracr . packet ( packet ) ; pkt . draw ( di , [ server_name , conn_id , 'packets' , i ] ) ; i += 1 ; } ) ; self . y += self . conn_pad ; } ) ; self . draw_referers ( ) ; self . draw_locations ( ) ; } ) ; }


function() {
			var self = this;
			var idx = self.capture_idx;
      self.w = (
        (idx.end - idx.start) / 1000 * self.pix_per_sec) +
        margin[1] + margin[3];
      self.h = margin[0] + margin[2];
      for (var s in idx.servers) {
        self.h += (self.server_pad * 2);
        self.h += ((idx.servers[s][1].length) * self.conn_pad);
      }
			console.log("resizing to " + self.w + " x " + self.h);
			paper.setSize(self.w, self.h);
			labels.setSize(self.label_w, self.h);
		}

function
(
)
{
var
self
=
this
;
var
idx
=
self
.
capture_idx
;
self
.
w
=
(
(
idx
.
end
idx
.
start
)
/
1000
*
self
.
pix_per_sec
)
+
margin
[
1
]
+
margin
[
3
]
;
self
.
h
=
margin
[
0
]
+
margin
[
2
]
;
for
(
var
s
in
idx
.
servers
)
{
self
.
h
+=
(
self
.
server_pad
*
2
)
;
self
.
h
+=
(
(
idx
.
servers
[
s
]
[
1
]
.
length
)
*
self
.
conn_pad
)
;
}
console
.
log
(
"resizing to "
+
self
.
w
+
" x "
+
self
.
h
)
;
paper
.
setSize
(
self
.
w
,
self
.
h
)
;
labels
.
setSize
(
self
.
label_w
,
self
.
h
)
;
}

change the paper and label sizes to suit the capture


function () {
      var self = this;
      var start_x = time_x(self.capture_idx.start);
      var end_x = time_x(self.capture_idx.end);
      var end_y = self.h - margin[2];
      var end_attrs = {
        stroke: "#666",
        "stroke-width": "1"
      };
      var label_attrs = {
        fill: "white",
        "font-size": "16",
        "opacity": ".5"
      };
      paper.path(
        "M" + start_x + "," + margin[0] + " " +
        "L" + start_x + "," + end_y).attr(end_attrs);
      var m;
      if (self.pix_per_sec <= 1000) {
        m = 1000;
      } else if (self.pix_per_sec <= 2000) {
        m = 500;
      } else if (self.pix_per_sec <= 3500) {
        m = 250;
      } else if (self.pix_per_sec <= 5000) {
        m = 100;
      } else {
        m = 50;
      }
      for (var i = self.capture_idx.start; i < self.capture_idx.end; i += m) {
        var i_x = time_x(i);
        paper.path(
          "M" + i_x + "," + margin[0] + " " +
          "L" + i_x + "," + end_y
        ).attr({
          stroke: "#444",
          "stroke-width": "1"
        });
        paper.text(i_x, end_y + 10,
          ((i - self.capture_idx.start) / 1000) + "s").attr(label_attrs);
        paper.text(i_x, margin[0] - 20,
          ((i - self.capture_idx.start) / 1000) + "s").attr(label_attrs);
      }
      paper.path(
        "M" + end_x + "," + margin[0] + " " +
        "L" + end_x + "," + end_y
      ).attr(end_attrs);
    }

function
(
)
{
var
self
=
this
;
var
start_x
=
time_x
(
self
.
capture_idx
.
start
)
;
var
end_x
=
time_x
(
self
.
capture_idx
.
end
)
;
var
end_y
=
self
.
h
margin
[
2
]
;
var
end_attrs
=
{
stroke
:
"#666"
,
"stroke-width"
:
"1"
}
;
var
label_attrs
=
{
fill
:
"white"
,
"font-size"
:
"16"
,
"opacity"
:
".5"
}
;
paper
.
path
(
"M"
+
start_x
+
","
+
margin
[
0
]
+
" "
+
"L"
+
start_x
+
","
+
end_y
)
.
attr
(
end_attrs
)
;
var
m
;
if
(
self
.
pix_per_sec
<=
1000
)
{
m
=
1000
;
}
else
if
(
self
.
pix_per_sec
<=
2000
)
{
m
=
500
;
}
else
if
(
self
.
pix_per_sec
<=
3500
)
{
m
=
250
;
}
else
if
(
self
.
pix_per_sec
<=
5000
)
{
m
=
100
;
}
else
{
m
=
50
;
}
for
(
var
i
=
self
.
capture_idx
.
start
;
i
<
self
.
capture_idx
.
end
;
i
+=
m
)
{
var
i_x
=
time_x
(
i
)
;
paper
.
path
(
"M"
+
i_x
+
","
+
margin
[
0
]
+
" "
+
"L"
+
i_x
+
","
+
end_y
)
.
attr
(
{
stroke
:
"#444"
,
"stroke-width"
:
"1"
}
)
;
paper
.
text
(
i_x
,
end_y
+
10
,
(
(
i
self
.
capture_idx
.
start
)
/
1000
)
+
"s"
)
.
attr
(
label_attrs
)
;
paper
.
text
(
i_x
,
margin
[
0
]
20
,
(
(
i
self
.
capture_idx
.
start
)
/
1000
)
+
"s"
)
.
attr
(
label_attrs
)
;
}
paper
.
path
(
"M"
+
end_x
+
","
+
margin
[
0
]
+
" "
+
"L"
+
end_x
+
","
+
end_y
)
.
attr
(
end_attrs
)
;
}

draw scale markings appropriate for the capture


function (val) {
			var self = this;
			console.log("zooming to " + val + "...");
			self.pix_per_sec = val;
			self.render();
		}

function
(
val
)
{
var
self
=
this
;
console
.
log
(
"zooming to "
+
val
+
"..."
)
;
self
.
pix_per_sec
=
val
;
self
.
render
(
)
;
}


function (start, end, y_adj, attrs) {
      var start_x = time_x(start) || margin[3];
      var end_x = time_x(end) || ui.w - margin[1];
      var y = ui.y + y_adj;
      var e = paper.path(
        "M" + start_x + "," + y + " " +
        "L" + end_x + "," + y
      ).attr(attrs || {});
      return e;
    }

function
(
start
,
end
,
y_adj
,
attrs
)
{
var
start_x
=
time_x
(
start
)
||
margin
[
3
]
;
var
end_x
=
time_x
(
end
)
||
ui
.
w
margin
[
1
]
;
var
y
=
ui
.
y
+
y_adj
;
var
e
=
paper
.
path
(
"M"
+
start_x
+
","
+
y
+
" "
+
"L"
+
end_x
+
","
+
y
)
.
attr
(
attrs
||
{
}
)
;
return
e
;
}

draw a horizontal line from the time offsets start to end with attrs. If start or end isn't set, use the left and right margins respectively. y_adj can be used to adjust y.

draw a horizontal line from the time offsets start to end with attrs . If start or end isn t set use the left and right margins respectively . y_adj can be used to adjust y .


function (when, len, attrs) {
      var x = time_x(when);
      var end_y = ui.y + len;
      var e = paper.path(
        "M" + x + "," + ui.y + " " +
        "L" + x + "," + end_y
      ).attr(attrs || {});
      return e;
    }

function
(
when
,
len
,
attrs
)
{
var
x
=
time_x
(
when
)
;
var
end_y
=
ui
.
y
+
len
;
var
e
=
paper
.
path
(
"M"
+
x
+
","
+
ui
.
y
+
" "
+
"L"
+
x
+
","
+
end_y
)
.
attr
(
attrs
||
{
}
)
;
return
e
;
}

draw a line at when from y as far as len pixels with attrs.

draw a line at when from y as far as len pixels with attrs .


function (name, value, cursor, single) {
      if (value) {
        if (! htracr.ui.urls[name]) {
          ui.urls[name] = {};
        }
        if (single === true) {
          ui.urls[name][value] = cursor;
        } else {
          if (! ui.urls[name][value]) {
            ui.urls[name][value] = [];
          }
          ui.urls[name][value].push(cursor);
        }
      }
    }

function ( name , value , cursor , single ) { if ( value ) { if ( ! htracr . ui . urls [ name ] ) { ui . urls [ name ] = { } ; } if ( single === true ) { ui . urls [ name ] [ value ] = cursor ; } else { if ( ! ui . urls [ name ] [ value ] ) { ui . urls [ name ] [ value ] = [ ] ; } ui . urls [ name ] [ value ] . push ( cursor ) ; } } }

save the cursor location for a named value


function time_x (t) {
    var self = this;
    if (t === null) {
      return null;
    }
    var delta = t - ui.capture_idx.start;
    if (delta < 0) {
      console.log('Negative delta for time ' + t);
    }
    var pix = delta * ui.pix_per_sec / 1000;
    var x = margin[3] + pix;
    return x;
  }

function
time_x
(
t
)
{
var
self
=
this
;
if
(
t
===
)
{
return
;
}
var
delta
=
t
ui
.
capture_idx
.
start
;
if
(
delta
<
0
)
{
console
.
log
(
'Negative delta for time '
+
t
)
;
}
var
pix
=
delta
*
ui
.
pix_per_sec
/
1000
;
var
x
=
margin
[
3
]
+
pix
;
return
x
;
}

given a time, return the corresponding x value for paper

given a time return the corresponding x value for paper


function wmic(callback) {
  var args = ['PROCESS', 'get', 'ParentProcessId,ProcessId'];
  var options = {windowsHide: true, windowsVerbatimArguments: true};
  bin('wmic', args, options, function(err, stdout, code) {
    if (err) {
      callback(err);
      return;
    }

    if (code !== 0) {
      callback(new Error('pidtree wmic command exited with code ' + code));
      return;
    }

    // Example of stdout
    //
    // ParentProcessId  ProcessId
    // 0                777

    try {
      stdout = stdout.split(os.EOL);

      var list = [];
      for (var i = 1; i < stdout.length; i++) {
        stdout[i] = stdout[i].trim();
        if (!stdout[i]) continue;
        stdout[i] = stdout[i].split(/\s+/);
        stdout[i][0] = parseInt(stdout[i][0], 10); // PPID
        stdout[i][1] = parseInt(stdout[i][1], 10); // PID
        list.push(stdout[i]);
      }

      callback(null, list);
    } catch (error) {
      callback(error);
    }
  });
}

Gets the list of all the pids of the system through the wmic command.
@param  {Function} callback(err, list)

Gets the list of all the pids of the system through the wmic command .


function list(PID, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }

  if (typeof options !== 'object') {
    options = {};
  }

  PID = parseInt(PID, 10);
  if (isNaN(PID) || PID < -1) {
    callback(new TypeError('The pid provided is invalid'));
    return;
  }

  getAll(function(err, list) {
    if (err) {
      callback(err);
      return;
    }

    // If the user wants the whole list just return it
    if (PID === -1) {
      for (var i = 0; i < list.length; i++) {
        list[i] = options.advanced
          ? {ppid: list[i][0], pid: list[i][1]}
          : (list[i] = list[i][1]);
      }

      callback(null, list);
      return;
    }

    var root;
    for (var l = 0; l < list.length; l++) {
      if (list[l][1] === PID) {
        root = options.advanced ? {ppid: list[l][0], pid: PID} : PID;
        break;
      }

      if (list[l][0] === PID) {
        root = options.advanced ? {pid: PID} : PID; // Special pids like 0 on *nix
      }
    }

    if (!root) {
      callback(new Error('No maching pid found'));
      return;
    }

    // Build the adiacency Hash Map (pid -> [children of pid])
    var tree = {};
    while (list.length > 0) {
      var e = list.pop();
      if (tree[e[0]]) {
        tree[e[0]].push(e[1]);
      } else {
        tree[e[0]] = [e[1]];
      }
    }

    // Starting by the PID provided by the user, traverse the tree using the
    // adiacency Hash Map until the whole subtree is visited.
    // Each pid encountered while visiting is added to the pids array.
    var idx = 0;
    var pids = [root];
    while (idx < pids.length) {
      var curpid = options.advanced ? pids[idx++].pid : pids[idx++];
      if (!tree[curpid]) continue;
      var len = tree[curpid].length;
      for (var j = 0; j < len; j++) {
        pids.push(
          options.advanced
            ? {ppid: curpid, pid: tree[curpid][j]}
            : tree[curpid][j]
        );
      }

      delete tree[curpid];
    }

    if (!options.root) {
      pids.shift(); // Remove root
    }

    callback(null, pids);
  });
}

Get the list of children and grandchildren pids of the given PID.
@param  {Number|String} PID A PID. If -1 will return all the pids.
@param  {Object} [options] Optional options object.
@param  {Boolean} [options.root=false] Include the provided PID in the list.
@param  {Boolean} [options.advanced=false] Returns a list of objects in the
format {pid: X, ppid: Y}.
@param  {Function} callback(err, list) Called when the list is ready.

Get the list of children and grandchildren pids of the given PID .


function list(pid, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = undefined;
  }

  if (typeof callback === 'function') {
    pidtree(pid, options, callback);
    return;
  }

  return pify(pidtree, pid, options);
}

function list ( pid , options , callback ) { if ( typeof options === 'function' ) { callback = options ; options = undefined ; } if ( typeof callback === 'function' ) { pidtree ( pid , options , callback ) ; return ; } return pify ( pidtree , pid , options ) ; }

Get the list of children pids of the given pid.
@public
@param  {Number|String} pid A PID. If -1 will return all the pids.
@param  {Object} [options] Optional options object.
@param  {Boolean} [options.root=false] Include the provided PID in the list.
@param  {Boolean} [options.advanced=false] Returns a list of objects in the
format {pid: X, ppid: Y}.
@param  {Function} [callback=undefined] Called when the list is ready. If not
provided a promise is returned instead.
@returns  {Promise.<Object[]>} Only when the callback is not provided.

Get the list of children pids of the given pid .


function get(callback) {
  if (file === undefined) {
    callback(
      new Error(
        os.platform() +
          ' is not supported yet, please open an issue (https://github.com/simonepri/pidtree)'
      )
    );
  }

  var list = require('./' + file);
  list(callback);
}

Gets the list of all the pids of the system.
@param  {Function} callback Called when the list is ready.

Gets the list of all the pids of the system .


function run(cmd, args, options, done) {
  if (typeof options === 'function') {
    done = options;
    options = undefined;
  }

  var executed = false;
  var ch = spawn(cmd, args, options);
  var stdout = '';
  var stderr = '';

  ch.stdout.on('data', function(d) {
    stdout += d.toString();
  });

  ch.stderr.on('data', function(d) {
    stderr += d.toString();
  });

  ch.on('error', function(err) {
    if (executed) return;
    executed = true;
    done(new Error(err));
  });

  ch.on('close', function(code) {
    if (executed) return;
    executed = true;

    if (stderr) {
      return done(new Error(stderr));
    }

    done(null, stdout, code);
  });
}

function run ( cmd , args , options , done ) { if ( typeof options === 'function' ) { done = options ; options = undefined ; } var executed = false ; var ch = spawn ( cmd , args , options ) ; var stdout = '' ; var stderr = '' ; ch . stdout . on ( 'data' , function ( d ) { stdout += d . toString ( ) ; } ) ; ch . stderr . on ( 'data' , function ( d ) { stderr += d . toString ( ) ; } ) ; ch . on ( 'error' , function ( err ) { if ( executed ) return ; executed = true ; done ( new Error ( err ) ) ; } ) ; ch . on ( 'close' , function ( code ) { if ( executed ) return ; executed = true ; if ( stderr ) { return done ( new Error ( stderr ) ) ; } done ( null , stdout , code ) ; } ) ; }

Spawn a binary and read its stdout.
@param  {String} cmd The name of the binary to spawn.
@param  {String[]} args The arguments for the binary.
@param  {Object} [options] Optional option for the spawn function.
@param  {Function} done(err, stdout)


function ps(callback) {
  var args = ['-A', '-o', 'ppid,pid'];

  bin('ps', args, function(err, stdout, code) {
    if (err) return callback(err);
    if (code !== 0) {
      return callback(new Error('pidtree ps command exited with code ' + code));
    }

    // Example of stdout
    //
    // PPID   PID
    //    1   430
    //  430   432
    //    1   727
    //    1  7166

    try {
      stdout = stdout.split(os.EOL);

      var list = [];
      for (var i = 1; i < stdout.length; i++) {
        stdout[i] = stdout[i].trim();
        if (!stdout[i]) continue;
        stdout[i] = stdout[i].split(/\s+/);
        stdout[i][0] = parseInt(stdout[i][0], 10); // PPID
        stdout[i][1] = parseInt(stdout[i][1], 10); // PID
        list.push(stdout[i]);
      }

      callback(null, list);
    } catch (error) {
      callback(error);
    }
  });
}

function
ps
(
callback
)
{
var
args
=
[
'-A'
,
'-o'
,
'ppid,pid'
]
;
bin
(
'ps'
,
args
,
function
(
err
,
stdout
,
code
)
{
if
(
err
)
return
callback
(
err
)
;
if
(
code
!==
0
)
{
return
callback
(
new
Error
(
'pidtree ps command exited with code '
+
code
)
)
;
}
// Example of stdout
//
// PPID   PID
//    1   430
//  430   432
//    1   727
//    1  7166
try
{
stdout
=
stdout
.
split
(
os
.
EOL
)
;
var
list
=
[
]
;
for
(
var
i
=
1
;
i
<
stdout
.
length
;
i
++
)
{
stdout
[
i
]
=
stdout
[
i
]
.
trim
(
)
;
if
(
!
stdout
[
i
]
)
continue
;
stdout
[
i
]
=
stdout
[
i
]
.
split
(
/
\s+
/
)
;
stdout
[
i
]
[
0
]
=
parseInt
(
stdout
[
i
]
[
0
]
,
10
)
;
// PPID
stdout
[
i
]
[
1
]
=
parseInt
(
stdout
[
i
]
[
1
]
,
10
)
;
// PID
list
.
push
(
stdout
[
i
]
)
;
}
callback
(
,
list
)
;
}
catch
(
error
)
{
callback
(
error
)
;
}
}
)
;
}

Gets the list of all the pids of the system through the ps command.
@param  {Function} callback(err, list)

Gets the list of all the pids of the system through the ps command .


function bootstrap () {
  var server = RPC.apply(null, arguments)
  var io = server.io

  var allQueries = []

  Object.keys(models).forEach(function (modelName) {
    var model = models[modelName]
    model._exposeCallback(server)
  })

  io.use(function (socket, next) {
    const registeredLQs = {}
    socket.moonridge = {
      registeredLQs: registeredLQs,
      user: {privilege_level: 0}
    } // default privilege level for any connected client

    socket.on('disconnect', function () {
      // clearing out liveQueries listeners
      debug(socket.id, ' socket disconnected, cleaning up LQ listeners')
      for (var LQId in registeredLQs) {
        var LQ = registeredLQs[LQId]
        LQ.removeListener(socket)
      }
    })

    next()
  })

  server.expose({
    MR: {
      getModels: function () {
        return Object.keys(models)
      },
      deAuthorize: function () {
        this.moonridge.user = {privilege_level: 0}	// for logging users out
      }
    }
  })

  if (process.env.MOONRIDGE_HEALTH === '1') {
    // this reveals any data that you use in queries to the public, so it should not be used in production when dealing with sensitive data

    server.expose({
      MR: {
        getHealth: function () {
          var allModels = {}
          var index = allQueries.length
          while (index--) {
            var modelQueriesForSerialization = {}
            var model = allQueries[index]
            for (var LQ in model.queries) {
              modelQueriesForSerialization[LQ] = Object.keys(model.queries[LQ].listeners).length
            }
            allModels[model.modelName] = modelQueriesForSerialization
          }
          return {
            pid: process.pid,
            memory: process.memoryUsage(),
            uptime: process.uptime(),   // in seconds
            liveQueries: allModels  // key is LQ.clientQuery and value is number of listening clients
          }
        }
      }
    })
  }

  return server
}

Shares the same signature as express.js listen method, because it passes arguments to it
@param {Number} port
@param {String} [hostname]
@param {Function} [Callback]
@returns {{rpcNsp: (Emitter), io: {Object}, server: http.Server}}

Shares the same signature as express . js listen method because it passes arguments to it


function (socket) {
    if (this.listeners[socket.id]) {
      delete this.listeners[socket.id]
      if (Object.keys(this.listeners).length === 0) {
        this.destroy() // this will delete a liveQuery from liveQueries
      }
    } else {
      return new Error('no listener present on LQ ' + this.qKey)
    }
  }

removes a socket listener from liveQuery and also destroys the whole liveQuery if no more listeners are present
@param socket


function modelInstance(data){
    var self = this;
    // Add any user supplied schema instance methods.
    if(schema){
      _.assign(self, schema.methods);
    }
    Model.call(self, data);
  }


function(assemble, next) {

      grunt.verbose.writeln('Validating options');

      if (utils.endsWithDot(assemble.options.ext)) {
        grunt.warn('Invalid ext "' + assemble.options.ext + '". ext cannot end with a period.');
        done(false);
      }

      // find an engine to use
      assemble.options.engine = assemble.options.engine || 'handlebars';
      grunt.verbose.ok('>> Current engine:'.yellow, assemble.options.engine);

      assemble.engine.load(assemble.options.engine);

      var initializeEngine = function(engine, options) { engine.init(options, { grunt: grunt, assemble: assemble }); };
      assemble.options.initializeEngine = assemble.options.initializeEngine || initializeEngine;

      var registerFunctions = function(engine) { engine.registerFunctions(); };
      assemble.options.registerFunctions = assemble.options.registerFunctions || registerFunctions;

      var registerPartial = function(engine, filename, content) { engine.registerPartial(filename, content); };
      assemble.options.registerPartial = assemble.options.registerPartial || registerPartial;

      assemble.partials = file.expand(assemble.options.partials);

      if (_.isArray(assemble.options.dataFiles) && assemble.options.dataFiles.length > 0) {
        assemble.dataFiles = file.expand(assemble.options.dataFiles);
        //assemble.options.data = {};
      }

      // Expand layout into layoutFiles if a glob pattern is specified
      if (assemble.options.layouts) {
        assemble.layoutFiles = file.expand({filter: 'isFile'}, assemble.options.layouts);
      }

      if (assemble.layoutFiles && assemble.layoutFiles.length !== 0) {
        grunt.verbose.writeln('Found layout files:'.yellow, assemble.layoutFiles);
      } else {
        assemble.layoutFiles = null;
      }

      assemble.options.initializeEngine(assemble.engine, assemble.options);
      assemble.options.registerFunctions(assemble.engine);

      next(assemble);
    }


function(buildDone) {
                // if there is a pages property, build the pages contained therein.
                if (assemble.options.pages) {
                  _.forOwn(assemble.options.pages, function(fileInfo, filename) {
                    if (!filename || filename.length === 0) {
                      grunt.warn('Pages need a filename.');
                      buildDone();
                      return false;
                    }
                    if (!buildPage(filename, fileInfo)) {
                      buildDone();
                      return false;
                    }
                  });
                }
                buildDone();
              }


function crossBrowser(property, value, prefix) {

    function ucase(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }

    var vendor = ['webkit', 'moz', 'ms', 'o'],
      properties = {};

    for (var i = 0; i < vendor.length; i++) {
      if (prefix) {
        value = value.replace(prefix, '-' + vendor[i] + '-' + prefix);
      }
      properties[ucase(vendor[i]) + ucase(property)] = value;
    }
    properties[property] = value;

    return properties;
  }

function crossBrowser ( property , value , prefix ) { function ucase ( string ) { return string . charAt ( 0 ) . toUpperCase ( ) + string . slice ( 1 ) ; } var vendor = [ 'webkit' , 'moz' , 'ms' , 'o' ] , properties = { } ; for ( var i = 0 ; i < vendor . length ; i ++ ) { if ( prefix ) { value = value . replace ( prefix , '-' + vendor [ i ] + '-' + prefix ) ; } properties [ ucase ( vendor [ i ] ) + ucase ( property ) ] = value ; } properties [ property ] = value ; return properties ; }


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		resultObjs[result.callbackId] = result;
		args = JSON.parse(decodeURIComponent(args["input"]));
		vibration.getInstance().vibration_request(result.callbackId, args);
		result.noResult(true);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; resultObjs [ result . callbackId ] = result ; args = JSON . parse ( decodeURIComponent ( args [ "input" ] ) ) ; vibration . getInstance ( ) . vibration_request ( result . callbackId , args ) ; result . noResult ( true ) ; }

These methods call into JNEXT.vibration which handles the communication through the JNEXT plugin to vibration_js.cpp Request vibration function

These methods call into JNEXT . vibration which handles the communication through the JNEXT plugin to vibration_js . cpp Request vibration function


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		resultObjs[result.callbackId] = result;
		readCallback = result.callbackId;
		var views = qnx.webplatform.getWebViews();
		var handle = null;
		var group = null;
		var z = -1;
		for (var i = 0; i < views.length; i++) {
			if (views[i].visible && views[i].zOrder > z){
				z = views[i].zOrder;
				group = views[i].windowGroup;
				handle = views[i].jsScreenWindowHandle;
			}
		}
		if (handle !== null) {
			var values = { group: group, handle: handle };
			result.ok(barcodescanner.getInstance().startRead(result.callbackId, values), true);
		} else {
			result.error("Failed to find window handle", false);
		}
	}

function
(
success
,
fail
,
args
,
env
)
{
var
result
=
new
PluginResult
(
args
,
env
)
;
resultObjs
[
result
.
callbackId
]
=
result
;
readCallback
=
result
.
callbackId
;
var
views
=
qnx
.
webplatform
.
getWebViews
(
)
;
var
handle
=
;
var
group
=
;
var
z
=
1
;
for
(
var
i
=
0
;
i
<
views
.
length
;
i
++
)
{
if
(
views
[
i
]
.
visible
&&
views
[
i
]
.
zOrder
>
z
)
{
z
=
views
[
i
]
.
zOrder
;
group
=
views
[
i
]
.
windowGroup
;
handle
=
views
[
i
]
.
jsScreenWindowHandle
;
}
}
if
(
handle
!==
)
{
var
values
=
{
group
:
group
,
handle
:
handle
}
;
result
.
ok
(
barcodescanner
.
getInstance
(
)
.
startRead
(
result
.
callbackId
,
values
)
,
true
)
;
}
else
{
result
.
error
(
"Failed to find window handle"
,
false
)
;
}
}


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		result.ok(passwordCrypto.getInstance().ping(), false);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; result . ok ( passwordCrypto . getInstance ( ) . ping ( ) , false ) ; }

These methods call into JNEXT.PasswordCrypto which handles the communication through the JNEXT plugin to PasswordCrypto_js.cpp

These methods call into JNEXT . PasswordCrypto which handles the communication through the JNEXT plugin to PasswordCrypto_js . cpp


function(id) {
        console.log('XXXX Received Event: ' + id);
    	$("#btnStartMonitor").prop('disabled', false);
    	$("#btnStopMonitor").prop('disabled', true);

        btLeHandler.initialise();
    }

function
(
id
)
{
console
.
log
(
'XXXX Received Event: '
+
id
)
;
$
(
"#btnStartMonitor"
)
.
prop
(
'disabled'
,
false
)
;
$
(
"#btnStopMonitor"
)
.
prop
(
'disabled'
,
true
)
;
btLeHandler
.
initialise
(
)
;
}


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		args = JSON.parse(decodeURIComponent(args["input"]));
		result.ok(gseCrypto.getInstance().hash(result.callbackId, args), false);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; args = JSON . parse ( decodeURIComponent ( args [ "input" ] ) ) ; result . ok ( gseCrypto . getInstance ( ) . hash ( result . callbackId , args ) , false ) ; }

These methods call into JNEXT.GSECrypto which handles the communication through the JNEXT plugin to gseCrypto_js.cpp

These methods call into JNEXT . GSECrypto which handles the communication through the JNEXT plugin to gseCrypto_js . cpp


function (success, fail, args) {
		args = JSON.parse(decodeURIComponent(args["input"]));
		// look for the UIWebView in the set of WebViews.
		var views = qnx.webplatform.getWebViews();
		var handle = null;
		var z = -1;
		for (var i = 0; i < views.length; i++) {
			if (views[i].visible && views[i].zOrder > z){
				z = views[i].zOrder;
				handle = views[i].jsScreenWindowHandle;
			}
		}
		if (handle !== null) {
			var values = { value: args, handle: handle };
			success(preventsleep.getInstance().setPreventSleep(values));
		} else {
			success("Unable to get window handle");
		}
	}

These methods call into preventsleepJNEXT.js which handles the communication through the JNEXT plugin to preventsleep_js.cpp

These methods call into preventsleepJNEXT . js which handles the communication through the JNEXT plugin to preventsleep_js . cpp


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		result.ok(simpleBtSppPlugin.getInstance().initialiseBluetooth(), false);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; result . ok ( simpleBtSppPlugin . getInstance ( ) . initialiseBluetooth ( ) , false ) ; }

These methods call into JNEXT.SimpleBtSppPlugin which handles the communication through the JNEXT plugin to simplebtsppplugin_js.cpp

These methods call into JNEXT . SimpleBtSppPlugin which handles the communication through the JNEXT plugin to simplebtsppplugin_js . cpp


function (success, fail, args) {
		args = JSON.parse(decodeURIComponent(args["input"]));
		vibration.getInstance().vibration_request(args);
		success();
	}

function ( success , fail , args ) { args = JSON . parse ( decodeURIComponent ( args [ "input" ] ) ) ; vibration . getInstance ( ) . vibration_request ( args ) ; success ( ) ; }

These methods call into vibrationJNEXT.js which handles the communication through the JNEXT plugin to vibration_js.cpp

These methods call into vibrationJNEXT . js which handles the communication through the JNEXT plugin to vibration_js . cpp


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		if (!initialiseBluetoothCallbackId) {
			initialiseBluetoothCallbackId = result.callbackId;
			resultObjs[result.callbackId] = result;
			result.ok(simpleXpBeaconPlugin.getInstance().initialiseBluetooth(result.callbackId), true);
		} else {
			result.error("Initialise Bluetooth failure", false);
		}
	}

function
(
success
,
fail
,
args
,
env
)
{
var
result
=
new
PluginResult
(
args
,
env
)
;
if
(
!
initialiseBluetoothCallbackId
)
{
initialiseBluetoothCallbackId
=
result
.
callbackId
;
resultObjs
[
result
.
callbackId
]
=
result
;
result
.
ok
(
simpleXpBeaconPlugin
.
getInstance
(
)
.
initialiseBluetooth
(
result
.
callbackId
)
,
true
)
;
}
else
{
result
.
error
(
"Initialise Bluetooth failure"
,
false
)
;
}
}

These methods call into JNEXT.SimpleXpBeaconPlugin which handles the communication through the JNEXT plugin to simpleXpbeaconplugin_js.cpp

These methods call into JNEXT . SimpleXpBeaconPlugin which handles the communication through the JNEXT plugin to simpleXpbeaconplugin_js . cpp


function (success, fail, args, env) {
		var result = new PluginResult(args, env);
		args = JSON.parse(decodeURIComponent(args["input"]));
		result.ok(mongoose.getInstance().start(args), false);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; args = JSON . parse ( decodeURIComponent ( args [ "input" ] ) ) ; result . ok ( mongoose . getInstance ( ) . start ( args ) , false ) ; }

These methods call into JNEXT.mongoose which handles the communication through the JNEXT plugin to mongoose_js.cpp

These methods call into JNEXT . mongoose which handles the communication through the JNEXT plugin to mongoose_js . cpp


function (success, fail, args, env) {
                var result = new PluginResult(args, env);
		args = JSON.parse(decodeURIComponent(args["input"]));
		result.ok(uPnP.getInstance().discover(result.callbackId, args), false);
	}

function ( success , fail , args , env ) { var result = new PluginResult ( args , env ) ; args = JSON . parse ( decodeURIComponent ( args [ "input" ] ) ) ; result . ok ( uPnP . getInstance ( ) . discover ( result . callbackId , args ) , false ) ; }

These methods call into JNEXT.UPnP which handles the communication through the JNEXT plugin to upnp_js.cpp

These methods call into JNEXT . UPnP which handles the communication through the JNEXT plugin to upnp_js . cpp


function mkextract (opts) {
  var chunk = null
  var indent = 0
  var number = 0

  opts = merge({}, {
    trim: true,
    dotted_names: false,
    parsers: [
      PARSERS.parse_tag,
      PARSERS.parse_type,
      PARSERS.parse_name,
      PARSERS.parse_description
    ]
  }, opts || {})

  /**
   * Read lines until they make a block
   * Return parsed block once fullfilled or null otherwise
   */
  return function extract (line) {
    var result = null
    var startPos = line.indexOf(MARKER_START)
    var endPos = line.indexOf(MARKER_END)

    // if open marker detected and it's not skip one
    if (startPos !== -1 && line.indexOf(MARKER_START_SKIP) !== startPos) {
      chunk = []
      indent = startPos + MARKER_START.length
    }

    // if we are on middle of comment block
    if (chunk) {
      var lineStart = indent
      var startWithStar = false

      // figure out if we slice from opening marker pos
      // or line start is shifted to the left
      var nonSpaceChar = line.match(/\S/)

      // skip for the first line starting with /** (fresh chunk)
      // it always has the right indentation
      if (chunk.length > 0 && nonSpaceChar) {
        if (nonSpaceChar[0] === '*') {
          lineStart = nonSpaceChar.index + 2
          startWithStar = true
        } else if (nonSpaceChar.index < indent) {
          lineStart = nonSpaceChar.index
        }
      }

      // slice the line until end or until closing marker start
      chunk.push({
        number: number,
        startWithStar: startWithStar,
        source: line.slice(lineStart, endPos === -1 ? line.length : endPos)
      })

      // finalize block if end marker detected
      if (endPos !== -1) {
        result = parse_block(chunk, opts)
        chunk = null
        indent = 0
      }
    }

    number += 1
    return result
  }
}

Produces `extract` function with internal state initialized

Produces extract function with internal state initialized


function tokenize(content) {
    var tokens = [];
    var parser = new htmlparser.Parser({
        onopentag: function(name, attribs) { },
        ontext: function(text) {
            var start = parser.startIndex;

            tokens.push({
                value: text,
                index: start,
                offset: text.length
            });
        },
        onclosetag: function(tagname) { }
    });
    parser.write(content);
    parser.end();

    return tokens;
}

function tokenize ( content ) { var tokens = [ ] ; var parser = new htmlparser . Parser ( { onopentag : function ( name , attribs ) { } , ontext : function ( text ) { var start = parser . startIndex ; tokens . push ( { value : text , index : start , offset : text . length } ) ; } , onclosetag : function ( tagname ) { } } ) ; parser . write ( content ) ; parser . end ( ) ; return tokens ; }

Tokenize some html content to return tokens of text


function tokenizeDefine(infos) {
    return tokenize.split(function(text, tok) {
        var _infos = _.isFunction(infos)? infos.apply(null, arguments) : _.clone(infos);
        if (!_infos) return null;

        // Defaults for the sugegstion
        _infos = _.defaults(_infos, {
            index: 0,
            message: "",
            replacements: []
        });

        _infos = _.extend(tok, _infos);

        _infos.message = _.template(_infos.message)(_infos);

        return _infos;
    });
}

function
tokenizeDefine
(
infos
)
{
return
tokenize
.
split
(
function
(
text
,
tok
)
{
var
_infos
=
_
.
isFunction
(
infos
)
infos
.
apply
(
,
arguments
)
:
_
.
clone
(
infos
)
;
if
(
!
_infos
)
return
;
// Defaults for the sugegstion
_infos
=
_
.
defaults
(
_infos
,
{
index
:
0
,
message
:
""
,
replacements
:
[
]
}
)
;
_infos
=
_
.
extend
(
tok
,
_infos
)
;
_infos
.
message
=
_
.
template
(
_infos
.
message
)
(
_infos
)
;
return
_infos
;
}
)
;
}

Convert a list of tokens to some suggestions


function tokenizeCheck() {
    var fn = tokenize.serie.apply(tokenize, arguments);

    return function(text, opts, callback) {
        try {
            callback(null, fn(text, opts));
        } catch(err) {
            callback(err);
        }
    };
}

function tokenizeCheck ( ) { var fn = tokenize . serie . apply ( tokenize , arguments ) ; return function ( text , opts , callback ) { try { callback ( null , fn ( text , opts ) ) ; } catch ( err ) { callback ( err ) ; } } ; }


function parseFile(input) {
    fileContent = fs.readFileSync(input, { encoding: "utf-8" });
    var ext = path.extname(input);

    if (ext == '.html') return tokenizeHTML(fileContent);

    return fileContent;
}

function parseFile ( input ) { fileContent = fs . readFileSync ( input , { encoding : "utf-8" } ) ; var ext = path . extname ( input ) ; if ( ext == '.html' ) return tokenizeHTML ( fileContent ) ; return fileContent ; }


function softReplace(contentBlock, nativeString, localizedString) {
  var escapedString = ignoreExtraSpaces(
    ignoreEmptyAttrs(
      utils.escapeRegExpSpecialChars(
        nativeString
      )
    )
  );
  var regex = new RegExp('([>"\']\\s*)(' + escapedString + ')(\\s*[<"\'])', 'g');
  return contentBlock.replace(regex, '$1' + localizedString + '$3');
}

function softReplace ( contentBlock , nativeString , localizedString ) { var escapedString = ignoreExtraSpaces ( ignoreEmptyAttrs ( utils . escapeRegExpSpecialChars ( nativeString ) ) ) ; var regex = new RegExp ( '([>"\']\\s*)(' + escapedString + ')(\\s*[<"\'])' , 'g' ) ; return contentBlock . replace ( regex , '$1' + localizedString + '$3' ) ; }

avoids unintentional localization of unrelated strings


function generateNonce(length) {
  return generateSecureRandom(length).then((nonce) => {
    const nonceString = base64js.fromByteArray(nonce);
    return nonceString;
  });
}

function generateNonce ( length ) { return generateSecureRandom ( length ) . then ( ( nonce ) => { const nonceString = base64js . fromByteArray ( nonce ) ; return nonceString ; } ) ; }

Generate the nonce using react-native-securerandom
@method generateNonce
@param  {int} length
@return  {Promise}

Generate the nonce using react - native - securerandom


function _isEqualArray(a, b) {
        if (a === b) {
            return true;
        }
        if ((a === undefined) || (b === undefined)) {
            return false;
        }
        var i = a.length;
        if (i !== b.length){
            return false;
        }
        while (i--) {
            if (a[i] !== b[i]) {
                return false;
            }
        }
        return true;
    }

function _isEqualArray ( a , b ) { if ( a === b ) { return true ; } if ( ( a === undefined ) || ( b === undefined ) ) { return false ; } var i = a . length ; if ( i !== b . length ) { return false ; } while ( i -- ) { if ( a [ i ] !== b [ i ] ) { return false ; } } return true ; }


function _destroyNode(node) {

        // Remove node from linked-list
        if (node._next) {
            node._next._prev = node._prev;
        }
        if (node._prev) {
            node._prev._next = node._next;
        }
        else {
            this._first = node._next;
        }

        // Destroy the node
        node.destroy();

        // Add node to pool
        if (this._pool.layoutNodes.size < MAX_POOL_SIZE) {
            this._pool.layoutNodes.size++;
            node._prev = undefined;
            node._next = this._pool.layoutNodes.first;
            this._pool.layoutNodes.first = node;
        }
    }

function
_destroyNode
(
node
)
{
// Remove node from linked-list
if
(
node
.
_next
)
{
node
.
_next
.
_prev
=
node
.
_prev
;
}
if
(
node
.
_prev
)
{
node
.
_prev
.
_next
=
node
.
_next
;
}
else
{
this
.
_first
=
node
.
_next
;
}
// Destroy the node
node
.
destroy
(
)
;
// Add node to pool
if
(
this
.
_pool
.
layoutNodes
.
size
<
MAX_POOL_SIZE
)
{
this
.
_pool
.
layoutNodes
.
size
++
;
node
.
_prev
=
undefined
;
node
.
_next
=
this
.
_pool
.
layoutNodes
.
first
;
this
.
_pool
.
layoutNodes
.
first
=
node
;
}
}


function _contextNext() {

        // Get the next node from the sequence
        if (!this._contextState.nextSequence) {
            return undefined;
        }
        if (this._context.reverse) {
            this._contextState.nextSequence = this._contextState.nextSequence.getNext();
            if (!this._contextState.nextSequence) {
                return undefined;
            }
        }
        var renderNode = this._contextState.nextSequence.get();
        if (!renderNode) {
            this._contextState.nextSequence = undefined;
            return undefined;
        }
        var nextSequence = this._contextState.nextSequence;
        if (!this._context.reverse) {
            this._contextState.nextSequence = this._contextState.nextSequence.getNext();
        }
        if (this._contextState.lastRenderNode === renderNode) {
          throw 'ViewSequence is corrupted, should never contain the same renderNode twice, index: ' + nextSequence.getIndex();
        }
        this._contextState.lastRenderNode = renderNode;
        return {
            renderNode: renderNode,
            viewSequence: nextSequence,
            next: true,
            index: ++this._contextState.nextGetIndex
        };
    }


function _contextPrev() {

        // Get the previous node from the sequence
        if (!this._contextState.prevSequence) {
            return undefined;
        }
        if (!this._context.reverse) {
            this._contextState.prevSequence = this._contextState.prevSequence.getPrevious();
            if (!this._contextState.prevSequence) {
                return undefined;
            }
        }
        var renderNode = this._contextState.prevSequence.get();
        if (!renderNode) {
            this._contextState.prevSequence = undefined;
            return undefined;
        }
        var prevSequence = this._contextState.prevSequence;
        if (this._context.reverse) {
            this._contextState.prevSequence = this._contextState.prevSequence.getPrevious();
        }
        if (this._contextState.lastRenderNode === renderNode) {
          throw 'ViewSequence is corrupted, should never contain the same renderNode twice, index: ' + prevSequence.getIndex();
        }
        this._contextState.lastRenderNode = renderNode;
        return {
            renderNode: renderNode,
            viewSequence: prevSequence,
            prev: true,
            index: --this._contextState.prevGetIndex
        };
    }


function _contextGet(contextNodeOrId) {
        if (this._nodesById && ((contextNodeOrId instanceof String) || (typeof contextNodeOrId === 'string'))) {
            var renderNode = this._nodesById[contextNodeOrId];
            if (!renderNode) {
                return undefined;
            }

            // Return array
            if (renderNode instanceof Array) {
                var result = [];
                for (var i = 0, j = renderNode.length; i < j; i++) {
                    result.push({
                        renderNode: renderNode[i],
                        arrayElement: true
                    });
                }
                return result;
            }

            // Create context node
            return {
                renderNode: renderNode,
                byId: true
            };
        }
        else {
            return contextNodeOrId;
        }
    }

function
_contextGet
(
contextNodeOrId
)
{
if
(
this
.
_nodesById
&&
(
(
contextNodeOrId
instanceof
String
)
||
(
typeof
contextNodeOrId
===
'string'
)
)
)
{
var
renderNode
=
this
.
_nodesById
[
contextNodeOrId
]
;
if
(
!
renderNode
)
{
return
undefined
;
}
// Return array
if
(
renderNode
instanceof
Array
)
{
var
result
=
[
]
;
for
(
var
i
=
0
,
j
=
renderNode
.
length
;
i
<
j
;
i
++
)
{
result
.
push
(
{
renderNode
:
renderNode
[
i
]
,
arrayElement
:
true
}
)
;
}
return
result
;
}
// Create context node
return
{
renderNode
:
renderNode
,
byId
:
true
}
;
}
else
{
return
contextNodeOrId
;
}
}


function _contextSet(contextNodeOrId, set) {
        var contextNode = this._nodesById ? _contextGet.call(this, contextNodeOrId) : contextNodeOrId;
        if (contextNode) {
            var node = contextNode.node;
            if (!node) {
                if (contextNode.next) {
                     if (contextNode.index < this._contextState.nextSetIndex) {
                        LayoutUtility.error('Nodes must be layed out in the same order as they were requested!');
                     }
                     this._contextState.nextSetIndex = contextNode.index;
                }
                else if (contextNode.prev) {
                     if (contextNode.index > this._contextState.prevSetIndex) {
                        LayoutUtility.error('Nodes must be layed out in the same order as they were requested!');
                     }
                     this._contextState.prevSetIndex = contextNode.index;
                }
                node = _contextGetCreateAndOrderNodes.call(this, contextNode.renderNode, contextNode.prev);
                node._viewSequence = contextNode.viewSequence;
                node._layoutCount++;
                if (node._layoutCount === 1) {
                    this._contextState.addCount++;
                }
                contextNode.node = node;
            }
            node.usesTrueSize = contextNode.usesTrueSize;
            node.trueSizeRequested = contextNode.trueSizeRequested;
            node.set(set, this._context.size);
            contextNode.set = set;
        }
        return set;
    }


function _resolveConfigSize(renderNode) {
        if (renderNode instanceof RenderNode) {
            var result = null;
            var target = renderNode.get();
            if (target) {
                result = _resolveConfigSize(target);
                if (result) {
                    return result;
                }
            }
            if (renderNode._child) {
                return _resolveConfigSize(renderNode._child);
            }
        }
        else if (renderNode instanceof Surface) {
            return renderNode.size ? {
                renderNode: renderNode,
                size: renderNode.size
            } : undefined;
        }
        else if (renderNode.options && renderNode.options.size) {
            return {
                renderNode: renderNode,
                size: renderNode.options.size
            };
        }
        return undefined;
    }

function _resolveConfigSize ( renderNode ) { if ( renderNode instanceof RenderNode ) { var result = null ; var target = renderNode . get ( ) ; if ( target ) { result = _resolveConfigSize ( target ) ; if ( result ) { return result ; } } if ( renderNode . _child ) { return _resolveConfigSize ( renderNode . _child ) ; } } else if ( renderNode instanceof Surface ) { return renderNode . size ? { renderNode : renderNode , size : renderNode . size } : undefined ; } else if ( renderNode . options && renderNode . options . size ) { return { renderNode : renderNode , size : renderNode . options . size } ; } return undefined ; }

Helper function that recursively discovers the configured size for a
given renderNode.

Helper function that recursively discovers the configured size for a given renderNode .


function _getRoundedValue3D(prop, def, precision, lockValue) {
        if (!prop || !prop.init) {
            return def;
        }
        return [
            prop.enabled[0] ? (Math.round((prop.curState.x + ((prop.endState.x - prop.curState.x) * lockValue)) / precision) * precision) : prop.endState.x,
            prop.enabled[1] ? (Math.round((prop.curState.y + ((prop.endState.y - prop.curState.y) * lockValue)) / precision) * precision) : prop.endState.y,
            prop.enabled[2] ? (Math.round((prop.curState.z + ((prop.endState.z - prop.curState.z) * lockValue)) / precision) * precision) : prop.endState.z
        ];
    }

function _getRoundedValue3D ( prop , def , precision , lockValue ) { if ( ! prop || ! prop . init ) { return def ; } return [ prop . enabled [ 0 ] ? ( Math . round ( ( prop . curState . x + ( ( prop . endState . x - prop . curState . x ) * lockValue ) ) / precision ) * precision ) : prop . endState . x , prop . enabled [ 1 ] ? ( Math . round ( ( prop . curState . y + ( ( prop . endState . y - prop . curState . y ) * lockValue ) ) / precision ) * precision ) : prop . endState . y , prop . enabled [ 2 ] ? ( Math . round ( ( prop . curState . z + ( ( prop . endState . z - prop . curState . z ) * lockValue ) ) / precision ) * precision ) : prop . endState . z ] ; }

Helper function for getting the property value.

Helper function for getting the property value .


function _forEachRenderable(callback) {
        if (this._nodesById) {
            for (var key in this._nodesById) {
                callback(this._nodesById[key]);
            }
        }
        else {
            var sequence = this._viewSequence.getHead();
            while (sequence) {
                var renderable = sequence.get();
                if (renderable) {
                    callback(renderable);
                }
                sequence = sequence.getNext();
            }
        }
    }

function _forEachRenderable ( callback ) { if ( this . _nodesById ) { for ( var key in this . _nodesById ) { callback ( this . _nodesById [ key ] ) ; } } else { var sequence = this . _viewSequence . getHead ( ) ; while ( sequence ) { var renderable = sequence . get ( ) ; if ( renderable ) { callback ( renderable ) ; } sequence = sequence . getNext ( ) ; } } }

Helper function to enumerate all the renderables in the datasource


function _getActualDirection(direction) {

        // When the direction is configured in the capabilities, look it up there
        if (this._layout.capabilities && this._layout.capabilities.direction) {

            // Multiple directions are supported
            if (Array.isArray(this._layout.capabilities.direction)) {
                for (var i = 0; i < this._layout.capabilities.direction.length; i++) {
                    if (this._layout.capabilities.direction[i] === direction) {
                        return direction;
                    }
                }
                return this._layout.capabilities.direction[0];
            }

            // Only one direction is supported, we must use that
            else {
                return this._layout.capabilities.direction;
            }
        }

        // Use Y-direction as a fallback
        return (direction === undefined) ? Utility.Direction.Y : direction;
    }

Calculates the actual in-use direction based on the given direction
and supported capabilities of the layout-function.

Calculates the actual in - use direction based on the given direction and supported capabilities of the layout - function .


function _getViewSequenceAtIndex(index, startViewSequence) {
        if (this._viewSequence.getAtIndex) {
            return this._viewSequence.getAtIndex(index, startViewSequence);
        }
        var viewSequence = startViewSequence || this._viewSequence;
        var i = viewSequence ? viewSequence.getIndex() : index;
        if (index > i) {
            while (viewSequence) {
                viewSequence = viewSequence.getNext();
                if (!viewSequence) {
                    return undefined;
                }
                i = viewSequence.getIndex();
                if (i === index) {
                    return viewSequence;
                }
                else if (index < i) {
                    return undefined;
                }
            }
        }
        else if (index < i) {
            while (viewSequence) {
                viewSequence = viewSequence.getPrevious();
                if (!viewSequence) {
                    return undefined;
                }
                i = viewSequence.getIndex();
                if (i === index) {
                    return viewSequence;
                }
                else if (index > i) {
                    return undefined;
                }
            }
        }
        return viewSequence;
    }

function _getViewSequenceAtIndex ( index , startViewSequence ) { if ( this . _viewSequence . getAtIndex ) { return this . _viewSequence . getAtIndex ( index , startViewSequence ) ; } var viewSequence = startViewSequence || this . _viewSequence ; var i = viewSequence ? viewSequence . getIndex ( ) : index ; if ( index > i ) { while ( viewSequence ) { viewSequence = viewSequence . getNext ( ) ; if ( ! viewSequence ) { return undefined ; } i = viewSequence . getIndex ( ) ; if ( i === index ) { return viewSequence ; } else if ( index < i ) { return undefined ; } } } else if ( index < i ) { while ( viewSequence ) { viewSequence = viewSequence . getPrevious ( ) ; if ( ! viewSequence ) { return undefined ; } i = viewSequence . getIndex ( ) ; if ( i === index ) { return viewSequence ; } else if ( index > i ) { return undefined ; } } } return viewSequence ; }

Helper function for finding the view-sequence node at the given position.

Helper function for finding the view - sequence node at the given position .


function _mouseDown(event) {

        // Check whether mouse-scrolling is enabled
        if (!this.options.mouseMove) {
            return;
        }

        // Reset any previous mouse-move operation that has not yet been
        // cleared.
        if (this._scroll.mouseMove) {
            this.releaseScrollForce(this._scroll.mouseMove.delta);
        }

        // Calculate start of move operation
        var current = [event.clientX, event.clientY];
        var time = _getEventTimestamp(event);
        this._scroll.mouseMove = {
            delta: 0,
            start: current,
            current: current,
            prev: current,
            time: time,
            prevTime: time
        };

        // Apply scroll force
        this.applyScrollForce(this._scroll.mouseMove.delta);
    }

Called whenever the user presses the mouse button on the scrollview


function _touchStart(event) {

        // Create touch-end event listener
        if (!this._touchEndEventListener) {
            this._touchEndEventListener = function(event2) {
                event2.target.removeEventListener('touchend', this._touchEndEventListener);
                _touchEnd.call(this, event2);
            }.bind(this);
        }

        // Remove any touches that are no longer active
        var oldTouchesCount = this._scroll.activeTouches.length;
        var i = 0;
        var j;
        var touchFound;
        while (i < this._scroll.activeTouches.length) {
            var activeTouch = this._scroll.activeTouches[i];
            touchFound = false;
            for (j = 0; j < event.touches.length; j++) {
                var touch = event.touches[j];
                if (touch.identifier === activeTouch.id) {
                    touchFound = true;
                    break;
                }
            }
            if (!touchFound) {
                //_log.cal(this, 'removing touch with id: ', activeTouch.id);
                this._scroll.activeTouches.splice(i, 1);
            }
            else {
                i++;
            }
        }

        // Process touch
        for (i = 0; i < event.touches.length; i++) {
            var changedTouch = event.touches[i];
            touchFound = false;
            for (j = 0; j < this._scroll.activeTouches.length; j++) {
                if (this._scroll.activeTouches[j].id === changedTouch.identifier) {
                    touchFound = true;
                    break;
                }
            }
            if (!touchFound) {
                var current = [changedTouch.clientX, changedTouch.clientY];
                var time = _getEventTimestamp(event);
                this._scroll.activeTouches.push({
                    id: changedTouch.identifier,
                    start: current,
                    current: current,
                    prev: current,
                    time: time,
                    prevTime: time
                });

                // The following listener is automatically removed after touchend is received
                // and ensures that the scrollview always received touchend.
                changedTouch.target.addEventListener('touchend', this._touchEndEventListener);
            }
        }

        // The first time a touch new touch gesture has arrived, emit event
        if (!oldTouchesCount && this._scroll.activeTouches.length) {
            this.applyScrollForce(0);
            this._scroll.touchDelta = 0;
        }
    }

Called whenever the user starts moving the scroll-view, using
touch gestures.

Called whenever the user starts moving the scroll - view using touch gestures .


function _touchEnd(event) {

        // Remove touch
        var primaryTouch = this._scroll.activeTouches.length ? this._scroll.activeTouches[0] : undefined;
        for (var i = 0; i < event.changedTouches.length; i++) {
            var changedTouch = event.changedTouches[i];
            for (var j = 0; j < this._scroll.activeTouches.length; j++) {
                var touch = this._scroll.activeTouches[j];
                if (touch.id === changedTouch.identifier) {

                    // Remove touch from active-touches
                    this._scroll.activeTouches.splice(j, 1);

                    // When a different touch now becomes the primary touch, update
                    // its start position to match the current move offset.
                    if ((j === 0) && this._scroll.activeTouches.length) {
                        var newPrimaryTouch = this._scroll.activeTouches[0];
                        newPrimaryTouch.start[0] = newPrimaryTouch.current[0] - (touch.current[0] - touch.start[0]);
                        newPrimaryTouch.start[1] = newPrimaryTouch.current[1] - (touch.current[1] - touch.start[1]);
                    }
                    break;
                }
            }
        }

        // Wait for all fingers to be released from the screen before resetting the move-spring
        if (!primaryTouch || this._scroll.activeTouches.length) {
            return;
        }

        // Determine velocity and add to particle
        var velocity = 0;
        var diffTime = primaryTouch.time - primaryTouch.prevTime;
        if ((diffTime > 0) && ((_getEventTimestamp(event) - primaryTouch.time) <= this.options.touchMoveNoVelocityDuration)) {
            var diffOffset = primaryTouch.current[this._direction] - primaryTouch.prev[this._direction];
            velocity = diffOffset / diffTime;
        }

        // Release scroll force
        var delta = this._scroll.touchDelta;
        var swipeDirection = (Math.abs(primaryTouch.current[0] - primaryTouch.prev[0]) > Math.abs(primaryTouch.current[1] - primaryTouch.prev[1])) ? 0 : 1;
        var allowSwipes = (swipeDirection === this._direction);
        this.releaseScrollForce(delta, velocity, allowSwipes);
        this._scroll.touchDelta = 0;
    }

Called whenever the user releases his fingers and the touch gesture
has completed. This will set the new position and if the user used a 'flick'
gesture give the scroll-offset particle a velocity and momentum into a
certain direction.

Called whenever the user releases his fingers and the touch gesture has completed . This will set the new position and if the user used a flick gesture give the scroll - offset particle a velocity and momentum into a certain direction .


function _scrollUpdate(event) {
        if (!this.options.enabled) {
            return;
        }
        var offset = Array.isArray(event.delta) ? event.delta[this._direction] : event.delta;
        this.scroll(offset);
    }

function _scrollUpdate ( event ) { if ( ! this . options . enabled ) { return ; } var offset = Array . isArray ( event . delta ) ? event . delta [ this . _direction ] : event . delta ; this . scroll ( offset ) ; }

Called whenever the user is scrolling the view using either a mouse
scroll wheel or a track-pad.

Called whenever the user is scrolling the view using either a mouse scroll wheel or a track - pad .


function _setParticle(position, velocity, phase) {
        if (position !== undefined) {
            //var oldPosition = this._scroll.particle.getPosition1D();
            this._scroll.particleValue = position;
            this._scroll.particle.setPosition1D(position);
            //_log.call(this, 'setParticle.position: ', position, ' (old: ', oldPosition, ', delta: ', position - oldPosition, ', phase: ', phase, ')');
            if (this._scroll.springValue !== undefined) {
                this._scroll.pe.wake();
            }
        }
        if (velocity !== undefined) {
            var oldVelocity = this._scroll.particle.getVelocity1D();
            if (oldVelocity !== velocity) {
                this._scroll.particle.setVelocity1D(velocity);
                //_log.call(this, 'setParticle.velocity: ', velocity, ' (old: ', oldVelocity, ', delta: ', velocity - oldVelocity, ', phase: ', phase, ')');
            }
        }
    }


function _calcScrollOffset(normalize, refreshParticle) {

        // When moving using touch-gestures, make the offset stick to the
        // finger. When the bounds is exceeded, decrease the scroll distance
        // by two.
        if (refreshParticle || (this._scroll.particleValue === undefined)) {
            this._scroll.particleValue = this._scroll.particle.getPosition1D();
            this._scroll.particleValue = Math.round(this._scroll.particleValue * 1000) / 1000;
        }

        // do stuff
        var scrollOffset = this._scroll.particleValue;
        if (this._scroll.scrollDelta || this._scroll.normalizedScrollDelta) {
            scrollOffset += this._scroll.scrollDelta + this._scroll.normalizedScrollDelta;
            if (((this._scroll.boundsReached & Bounds.PREV) && (scrollOffset > this._scroll.springPosition)) ||
               ((this._scroll.boundsReached & Bounds.NEXT) && (scrollOffset < this._scroll.springPosition)) ||
               (this._scroll.boundsReached === Bounds.BOTH)) {
                scrollOffset = this._scroll.springPosition;
            }
            if (normalize) {
                if (!this._scroll.scrollDelta) {
                    this._scroll.normalizedScrollDelta = 0;
                    _setParticle.call(this, scrollOffset, undefined, '_calcScrollOffset');
                }
                this._scroll.normalizedScrollDelta += this._scroll.scrollDelta;
                this._scroll.scrollDelta = 0;
            }
        }

        if (this._scroll.scrollForceCount && this._scroll.scrollForce) {
            if (this._scroll.springPosition !== undefined) {
                scrollOffset = (scrollOffset + this._scroll.scrollForce + this._scroll.springPosition) / 2.0;
            }
            else {
                scrollOffset += this._scroll.scrollForce;
            }
        }

        // Prevent the scroll position from exceeding the bounds when overscroll is disabled
        if (!this.options.overscroll) {
            if ((this._scroll.boundsReached === Bounds.BOTH) ||
                ((this._scroll.boundsReached === Bounds.PREV) && (scrollOffset > this._scroll.springPosition)) ||
                ((this._scroll.boundsReached === Bounds.NEXT) && (scrollOffset < this._scroll.springPosition))) {
                scrollOffset = this._scroll.springPosition;
            }
        }

        //_log.call(this, 'scrollOffset: ', scrollOffset, ', particle:', this._scroll.particle.getPosition1D(), ', moveToPosition: ', this._scroll.moveToPosition, ', springPosition: ', this._scroll.springPosition);
        return scrollOffset;
    }


function _snapToPage() {

        // Check whether pagination is active
        if (!this.options.paginated ||
            this._scroll.scrollForceCount || //don't paginate while moving
            (this._scroll.springPosition !== undefined)) {
            return;
        }

        // When the energy is below the thresshold, paginate to the current page
        var item;
        switch (this.options.paginationMode) {
            case PaginationMode.SCROLL:
                if (!this.options.paginationEnergyThreshold || (Math.abs(this._scroll.particle.getEnergy()) <= this.options.paginationEnergyThreshold)) {
                    item = this.options.alignment ? this.getLastVisibleItem() : this.getFirstVisibleItem();
                    if (item && item.renderNode) {
                        this.goToRenderNode(item.renderNode);
                    }
                }
                break;
            case PaginationMode.PAGE:
                item = this.options.alignment ? this.getLastVisibleItem() : this.getFirstVisibleItem();
                if (item && item.renderNode) {
                    this.goToRenderNode(item.renderNode);
                }
                break;
        }
    }

Snaps to a page when pagination is enabled.

Snaps to a page when pagination is enabled .


function _normalizePrevViewSequence(scrollOffset) {
        var count = 0;
        var normalizedScrollOffset = scrollOffset;
        var normalizeNextPrev = false;
        var node = this._nodes.getStartEnumNode(false);
        while (node) {
            if (!node._invalidated || !node._viewSequence) {
                break;
            }
            if (normalizeNextPrev) {
                this._viewSequence = node._viewSequence;
                normalizedScrollOffset = scrollOffset;
                normalizeNextPrev = false;
            }
            if ((node.scrollLength === undefined) || node.trueSizeRequested || (scrollOffset < 0)) {
                break;
            }
            scrollOffset -= node.scrollLength;
            count++;
            if (node.scrollLength) {
                if (this.options.alignment) {
                    normalizeNextPrev = (scrollOffset >= 0);
                }
                else {
                    if (Math.round(scrollOffset) >= 0) {
                        this._viewSequence = node._viewSequence;
                        normalizedScrollOffset = scrollOffset;
                    }
                }
            }
            node = node._prev;
        }
        return normalizedScrollOffset;
    }

function _normalizePrevViewSequence ( scrollOffset ) { var count = 0 ; var normalizedScrollOffset = scrollOffset ; var normalizeNextPrev = false ; var node = this . _nodes . getStartEnumNode ( false ) ; while ( node ) { if ( ! node . _invalidated || ! node . _viewSequence ) { break ; } if ( normalizeNextPrev ) { this . _viewSequence = node . _viewSequence ; normalizedScrollOffset = scrollOffset ; normalizeNextPrev = false ; } if ( ( node . scrollLength === undefined ) || node . trueSizeRequested || ( scrollOffset < 0 ) ) { break ; } scrollOffset -= node . scrollLength ; count ++ ; if ( node . scrollLength ) { if ( this . options . alignment ) { normalizeNextPrev = ( scrollOffset >= 0 ) ; } else { if ( Math . round ( scrollOffset ) >= 0 ) { this . _viewSequence = node . _viewSequence ; normalizedScrollOffset = scrollOffset ; } } } node = node . _prev ; } return normalizedScrollOffset ; }

Normalizes the view-sequence node so that the view-sequence is near to 0.

Normalizes the view - sequence node so that the view - sequence is near to 0 .