Input: Decorate the given WebPage with handlers to produce verbose output . Source : https : // newspaint . wordpress . com / 2013 / 04 / 25 / getting - to - the - bottom - of - why - a - phantomjs - page - load - fails / [CODESPLIT] function verbose ( page ) { page . onResourceError = function ( resourceError ) { system . stderr . writeLine ( '= onResourceError()' ) ; system . stderr . writeLine ( '  - unable to load url: "' + resourceError . url + '"' ) ; system . stderr . writeLine ( '  - error code: ' + resourceError . errorCode + ', description: ' + resourceError . errorString ) ; } ; page . onError = function ( msg , trace ) { system . stderr . writeLine ( '= onError()' ) ; var msgStack = [ '  ERROR: ' + msg ] ; if ( trace ) { msgStack . push ( '  TRACE:' ) ; trace . forEach ( function ( t ) { msgStack . push ( '    -> ' + t . file + ': ' + t . line + ( t . function ? ' (in function "' + t . function + '")' : '' ) ) ; } ) ; } system . stderr . writeLine ( msgStack . join ( '\n' ) ) ; } ; page . onResourceRequested = function ( request ) { system . stderr . writeLine ( '= onResourceRequested()' ) ; system . stderr . writeLine ( '  request: ' + JSON . stringify ( request , undefined , 4 ) ) ; } ; page . onResourceReceived = function ( response ) { system . stderr . writeLine ( '= onResourceReceived()' ) ; system . stderr . writeLine ( '  id: ' + response . id + ', stage: "' + response . stage + '", response: ' + JSON . stringify ( response ) ) ; } ; page . onLoadStarted = function ( ) { system . stderr . writeLine ( '= onLoadStarted()' ) ; var currentUrl = page . evaluate ( function ( ) { return window . location . href ; } ) ; system . stderr . writeLine ( '  leaving url: ' + currentUrl ) ; } ; page . onNavigationRequested = function ( url , type , willNavigate , main ) { system . stderr . writeLine ( '= onNavigationRequested' ) ; system . stderr . writeLine ( '  destination_url: ' + url ) ; system . stderr . writeLine ( '  type (cause): ' + type ) ; system . stderr . writeLine ( '  will navigate: ' + willNavigate ) ; system . stderr . writeLine ( '  from page\'s main frame: ' + main ) ; } ; page . onLoadFinished = function ( status ) { system . stderr . writeLine ( '= onLoadFinished()' ) ; system . stderr . writeLine ( '  status: ' + status ) ; } ; }


Input: create Creates the input generator based on the input string which must match a js file in this directory . So if input === robots then executes require ( . / robots ) ; Unsupported input generator types return a null generator . [CODESPLIT] function ( input ) { var result = { run : function ( ) { return [ ] ; } , __null : true } , hasInput ; if ( input ) { input = ( "" + input ) . replace ( " " , "" ) . toLowerCase ( ) ; hasInput = input && input . charAt ( 0 ) !== '_' && input !== "index" ; } try { if ( hasInput ) { result = require ( "./" + input ) ; } } catch ( e ) { console . error ( "Input generator load failed '" + input + "'" , e ) /* return the "null" generator on error */ } return result ; }


Input: Normalize the given object to a function . [CODESPLIT] function normalize ( obj ) { var result = obj ; if ( typeof obj !== "function" ) { if ( typeof obj !== "undefined" ) { if ( Object . prototype . toString . call ( obj ) !== "[object Object]" ) { result = ( function ( value ) { return function ( ) { return value ; } ; } ( obj ) ) ; } else { result = ( function ( o ) { return function ( key , passthru ) { if ( o [ key ] === void 0 ) { return o . __default || ( passthru ? key : undefined ) ; } else { return o [ key ] ; } } ; } ( obj ) ) ; } } else { result = function ( passthru ) { return passthru ; } ; } } return result ; }


Input: If a normalized option was overriden but a default still undefined supply one . The result could still be undefined but only if the default is undefined . [CODESPLIT] function supplyMissingDefault ( options , name ) { if ( options [ name ] ( ) === void 0 ) { options [ name ] = _ . wrap ( options [ name ] , function ( func , key ) { var res = func ( key ) ; return res === void 0 ? defaults [ name ] : res ; } ) ; } }


