// Path: parent/bundles/com.google.eclipse.mechanic/src/com/google/eclipse/mechanic/plugin/core/MechanicPlugin.java
// public class MechanicPlugin extends AbstractUIPlugin {
// 
//   // The plug-in ID
//   public static final String PLUGIN_ID = "com.google.eclipse.mechanic";
// 
//   // The shared instance
//   private static MechanicPlugin plugin;
// 
//   private IMechanicPreferences mechanicPreferences;
// 
//   private volatile IPreferenceRecordingService preferenceRecordingService =
//       new PreferenceRecordingService();
// 
//   private PopupNotifier popupNotifier;
// 
//   public MechanicPlugin() {
//     plugin = this;
//   }
// 
//   @Override 
//   public void start(BundleContext context) throws Exception {
//     super.start(context);
// 
//     mechanicPreferences = new MechanicPreferences();
// 
//     // popup notifier must start before the mechanic service in order to
//     // catch the first statuses.
//     popupNotifier = new PopupNotifier(MechanicService.getInstance(), getMechanicPreferences());
//     popupNotifier.initialize();
// 
//     UriCaches.initialize();
// 
//     // immediately start the mechanic service
//     MechanicService.getInstance().start();
//   }
// 
//   @Override 
//   public void stop(BundleContext context) throws Exception {
//     MechanicService.getInstance().stop();
//     UriCaches.destroy();
//     popupNotifier.dispose();
//     TasksExtensionPoint.dispose();
//     ScannersExtensionPoint.dispose();
//     ResourceTaskProvidersExtensionPoint.dispose();
//     plugin = null;
//     super.stop(context);
//   }
// 
//   /**
//    * Keep this around as some of the generated code expects it.
//    * @return shared instance of this plug-in class
//    */
//   public static MechanicPlugin getDefault() {
//     return plugin;
//   }
// 
//   /**
//    * Returns an image descriptor for the image file at the given plug-in
//    * relative path
//    *
//    * @param path the path
//    * @return the image descriptor
//    */
//   public static ImageDescriptor getImageDescriptor(String path) {
//     return imageDescriptorFromPlugin(PLUGIN_ID, path);
//   }
// 
//   public IPreferenceRecordingService getPreferenceRecordingService() {
//     if (preferenceRecordingService == null) {
//       preferenceRecordingService = new PreferenceRecordingService();
//     }
// 
//     return preferenceRecordingService;
//   }
// 
//   public IMechanicPreferences getMechanicPreferences() {
//     return mechanicPreferences;
//   }
// }


import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.eclipse.mechanic.plugin.core.MechanicPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.osgi.service.prefs.BackingStoreException;
import java.util.List;
import java.util.Set;
  private List<PreferenceChange> changeLog = Lists.newArrayList();

  /**
   * Starts the process of recording changes to the eclipse preference tree.
   * Recording may only occur once per recorder.
   * 
   * @throws CoreException if there is a problem with the preference tree
   *         itself.
   * @throws IllegalStateException if this object has already been used to
   *         record.
   */
  public void startRecording() throws CoreException {
    synchronized (lock) {
      Preconditions.checkState(currState == State.IDLE, "Recorder object has already recorded preference changes.");

      currState = State.RECORDING;

      this.addListeners(Platform.getPreferencesService().getRootNode());
    }
  }

  private void addListeners(IEclipsePreferences node) throws CoreException {
    addListener(node);

    try {
      for (String childName : node.childrenNames()) {
        IEclipsePreferences child = (IEclipsePreferences) node.node(childName);
        this.addListeners(child);
      }
    } catch (BackingStoreException e) {
// Path: parent/bundles/com.google.eclipse.mechanic/src/com/google/eclipse/mechanic/plugin/core/MechanicPlugin.java
// public class MechanicPlugin extends AbstractUIPlugin {
// 
//   // The plug-in ID
//   public static final String PLUGIN_ID = "com.google.eclipse.mechanic";
// 
//   // The shared instance
//   private static MechanicPlugin plugin;
// 
//   private IMechanicPreferences mechanicPreferences;
// 
//   private volatile IPreferenceRecordingService preferenceRecordingService =
//       new PreferenceRecordingService();
// 
//   private PopupNotifier popupNotifier;
// 
//   public MechanicPlugin() {
//     plugin = this;
//   }
// 
//   @Override 
//   public void start(BundleContext context) throws Exception {
//     super.start(context);
// 
//     mechanicPreferences = new MechanicPreferences();
// 
//     // popup notifier must start before the mechanic service in order to
//     // catch the first statuses.
//     popupNotifier = new PopupNotifier(MechanicService.getInstance(), getMechanicPreferences());
//     popupNotifier.initialize();
// 
//     UriCaches.initialize();
// 
//     // immediately start the mechanic service
//     MechanicService.getInstance().start();
//   }
// 
//   @Override 
//   public void stop(BundleContext context) throws Exception {
//     MechanicService.getInstance().stop();
//     UriCaches.destroy();
//     popupNotifier.dispose();
//     TasksExtensionPoint.dispose();
//     ScannersExtensionPoint.dispose();
//     ResourceTaskProvidersExtensionPoint.dispose();
//     plugin = null;
//     super.stop(context);
//   }
// 
//   /**
//    * Keep this around as some of the generated code expects it.
//    * @return shared instance of this plug-in class
//    */
//   public static MechanicPlugin getDefault() {
//     return plugin;
//   }
// 
//   /**
//    * Returns an image descriptor for the image file at the given plug-in
//    * relative path
//    *
//    * @param path the path
//    * @return the image descriptor
//    */
//   public static ImageDescriptor getImageDescriptor(String path) {
//     return imageDescriptorFromPlugin(PLUGIN_ID, path);
//   }
// 
//   public IPreferenceRecordingService getPreferenceRecordingService() {
//     if (preferenceRecordingService == null) {
//       preferenceRecordingService = new PreferenceRecordingService();
//     }
// 
//     return preferenceRecordingService;
//   }
// 
//   public IMechanicPreferences getMechanicPreferences() {
//     return mechanicPreferences;
//   }
// }


// Path: parent/bundles/com.google.eclipse.mechanic/src/com/google/eclipse/mechanic/core/recorder/PreferenceRecorder.java
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.eclipse.mechanic.plugin.core.MechanicPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.osgi.service.prefs.BackingStoreException;
import java.util.List;
import java.util.Set;

  private List<PreferenceChange> changeLog = Lists.newArrayList();

  /**
   * Starts the process of recording changes to the eclipse preference tree.
   * Recording may only occur once per recorder.
   * 
   * @throws CoreException if there is a problem with the preference tree
   *         itself.
   * @throws IllegalStateException if this object has already been used to
   *         record.
   */
  public void startRecording() throws CoreException {
    synchronized (lock) {
      Preconditions.checkState(currState == State.IDLE, "Recorder object has already recorded preference changes.");

      currState = State.RECORDING;

      this.addListeners(Platform.getPreferencesService().getRootNode());
    }
  }

  private void addListeners(IEclipsePreferences node) throws CoreException {
    addListener(node);

    try {
      for (String childName : node.childrenNames()) {
        IEclipsePreferences child = (IEclipsePreferences) node.node(childName);
        this.addListeners(child);
      }
    } catch (BackingStoreException e) {
      throw new CoreException(new Status(IStatus.ERROR, MechanicPlugin.PLUGIN_ID,