lib/search.js
function queueSearcher(data, cb) {
  // validate
  if (data.team && data.team.length > 0 && data.input && data.member && data.categories && data.categories.length > 0) {

    // log the search
    GLOBAL.svc.indexer.saveSearchLog({searchID: GLOBAL.svc.indexer.searchID(data), searchDate: new Date()}, utils.passingError);
    // process it by each member
    data.team.forEach(function(m) {
      var user = auth.getUserByUsername(m), context = { member: user.username, input: data.input, relevance: data.relevance, team: data.team, categories: data.categories};
      // user not found
      if (!user) {
        console.log('queueSearch: user not found', m);
      } else {
        console.log('execing', data, 'user', user);
        // it's a searcher, add links
        if (user.type === 'Searcher') {
          if (user.api) {
            // use query template or just the term
            context.query = (user.template || '$SBQUERY').replace('$SBQUERY', data.input);
            context.targetResults = data.targetResults || 10;
            // one callback per uri
            searchAPIs.exec(user.api, context, function(err, uri, resultContext) {
              console.log('got a link', uri);
              var status;
              if (err) {
                utils.passingError(err);
              } else {
                status = { uri: uri, source: resultContext.referers };
                queueLink(uri, resultContext);
              }
              if (cb) {
                cb(err, status);
              }
            });
          // scrape style location
          } else if (user.locations) {
            user.locations.split('\n').forEach(function(l) {
              l = l.replace('$SBQUERY', data.input);
              GLOBAL.info(' /queueSearch', l);
              queueLink(l, context);
            });
          } else {
            GLOBAL.error('unknown searcher type', user);
          }
        // an annotator or individual
        } else {
          GLOBAL.info(' /queueSearch', data.uri);
          queueLink(data.uri, context);
        }
      }
    });
  } else {
    console.log('missing data', data);
  }
}
function queueSearcher(data, cb) {
  // validate
  if (data.team && data.team.length > 0 && data.input && data.member && data.categories && data.categories.length > 0) {

    // log the search
    GLOBAL.svc.indexer.saveSearchLog({searchID: GLOBAL.svc.indexer.searchID(data), searchDate: new Date()}, utils.passingError);
    // process it by each member
    data.team.forEach(function(m) {
      var user = auth.getUserByUsername(m), context = { member: user.username, input: data.input, relevance: data.relevance, team: data.team, categories: data.categories};
      // user not found
      if (!user) {
        console.log('queueSearch: user not found', m);
      } else {
        console.log('execing', data, 'user', user);
        // it's a searcher, add links
        if (user.type === 'Searcher') {
          if (user.api) {
            // use query template or just the term
            context.query = (user.template || '$SBQUERY').replace('$SBQUERY', data.input);
            context.targetResults = data.targetResults || 10;
            // one callback per uri
            searchAPIs.exec(user.api, context, function(err, uri, resultContext) {
              console.log('got a link', uri);
              var status;
              if (err) {
                utils.passingError(err);
              } else {
                status = { uri: uri, source: resultContext.referers };
                queueLink(uri, resultContext);
              }
              if (cb) {
                cb(err, status);
              }
            });
          // scrape style location
          } else if (user.locations) {
            user.locations.split('\n').forEach(function(l) {
              l = l.replace('$SBQUERY', data.input);
              GLOBAL.info(' /queueSearch', l);
              queueLink(l, context);
            });
          } else {
            GLOBAL.error('unknown searcher type', user);
          }
        // an annotator or individual
        } else {
          GLOBAL.info(' /queueSearch', data.uri);
          queueLink(data.uri, context);
        }
      }
    });
  } else {
    console.log('missing data', data);
  }
}
function queueSearcher ( data , cb ) { // validate if ( data . team && data . team . length > 0 && data . input && data . member && data . categories && data . categories . length > 0 ) { // log the search GLOBAL . svc . indexer . saveSearchLog ( { searchID : GLOBAL . svc . indexer . searchID ( data ) , searchDate : new Date ( ) } , utils . passingError ) ; // process it by each member data . team . forEach ( function ( m ) { var user = auth . getUserByUsername ( m ) , context = { member : user . username , input : data . input , relevance : data . relevance , team : data . team , categories : data . categories } ; // user not found if ( ! user ) { console . log ( 'queueSearch: user not found' , m ) ; } else { console . log ( 'execing' , data , 'user' , user ) ; // it's a searcher, add links if ( user . type === 'Searcher' ) { if ( user . api ) { // use query template or just the term context . query = ( user . template || '$SBQUERY' ) . replace ( '$SBQUERY' , data . input ) ; context . targetResults = data . targetResults || 10 ; // one callback per uri searchAPIs . exec ( user . api , context , function ( err , uri , resultContext ) { console . log ( 'got a link' , uri ) ; var status ; if ( err ) { utils . passingError ( err ) ; } else { status = { uri : uri , source : resultContext . referers } ; queueLink ( uri , resultContext ) ; } if ( cb ) { cb ( err , status ) ; } } ) ; // scrape style location } else if ( user . locations ) { user . locations . split ( '\n' ) . forEach ( function ( l ) { l = l . replace ( '$SBQUERY' , data . input ) ; GLOBAL . info ( ' /queueSearch' , l ) ; queueLink ( l , context ) ; } ) ; } else { GLOBAL . error ( 'unknown searcher type' , user ) ; } // an annotator or individual } else { GLOBAL . info ( ' /queueSearch' , data . uri ) ; queueLink ( data . uri , context ) ; } } } ) ; } else { console . log ( 'missing data' , data ) ; } }
Process queued searches by members.  receives form data, validates it passes links via queueLink for Searchers, queues up found links use cb to send updates
Process queued searches by members . receives form data validates it passes links via queueLink for Searchers queues up found links use cb to send updates