@Override
 @NotNull
 public synchronized VirtualFilePointer duplicate(
     @NotNull VirtualFilePointer pointer,
     @NotNull Disposable parent,
     @Nullable VirtualFilePointerListener listener) {
   VirtualFile file = pointer.getFile();
   return file == null
       ? create(pointer.getUrl(), parent, listener)
       : create(file, parent, listener);
 }
    @Override
    public void before(@NotNull final List<? extends VFileEvent> events) {
      cleanContainerCaches();
      List<VirtualFilePointer> toFireEvents = new ArrayList<VirtualFilePointer>();
      List<String> toUpdateUrl = new ArrayList<String>();

      synchronized (VirtualFilePointerManagerImpl.this) {
        for (VFileEvent event : events) {
          if (event instanceof VFileDeleteEvent) {
            final VFileDeleteEvent deleteEvent = (VFileDeleteEvent) event;
            String url = deleteEvent.getFile().getPath();
            addPointersUnder(url, true, toFireEvents);
          } else if (event instanceof VFileCreateEvent) {
            final VFileCreateEvent createEvent = (VFileCreateEvent) event;
            String url = createEvent.getPath();
            addPointersUnder(url, false, toFireEvents);
          } else if (event instanceof VFileCopyEvent) {
            final VFileCopyEvent copyEvent = (VFileCopyEvent) event;
            String url = copyEvent.getNewParent().getPath() + "/" + copyEvent.getFile().getName();
            addPointersUnder(url, false, toFireEvents);
          } else if (event instanceof VFileMoveEvent) {
            final VFileMoveEvent moveEvent = (VFileMoveEvent) event;
            List<VirtualFilePointer> pointers = new ArrayList<VirtualFilePointer>();
            addPointersUnder(moveEvent.getFile().getPath(), false, pointers);
            for (VirtualFilePointer pointer : pointers) {
              VirtualFile file = pointer.getFile();
              if (file != null) {
                toUpdateUrl.add(file.getPath());
              }
            }
          } else if (event instanceof VFilePropertyChangeEvent) {
            final VFilePropertyChangeEvent change = (VFilePropertyChangeEvent) event;
            if (VirtualFile.PROP_NAME.equals(change.getPropertyName())) {
              List<VirtualFilePointer> pointers = new ArrayList<VirtualFilePointer>();
              addPointersUnder(change.getFile().getPath(), false, pointers);
              for (VirtualFilePointer pointer : pointers) {
                VirtualFile file = pointer.getFile();
                if (file != null) {
                  toUpdateUrl.add(file.getPath());
                }
              }
            }
          }
        }

        myEvents = new ArrayList<EventDescriptor>();
        for (VirtualFilePointerListener listener : myUrlToPointerMaps.keySet()) {
          if (listener == null) continue;
          EventDescriptor event = new EventDescriptor(listener, toFireEvents);
          myEvents.add(event);
        }
      }

      for (EventDescriptor event : myEvents) {
        event.fireBefore();
      }

      if (!toFireEvents.isEmpty()) {
        VirtualFilePointer[] arr =
            toFireEvents.toArray(new VirtualFilePointer[toFireEvents.size()]);
        myBus.syncPublisher(VirtualFilePointerListener.TOPIC).beforeValidityChanged(arr);
      }

      myPointersToUpdate = toFireEvents;
      myUrlsToUpdate = toUpdateUrl;
    }