anchor.diff:     * browsers the hashChange event is used instead.
      */
     void listen({bool ignoreClick: false}) {
  +    _logger.finest('listen ignoreClick=$ignoreClick');
       if (_listen) {
         throw new StateError('listen can only be called once');
       }
       _listen = true;
       if (_useFragment) {
         _window.onHashChange.listen((_) {
  -        return route(_normalizeHash(_window.location.hash));
  +        route(_normalizeHash(_window.location.hash)).then((allowed) {
  +          // if not allowed, we need to restore the browser location
  +          if (!allowed) {
  +            _window.history.forward();
  +          }
  +        });
         });
         route(_normalizeHash(_window.location.hash));
       } else {
  -      _window.onPopState.listen((_) => route(_window.location.pathname));
  +      _window.onPopState.listen((_) {
  +        var path = '${_window.location.pathname}${_window.location.hash}';
  +        route(path).then((allowed) {
  +          // if not allowed, we need to restore the browser location
  +          if (!allowed) {
  +            _window.history.forward();
  +          }
  +        });
  +      });
       }
       if (!ignoreClick) {
  -      _window.onClick.listen((e) {
  +      _logger.finest('listen on win');
  +      _window.onClick.listen((Event e) {
           if (e.target is AnchorElement) {
             AnchorElement anchor = e.target;
             if (anchor.host == _window.location.host) {
  +            _logger.finest('clicked ${anchor.pathname}${anchor.hash}');
               e.preventDefault();
  -            var hash = (anchor.hash == '') ? '' : anchor.hash;
               var path;
               if (_useFragment) {
  -              path = hash.substring(1);
  +              path = _normalizeHash(anchor.hash);
               } else {
  -              path = '${anchor.pathname}$hash';
  +              path = '${anchor.pathname}${anchor.hash}';
               }
               route(path).then((allowed) {
                 if (allowed) {
  
positive.code:     return '[Route: $name]';
    }
  
    String reverse(String tail) {
      return path.reverse(parameters: _lastEvent.parameters, tail: tail);
    }
  
    void renotify() {
      print('$parent ${parent._currentRoute} $this');
      if (parent != null && identical(parent._currentRoute, this)) {
        print('renotify..... YES');
        _onRouteController.add(_lastEvent);
      } else {
        print('renotify..... NO');
      }
    }
  }
  
  class RouteEvent {
    final String path;
    final Map parameters;
  
negative.code:     _routes[name] = route;
    }
  
    /**
     * Returns a route node at the end of the given route path. Route path
     * dot delimited string of route names.
     */
    Route getRoute(String routePath) {
      var routeName = routePath.split('.').first;
      if (!_routes.containsKey(routeName)) {
  