text: /** 
   *  The pattern adaptor listens for newListener and removeListener
   *  events. When patterns are added or removed it compiles the JSONPath
   *  and wires them up.
   *  
   *  When nodes and paths are found it emits the fully-qualified match 
   *  events with parameters ready to ship to the outside world
   */
  
  function patternAdapter(oboeBus, jsonPathCompiler) {
  
     var predicateEventMap = {
        node:oboeBus(NODE_CLOSED)
     ,  path:oboeBus(NODE_OPENED)
     };
       
     function emitMatchingNode(emitMatch, node, ascent) {
           
        /* 
           We're now calling to the outside world where Lisp-style 
           lists will not be familiar. Convert to standard arrays. 
     
           Also, reverse the order because it is more common to 
           list paths "root to leaf" than "leaf to root"  */
        var descent     = reverseList(ascent);
                  
        emitMatch(
           node,
           
           // To make a path, strip off the last item which is the special
           // ROOT_PATH token for the 'path' to the root node          
           listAsArray(tail(map(keyOf,descent))),  // path
           listAsArray(map(nodeOf, descent))       // ancestors    
        );         
     }
  
     /* 
      * Set up the catching of events such as NODE_CLOSED and NODE_OPENED and, if 
      * matching the specified pattern, propagate to pattern-match events such as 
      * oboeBus('node:!')
      * 
      * 
      * 
      * @param {Function} predicateEvent 
      *          either oboeBus(NODE_CLOSED) or oboeBus(NODE_OPENED).
      * @param {Function} compiledJsonPath          
      */
     function addUnderlyingListener( fullEventName, predicateEvent, compiledJsonPath ){
     
        var emitMatch = oboeBus(fullEventName).emit;
     
        predicateEvent.on( function (ascent) {
  
           var maybeMatchingMapping = compiledJsonPath(ascent);
  
           /* Possible values for maybeMatchingMapping are now:
  
            false: 
            we did not match 
  
            an object/array/string/number/null: 
            we matched and have the node that matched.
            Because nulls are valid json values this can be null.
  
            undefined:
            we matched but don't have the matching node yet.
            ie, we know there is an upcoming node that matches but we 
            can't say anything else about it. 
            */
           if (maybeMatchingMapping !== false) {
  
              emitMatchingNode(
                 emitMatch, 
                 nodeOf(maybeMatchingMapping), 
                 ascent
              );
           }
        }, fullEventName);
       
        oboeBus('removeListener').on( function(removedEventName){
  
           // if the fully qualified match event listener is later removed, clean up 
           // by removing the underlying listener if it was the last using that pattern:
        
           if( removedEventName == fullEventName ) {
           
              if( !oboeBus(removedEventName).listeners(  )) {
                 predicateEvent.un( fullEventName );
              }
           }
        });   
     }
  
     oboeBus('newListener').on( function(fullEventName){
  
        var match = /(node|path):(.*)/.exec(fullEventName);
        
        if( match ) {
           var predicateEvent = predicateEventMap[match[1]];
                      
           if( !predicateEvent.hasListener( fullEventName) ) {  
                    
              addUnderlyingListener(
                 fullEventName,
                 predicateEvent, 
                 jsonPathCompiler( match[2] )
              );
           }
        }    
     })
  
  }
  