Input: Prepare options for use by an input generator . [CODESPLIT] function prepOptions ( options , listener ) { // Ensure defaults are represented common . ensure ( options , defaults ) ; // Normalize certain arguments if they are not functions. // The certain arguments are per-page options. // However, outputPath is a special case [ "selector" , "timeout" , "useJQuery" , "verbose" , "phantomjsOptions" ] . forEach ( function ( perPageOption ) { options [ perPageOption ] = normalize ( options [ perPageOption ] ) ; supplyMissingDefault ( options , perPageOption ) ; } ) ; options . _inputEmitter = new EventEmitter ( ) ; options . _inputEmitter . on ( "input" , listener ) ; }


Input: Get an output path for a page . [CODESPLIT] function getOutputPath ( options , page , parse ) { var pagePart = urlm . parse ( page ) , // if outputPath was normalized with an object, let the key passthru outputPath = options . outputPath ( page , true ) ; // check for bad output path if ( ! outputPath ) { return false ; } // if the outputPath is really still a url, fix it to path+hash if ( common . isUrl ( outputPath ) ) { outputPath = pagePart . path + ( pagePart . hash ? pagePart . hash : "" ) ; } // if the caller wants the url parse output, return it if ( parse ) { parse . url = pagePart ; } return outputPath ; }


Input: Using the options map the given page to an output path . [CODESPLIT] function mapOutputFile ( options , page , parse ) { if ( ! _ . isFunction ( options . outputPath ) ) { options . outputPath = normalize ( options . outputPath ) ; } var outputPath = getOutputPath ( options , page , parse ) ; var outputDir = options . outputDir ; var fileName = "index.html" ; if ( options . sitemapOutputDir ) { outputDir = path . join ( options . outputDir , options . sitemapOutputDir ) ; fileName = "" ; } return ( outputPath && path . join ( outputDir , outputPath , fileName ) ) || false ; }


Input: Run the input generator . [CODESPLIT] function ( options , generator , listener ) { options = options || { } ; prepOptions ( options , listener ) ; return generator ( options ) ; }


Input: Generate the input Emit the event that contains the input hash [CODESPLIT] function ( options , page ) { var parse = { } ; var outputFile = mapOutputFile ( options , page , parse ) ; if ( outputFile ) { options . _inputEmitter . emit ( "input" , { outputFile : outputFile , // make the url url : urlm . format ( { protocol : options . protocol , auth : options . auth , hostname : options . hostname , port : options . port , pathname : parse . url . pathname , search : parse . url . search , hash : parse . url . hash } ) , // map the input page to a selector selector : options . selector ( page ) , // map the input page to a timeout timeout : options . timeout ( page ) , checkInterval : options . checkInterval , // map the input page to a useJQuery flag useJQuery : options . useJQuery ( page ) , // map the input page to a verbose flag verbose : options . verbose ( page ) , // map the input page to phantomJS options phantomjsOptions : options . phantomjsOptions ( page ) , // useful for testing, debugging __page : page } ) ; } return outputFile ; }


Input: Check if a path exists . [CODESPLIT] function pathExists ( path , options ) { options = options || { returnFile : false } ; // Defaults to F_OK return nodeCall ( fs . access , path ) . then ( function ( ) { return options . returnFile ? path : true ; } ) . catch ( function ( ) { if ( fs . existsSync ( path ) ) { return options . returnFile ? path : true ; } return false ; } ) ; }


Input: Determine the default phantomJS module path . This is overridden by the phatomjs option . [CODESPLIT] function ( ) { // If the path we're given by phantomjs is to a .cmd, it is pointing to a global copy. // Using the cmd as the process to execute causes problems cleaning up the processes // so we walk from the cmd to the phantomjs.exe and use that instead. var phantomSource = require ( "phantomjs-prebuilt" ) . path ; if ( path . extname ( phantomSource ) . toLowerCase ( ) === ".cmd" ) { return path . join ( path . dirname ( phantomSource ) , "//node_modules//phantomjs-prebuilt//lib//phantom//bin//phantomjs.exe" ) ; } return phantomSource ; }


Input: The worker task that launches phantomjs . [CODESPLIT] function worker ( input , options , notifier , qcb ) { var cp , customModule , snapshotScript = options . snapshotScript , phantomjsOptions = Array . isArray ( input . phantomjsOptions ) ? input . phantomjsOptions : [ input . phantomjsOptions ] ; // If the outputFile has NOT already been seen by the notifier, process. if ( ! notifier . known ( input . outputFile ) ) { // map snapshotScript object script to a real path if ( _ . isObject ( options . snapshotScript ) ) { snapshotScript = path . join ( __dirname , phantomDir , options . snapshotScript . script ) + ".js" ; customModule = options . snapshotScript . module ; } cp = spawn ( options . phantomjs , phantomjsOptions . concat ( [ snapshotScript , input . outputFile , input . url , input . selector , input . timeout , input . checkInterval , input . useJQuery , input . verbose , customModule ] ) , { cwd : process . cwd ( ) , stdio : "inherit" , detached : true } ) ; cp . on ( "error" , function ( e ) { notifier . remove ( input . outputFile ) ; notifier . setError ( e ) ; console . error ( e ) ; qcb ( e ) ; } ) ; cp . on ( "exit" , function ( code ) { qcb ( code ) ; } ) ; // start counting notifier . add ( input . outputFile , input . timeout ) ; } else { // The input.outputFile is being or has been processed this run. qcb ( 0 ) ; } }


Input: Prepare html snapshots options . [CODESPLIT] function prepOptions ( options ) { // ensure this module's defaults are represented in the options. common . ensure ( options , defaults ) ; // if array data source, ensure input type is "array". if ( Array . isArray ( options . source ) ) { options . input = "array" ; } }


Input: Run all the snapshots using the requested inputGenerator [CODESPLIT] function ( options , listener ) { var inputGenerator , notifier , started , result , q , emitter , completion ; options = options || { } ; prepOptions ( options ) ; // create the inputGenerator, default to robots inputGenerator = inputFactory . create ( options . input ) ; // clean the snapshot output directory if ( options . outputDirClean ) { rimraf ( options . outputDir ) ; } // start async completion notification. notifier = new Notifier ( ) ; emitter = new EventEmitter ( ) ; started = notifier . start ( options . pollInterval , inputGenerator , function ( err , completed ) { emitter . emit ( "complete" , err , completed ) ; } ) ; if ( started ) { // create the completion Promise. completion = new Promise ( function ( resolve , reject ) { function completionResolver ( err , completed ) { try { _ . isFunction ( listener ) && listener ( err , completed ) ; } catch ( e ) { console . error ( "User supplied listener exception" , e ) ; } if ( err ) { err . notCompleted = notifier . filesNotDone ; err . completed = completed ; reject ( err ) ; } else { resolve ( completed ) ; } } emitter . addListener ( "complete" , completionResolver ) ; } ) ; // create a worker queue with a parallel process limit. q = asyncLib . queue ( function ( task , callback ) { task ( _ . once ( callback ) ) ; } , options . processLimit ) ; // have the queue call notifier.empty when last item //  from the queue is given to a worker. q . empty = notifier . qEmpty . bind ( notifier ) ; // expose abort callback to input generators via options. options . _abort = function ( err ) { notifier . abort ( q , err ) ; } ; // generate input for the snapshots. result = inputGenerator . run ( options , function ( input ) { // give the worker the input and place into the queue q . push ( _ . partial ( worker , input , options , notifier ) ) ; } ) // after input generation, resolve on browser completion. . then ( function ( ) { return completion ; } ) ; } else { result = Promise . reject ( "failed to start async notifier" ) ; } return result ; }


Input:
Create the lock factory . [CODESPLIT] function createLockFactory ( ) { // Create the per instance async lock. var lock = new AsyncLock ( ) ; // Make a random id var rid = crypto . randomBytes ( 16 ) . toString ( "hex" ) ; /**
   * Force a serial execution context.
   *
   * @param {Function} fn - The function to guard.
   * @param {Number} timeout - The max time to wait for the lock.
   */ return function lockFactory ( fn , timeout ) { return function protectedContext ( ) { lock . acquire ( "cs-guard-" + rid , function ( done ) { fn ( function ( ) { done ( null , 0 ) ; } ) ; } , NOOP , { timeout : timeout } ) ; } ; } ; }


Input: Notifier Constructor Polls the outputDir and when all the files exist calls the listener indicating the snapshots are done . [CODESPLIT] function Notifier ( ) { // Create the serial execution context mechanism. this . csFactory = createLockFactory ( ) ; // The private files collection // Contains a file and timer: "filename": {timer: timerid} // Used for tracking work left to do. When empty, work is done. this . files = { } ; // Contains files successfully processed this . filesDone = [ ] ; // Contains files unsuccessfully processed this . filesNotDone = [ ] ; // true if a timeout occurred, or set by abort this . errors = [ ] ; // the holder of the current failure timeout padding this . padTimeout = TIMEOUT_PAD_FLOOR ; // our reference to the listener this . callback = null ; // our reference to the watcher (an interval id) // initial value undefined is important // this.watcher; // the working pollInterval for this run // this.interval // flag set by qEmpty callback // when the last item from the queue is given to a worker this . qempty = false ; }


Input: Start a watch interval when a file exists remove it from our files array . If the files array is empty call the listener and stop the watch interval . [CODESPLIT] function start ( pollInterval , input , listener ) { var result = ( pollInterval > 0 && typeof listener === "function" && ( ! ! input ) ) ; if ( result ) { if ( this . isStarted ( ) ) { throw new Error ( "Notifier already started" ) ; } this . callback = listener ; this . interval = parseInt ( pollInterval , 10 ) ; // Poll the filesystem for the files to exist // Checks the child process expected output to determine success or failure // if the file exists, then it succeeded. this . watcher = setInterval ( this . csFactory ( function ( done ) { var self = this ; var eoi = typeof input . EOI === "function" && input . EOI ( ) ; if ( eoi ) { Promise . all ( Object . keys ( self . files ) . map ( function ( file ) { return pathExists ( file , { returnFile : true } ) ; } ) ) . then ( function ( files ) { var callback = self . callback ; try { files . forEach ( function ( file ) { file && self . _remove ( file , true ) ; } ) ; if ( self . _isDone ( ) ) { self . _closeWatcher ( ) ; if ( self . callback ) { self . callback = null ; setImmediate ( function ( ) { callback ( self . getError ( ) , self . filesDone ) ; } ) ; } } } catch ( e ) { console . error ( e ) ; } done ( ) ; } ) ; } else { done ( ) ; } } . bind ( this ) , L_WAIT ) , this . interval ) ; } else { console . error ( "Bad poll interval, async listener, or input generator supplied" ) ; } return result ; }


Input: Add a file to the files array if it s not there . [CODESPLIT] function add ( outputFile , timeout ) { var failTimeout = timeout ; var timer ; if ( ! this . isStarted ( ) ) { throw new Error ( "MUST call `start` before `add`" ) ; } if ( ! this . _exists ( outputFile ) ) { // make sure we evaluate after the child process failTimeout = parseInt ( timeout , 10 ) + parseInt ( this . padTimeout , 10 ) ; // Stagger and grow the failure timeout padding, add 1s every 10 processes this . padTimeout += 100 ; // setup a timeout handler to detect failure timer = setTimeout ( this . csFactory ( function ( done ) { var self = this ; // if the output file has not already been removed if ( self . _exists ( outputFile ) ) { pathExists ( outputFile ) . then ( function ( fsExists ) { var callback = self . callback ; try { if ( ! fsExists ) { self . _setError ( new Error ( "'" + outputFile + "' did not get a snapshot before timeout" ) ) ; } self . _remove ( outputFile , fsExists ) ; if ( self . _isDone ( ) ) { self . _closeWatcher ( ) ; if ( self . callback ) { self . callback = null ; setImmediate ( function ( ) { callback ( self . getError ( ) , self . filesDone ) ; } ) ; } } } catch ( e ) { console . error ( e ) ; } done ( ) ; } ) ; } else { done ( ) ; } } . bind ( this ) , L_WAIT ) , parseInt ( failTimeout , 10 ) ) ; // add the file tracking object this . files [ outputFile ] = { timer : timer } ; } }


Input: Check if a file is being processed or has already been processed . [CODESPLIT] function known ( outputFile ) { var result = false ; this . csFactory ( function ( done ) { result = this . _exists ( outputFile ) || this . filesDone . indexOf ( outputFile ) > - 1 ; done ( ) ; } . bind ( this ) , L_WAIT ) ( ) ; return result ; }


Input: Remove a file from the files array if it s there . Unprotected version . [CODESPLIT] function _remove ( outputFile , done ) { if ( this . _exists ( outputFile ) ) { if ( done ) { this . filesDone . push ( outputFile ) ; } else { this . filesNotDone . push ( outputFile ) ; } clearTimeout ( this . files [ outputFile ] . timer ) ; delete this . files [ outputFile ] ; } }


Input: Remove a file from the files array if it s there . Protected version . [CODESPLIT] function remove ( outputFile , done ) { this . csFactory ( function ( _done ) { this . _remove ( outputFile , done ) ; _done ( ) ; } . bind ( this ) , L_WAIT ) ( ) ; }


Input: Provides a way to abort what this is doing . Causes conditions so that if isStarted the poll interval will exit cleanup and call the listener back . If not started the listener does not get called . This relationship is set in html - snapshots . js : listener == notifier . start [CODESPLIT] function abort ( q , err ) { this . csFactory ( function ( done ) { try { // for each file, clearTimeout and delete the object Object . keys ( this . files ) . forEach ( function ( file ) { clearTimeout ( this . files [ file ] . timer ) ; delete this . files [ file ] ; } , this ) ; // if nothing is waiting, make sure empty is set this . qempty = ! q . length ( ) ; // set the error this . _setError ( err ) ; } catch ( e ) { console . error ( e ) ; } done ( ) ; } . bind ( this ) , L_WAIT ) ( ) ; }


Input: waitFor [CODESPLIT] function waitFor ( testFx , onReady , onTimeout , timeout , checkInterval ) { var condition = false , interval = setInterval ( function ( ) { if ( ( new Date ( ) . getTime ( ) - start < timeout ) && ! condition ) { // If not timeout yet and condition not yet fulfilled condition = testFx ( ) ; } else { clearInterval ( interval ) ; // Stop this interval if ( ! condition ) { // If condition still not fulfilled (timeout but condition is 'false') onTimeout ( ) ; } else { // Condition fulfilled (timeout and/or condition is 'true') onReady ( ( new Date ( ) . getTime ( ) - start ) ) ; } } } , checkInterval ) ; }


Input: snapshot [CODESPLIT] function snapshot ( options , detector , filter ) { filter = filter || function ( content ) { return content ; } ; console . log ( "Creating snapshot for " + options . url + "..." ) ; // https://github.com/ariya/phantomjs/issues/10930 page . customHeaders = { "Accept-Encoding" : "identity" } ; // add optional verbose output if ( options . verbose ) { verbose ( page ) ; } // create the snapshot page . open ( options . url , { resourceTimeout : options . timeout - 300 // a little space to report problems. } , function ( status ) { if ( status !== "success" ) { // if phantomJS could not load the page, so end right now globals . exit ( 2 , "Unable to load page " + options . url ) ; } else { // phantomJS loaded the page, so wait for it to be ready waitFor ( // The test to determine readiness function ( ) { return page . evaluate ( detector , { selector : options . selector , url : options . url } ) ; } , // The onReady callback function ( time ) { fs . write ( options . outputFile , filter ( page . content ) , "w" ) ; globals . exit ( 0 , "snapshot for " + options . url + " finished in " + time + " ms\n  written to " + options . outputFile ) ; } , // The onTimeout callback function ( ) { globals . exit ( 1 , "timed out waiting for " + options . selector + " to become visible for " + options . url ) ; } , options . timeout , options . checkInterval ) ; } } ) ; }


Input: The onReady callback [CODESPLIT] function ( time ) { fs . write ( options . outputFile , filter ( page . content ) , "w" ) ; globals . exit ( 0 , "snapshot for " + options . url + " finished in " + time + " ms\n  written to " + options . outputFile ) ; }


Input: Generate input for one line of a simple robots . txt file Does not support wildcards . [CODESPLIT] function oneline ( line , options ) { var key = "Allow: " , index = line . indexOf ( key ) ; if ( index !== - 1 ) { var page = line . substr ( index + key . length ) . replace ( / ^\s+|\s+$ / g , "" ) ; return page . indexOf ( "*" ) === - 1 && base . input ( options , page ) ; } return true ; }


Input: Retrieves robots . txt from url and parses it . [CODESPLIT] function getRobotsUrl ( options , callback ) { request ( { url : options . source , timeout : options . timeout ( ) } , function ( err , res , body ) { var error = err || common . checkResponse ( res , "text/plain" ) ; if ( error ) { callback ( common . prependMsgToErr ( error , options . source , true ) ) ; } else { body . toString ( ) . split ( '\n' ) . every ( function ( line ) { // Process the line input, but break if base.input returns false. // For now, this can only happen if no outputDir is defined, //   which is a fatal bad option problem and will happen immediately. if ( ! oneline ( line , options ) ) { error = common . prependMsgToErr ( base . generatorError ( ) , line , true ) ; return false ; } return true ; } ) ; callback ( error ) ; } } ) ; }


Input: Reads the robots . txt file and parses it . [CODESPLIT] function getRobotsFile ( options , callback ) { fs . readFile ( options . source , function ( err , data ) { if ( ! err ) { data . toString ( ) . split ( '\n' ) . every ( function ( line ) { // Process the line input, but break if base.input returns false. // For now, this can only happen if no outputDir is defined, //   which is a fatal bad option problem and will happen immediately. if ( ! oneline ( line , options ) ) { err = common . prependMsgToErr ( base . generatorError ( ) , line , true ) ; return false ; } return true ; } ) ; } callback ( err ) ; } ) ; }


Input: Generate the snapshot arguments from a robots . txt file . Each line that has Allow : contains a url we need a snapshot for . This can return true on error for true async . An async error is supplied to listener in this case via _abort . [CODESPLIT] function generateInput ( options ) { return nodeCall ( common . isUrl ( options . source ) ? getRobotsUrl : getRobotsFile , options ) . catch ( function ( err ) { options . _abort ( err ) ; } ) . then ( function ( ) { base . EOI ( robots ) ; } ) ; }


Input: Use plain Web API detection with standard selectors https : // developer . mozilla . org / en - US / docs / Web / Guide / CSS / Getting_Started / Selectors Returns true on element visibility [CODESPLIT] function ( options ) { var result = false ; var el = document . querySelector ( options . selector ) ; if ( el ) { // el must be an HTMLElement that is visible result = el . offsetWidth && el . offsetHeight ; } return result ; }


Input: Bubbles up values that do not nest to the furthest key . [CODESPLIT] function bubble ( values ) { return values . map ( d => { if ( d . key && d . values ) { if ( d . values [ 0 ] . key === "undefined" ) return d . values [ 0 ] . values [ 0 ] ; else d . values = bubble ( d . values ) ; } return d ; } ) ; }


Input: exclude b from a and return remainder cidrs [CODESPLIT] function exclude ( a , b , v ) { const aStart = a . start ( { type : "bigInteger" } ) ; const bStart = b . start ( { type : "bigInteger" } ) ; const aEnd = a . end ( { type : "bigInteger" } ) ; const bEnd = b . end ( { type : "bigInteger" } ) ; const parts = [ ] ; // compareTo returns negative if left is less than right //       aaa //   bbb //   aaa //       bbb if ( aStart . compareTo ( bEnd ) > 0 || aEnd . compareTo ( bStart ) < 0 ) { return [ a . cidr ] ; } //   aaa //   bbb if ( aStart . compareTo ( bStart ) === 0 && aEnd . compareTo ( bEnd ) === 0 ) { return [ ] ; } //   aa //  bbbb if ( aStart . compareTo ( bStart ) > 0 && aEnd . compareTo ( bEnd ) < 0 ) { return [ ] ; } // aaaa //   bbbb // aaaa //   bb if ( aStart . compareTo ( bStart ) < 0 && aEnd . compareTo ( bEnd ) <= 0 ) { parts . push ( { start : aStart , end : bStart . subtract ( one ) , } ) ; } //    aaa //   bbb //   aaaa //   bbb if ( aStart . compareTo ( bStart ) >= 0 && aEnd . compareTo ( bEnd ) > 0 ) { parts . push ( { start : bEnd . add ( one ) , end : aEnd , } ) ; } //  aaaa //   bb if ( aStart . compareTo ( bStart ) < 0 && aEnd . compareTo ( bEnd ) > 0 ) { parts . push ( { start : aStart , end : bStart . subtract ( one ) , } ) ; parts . push ( { start : bEnd . add ( one ) , end : aEnd , } ) ; } const remaining = [ ] ; for ( const part of parts ) { for ( const subpart of subparts ( part , v ) ) { remaining . push ( formatPart ( subpart , v ) ) ; } } return cidrTools . merge ( remaining ) ; }


Input: heart beat [CODESPLIT] function heartBeat ( ) { var isEmpty = true ; //process event queue var eventChanges = false ; for ( var device_id in eventQueue ) { if ( eventQueue [ device_id ] . length > 0 ) { eventChanges = true ; if ( eventQueue [ device_id ] . length <= conf . max_events ) { self . add_request ( { device_id : device_id , events : eventQueue [ device_id ] } ) ; eventQueue [ device_id ] = [ ] ; } else { var events = eventQueue [ device_id ] . splice ( 0 , conf . max_events ) ; self . add_request ( { device_id : device_id , events : events } ) ; } } } if ( eventChanges ) { isEmpty = false ; storeSet ( "cly_bulk_event" , eventQueue ) ; } //process request queue into bulk requests if ( requestQueue . length > 0 ) { isEmpty = false ; if ( requestQueue . length <= conf . bulk_size ) { toBulkRequestQueue ( { app_key : conf . app_key , requests : JSON . stringify ( requestQueue ) } ) ; requestQueue = [ ] ; } else { var requests = requestQueue . splice ( 0 , conf . bulk_size ) ; toBulkRequestQueue ( { app_key : conf . app_key , requests : JSON . stringify ( requests ) } ) ; } storeSet ( "cly_req_queue" , requestQueue ) ; } //process bulk request queue if ( bulkQueue . length > 0 && readyToProcess && getTimestamp ( ) > failTimeout ) { isEmpty = false ; readyToProcess = false ; var params = bulkQueue . shift ( ) ; log ( "Processing request" , params ) ; makeRequest ( params , function ( err , params ) { log ( "Request Finished" , params , err ) ; if ( err ) { bulkQueue . unshift ( params ) ; failTimeout = getTimestamp ( ) + conf . fail_timeout ; } storeSet ( "cly_bulk_queue" , bulkQueue ) ; readyToProcess = true ; } ) ; } if ( isEmpty ) { empty_count ++ ; if ( empty_count === 3 ) { empty_count = 0 ; if ( empty_queue_callback ) { empty_queue_callback ( ) ; } } } if ( initiated ) { setTimeout ( heartBeat , conf . interval ) ; } }


Input: log stuff [CODESPLIT] function log ( ) { if ( conf . debug && typeof console !== "undefined" ) { if ( arguments [ 1 ] && typeof arguments [ 1 ] === "object" ) { arguments [ 1 ] = JSON . stringify ( arguments [ 1 ] ) ; } console . log ( Array . prototype . slice . call ( arguments ) . join ( "\n" ) ) ; } }


Input: get unique timestamp in miliseconds [CODESPLIT] function getMsTimestamp ( ) { var ts = new Date ( ) . getTime ( ) ; if ( lastMsTs >= ts ) { lastMsTs ++ ; } else { lastMsTs = ts ; } return lastMsTs ; }


Input: parsing host and port information from url [CODESPLIT] function parseUrl ( url ) { var serverOptions = { host : "localhost" , port : 80 } ; if ( url . indexOf ( "https" ) === 0 ) { serverOptions . port = 443 ; } var host = url . split ( "://" ) . pop ( ) ; serverOptions . host = host ; var lastPos = host . indexOf ( ":" ) ; if ( lastPos > - 1 ) { serverOptions . host = host . slice ( 0 , lastPos ) ; serverOptions . port = Number ( host . slice ( lastPos + 1 , host . length ) ) ; } return serverOptions ; }


Input: convert JSON object to query params [CODESPLIT] function prepareParams ( params ) { var str = [ ] ; for ( var i in params ) { str . push ( i + "=" + encodeURIComponent ( params [ i ] ) ) ; } return str . join ( "&" ) ; }


Input: removing trailing slashes [CODESPLIT] function stripTrailingSlash ( str ) { if ( str . substr ( str . length - 1 ) === "/" ) { return str . substr ( 0 , str . length - 1 ) ; } return str ; }


Input: retrieve only specific properties from object [CODESPLIT] function getProperties ( orig , props ) { var ob = { } ; var prop ; for ( var i = 0 ; i < props . length ; i ++ ) { prop = props [ i ] ; if ( typeof orig [ prop ] !== "undefined" ) { ob [ prop ] = orig [ prop ] ; } } return ob ; }


Input: internal method for events in case there is no consent for custom events but internal events has consents [CODESPLIT] function add_cly_events ( event ) { if ( ! event . key ) { log ( "Event must have key property" ) ; return ; } if ( cluster . isMaster ) { if ( ! event . count ) { event . count = 1 ; } var props = [ "key" , "count" , "sum" , "dur" , "segmentation" ] ; var e = getProperties ( event , props ) ; e . timestamp = getMsTimestamp ( ) ; var date = new Date ( ) ; e . hour = date . getHours ( ) ; e . dow = date . getDay ( ) ; log ( "Adding event: " , event ) ; eventQueue . push ( e ) ; storeSet ( "cly_event" , eventQueue ) ; } else { process . send ( { cly : { event : event } } ) ; } }


Input: PRIVATE METHODS [CODESPLIT] function reportViewDuration ( ) { if ( lastView ) { if ( ! platform ) { getMetrics ( ) ; } var segments = { "name" : lastView , "segment" : platform } ; //track pageview if ( Countly . check_consent ( "views" ) ) { add_cly_events ( { "key" : "[CLY]_view" , "dur" : getTimestamp ( ) - lastViewTime , "segmentation" : segments } ) ; } lastView = null ; } }


Input: prepare request by adding basic info to it [CODESPLIT] function prepareRequest ( request ) { request . app_key = Countly . app_key ; request . device_id = Countly . device_id ; request . sdk_name = SDK_NAME ; request . sdk_version = SDK_VERSION ; if ( Countly . check_consent ( "location" ) ) { if ( Countly . country_code ) { request . country_code = Countly . country_code ; } if ( Countly . city ) { request . city = Countly . city ; } if ( Countly . ip_address !== null ) { request . ip_address = Countly . ip_address ; } } else { request . location = "" ; } request . timestamp = getMsTimestamp ( ) ; var date = new Date ( ) ; request . hour = date . getHours ( ) ; request . dow = date . getDay ( ) ; }


Input: insert request to queue [CODESPLIT] function toRequestQueue ( request ) { if ( cluster . isMaster ) { if ( ! Countly . app_key || ! Countly . device_id ) { log ( "app_key or device_id is missing" ) ; return ; } prepareRequest ( request ) ; if ( requestQueue . length > queueSize ) { requestQueue . shift ( ) ; } requestQueue . push ( request ) ; storeSet ( "cly_queue" , requestQueue ) ; } else { process . send ( { cly : { cly_queue : request } } ) ; } }


Input: heart beat [CODESPLIT] function heartBeat ( ) { //extend session if needed if ( sessionStarted && autoExtend && trackTime ) { var last = getTimestamp ( ) ; if ( last - lastBeat > sessionUpdate ) { Countly . session_duration ( last - lastBeat ) ; lastBeat = last ; } } //process event queue if ( eventQueue . length > 0 ) { if ( eventQueue . length <= maxEventBatch ) { toRequestQueue ( { events : JSON . stringify ( eventQueue ) } ) ; eventQueue = [ ] ; } else { var events = eventQueue . splice ( 0 , maxEventBatch ) ; toRequestQueue ( { events : JSON . stringify ( events ) } ) ; } storeSet ( "cly_event" , eventQueue ) ; } //process request queue with event queue if ( requestQueue . length > 0 && readyToProcess && getTimestamp ( ) > failTimeout ) { readyToProcess = false ; var params = requestQueue . shift ( ) ; //check if any consent to sync if ( Object . keys ( syncConsents ) . length ) { if ( consentTimer ) { clearTimeout ( consentTimer ) ; consentTimer = null ; } params . consent = JSON . stringify ( syncConsents ) ; syncConsents = { } ; } log ( "Processing request" , params ) ; makeRequest ( Countly . url , apiPath , params , function ( err , params ) { log ( "Request Finished" , params , err ) ; if ( err ) { requestQueue . unshift ( params ) ; failTimeout = getTimestamp ( ) + failTimeoutAmount ; } storeSet ( "cly_queue" , requestQueue ) ; readyToProcess = true ; } ) ; } setTimeout ( heartBeat , beatInterval ) ; }


Input: get metrics of the browser [CODESPLIT] function getMetrics ( ) { var m = JSON . parse ( JSON . stringify ( metrics ) ) ; //getting app version m . _app_version = m . _app_version || Countly . app_version ; m . _os = m . _os || os . type ( ) ; m . _os_version = m . _os_version || os . release ( ) ; platform = os . type ( ) ; log ( "Got metrics" , m ) ; return m ; }


Input: sending HTTP request [CODESPLIT] function makeRequest ( url , path , params , callback ) { try { log ( "Sending HTTP request" ) ; var serverOptions = parseUrl ( url ) ; var data = prepareParams ( params ) ; var method = "GET" ; var options = { host : serverOptions . host , port : serverOptions . port , path : path + "?" + data , method : "GET" } ; if ( data . length >= 2000 ) { method = "POST" ; } else if ( Countly . force_post ) { method = "POST" ; } if ( method === "POST" ) { options . method = "POST" ; options . path = path ; options . headers = { "Content-Type" : "application/x-www-form-urlencoded" , "Content-Length" : Buffer . byteLength ( data ) } ; } var protocol = http ; if ( url . indexOf ( "https" ) === 0 ) { protocol = https ; } var req = protocol . request ( options , function ( res ) { var str = "" ; res . on ( "data" , function ( chunk ) { str += chunk ; } ) ; res . on ( "end" , function ( ) { if ( res . statusCode >= 200 && res . statusCode < 300 ) { callback ( false , params , str ) ; } else { callback ( true , params ) ; } } ) ; } ) ; if ( method === "POST" ) { // write data to request body req . write ( data ) ; } req . on ( "error" , function ( err ) { log ( "Connection failed." , err ) ; if ( typeof callback === "function" ) { callback ( true , params ) ; } } ) ; req . end ( ) ; } catch ( e ) { // fallback log ( "Failed HTTP request" , e ) ; if ( typeof callback === "function" ) { callback ( true , params ) ; } } }


Input: Creates a promise that is resolved when all input promises have been settled . The returned Promise is resolved with an array of Promise . Inspection objects . [CODESPLIT] function allSettled ( promises ) { "use strict" ; const wrappedPromises = promises . map ( ( curPromise ) => curPromise . reflect ( ) ) ; return Promise . all ( wrappedPromises ) ; }


Input: Check if there’s no word before index . [CODESPLIT] function firstWord ( parent , index ) { var siblings = parent . children while ( index -- ) { if ( is ( 'WordNode' , siblings [ index ] ) ) { return false } } return true }


Input: Get the next word . [CODESPLIT] function after ( parent , index ) { var siblings = parent . children var sibling = siblings [ ++ index ] var other if ( is ( 'WhiteSpaceNode' , sibling ) ) { sibling = siblings [ ++ index ] if ( is ( 'PunctuationNode' , sibling ) && punctuation . test ( toString ( sibling ) ) ) { sibling = siblings [ ++ index ] } if ( is ( 'WordNode' , sibling ) ) { other = sibling } } return other }


Input: Classify a word . [CODESPLIT] function classify ( value ) { var type = null var normal value = value . replace ( digits , toWords ) . split ( split , 1 ) [ 0 ] normal = lower ( value ) if ( requiresA ( value ) ) { type = 'a' } if ( requiresAn ( value ) ) { type = type === 'a' ? 'a-or-an' : 'an' } if ( ! type && normal === value ) { type = vowel . test ( normal . charAt ( 0 ) ) ? 'an' : 'a' } return type }


Input: Create a test based on a list of phrases . [CODESPLIT] function factory ( list ) { var expressions = [ ] var sensitive = [ ] var insensitive = [ ] construct ( ) return test function construct ( ) { var length = list . length var index = - 1 var value var normal while ( ++ index < length ) { value = list [ index ] normal = value === lower ( value ) if ( value . charAt ( value . length - 1 ) === '*' ) { // Regexes are insensitive now, once we need them this should check for // `normal` as well. expressions . push ( new RegExp ( '^' + value . slice ( 0 , - 1 ) , 'i' ) ) } else if ( normal ) { insensitive . push ( value ) } else { sensitive . push ( value ) } } } function test ( value ) { var normal = lower ( value ) var length var index if ( sensitive . indexOf ( value ) !== - 1 || insensitive . indexOf ( normal ) !== - 1 ) { return true } length = expressions . length index = - 1 while ( ++ index < length ) { if ( expressions [ index ] . test ( value ) ) { return true } } return false } }


Input: bind collections controllers dbctrl - db controller forcerebind - if <code > true< / code > force rebind all collection controllers otherwise check added / deleted collections [CODESPLIT] function ( dbctrl , forcerebind ) { var octrls = forcerebind ? [ ] : cchistory ; var nctrls = [ ] ; var dbMeta = cdb . jb . getDBMeta ( ) ; if ( dbMeta && dbMeta . collections ) { for ( var j = 0 ; j < dbMeta . collections . length ; ++ j ) { var collection = dbMeta . collections [ j ] ; var ci ; if ( ( ci = octrls . indexOf ( collection . name ) ) != - 1 ) { nctrls . push ( collection . name ) ; octrls . splice ( ci , 1 ) ; } else if ( ! dbctrl [ collection . name ] ) { nctrls . push ( collection . name ) ; dbctrl [ collection . name ] = colctl ( dbctrl , collection . name ) ; } } } for ( var i = 0 ; i < octrls . length ; ++ i ) { delete dbctrl [ octrls [ i ] ] ; } // save current known collections cchistory = nctrls ; }


Input: collection controller ( creation function ) [CODESPLIT] function ( db , cname ) { // build arguments function: add <cname> as first argument var buildargs = function ( args ) { var result = [ cname ] ; // args is Object, we need to iterate all fields with numeric key for collecting arguments for ( var i = 0 ; args [ i ] ; ++ i ) { result . push ( args [ i ] ) ; } return result ; } ; // method names for creating aliases (db.<method>(cname, ...) -> db.cname.<method>(...)) var mnames = [ "save" , "load" , "remove" , "find" , "findOne" , "update" , "count" , "dropCollection" , "dropIndexes" , "optimizeIndexes" , "ensureStringIndex" , "rebuildStringIndex" , "dropStringIndex" , "ensureIStringIndex" , "rebuildIStringIndex" , "dropIStringIndex" , "ensureNumberIndex" , "rebuildNumberIndex" , "dropNumberIndex" , "ensureArrayIndex" , "rebuildArrayIndex" , "dropArrayIndex" ] ; // bind method alias var mbind = function ( mname ) { return function ( ) { return db [ mname ] . apply ( db , buildargs ( arguments ) ) ; } } ; // collection controller impl var colctlimpl = { inspect : function ( ) { return '\u001b[' + 36 + 'm' + "[Collection]" + '\u001b[' + 39 + 'm' ; } } ; var mname ; // wrap methods for ( var i = 0 ; i < mnames . length ; ++ i ) { mname = mnames [ i ] ; colctlimpl [ mname ] = mbind ( mname ) ; if ( helpGetters [ mname ] ) { Object . defineProperty ( colctlimpl [ mname ] , '_help_' , { value : helpGetters [ mname ] ( true ) } ) ; } } return colctlimpl }


Input: build arguments function : add <cname > as first argument [CODESPLIT] function ( args ) { var result = [ cname ] ; // args is Object, we need to iterate all fields with numeric key for collecting arguments for ( var i = 0 ; args [ i ] ; ++ i ) { result . push ( args [ i ] ) ; } return result ; }


Input: db - db controller mname - method name frc - force rebind collections controllers . if <code > false< / code > db meta will be reloaded only if method executes on unknown collection . argl - arguments count ( for register callback as last argument ) [CODESPLIT] function ( db , mname , frc ) { return function ( ) { var cname = arguments [ 0 ] ; var args = [ cname ] ; // copy all arguments except first and last for ( var i = 1 ; i < arguments . length - 1 ; ++ i ) { args . push ( arguments [ i ] ) ; } // creating callback with collection rebuilding var ccb = function ( rcb ) { return function ( ) { if ( frc || ! db [ cname ] ) { bindColCtls ( db ) ; } if ( rcb ) { rcb . apply ( this , arguments ) ; } } } ; if ( arguments . length > 1 ) { if ( typeof arguments [ arguments . length - 1 ] === 'function' ) { // wrap existing callback args . push ( ccb ( arguments [ arguments . length - 1 ] ) ) ; } else { // adding registering callback after last argument args . push ( arguments [ arguments . length - 1 ] ) ; args . push ( ccb ( ) ) ; } } else { args . push ( ccb ( ) ) ; } return cdb . jb [ mname ] . apply ( cdb . jb , args ) ; } }


Input: creating callback with collection rebuilding [CODESPLIT] function ( rcb ) { return function ( ) { if ( frc || ! db [ cname ] ) { bindColCtls ( db ) ; } if ( rcb ) { rcb . apply ( this , arguments ) ; } } }


Input: The nodejs database wrapper . [CODESPLIT] function ( ) { Object . defineProperty ( this , "_impl" , { value : new EJDBImpl ( ) , configurable : false , enumerable : false , writable : false } ) ; return this ; }


Input: / * - ( cname [ cb ] ) - ( cname qobj [ cb ] ) - ( cname qobj hints [ cb ] ) - ( cname qobj qobjarr [ cb ] ) - ( cname qobj qobjarr hints [ cb ] ) [CODESPLIT] function parseQueryArgs ( args ) { var cname , qobj , orarr , hints , cb ; var i = 0 ; cname = args [ i ++ ] ; if ( typeof cname !== "string" ) { throw new Error ( "Collection name 'cname' argument must be specified" ) ; } var next = args [ i ++ ] ; if ( typeof next === "function" ) { cb = next ; } else { qobj = next ; } next = args [ i ++ ] ; if ( next !== undefined ) { if ( Array . isArray ( next ) ) { orarr = next ; next = args [ i ++ ] ; } else if ( typeof next === "object" ) { hints = next ; orarr = null ; next = args [ i ++ ] ; } if ( ! hints && typeof next === "object" ) { hints = next ; next = args [ i ++ ] ; } if ( typeof next === "function" ) { cb = next ; } } return [ cname , ( qobj || { } ) , ( orarr || [ ] ) , ( hints || { } ) , ( cb || null ) ] ; }


Input: used to start at 0 each time . [CODESPLIT] function dummyText ( opts ) { var corpus = opts . corpus || 'lorem' , i = opts . start , isRandom = typeof ( i ) === 'undefined' , mustReset = typeof ( origin ) === 'undefined' , skip = opts . skip || 1 , sentences = opts . sentences || 1 , words = opts . words , text = texts [ corpus ] || texts . lorem , len = text . length , output = [ ] , s ; if ( isRandom ) { i = Math . floor ( Math . random ( ) * len ) ; } if ( mustReset ) { origin = i ; } if ( isRandom ) { // possible modulo of a negative number, so take care here. i = ( ( i + len - origin ) % len + len ) % len ; } while ( sentences -- ) { s = text [ i ] ; if ( words ) { s = s . split ( ' ' ) . slice ( 0 , words ) . join ( ' ' ) ; } output . push ( s ) ; i = ( i + skip ) % len ; } return output . join ( ' ' ) ; }


Input: Takes a set of reconnect options defined in README [CODESPLIT] function Back ( options ) { if ( ! ( this instanceof Back ) ) { return new Back ( options ) ; } this . settings = extend ( options ) ; this . reconnect = null ; }


Input:
### setup Called when a Map constructor is defined / extended to perform any initialization behavior for the new constructor function . [CODESPLIT] function ( baseMap ) { Construct . setup . apply ( this , arguments ) ; // A cached list of computed properties on the prototype. this . _computedPropertyNames = [ ] ; // Do not run if we are defining can.Map. if ( Map ) { addTypeEvents ( this ) ; this [ canSymbol . for ( "can.defineInstanceKey" ) ] = function ( prop , definition ) { if ( definition . value !== undefined ) { this . defaults [ prop ] = definition . value ; } if ( definition . enumerable === false ) { this . enumerable [ prop ] = false ; } } ; // Provide warnings if can.Map is used incorrectly. //!steal-remove-start if ( process . env . NODE_ENV !== 'production' ) { if ( this . prototype . define && ! mapHelpers . define ) { dev . warn ( "can/map/define is not included, yet there is a define property " + "used. You may want to add this plugin." ) ; } if ( this . define && ! mapHelpers . define ) { dev . warn ( "The define property should be on the map's prototype properties, " + "not the static properties. Also, can/map/define is not included." ) ; } } //!steal-remove-end // Create a placeholder for default values. if ( ! this . defaults ) { this . defaults = { } ; } if ( ! this . enumerable ) { this . enumerable = { } ; } // Go through everything on the prototype.  If it's a primitive, // treat it as a default value.  If it's a compute, identify it so // it can be setup as a computed property. for ( var prop in this . prototype ) { if ( prop !== "define" && prop !== "constructor" && ( typeof this . prototype [ prop ] !== "function" || this . prototype [ prop ] . prototype instanceof Construct ) ) { this . defaults [ prop ] = this . prototype [ prop ] ; } else if ( canReflect . isObservableLike ( this . prototype [ prop ] ) ) { this . _computedPropertyNames . push ( prop ) ; } } // If define is a function, call it with this can.Map if ( mapHelpers . define ) { mapHelpers . define ( this , baseMap . prototype . define ) ; } } // If we inherit from can.Map, but not can.List, create a can.List that // creates instances of this Map type. // This is something List should weave in. /*if (can.List && !(this.prototype instanceof can.List)) {
				this.List = Map.List.extend({
					Map: this
				}, {});
			}*/ }


Input: ### setup Initializes the map instance s behavior . [CODESPLIT] function ( obj ) { if ( canReflect . isObservableLike ( obj ) && typeof obj . serialize === "function" ) { obj = obj . serialize ( ) ; } // Where we keep the values of the compute. this . _data = Object . create ( null ) ; // The namespace this `object` uses to listen to events. CID ( this , ".map" ) ; this . _setupComputedProperties ( ) ; var teardownMapping = obj && mapHelpers . addToMap ( obj , this ) ; var defaultValues = this . _setupDefaults ( obj ) ; var data = assign ( canReflect . assignDeep ( { } , defaultValues ) , obj ) ; this . attr ( data ) ; if ( teardownMapping ) { teardownMapping ( ) ; } }


Input: ### _setupComputes Sets up computed properties on a Map . Stores information for each computed property on this . _computedAttrs that looks like : { // the number of bindings on this property count : 1 // a handler that forwards events on the compute // to the map instance handler : handler compute : compute // the compute } [CODESPLIT] function ( ) { this . _computedAttrs = Object . create ( null ) ; var computes = this . constructor . _computedPropertyNames ; for ( var i = 0 , len = computes . length ; i < len ; i ++ ) { var attrName = computes [ i ] ; mapHelpers . addComputedAttr ( this , attrName , this [ attrName ] ) ; } }


Input: ### attr The primary get / set interface for can . Map . Calls _get _set or _attrs depending on how it is called . [CODESPLIT] function ( attr , val ) { var type = typeof attr ; if ( attr === undefined ) { return this . _getAttrs ( ) ; } else if ( type !== "string" && type !== "number" ) { // Get or set multiple attributes. return this . _setAttrs ( attr , val ) ; } else if ( arguments . length === 1 ) { // Get a single attribute. return this . _get ( attr ) ; } else { // Set an attribute. this . _set ( attr + "" , val ) ; return this ; } }


Input: ### _get Handles reading nested properties like foo . bar by getting the value of foo and recursively calling _get for the value of bar . To read the actual values _get calls ___get . [CODESPLIT] function ( attr ) { attr = attr + "" ; var dotIndex = attr . indexOf ( '.' ) ; if ( dotIndex >= 0 ) { // Attempt to get the value anyway in case // somone wrote `new can.Map({"foo.bar": 1})`. var value = this . ___get ( attr ) ; if ( value !== undefined ) { ObservationRecorder . add ( this , attr ) ; return value ; } var first = attr . substr ( 0 , dotIndex ) , second = attr . substr ( dotIndex + 1 ) ; var current = this . __get ( first ) ; return current && canReflect . getKeyValue ( current , second ) ; } else { return this . __get ( attr ) ; } }


Input: ### __get Signals can . compute that an observable property is being read . [CODESPLIT] function ( attr ) { if ( ! unobservable [ attr ] && ! this . _computedAttrs [ attr ] ) { ObservationRecorder . add ( this , attr ) ; } return this . ___get ( attr ) ; }


Input: ### ___get When called with an argument returns the value of this property . If that property is represented by a computed attribute return the value of that compute . If no argument is provided return the raw data . [CODESPLIT] function ( attr ) { if ( attr !== undefined ) { var computedAttr = this . _computedAttrs [ attr ] ; if ( computedAttr ) { // return computedAttr.compute(); return canReflect . getValue ( computedAttr . compute ) ; } else { return hasOwnProperty . call ( this . _data , attr ) ? this . _data [ attr ] : undefined ; } } else { return this . _data ; } }


Input: ### _set Handles setting nested properties by finding the nested observable and recursively calling _set on it . Eventually it calls __set with the __type converted value to set and the current value . The current value is passed for two reasons : - so __set can trigger an event if the value has changed . - for advanced setting behavior that define . set can do . If the map is initializing the current value does not need to be read because no change events are dispatched anyway . [CODESPLIT] function ( attr , value , keepKey ) { attr = attr + "" ; var dotIndex = attr . indexOf ( '.' ) , current ; if ( dotIndex >= 0 && ! keepKey ) { var first = attr . substr ( 0 , dotIndex ) , second = attr . substr ( dotIndex + 1 ) ; current = this [ inSetupSymbol ] ? undefined : this . ___get ( first ) ; if ( canReflect . isMapLike ( current ) ) { canReflect . setKeyValue ( current , second , value ) ; } else { current = this [ inSetupSymbol ] ? undefined : this . ___get ( attr ) ; // //Convert if there is a converter.  Remove in 3.0. if ( this . __convert ) { value = this . __convert ( attr , value ) ; } this . __set ( attr , this . __type ( value , attr ) , current ) ; } } else { current = this [ inSetupSymbol ] ? undefined : this . ___get ( attr ) ; // //Convert if there is a converter.  Remove in 3.0. if ( this . __convert ) { value = this . __convert ( attr , value ) ; } this . __set ( attr , this . __type ( value , attr ) , current ) ; } }


Input: ## __type Converts set values to another type . By default this converts Objects to can . Maps and Arrays to can . Lists . This also makes it so if a plain JavaScript object has already been converted to a list or map that same list or map instance is used . [CODESPLIT] function ( value , prop ) { if ( typeof value === "object" && ! canReflect . isObservableLike ( value ) && mapHelpers . canMakeObserve ( value ) && ! canReflect . isListLike ( value ) ) { var cached = mapHelpers . getMapFromObject ( value ) ; if ( cached ) { return cached ; } var MapConstructor = this . constructor . Map || Map ; return new MapConstructor ( value ) ; } return value ; }


Input: ## __set Handles firing events if the value has changed and works with the bubble helpers to setup bubbling . Calls ___set to do the actual setting . [CODESPLIT] function ( prop , value , current ) { if ( value !== current || ! Object . prototype . hasOwnProperty . call ( this . _data , prop ) ) { var computedAttr = this . _computedAttrs [ prop ] ; // Dispatch an "add" event if adding a new property. var changeType = computedAttr || current !== undefined || hasOwnProperty . call ( this . ___get ( ) , prop ) ? "set" : "add" ; // Set the value on `_data` and set up bubbling. this . ___set ( prop , typeof value === "object" ? bubble . set ( this , prop , value , current ) : value ) ; // Computed properties change events are already forwarded except if // no one is listening to them. if ( ! computedAttr || ! computedAttr . count ) { this . _triggerChange ( prop , changeType , value , current ) ; } // Stop bubbling old nested maps. if ( typeof current === "object" ) { bubble . teardownFromParent ( this , current ) ; } } }


Input: ### ___set Directly saves the set value as a property on _data or sets the computed attribute . [CODESPLIT] function ( prop , val ) { var computedAttr = this . _computedAttrs [ prop ] ; if ( computedAttr ) { canReflect . setValue ( computedAttr . compute , val ) ; } else { this . _data [ prop ] = val ; } // Adds the property directly to the map instance. But first, // checks that it's not overwriting a method. This should be removed // in 3.0. if ( typeof this . constructor . prototype [ prop ] !== 'function' && ! computedAttr ) { this [ prop ] = val ; } }


Input: ### _remove Handles removing nested observes . [CODESPLIT] function ( attr ) { // If this is List. var parts = mapHelpers . attrParts ( attr ) , // The actual property to remove. prop = parts . shift ( ) , // The current value. current = this . ___get ( prop ) ; // If we have more parts, call `removeAttr` on that part. if ( parts . length && current ) { return canReflect . deleteKeyValue ( current , parts . join ( "." ) ) ; } else { // If attr does not have a `.` if ( typeof attr === 'string' && ! ! ~ attr . indexOf ( '.' ) ) { prop = attr ; } this . __remove ( prop , current ) ; return current ; } }


Input: ### __remove Handles triggering an event if a property could be removed . [CODESPLIT] function ( prop , current ) { if ( prop in this . _data ) { this . ___remove ( prop ) ; // Let others now this property has been removed. this . _triggerChange ( prop , "remove" , undefined , current ) ; } }


Input: ### ___serialize Serializes a property . Uses map helpers to recursively serialize nested observables . [CODESPLIT] function ( name , val ) { if ( this . _legacyAttrBehavior ) { return mapHelpers . getValue ( this , name , val , "serialize" ) ; } else { return canReflect . serialize ( val , CIDMap ) ; } }


Input: ### _setAttrs Sets multiple properties on this object at once . First goes through all current properties and either merges or removes old properties . Then it goes through the remaining ones to be added and sets those properties . [CODESPLIT] function ( props , remove ) { if ( this . _legacyAttrBehavior ) { return this . __setAttrs ( props , remove ) ; } if ( remove === true || remove === "true" ) { this [ canSymbol . for ( "can.updateDeep" ) ] ( props ) ; } else { this [ canSymbol . for ( "can.assignDeep" ) ] ( props ) ; } return this ; }


Input: ### _triggerChange A helper function used to trigger events on this map . If the map is bubbling this will fire a change event . Otherwise it only fires a named event . Triggers a __keys event if a property has been added or removed . [CODESPLIT] function ( attr , how , newVal , oldVal , batchNum ) { canQueues . batch . start ( ) ; if ( bubble . isBubbling ( this , "change" ) ) { canEvent . dispatch . call ( this , { type : "change" , target : this , batchNum : batchNum } , [ attr , how , newVal , oldVal ] ) ; } canEvent . dispatch . call ( this , { type : attr , target : this , batchNum : batchNum , patches : [ { type : "set" , key : attr , value : newVal } ] } , [ newVal , oldVal ] ) ; if ( how === "remove" || how === "add" ) { canEvent . dispatch . call ( this , { type : "__keys" , target : this , batchNum : batchNum } ) ; } canQueues . batch . stop ( ) ; }


Input: ### compute Creates a compute that represents a value on this map . If the property is a function on the prototype a function compute wil be created . Otherwise a compute will be created that reads the observable attributes [CODESPLIT] function ( prop ) { if ( typeof this . constructor . prototype [ prop ] === "function" ) { return canCompute ( this [ prop ] , this ) ; } else { var reads = ObserveReader . reads ( prop ) ; var last = reads . length - 1 ; return canCompute ( function ( newVal ) { if ( arguments . length ) { ObserveReader . write ( this , reads [ last ] . key , newVal , { } ) ; } else { return ObserveReader . get ( this , prop ) ; } } , this ) ; } }


Input: ### each loops through all the key - value pairs on this map . [CODESPLIT] function ( callback , context ) { var key , item ; var keys = canReflect . getOwnEnumerableKeys ( this ) ; for ( var i = 0 , len = keys . length ; i < len ; i ++ ) { key = keys [ i ] ; item = this . attr ( key ) ; if ( callback . call ( context || item , item , key , this ) === false ) { break ; } } return this ; }


Input: ### _each Iterator that does not trigger live binding . [CODESPLIT] function ( callback ) { var data = this . ___get ( ) ; for ( var prop in data ) { if ( hasOwnProperty . call ( data , prop ) ) { callback ( data [ prop ] , prop ) ; } } }


Input: - shape [CODESPLIT] function ( ) { if ( ! this [ inSetupSymbol ] ) { ObservationRecorder . add ( this , '__keys' ) ; } var enumerable = this . constructor . enumerable ; if ( enumerable ) { return Object . keys ( this . _data ) . filter ( function ( key ) { return enumerable [ key ] !== false ; } , this ) ; } else { return Object . keys ( this . _data ) ; } }


Input: - shape get / set - [CODESPLIT] function ( source ) { canQueues . batch . start ( ) ; // TODO: we should probably just throw an error instead of cleaning canReflect . assignDeepMap ( this , mapHelpers . removeSpecialKeys ( canReflect . assignMap ( { } , source ) ) ) ; canQueues . batch . stop ( ) ; }


Input: observable [CODESPLIT] function ( key , handler , queue ) { var translationHandler = function ( ev , newValue , oldValue ) { handler . call ( this , newValue , oldValue ) ; } ; singleReference . set ( handler , this , translationHandler , key ) ; this . addEventListener ( key , translationHandler , queue ) ; }


Input: See https : // github . com / broofa / node - uuid for API details [CODESPLIT] function v1 ( options , buf , offset ) { var i = buf && offset || 0 ; var b = buf || [ ] ; options = options || { } ; var clockseq = options . clockseq !== undefined ? options . clockseq : _clockseq ; // UUID timestamps are 100 nano-second units since the Gregorian epoch, // (1582-10-15 00:00).  JSNumbers aren't precise enough for this, so // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. var msecs = options . msecs !== undefined ? options . msecs : new Date ( ) . getTime ( ) ; // Per 4.2.1.2, use count of uuid's generated during the current clock // cycle to simulate higher resolution clock var nsecs = options . nsecs !== undefined ? options . nsecs : _lastNSecs + 1 ; // Time since last uuid creation (in msecs) var dt = ( msecs - _lastMSecs ) + ( nsecs - _lastNSecs ) / 10000 ; // Per 4.2.1.2, Bump clockseq on clock regression if ( dt < 0 && options . clockseq === undefined ) { clockseq = clockseq + 1 & 0x3fff ; } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new // time interval if ( ( dt < 0 || msecs > _lastMSecs ) && options . nsecs === undefined ) { nsecs = 0 ; } // Per 4.2.1.2 Throw error if too many uuids are requested if ( nsecs >= 10000 ) { throw new Error ( 'uuid.v1(): Can\'t create more than 10M uuids/sec' ) ; } _lastMSecs = msecs ; _lastNSecs = nsecs ; _clockseq = clockseq ; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch msecs += 12219292800000 ; // `time_low` var tl = ( ( msecs & 0xfffffff ) * 10000 + nsecs ) % 0x100000000 ; b [ i ++ ] = tl >>> 24 & 0xff ; b [ i ++ ] = tl >>> 16 & 0xff ; b [ i ++ ] = tl >>> 8 & 0xff ; b [ i ++ ] = tl & 0xff ; // `time_mid` var tmh = ( msecs / 0x100000000 * 10000 ) & 0xfffffff ; b [ i ++ ] = tmh >>> 8 & 0xff ; b [ i ++ ] = tmh & 0xff ; // `time_high_and_version` b [ i ++ ] = tmh >>> 24 & 0xf | 0x10 ; // include version b [ i ++ ] = tmh >>> 16 & 0xff ; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) b [ i ++ ] = clockseq >>> 8 | 0x80 ; // `clock_seq_low` b [ i ++ ] = clockseq & 0xff ; // `node` var node = options . node || _nodeId ; for ( var n = 0 ; n < 6 ; n ++ ) { b [ i + n ] = node [ n ] ; } return buf ? buf : unparse ( b ) ; }


Input: Create css build function [CODESPLIT] function css ( files , output , options ) { options = Object . assign ( { banner : false } , options ) ; return ( ) => { var build = gulp . src ( files ) if ( options . banner ) build = build . pipe ( $ . header ( banner , { pkg } ) ) ; build = build . pipe ( $ . rename ( 'd3.compose.css' ) ) . pipe ( gulp . dest ( output ) ) ; return build ; } ; }


Input: Approximate gulp 4 . 0 series [CODESPLIT] function series ( ) { const tasks = Array . prototype . slice . call ( arguments ) ; var fn = cb => cb ( ) ; if ( typeof tasks [ tasks . length - 1 ] === 'function' ) fn = tasks . pop ( ) ; return ( cb ) => { const tasks_with_cb = tasks . concat ( [ ( err ) => { if ( err ) return cb ( err ) ; fn ( cb ) ; } ] ) ; runSequence . apply ( this , tasks_with_cb ) ; } }


Input: Placeholder until formal constraints / layouts are added [CODESPLIT] function toSurround ( description ) { if ( ! Array . isArray ( description ) ) { description = [ layered ( description ) ] ; } var positions = extractSurroundPositions ( description ) ; var top = positions . top ; var right = positions . right ; var bottom = positions . bottom ; var left = positions . left ; var middle = positions . middle ; var container = { _id : '_container' } ; var topEdge = top [ top . length - 1 ] && constraint . eq ( top [ top . length - 1 ] , 'bottom' ) || 0 ; var rightEdge = right [ 0 ] && constraint . eq ( right [ 0 ] , 'left' ) || constraint . eq ( container , 'right' ) ; var bottomEdge = bottom [ 0 ] && constraint . eq ( bottom [ 0 ] , 'top' ) || constraint . eq ( container , 'bottom' ) ; var leftEdge = left [ left . length - 1 ] && constraint . eq ( left [ left . length - 1 ] , 'right' ) || 0 ; top = top . map ( function ( item , i , items ) { var layout = { _position : 'top' , top : items [ i - 1 ] && constraint . eq ( items [ i - 1 ] , 'bottom' ) || 0 , left : leftEdge , right : rightEdge , width : constraint . flex ( ) } ; item = assign ( { } , item ) ; item . props = assign ( layout , item . props ) ; return item ; } ) ; right = right . map ( function ( item , i , items ) { var layout = { _position : 'right' , right : items [ i + 1 ] && constraint . eq ( items [ i + 1 ] , 'left' ) || constraint . eq ( container , 'right' ) , top : topEdge , bottom : bottomEdge , height : constraint . flex ( ) } ; item = assign ( { } , item ) ; item . props = assign ( layout , item . props ) ; return item ; } ) ; bottom = bottom . map ( function ( item , i , items ) { var layout = { _position : 'bottom' , bottom : items [ i + 1 ] && constraint . eq ( items [ i + 1 ] , 'top' ) || constraint . eq ( container , 'bottom' ) , left : leftEdge , right : rightEdge , width : constraint . flex ( ) } ; item = assign ( { } , item ) ; item . props = assign ( layout , item . props ) ; return item ; } ) ; left = left . map ( function ( item , i , items ) { var layout = { _position : 'left' , left : items [ i - 1 ] && constraint . eq ( items [ i - 1 ] , 'right' ) || 0 , top : topEdge , bottom : bottomEdge , height : constraint . flex ( ) } ; item = assign ( { } , item ) ; item . props = assign ( layout , item . props ) ; return item ; } ) ; middle = middle . map ( function ( item ) { var layout = { _position : 'middle' , top : topEdge , right : rightEdge , bottom : bottomEdge , left : leftEdge , width : constraint . flex ( ) , height : constraint . flex ( ) } ; item = assign ( { } , item ) ; item . props = assign ( layout , item . props ) ; return item ; } ) ; var allItems = top . concat ( left ) . concat ( middle ) . concat ( right ) . concat ( bottom ) ; var byId = { } ; var ordered = [ ] ; allItems . forEach ( function ( item ) { byId [ item . _id ] = item ; ordered . push ( item . _id ) ; } ) ; return { byId : byId , ordered : ordered } ; }


Input: This sync function for Couchbase Sync Gateway was generated by synctos : https : // github . com / Kashoo / synctos [CODESPLIT] function synctos ( doc , oldDoc ) { // Whether the given value is either null or undefined function isValueNullOrUndefined ( value ) { return value === void 0 || value === null ; } // Whether the given document is missing/nonexistant (i.e. null or undefined) or deleted (its "_deleted" property is true) function isDocumentMissingOrDeleted ( candidate ) { return isValueNullOrUndefined ( candidate ) || candidate . _deleted ; } // A property validator that is suitable for use on type identifier properties. Ensures the value is a string, is neither null nor // undefined, is not an empty string and cannot be modified. var typeIdValidator = { type : 'string' , required : true , mustNotBeEmpty : true , immutable : true } ; // A type filter that matches on the document's type property function simpleTypeFilter ( doc , oldDoc , candidateDocType ) { if ( oldDoc ) { if ( doc . _deleted ) { return oldDoc . type === candidateDocType ; } else { return doc . type === oldDoc . type && oldDoc . type === candidateDocType ; } } else { return doc . type === candidateDocType ; } } // Retrieves the old doc's effective value. If it is null, undefined or its "_deleted" property is true, returns null. Otherwise, returns // the value of the "oldDoc" parameter. function resolveOldDoc ( ) { return ! isDocumentMissingOrDeleted ( oldDoc ) ? oldDoc : null ; } // Add the specified padding to the right of the given string value until its length matches the desired length function padRight ( value , desiredLength , padding ) { while ( value . length < desiredLength ) { value += padding ; } return value ; } // Determine if a given value is an integer. Exists because Number.isInteger is not supported by Sync Gateway's JavaScript engine. function isValueAnInteger ( value ) { return typeof value === 'number' && isFinite ( value ) && Math . floor ( value ) === value ; } // Retrieves the effective value of a top-level document constraint (e.g. "channels", "documentIdRegexPattern", "accessAssignments") function resolveDocumentConstraint ( constraintDefinition ) { if ( typeof constraintDefinition === 'function' ) { return constraintDefinition ( doc , resolveOldDoc ( ) ) ; } else { return constraintDefinition ; } } // Converts a given value to a JSON string. Exists because JSON.stringify is not supported by all versions of Sync // Gateway's JavaScript engine. var jsonStringify = ( typeof JSON !== 'undefined' && JSON . stringify ) ? JSON . stringify : importSyncFunctionFragment ( 'json-stringify-module.js' ) ; var utils = { isDocumentMissingOrDeleted : isDocumentMissingOrDeleted , isValueAnInteger : isValueAnInteger , isValueNullOrUndefined : isValueNullOrUndefined , jsonStringify : jsonStringify , padRight : padRight , resolveOldDoc : resolveOldDoc , resolveDocumentConstraint : resolveDocumentConstraint } ; // The document authorization module is responsible for verifying the user's permissions (e.g. roles, channels) var authorizationModule = importSyncFunctionFragment ( './authorization-module.js' ) ( utils ) ; // The document validation module is responsible for verifying the document's contents var validationModule = importSyncFunctionFragment ( './validation-module.js' ) ( utils , simpleTypeFilter , typeIdValidator ) ; // The access assignment module is responsible for dynamically assigning channels and roles to users var accessAssignmentModule = importSyncFunctionFragment ( './access-assignment-module.js' ) ( utils ) ; // The expiry module is responsible for controlling when the document will expire and be purged from the DB var expiryModule = importSyncFunctionFragment ( './expiry-module.js' ) ( utils ) ; var rawDocDefinitions = $DOCUMENT_DEFINITIONS_PLACEHOLDER$ ; var docDefinitions ; if ( typeof rawDocDefinitions === 'function' ) { docDefinitions = rawDocDefinitions ( ) ; } else { docDefinitions = rawDocDefinitions ; } function getDocumentType ( ) { var effectiveOldDoc = resolveOldDoc ( ) ; for ( var docType in docDefinitions ) { var docDefn = docDefinitions [ docType ] ; if ( docDefn . typeFilter ( doc , effectiveOldDoc , docType ) ) { return docType ; } } // The document type does not exist return null ; } // Now put the pieces together var theDocType = getDocumentType ( ) ; if ( isValueNullOrUndefined ( theDocType ) ) { if ( doc . _deleted ) { // Attempting to delete a document whose type is unknown. This may occur when bucket access/sharing // (https://developer.couchbase.com/documentation/mobile/current/guides/sync-gateway/shared-bucket-access.html) // is enabled and the document was deleted via the Couchbase SDK or if the document belongs to a type that existed // in a previous version of the document definitions but has since been removed. Verify that the user has // administrator access and then simply assign the public channel // (https://developer.couchbase.com/documentation/mobile/current/guides/sync-gateway/channels/index.html#special-channels) // to the document so that other users will get a 404 Not Found if they attempt to fetch (i.e. "view") the deleted // document rather than a 403 Forbidden. requireAccess ( [ ] ) ; // This test can only be satisfied via the admin API channel ( '!' ) ; return ; } else { var errorMessage = 'Unknown document type' ; var error = new Error ( errorMessage ) ; error . forbidden = errorMessage ; throw error ; } } var theDocDefinition = docDefinitions [ theDocType ] ; var customActionMetadata = { documentTypeId : theDocType , documentDefinition : theDocDefinition } ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onTypeIdentificationSucceeded === 'function' ) { theDocDefinition . customActions . onTypeIdentificationSucceeded ( doc , oldDoc , customActionMetadata ) ; } customActionMetadata . authorization = authorizationModule . authorize ( doc , oldDoc , theDocDefinition ) ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onAuthorizationSucceeded === 'function' ) { theDocDefinition . customActions . onAuthorizationSucceeded ( doc , oldDoc , customActionMetadata ) ; } validationModule . validateDoc ( doc , oldDoc , theDocDefinition , theDocType ) ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onValidationSucceeded === 'function' ) { theDocDefinition . customActions . onValidationSucceeded ( doc , oldDoc , customActionMetadata ) ; } if ( theDocDefinition . accessAssignments && ! doc . _deleted ) { var accessAssignments = accessAssignmentModule . assignUserAccess ( doc , oldDoc , theDocDefinition ) ; if ( accessAssignments . length > 0 ) { customActionMetadata . accessAssignments = accessAssignments ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onAccessAssignmentsSucceeded === 'function' ) { theDocDefinition . customActions . onAccessAssignmentsSucceeded ( doc , oldDoc , customActionMetadata ) ; } } } if ( ! isValueNullOrUndefined ( theDocDefinition . expiry ) && ! doc . _deleted ) { customActionMetadata . expiryDate = expiryModule . setDocExpiry ( doc , oldDoc , theDocDefinition . expiry ) ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onExpiryAssignmentSucceeded === 'function' ) { theDocDefinition . customActions . onExpiryAssignmentSucceeded ( doc , oldDoc , customActionMetadata ) ; } } // Getting here means the document revision is authorized and valid, and the appropriate channel(s) should now be assigned var allDocChannels = authorizationModule . getAllDocChannels ( theDocDefinition ) ; channel ( allDocChannels ) ; customActionMetadata . documentChannels = allDocChannels ; if ( theDocDefinition . customActions && typeof theDocDefinition . customActions . onDocumentChannelAssignmentSucceeded === 'function' ) { theDocDefinition . customActions . onDocumentChannelAssignmentSucceeded ( doc , oldDoc , customActionMetadata ) ; } }


Input: A type filter that matches on the document s type property [CODESPLIT] function simpleTypeFilter ( doc , oldDoc , candidateDocType ) { if ( oldDoc ) { if ( doc . _deleted ) { return oldDoc . type === candidateDocType ; } else { return doc . type === oldDoc . type && oldDoc . type === candidateDocType ; } } else { return doc . type === candidateDocType ; } }


Input: Add the specified padding to the right of the given string value until its length matches the desired length [CODESPLIT] function padRight ( value , desiredLength , padding ) { while ( value . length < desiredLength ) { value += padding ; } return value ; }


Input: Transforms the given item or items into a new list of items with the specified prefix ( if any ) appended to each element [CODESPLIT] function resolveCollectionItems ( originalItems , itemPrefix ) { if ( utils . isValueNullOrUndefined ( originalItems ) ) { return [ ] ; } else if ( Array . isArray ( originalItems ) ) { var resultItems = [ ] ; for ( var i = 0 ; i < originalItems . length ; i ++ ) { var item = originalItems [ i ] ; if ( utils . isValueNullOrUndefined ( item ) ) { continue ; } resultItems . push ( prefixItem ( item , itemPrefix ) ) ; } return resultItems ; } else { // Represents a single item return [ prefixItem ( originalItems , itemPrefix ) ] ; } }


Input: Transforms the given collection definition which may have been defined as a single item a list of items or a function that returns a list of items into a simple list where each item has the specified prefix if any [CODESPLIT] function resolveCollectionDefinition ( doc , oldDoc , collectionDefinition , itemPrefix ) { if ( utils . isValueNullOrUndefined ( collectionDefinition ) ) { return [ ] ; } else { if ( typeof collectionDefinition === 'function' ) { var fnResults = collectionDefinition ( doc , oldDoc ) ; return resolveCollectionItems ( fnResults , itemPrefix ) ; } else { return resolveCollectionItems ( collectionDefinition , itemPrefix ) ; } } }


Input: Assigns channel access to users / roles [CODESPLIT] function assignChannelsToUsersAndRoles ( doc , oldDoc , accessAssignmentDefinition ) { var usersAndRoles = [ ] ; var users = resolveCollectionDefinition ( doc , oldDoc , accessAssignmentDefinition . users ) ; for ( var userIndex = 0 ; userIndex < users . length ; userIndex ++ ) { usersAndRoles . push ( users [ userIndex ] ) ; } var roles = resolveRoleCollectionDefinition ( doc , oldDoc , accessAssignmentDefinition . roles ) ; for ( var roleIndex = 0 ; roleIndex < roles . length ; roleIndex ++ ) { usersAndRoles . push ( roles [ roleIndex ] ) ; } var channels = resolveCollectionDefinition ( doc , oldDoc , accessAssignmentDefinition . channels ) ; access ( usersAndRoles , channels ) ; return { type : 'channel' , usersAndRoles : usersAndRoles , channels : channels } ; }


Input: Assigns role access to users [CODESPLIT] function assignRolesToUsers ( doc , oldDoc , accessAssignmentDefinition ) { var users = resolveCollectionDefinition ( doc , oldDoc , accessAssignmentDefinition . users ) ; var roles = resolveRoleCollectionDefinition ( doc , oldDoc , accessAssignmentDefinition . roles ) ; role ( users , roles ) ; return { type : 'role' , users : users , roles : roles } ; }


Input: Assigns role access to users and / or channel access to users / roles according to the given access assignment definitions [CODESPLIT] function assignUserAccess ( doc , oldDoc , documentDefinition ) { var effectiveOldDoc = utils . resolveOldDoc ( ) ; var accessAssignmentDefinitions = resolveAccessAssignmentsDefinition ( doc , effectiveOldDoc , documentDefinition . accessAssignments ) ; var effectiveAssignments = [ ] ; for ( var assignmentIndex = 0 ; assignmentIndex < accessAssignmentDefinitions . length ; assignmentIndex ++ ) { var definition = accessAssignmentDefinitions [ assignmentIndex ] ; if ( definition . type === 'role' ) { effectiveAssignments . push ( assignRolesToUsers ( doc , effectiveOldDoc , definition ) ) ; } else if ( definition . type === 'channel' || utils . isValueNullOrUndefined ( definition . type ) ) { effectiveAssignments . push ( assignChannelsToUsersAndRoles ( doc , effectiveOldDoc , definition ) ) ; } } return effectiveAssignments ; }


Input: A document definition may define its authorizations ( channels roles or users ) for each operation type ( view add replace delete or write ) as either a string or an array of strings . In either case add them to the list if they are not already present . [CODESPLIT] function appendToAuthorizationList ( allAuthorizations , authorizationsToAdd ) { if ( ! utils . isValueNullOrUndefined ( authorizationsToAdd ) ) { if ( Array . isArray ( authorizationsToAdd ) ) { for ( var i = 0 ; i < authorizationsToAdd . length ; i ++ ) { var authorization = authorizationsToAdd [ i ] ; if ( allAuthorizations . indexOf ( authorization ) < 0 ) { allAuthorizations . push ( authorization ) ; } } } else if ( allAuthorizations . indexOf ( authorizationsToAdd ) < 0 ) { allAuthorizations . push ( authorizationsToAdd ) ; } } }


Input: Retrieves a list of channels the document belongs to based on its specified type [CODESPLIT] function getAllDocChannels ( docDefinition ) { var docChannelMap = utils . resolveDocumentConstraint ( docDefinition . channels ) ; var allChannels = [ ] ; if ( docChannelMap ) { appendToAuthorizationList ( allChannels , docChannelMap . view ) ; appendToAuthorizationList ( allChannels , docChannelMap . write ) ; appendToAuthorizationList ( allChannels , docChannelMap . add ) ; appendToAuthorizationList ( allChannels , docChannelMap . replace ) ; appendToAuthorizationList ( allChannels , docChannelMap . remove ) ; } return allChannels ; }


Input: Retrieves a list of authorizations ( e . g . channels roles users ) for the current document write operation type ( add replace or remove ) [CODESPLIT] function getRequiredAuthorizations ( doc , oldDoc , authorizationDefinition ) { var authorizationMap = utils . resolveDocumentConstraint ( authorizationDefinition ) ; if ( utils . isValueNullOrUndefined ( authorizationMap ) ) { // This document type does not define any authorizations (channels, roles, users) at all return null ; } var requiredAuthorizations = [ ] ; var writeAuthorizationFound = false ; if ( authorizationMap . write ) { writeAuthorizationFound = true ; appendToAuthorizationList ( requiredAuthorizations , authorizationMap . write ) ; } if ( doc . _deleted ) { if ( authorizationMap . remove ) { writeAuthorizationFound = true ; appendToAuthorizationList ( requiredAuthorizations , authorizationMap . remove ) ; } } else if ( ! utils . isDocumentMissingOrDeleted ( oldDoc ) && authorizationMap . replace ) { writeAuthorizationFound = true ; appendToAuthorizationList ( requiredAuthorizations , authorizationMap . replace ) ; } else if ( utils . isDocumentMissingOrDeleted ( oldDoc ) && authorizationMap . add ) { writeAuthorizationFound = true ; appendToAuthorizationList ( requiredAuthorizations , authorizationMap . add ) ; } if ( writeAuthorizationFound ) { return requiredAuthorizations ; } else { // This document type does not define any authorizations (channels, roles, users) that apply to this particular write operation type return null ; } }


Input: Ensures the user is authorized to create / replace / delete this document [CODESPLIT] function authorize ( doc , oldDoc , docDefinition ) { var authorizedChannels = getRequiredAuthorizations ( doc , oldDoc , docDefinition . channels ) ; var authorizedRoles = getRequiredAuthorizations ( doc , oldDoc , docDefinition . authorizedRoles ) ; var authorizedUsers = getRequiredAuthorizations ( doc , oldDoc , docDefinition . authorizedUsers ) ; var channelMatch = false ; if ( authorizedChannels ) { try { requireAccess ( authorizedChannels ) ; channelMatch = true ; } catch ( ex ) { // The user has none of the authorized channels if ( ! authorizedRoles && ! authorizedUsers ) { // ... and the document definition does not specify any authorized roles or users throw ex ; } } } var roleMatch = false ; if ( authorizedRoles ) { try { requireRole ( authorizedRoles ) ; roleMatch = true ; } catch ( ex ) { // The user belongs to none of the authorized roles if ( ! authorizedChannels && ! authorizedUsers ) { // ... and the document definition does not specify any authorized channels or users throw ex ; } } } var userMatch = false ; if ( authorizedUsers ) { try { requireUser ( authorizedUsers ) ; userMatch = true ; } catch ( ex ) { // The user does not match any of the authorized usernames if ( ! authorizedChannels && ! authorizedRoles ) { // ... and the document definition does not specify any authorized channels or roles throw ex ; } } } if ( ! authorizedChannels && ! authorizedRoles && ! authorizedUsers ) { // The document type does not define any channels, roles or users that apply to this particular write operation type, so fall back to // Sync Gateway's default behaviour for an empty channel list: 403 Forbidden for requests via the public API and either 200 OK or 201 // Created for requests via the admin API. That way, the admin API will always be able to create, replace or remove documents, // regardless of their authorized channels, roles or users, as intended. requireAccess ( [ ] ) ; } else if ( ! channelMatch && ! roleMatch && ! userMatch ) { // None of the authorization methods (e.g. channels, roles, users) succeeded var errorMessage = 'missing channel access' ; var error = new Error ( errorMessage ) ; error . forbidden = errorMessage ; throw error ; } return { channels : authorizedChannels , roles : authorizedRoles , users : authorizedUsers } ; }


Input: Output help information if necessary [CODESPLIT] function outputHelpIfNecessary ( cmd , options ) { options = options || [ ] ; for ( var i = 0 ; i < options . length ; i ++ ) { if ( options [ i ] === '--help' || options [ i ] === '-h' ) { cmd . outputHelp ( ) ; process . exit ( 0 ) ; } } }


Input: Takes an argument an returns its human readable equivalent for help usage . [CODESPLIT] function humanReadableArgName ( arg ) { var nameOutput = arg . name + ( arg . variadic === true ? '...' : '' ) ; return arg . required ? '<' + nameOutput + '>' : '[' + nameOutput + ']' ; }


Input: The following functions are nested within this function so they can share access to the doc oldDoc and validationErrors params and the attachmentReferenceValidators and itemStack variables [CODESPLIT] function validateObjectProperties ( propertyValidators , allowUnknownProperties , ignoreInternalProperties ) { var currentItemEntry = itemStack [ itemStack . length - 1 ] ; var objectValue = currentItemEntry . itemValue ; var oldObjectValue = currentItemEntry . oldItemValue ; var supportedProperties = [ ] ; for ( var propertyValidatorName in propertyValidators ) { var validator = propertyValidators [ propertyValidatorName ] ; if ( utils . isValueNullOrUndefined ( validator ) || utils . isValueNullOrUndefined ( resolveItemConstraint ( validator . type ) ) ) { // Skip over non-validator fields/properties continue ; } var propertyValue = objectValue [ propertyValidatorName ] ; var oldPropertyValue ; if ( ! utils . isValueNullOrUndefined ( oldObjectValue ) ) { oldPropertyValue = oldObjectValue [ propertyValidatorName ] ; } supportedProperties . push ( propertyValidatorName ) ; itemStack . push ( { itemValue : propertyValue , oldItemValue : oldPropertyValue , itemName : propertyValidatorName } ) ; validateItemValue ( validator ) ; itemStack . pop ( ) ; } // Verify there are no unsupported properties in the object if ( ! allowUnknownProperties ) { for ( var propertyName in objectValue ) { if ( ignoreInternalProperties && propertyName . indexOf ( '_' ) === 0 ) { // These properties are special cases that should always be allowed - generally only applied at the root // level of the document continue ; } if ( supportedProperties . indexOf ( propertyName ) < 0 ) { var objectPath = buildItemPath ( itemStack ) ; var fullPropertyPath = objectPath ? objectPath + '.' + propertyName : propertyName ; validationErrors . push ( 'property "' + fullPropertyPath + '" is not supported' ) ; } } } }


Input: Constructs the fully qualified path of the item at the top of the given stack [CODESPLIT] function buildItemPath ( itemStack ) { var nameComponents = [ ] ; for ( var i = 0 ; i < itemStack . length ; i ++ ) { var itemName = itemStack [ i ] . itemName ; if ( ! itemName ) { // Skip null or empty names (e.g. the first element is typically the root of the document, which has no name) continue ; } else if ( nameComponents . length < 1 || itemName . indexOf ( '[' ) === 0 ) { nameComponents . push ( itemName ) ; } else { nameComponents . push ( '.' + itemName ) ; } } return nameComponents . join ( '' ) ; }


Input: Defined as a function rather than a plain object because it contains lazy references that result in recursive references between the complex types ( e . g . array object hashtable ) and the main propertyValidators schema [CODESPLIT] function typeSpecificConstraintSchemas ( ) { return { any : { } , string : { mustNotBeEmpty : dynamicConstraintSchema ( joi . boolean ( ) ) , mustBeTrimmed : dynamicConstraintSchema ( joi . boolean ( ) ) , regexPattern : dynamicConstraintSchema ( regexSchema ) , minimumLength : dynamicConstraintSchema ( integerSchema . min ( 0 ) ) , maximumLength : maximumSizeConstraintSchema ( 'minimumLength' ) , minimumValue : dynamicConstraintSchema ( joi . string ( ) ) , minimumValueExclusive : dynamicConstraintSchema ( joi . string ( ) ) , maximumValue : dynamicConstraintSchema ( joi . string ( ) ) , maximumValueExclusive : dynamicConstraintSchema ( joi . string ( ) ) , mustEqualIgnoreCase : dynamicConstraintSchema ( joi . string ( ) ) } , integer : { minimumValue : dynamicConstraintSchema ( integerSchema ) , minimumValueExclusive : dynamicConstraintSchema ( integerSchema ) , maximumValue : maximumValueInclusiveNumberConstraintSchema ( integerSchema ) , maximumValueExclusive : maximumValueExclusiveNumberConstraintSchema ( integerSchema ) } , float : { minimumValue : dynamicConstraintSchema ( joi . number ( ) ) , minimumValueExclusive : dynamicConstraintSchema ( joi . number ( ) ) , maximumValue : maximumValueInclusiveNumberConstraintSchema ( joi . number ( ) ) , maximumValueExclusive : maximumValueExclusiveNumberConstraintSchema ( joi . number ( ) ) } , boolean : { } , datetime : { minimumValue : dynamicConstraintSchema ( datetimeSchema ) , minimumValueExclusive : dynamicConstraintSchema ( datetimeSchema ) , maximumValue : dynamicConstraintSchema ( datetimeSchema ) , maximumValueExclusive : dynamicConstraintSchema ( datetimeSchema ) } , date : { minimumValue : dynamicConstraintSchema ( dateOnlySchema ) , minimumValueExclusive : dynamicConstraintSchema ( dateOnlySchema ) , maximumValue : dynamicConstraintSchema ( dateOnlySchema ) , maximumValueExclusive : dynamicConstraintSchema ( dateOnlySchema ) } , time : { minimumValue : dynamicConstraintSchema ( timeOnlySchema ) , minimumValueExclusive : dynamicConstraintSchema ( timeOnlySchema ) , maximumValue : dynamicConstraintSchema ( timeOnlySchema ) , maximumValueExclusive : dynamicConstraintSchema ( timeOnlySchema ) } , timezone : { minimumValue : dynamicConstraintSchema ( timezoneSchema ) , minimumValueExclusive : dynamicConstraintSchema ( timezoneSchema ) , maximumValue : dynamicConstraintSchema ( timezoneSchema ) , maximumValueExclusive : dynamicConstraintSchema ( timezoneSchema ) } , enum : { predefinedValues : dynamicConstraintSchema ( joi . array ( ) . required ( ) . min ( 1 ) . items ( [ integerSchema , joi . string ( ) ] ) ) } , uuid : { minimumValue : dynamicConstraintSchema ( uuidSchema ) , minimumValueExclusive : dynamicConstraintSchema ( uuidSchema ) , maximumValue : dynamicConstraintSchema ( uuidSchema ) , maximumValueExclusive : dynamicConstraintSchema ( uuidSchema ) } , attachmentReference : { maximumSize : dynamicConstraintSchema ( integerSchema . min ( 1 ) . max ( 20971520 ) ) , supportedExtensions : dynamicConstraintSchema ( joi . array ( ) . min ( 1 ) . items ( joi . string ( ) ) ) , supportedContentTypes : dynamicConstraintSchema ( joi . array ( ) . min ( 1 ) . items ( joi . string ( ) . min ( 1 ) ) ) , regexPattern : dynamicConstraintSchema ( regexSchema ) } , array : { mustNotBeEmpty : dynamicConstraintSchema ( joi . boolean ( ) ) , minimumLength : dynamicConstraintSchema ( integerSchema . min ( 0 ) ) , maximumLength : maximumSizeConstraintSchema ( 'minimumLength' ) , arrayElementsValidator : dynamicConstraintSchema ( joi . lazy ( ( ) => schema ) ) } , object : { allowUnknownProperties : dynamicConstraintSchema ( joi . boolean ( ) ) , propertyValidators : dynamicConstraintSchema ( joi . object ( ) . min ( 1 ) . pattern ( / ^.+$ / , joi . lazy ( ( ) => schema ) ) ) } , hashtable : { minimumSize : dynamicConstraintSchema ( integerSchema . min ( 0 ) ) , maximumSize : maximumSizeConstraintSchema ( 'minimumSize' ) , hashtableKeysValidator : dynamicConstraintSchema ( joi . object ( ) . keys ( { mustNotBeEmpty : dynamicConstraintSchema ( joi . boolean ( ) ) , regexPattern : dynamicConstraintSchema ( regexSchema ) } ) ) , hashtableValuesValidator : dynamicConstraintSchema ( joi . lazy ( ( ) => schema ) ) } , conditional : { validationCandidates : dynamicConstraintSchema ( conditionalValidationCandidatesSchema ( ) ) . required ( ) } } ; }


Input: Checks that a business ID is valid ( an integer greater than 0 ) and is not changed from the old version of the document [CODESPLIT] function validateBusinessIdProperty ( doc , oldDoc , currentItemEntry , validationItemStack ) { var parentObjectElement = validationItemStack [ validationItemStack . length - 1 ] ; var businessId = currentItemEntry . itemValue ; var oldBusinessId = currentItemEntry . oldItemValue ; var validationErrors = [ ] ; if ( parentObjectElement . oldItemValue && oldBusinessId !== businessId ) { validationErrors . push ( 'cannot change "businessId" property' ) ; } return validationErrors ; }


Input: Retrieves the ID of the business to which the document belongs [CODESPLIT] function getBusinessId ( doc , oldDoc ) { var regex = / ^biz\.([A-Za-z0-9_-]+)(?:\..+)?$ / ; var matchGroups = regex . exec ( doc . _id ) ; if ( matchGroups ) { return matchGroups [ 1 ] ; } else if ( oldDoc && oldDoc . businessId ) { // The document ID doesn't contain a business ID, so use the property from the old document return oldDoc . businessId || null ; } else { // Neither the document ID nor the old document's contents contain a business ID, so use the property from the new document return doc . businessId || null ; } }


Input: Builds a function that returns the view add replace remove channels extrapolated from the specified base privilege name which is formatted according to the de facto Books convention of VIEW_FOOBAR ADD_FOOBAR CHANGE_FOOBAR and REMOVE_FOOBAR assuming the base privilege name is FOOBAR [CODESPLIT] function toDefaultSyncChannels ( doc , oldDoc , basePrivilegeName ) { var businessId = getBusinessId ( doc , oldDoc ) ; return function ( doc , oldDoc ) { return { view : [ toSyncChannel ( businessId , 'VIEW_' + basePrivilegeName ) ] , add : [ toSyncChannel ( businessId , 'ADD_' + basePrivilegeName ) ] , replace : [ toSyncChannel ( businessId , 'CHANGE_' + basePrivilegeName ) ] , remove : [ toSyncChannel ( businessId , 'REMOVE_' + basePrivilegeName ) ] } ; } ; }


Input: Check that a given value is a valid ISO 8601 format date string with optional time and time zone components [CODESPLIT] function isIso8601DateTimeString ( value ) { var dateAndTimePieces = splitDateAndTime ( value ) ; var date = extractDateStructureFromDateAndTime ( dateAndTimePieces ) ; if ( date ) { var timeAndTimezone = extractTimeStructuresFromDateAndTime ( dateAndTimePieces ) ; var time = timeAndTimezone . time ; var timezone = timeAndTimezone . timezone ; return isValidDateStructure ( date ) && isValidTimeStructure ( time ) && ( timezone === null || isValidTimeZoneStructure ( timezone ) ) ; } else { return false ; } }


Input: Converts the given time to the number of milliseconds since hour 0 [CODESPLIT] function normalizeIso8601Time ( time , timezoneOffsetMinutes ) { var msPerSecond = 1000 ; var msPerMinute = 60000 ; var msPerHour = 3600000 ; var effectiveTimezoneOffset = timezoneOffsetMinutes || 0 ; var rawTimeMs = ( time . hour * msPerHour ) + ( time . minute * msPerMinute ) + ( time . second * msPerSecond ) + time . millisecond ; return rawTimeMs - ( effectiveTimezoneOffset * msPerMinute ) ; }


Input: Compares the given time strings . Returns a negative number if a is less than b a positive number if a is greater than b or zero if a and b are equal . [CODESPLIT] function compareTimes ( a , b ) { if ( typeof a !== 'string' || typeof b !== 'string' ) { return NaN ; } return normalizeIso8601Time ( parseIso8601Time ( a ) ) - normalizeIso8601Time ( parseIso8601Time ( b ) ) ; }


Input: Compares the given date representations . Returns a negative number if a is less than b a positive number if a is greater than b or zero if a and b are equal . [CODESPLIT] function compareDates ( a , b ) { var aPieces = extractDatePieces ( a ) ; var bPieces = extractDatePieces ( b ) ; if ( aPieces === null || bPieces === null ) { return NaN ; } for ( var pieceIndex = 0 ; pieceIndex < aPieces . length ; pieceIndex ++ ) { if ( aPieces [ pieceIndex ] < bPieces [ pieceIndex ] ) { return - 1 ; } else if ( aPieces [ pieceIndex ] > bPieces [ pieceIndex ] ) { return 1 ; } } // If we got here, the two parameters represent the same date/point in time return 0 ; }


Input: Converts an ISO 8601 time zone into the number of minutes offset from UTC [CODESPLIT] function normalizeIso8601TimeZone ( value ) { return value ? value . multiplicationFactor * ( ( value . hour * 60 ) + value . minute ) : - ( new Date ( ) . getTimezoneOffset ( ) ) ; }


Input:
////////////////////////////////////////////////////////////////////////////////////////////// Only Function Definitions Beyond This Point The main process of starting an xGraph System . [CODESPLIT] async function initiate ( ) { log . i ( '--Nexus/Initiate' ) ; let Setup = { } ; let Start = { } ; cacheInterface = new CacheInterface ( { path : __options . cache , log } ) ; let cache = await cacheInterface . loadCache ( ) ; Start = cache . start ; Setup = cache . setup ; Stop = Object . assign ( Stop , cache . stop ) ; await setup ( ) ; await start ( ) ; run ( ) ; ///////////////////////////////////////////////////////////////////////////////////////// // // Only Helper Functions Beyond This Point // // /**
				 * Call setup on the required Module Apexes
				 */ async function setup ( ) { log . i ( '--Nexus/Setup' ) ; //build the setup promise array let setupArray = [ ] ; for ( let pid in Setup ) { setupArray . push ( new Promise ( ( resolve , _reject ) => { let com = { } ; com . Cmd = Setup [ pid ] ; com . Passport = { } ; com . Passport . To = pid ; com . Passport . Pid = genPid ( ) ; sendMessage ( com , resolve ) ; } ) ) ; } await Promise . all ( setupArray ) ; log . v ( '--Nexus: All Setups Complete' ) ; } /**
				 * Call Start on the required Module Apexes
				 */ async function start ( ) { log . i ( '--Nexus/Start' ) ; //build the setup promise array let startArray = [ ] ; for ( let pid in Start ) { startArray . push ( new Promise ( ( resolve , _reject ) => { let com = { } ; com . Cmd = Start [ pid ] ; com . Passport = { } ; com . Passport . To = pid ; com . Passport . Pid = genPid ( ) ; sendMessage ( com , resolve ) ; } ) ) ; } await Promise . all ( startArray ) ; log . v ( '--Nexus: All Starts Complete' ) ; } /**
				 * Send Finished command if the process was generated
				 */ function run ( ) { log . i ( '--Nexus/Run' ) ; if ( 'send' in process ) { process . send ( '{"Cmd":"Finished"}' ) ; } } }


Input: /////////////////////////////////////////////////////////////////////////////////////// Only Helper Functions Beyond This Point Call setup on the required Module Apexes [CODESPLIT] async function setup ( ) { log . i ( '--Nexus/Setup' ) ; //build the setup promise array let setupArray = [ ] ; for ( let pid in Setup ) { setupArray . push ( new Promise ( ( resolve , _reject ) => { let com = { } ; com . Cmd = Setup [ pid ] ; com . Passport = { } ; com . Passport . To = pid ; com . Passport . Pid = genPid ( ) ; sendMessage ( com , resolve ) ; } ) ) ; } await Promise . all ( setupArray ) ; log . v ( '--Nexus: All Setups Complete' ) ; }


Input: Call Start on the required Module Apexes [CODESPLIT] async function start ( ) { log . i ( '--Nexus/Start' ) ; //build the setup promise array let startArray = [ ] ; for ( let pid in Start ) { startArray . push ( new Promise ( ( resolve , _reject ) => { let com = { } ; com . Cmd = Start [ pid ] ; com . Passport = { } ; com . Passport . To = pid ; com . Passport . Pid = genPid ( ) ; sendMessage ( com , resolve ) ; } ) ) ; } await Promise . all ( startArray ) ; log . v ( '--Nexus: All Starts Complete' ) ; }


Input: Helper Functions as well as Entity definition [CODESPLIT] async function exit ( code = 0 ) { log . i ( '--Nexus/Stop' ) ; //build the Stop promise array let stopTasks = [ ] ; log . i ( 'Nexus unloading node modules' ) ; log . v ( Object . keys ( require . cache ) . join ( '\n' ) ) ; for ( let pid in Stop ) { stopTasks . push ( new Promise ( ( resolve , _reject ) => { let com = { } ; com . Cmd = Stop [ pid ] ; com . Passport = { } ; com . Passport . To = pid ; com . Passport . Pid = genPid ( ) ; sendMessage ( com , resolve ) ; } ) ) ; } await Promise . all ( stopTasks ) ; log . v ( '--Nexus: All Stops Complete' ) ; dispatchEvent ( 'exit' , { exitCode : code } ) ; }


Input: Send a message from an entity to an Apex entity . If a callback is provided return when finished [CODESPLIT] function sendMessage ( com , fun = _ => _ ) { if ( ! ( 'Passport' in com ) ) { log . w ( 'Message has no Passport, ignored' ) ; log . w ( '    ' + JSON . stringify ( com ) ) ; fun ( 'No Passport' ) ; return ; } if ( ! ( 'To' in com . Passport ) || ! com . Passport . To ) { log . w ( 'Message has no destination entity, ignored' ) ; log . w ( '    ' + JSON . stringify ( com ) ) ; fun ( 'No recipient in message' , com ) ; return ; } if ( ! ( 'Pid' in com . Passport ) ) { log . w ( 'Message has no message id, ignored' ) ; log . w ( '    ' + JSON . stringify ( com ) ) ; fun ( 'No message id' , com ) ; return ; } let pid = com . Passport . To ; let apx = com . Passport . Apex || pid ; if ( pid in EntCache ) { done ( null , EntCache [ pid ] ) ; return ; } else { getEntityContext ( pid , done ) ; } async function done ( err , entContextVolatile ) { let entApex = await new Promise ( res => entContextVolatile . lock ( ( val ) => { res ( val . Apex ) ; return val ; } ) ) ; if ( err ) { log . w ( err ) ; log . w ( JSON . stringify ( com , null , 2 ) ) ; fun ( err , com ) ; return ; } //TODO pid instanceOf ApexEntity if ( ( EntCache [ pid ] . Apex == EntCache [ pid ] . Pid ) || ( entApex == apx ) ) { let entContext = await new Promise ( res => entContextVolatile . lock ( ( context ) => { res ( context ) ; return context ; } ) ) ; entContext . instance . dispatch ( com , reply ) ; } else { let err = 'Trying to send a message to a non-Apex' + 'entity outside of the sending module' ; log . w ( err ) ; log . w ( JSON . stringify ( com , null , 2 ) ) ; fun ( err , com ) ; } } function reply ( err , q ) { // log.i('NEXUS MESSAGE:', com) fun ( err , q ) ; } }