LISTSERV mailing list manager LISTSERV 16.5

Help for HPS-SVN Archives


HPS-SVN Archives

HPS-SVN Archives


HPS-SVN@LISTSERV.SLAC.STANFORD.EDU


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Proportional Font

LISTSERV Archives

LISTSERV Archives

HPS-SVN Home

HPS-SVN Home

HPS-SVN  July 2015

HPS-SVN July 2015

Subject:

r3265 - in /java/branches/conditions-HPSJAVA-517: ./ src/main/java/org/hps/conditions/ src/main/java/org/hps/conditions/api/ src/main/java/org/hps/conditions/cli/ src/main/java/org/hps/conditions/database/ src/main/java/org/hps/conditions/ecal/ src/test/java/org/hps/conditions/ src/test/java/org/hps/conditions/api/

From:

[log in to unmask]

Reply-To:

Notification of commits to the hps svn repository <[log in to unmask]>

Date:

Fri, 17 Jul 2015 23:51:17 -0000

Content-Type:

text/plain

Parts/Attachments:

Parts/Attachments

text/plain (1143 lines)

Author: [log in to unmask]
Date: Fri Jul 17 16:50:54 2015
New Revision: 3265

Log:
Rework of conditions tagging.  Multiple tags on conditions records now supported.  Using more than one tag at a time is supported too.  Simplify the tag command line interface (it is much simpler now).  Some other small fixes and changes.  HPSJAVA-517

Added:
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsTag.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java
    java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java
Modified:
    java/branches/conditions-HPSJAVA-517/   (props changed)
    java/branches/conditions-HPSJAVA-517/pom.xml
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ConditionsDriver.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsRecord.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/TableMetaData.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AbstractCommand.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AddCommand.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/CommandLineTool.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/TagCommand.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
    java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ecal/EcalPulseWidth.java
    java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/EngRunConditionsTest.java

Modified: java/branches/conditions-HPSJAVA-517/pom.xml
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/pom.xml	(original)
+++ java/branches/conditions-HPSJAVA-517/pom.xml	Fri Jul 17 16:50:54 2015
@@ -38,6 +38,7 @@
                         <exclude>org/hps/conditions/ecal/EcalHardwareConditionsTest.java</exclude>
                         <exclude>org/hps/conditions/database/CollectionIdTest.java</exclude>
                         <exclude>org/hps/conditions/svt/SvtTimingConstantsTest.java</exclude>
+                        <exclude>org/hps/conditions/api/ConditionsTagTest.java</exclude>
                         <exclude>org/hps/conditions/dummy/**.java</exclude>
                     </excludes>
                 </configuration>

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ConditionsDriver.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ConditionsDriver.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ConditionsDriver.java	Fri Jul 17 16:50:54 2015
@@ -75,7 +75,7 @@
 
         if (this.tag != null) {
             // Set a tag for filtering ConditionsRecord objects.
-            conditionsManager.setTag(this.tag);
+            conditionsManager.addTag(this.tag);
         }
         if (this.detectorName != null) {
             // The manager can only be initialized here if there is a user supplied detector name.

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsRecord.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsRecord.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsRecord.java	Fri Jul 17 16:50:54 2015
@@ -358,9 +358,11 @@
     /**
      * Get the string tag associated with these conditions.
      *
+     * @deprecated Use the {@link ConditionsTag} class instead.
      * @return The string tag.
      */
     @Field(names = {"tag"})
+    @Deprecated
     public String getTag() {
         return this.getFieldValue("tag");
     }

Added: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsTag.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsTag.java	(added)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/ConditionsTag.java	Fri Jul 17 16:50:54 2015
@@ -0,0 +1,101 @@
+package org.hps.conditions.api;
+
+import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
+import org.hps.conditions.database.ConditionsTagConverter;
+import org.hps.conditions.database.Converter;
+import org.hps.conditions.database.Field;
+import org.hps.conditions.database.Table;
+
+/**
+ * Conditions tag specifying a set of grouped {@link ConditionsRecord} objects by their row IDs in the database along 
+ * with a tag name.
+ * <p>
+ * The run numbers of conditions in the tag with the same key are allowed to overlap.  In this case, the 
+ * disambiguation is performed at run-time within the job using a {@link org.hps.conditions.database.MultipleCollectionsAction}.
+ *  
+ * @author Jeremy McCormick, SLAC
+ */
+@Table(names = {"conditions_tags"})
+@Converter(converter = ConditionsTagConverter.class)
+public final class ConditionsTag extends BaseConditionsObject {
+    
+    static {
+        /* 
+         * HACK: Remove collection_id from the list of fields; it is defined by the BaseConditionsObject super-class
+         * but not defined in this class's table schema.
+         */
+        TableRegistry.getTableRegistry().findByObjectType(ConditionsTag.class).get(0).removeField("collection_id");
+    }
+
+    /**
+     * Collection of tag records.
+     */
+    public static final class ConditionsTagCollection extends BaseConditionsObjectCollection<ConditionsTag> {
+
+        /**
+         * Return <code>true</code> if the collection contains this conditions record (it is in the tag).
+         * 
+         * @param conditionsRecord the conditions record
+         * @return <code>true</code> if the collection contains this conditions record
+         */
+        public boolean contains(final ConditionsRecord conditionsRecord) {
+            for (final ConditionsTag tagRecord : this.getObjects()) {
+                if (tagRecord.getConditionsId().equals(conditionsRecord.getRowId())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        
+        /**
+         * Return a new filtered collection containing only those records that are referenced by this tag.
+         * 
+         * @param conditionsRecordCollection the conditions records to filter
+         * @return the filtered collection
+         */
+        public ConditionsRecordCollection filter(final ConditionsRecordCollection conditionsRecordCollection) {
+            final ConditionsRecordCollection tagConditionsRecordCollection = new ConditionsRecordCollection();
+            for (final ConditionsRecord record : conditionsRecordCollection) {
+                if (this.contains(record)) {
+                    try {
+                        tagConditionsRecordCollection.add(record);
+                    } catch (final ConditionsObjectException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+            return tagConditionsRecordCollection;
+        }
+    }
+
+    /**
+     * Create a conditions tag record.
+     * 
+     * @param conditionsId the referenced conditions record
+     * @param tag the tag name
+     */
+    public ConditionsTag(final int conditionsId, final String tag) {
+        this.setFieldValue("conditions_id", conditionsId);
+        this.setFieldValue("tag", tag);
+    }
+
+    /**
+     * Get the ID of the referenced conditions record.
+     * 
+     * @return the ID of the referenced conditions record
+     */
+    @Field(names = {"conditions_id"})
+    public Integer getConditionsId() {
+        return this.getFieldValue("conditions_id");
+    }
+
+    /**
+     * Get the tag name.
+     * 
+     * @return the tag name
+     */
+    @Field(names = {"tag"})
+    public String getTag() {
+        return this.getFieldValue("tag");
+    }
+}

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/TableMetaData.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/TableMetaData.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/api/TableMetaData.java	Fri Jul 17 16:50:54 2015
@@ -262,9 +262,16 @@
         buff.append('\n');
         return buff.toString();
     }
-
-    // TODO: add methods for getting SQL strings for PreparedStatements; can be setup once at initialization time for
-    // each table
+    
+    /**
+     * Method for removing a field that was found using the automatic introspection methods.
+     */
+    void removeField(String fieldName) {
+        fieldNames.remove(fieldName);
+        fieldTypes.remove(fieldName);
+    }
+
+    // TODO: add methods for getting SQL strings for PreparedStatements; can be setup once at initialization time for each table
     // String getSelectStatement();
     // String getInsertStatement();
     // String getUpdateStatement();

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AbstractCommand.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AbstractCommand.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AbstractCommand.java	Fri Jul 17 16:50:54 2015
@@ -6,6 +6,7 @@
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.Parser;
 import org.apache.commons.cli.PosixParser;
+import org.hps.conditions.database.DatabaseConditionsManager;
 
 /**
  * This is the API that sub-commands such as 'load' or 'print' must implement in the conditions command line interface.
@@ -108,4 +109,12 @@
         final HelpFormatter help = new HelpFormatter();
         help.printHelp(this.getName(), this.getOptions());
     }
+    
+    /**
+     * Convenience method for getting the conditions manager.
+     * @return the conditions manager
+     */
+    public DatabaseConditionsManager getManager() {
+        return DatabaseConditionsManager.getInstance();
+    }
 }

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AddCommand.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AddCommand.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/AddCommand.java	Fri Jul 17 16:50:54 2015
@@ -41,7 +41,6 @@
         OPTIONS.getOption("t").setRequired(true);
         OPTIONS.addOption("c", true, "collection ID (required)");
         OPTIONS.getOption("c").setRequired(true);
-        OPTIONS.addOption("T", true, "tag value (optional)");
         OPTIONS.addOption("u", true, "user name (optional)");
         OPTIONS.addOption("m", true, "notes about this conditions set (optional)");
     }
@@ -67,7 +66,7 @@
      * @return the new conditions record
      */
     private ConditionsRecord createConditionsRecord(final int runStart, final int runEnd, final String tableName,
-            final String name, final int collectionId, final String createdBy, final String tag, final String notes) {
+            final String name, final int collectionId, final String createdBy, final String notes) {
         final ConditionsRecord conditionsRecord = new ConditionsRecord();
         final FieldValuesMap fieldValues = new FieldValuesMap();
         fieldValues.setValue("run_start", runStart);
@@ -76,9 +75,6 @@
         fieldValues.setValue("name", name);
         fieldValues.setValue("collection_id", collectionId);
         fieldValues.setValue("created_by", createdBy);
-        if (tag != null) {
-            fieldValues.setValue("tag", tag);
-        }
         if (notes != null) {
             fieldValues.setValue("notes", notes);
         }
@@ -134,12 +130,6 @@
             createdBy = commandLine.getOptionValue("u");
         }
 
-        // Tag to assign (optional).
-        String tag = null;
-        if (commandLine.hasOption("T")) {
-            tag = commandLine.getOptionValue("T");
-        }
-
         // Notes (optional).
         String notes = null;
         if (commandLine.hasOption("m")) {
@@ -148,7 +138,7 @@
 
         // Create the conditions record to insert.
         final ConditionsRecord conditionsRecord = this.createConditionsRecord(runStart, runEnd, tableName, name,
-                collectionId, createdBy, tag, notes);
+                collectionId, createdBy, notes);
         LOGGER.info("inserting conditions record ..." + '\n' + conditionsRecord);
         try {
             boolean createdConnection = false;

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/CommandLineTool.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/CommandLineTool.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/CommandLineTool.java	Fri Jul 17 16:50:54 2015
@@ -202,7 +202,7 @@
         // User specified tag of conditions records.
         if (commandLine.hasOption("t")) {
             final String tag = commandLine.getOptionValue("t");
-            this.conditionsManager.setTag(tag);
+            this.conditionsManager.addTag(tag);
             LOGGER.config("using tag " + tag);
         }
 

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/TagCommand.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/TagCommand.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/cli/TagCommand.java	Fri Jul 17 16:50:54 2015
@@ -1,9 +1,9 @@
 package org.hps.conditions.cli;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -12,54 +12,81 @@
 import org.apache.commons.cli.Options;
 import org.hps.conditions.api.ConditionsObjectException;
 import org.hps.conditions.api.ConditionsRecord;
-import org.hps.conditions.api.TableRegistry;
 import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
+import org.hps.conditions.api.ConditionsTag;
+import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
 import org.hps.conditions.api.DatabaseObjectException;
 import org.hps.conditions.api.TableMetaData;
-import org.hps.conditions.database.DatabaseConditionsManager;
-import org.lcsim.conditions.ConditionsManager.ConditionsNotFoundException;
+import org.hps.conditions.api.TableRegistry;
+import org.hps.conditions.database.MultipleCollectionsAction;
+import org.lcsim.util.log.DefaultLogFormatter;
 import org.lcsim.util.log.LogUtil;
 
 /**
  * Create a conditions system tag.
+ * <p>
+ * The tag groups together conditions records from the <i>conditions</i> database table with a run validity range that 
+ * is between a specified starting and ending run.
+ * <p>
+ * Tagging will not disambiguate overlapping conditions, which is done at run-time based on the current run number.
  *
  * @author Jeremy McCormick, SLAC
  */
-public class TagCommand extends AbstractCommand {
-
-    /**
-     * The default detector name (dummy detector).
-     */
-    private static final String DETECTOR_NAME = "HPS-dummy-detector";
-
-    /**
-     * Setup logger.
-     */
-    private static final Logger LOGGER = LogUtil.create(TagCommand.class);
-
+final class TagCommand extends AbstractCommand {
+
+    /**
+     * Setup the logger.
+     */
+    private static final Logger LOGGER = LogUtil.create(TagCommand.class, new DefaultLogFormatter(), Level.ALL);
+    
     /**
      * Defines command options.
      */
     private static Options OPTIONS = new Options();
 
     /**
-     * Define command options.
+     * Define all command options.
      */
     static {
         OPTIONS.addOption(new Option("h", false, "Show help for tag command"));
-        OPTIONS.addOption(new Option("r", true, "List of run numbers to scan (at least one must be provided)"));
-        OPTIONS.getOption("r").setArgs(Option.UNLIMITED_VALUES);
-        OPTIONS.getOption("r").setRequired(true);
-        OPTIONS.addOption(new Option("t", true, "The new conditions tag"));
+        OPTIONS.addOption(new Option("t", true, "Conditions tag name"));
+        OPTIONS.addOption(new Option("s", true, "Starting run number (required)"));
+        OPTIONS.getOption("s").setRequired(true);
+        OPTIONS.addOption(new Option("e", true, "Ending run number (default is unlimited)"));
         OPTIONS.getOption("t").setRequired(true);
-        OPTIONS.addOption(new Option("f", false, "Don't prompt before making tag (careful!)"));
+        OPTIONS.addOption(new Option("m", true,
+                "MultipleCollectionsAction to use for disambiguation (default is LAST_CREATED)"));
+        OPTIONS.addOption(new Option("d", false, "Don't prompt before making tag (be careful!)"));
     }
 
     /**
      * Class constructor.
      */
     TagCommand() {
-        super("tag", "Tag a set of collections by copying their conditions records", OPTIONS);
+        super("tag", "Tag a set of conditions records to group them together", OPTIONS);
+    }
+
+    /**
+     * Create the collection with the records for creating a new conditions "tag".
+     *
+     * @param tagConditionsRecordCollection the tag record collection
+     * @param tagName the tag name
+     * @return the tag record collection
+     */
+    private ConditionsTagCollection createConditionsTagCollection(
+            final ConditionsRecordCollection tagConditionsRecordCollection, final String tagName) {
+        final ConditionsTagCollection conditionsTagCollection = new ConditionsTagCollection();
+        conditionsTagCollection.setConnection(this.getManager().getConnection());
+        conditionsTagCollection.setTableMetaData(TableRegistry.getTableRegistry().findByTableName("conditions_tags"));
+        for (final ConditionsRecord conditionsRecord : tagConditionsRecordCollection) {
+            final ConditionsTag conditionsTag = new ConditionsTag(conditionsRecord.getRowId(), tagName);
+            try {
+                conditionsTagCollection.add(conditionsTag);
+            } catch (final ConditionsObjectException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return conditionsTagCollection;
     }
 
     /**
@@ -70,108 +97,154 @@
 
         final CommandLine commandLine = this.parse(arguments);
 
-        final Set<Integer> runNumbers = new LinkedHashSet<Integer>();
-        if (commandLine.getOptionValues("r") == null) {
-            throw new RuntimeException("Missing -r argument with list of run numbers.");
-        }
-        for (final String value : commandLine.getOptionValues("r")) {
-            runNumbers.add(Integer.parseInt(value));
-        }
-        if (runNumbers.size() == 0) {
-            throw new RuntimeException("At least one run number must be provided with the -r switch.");
-        }
-
-        final String newTag;
+        // New tag name.
+        final String tagName;
         if (commandLine.hasOption("t")) {
-            newTag = commandLine.getOptionValue("t");
+            tagName = commandLine.getOptionValue("t");
+            LOGGER.info("tag name set to " + tagName);
         } else {
             throw new RuntimeException("Missing required -t argument with the tag name.");
         }
 
-        boolean dontPrompt = false;
-        if (commandLine.hasOption("f")) {
-            dontPrompt = true;
-        }
-
-        final ConditionsRecordCollection tagRecords = new ConditionsRecordCollection();
-        final Set<Integer> addedIds = new HashSet<Integer>();
-
-        final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
-        manager.setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
-        manager.setLogLevel(Level.ALL);
-
-        // Scan through all the runs between the start and end run, inclusive.
-        for (final Integer run : runNumbers) {
-            try {
-                // Setup the conditions manager with the run number.
-                manager.setDetector(TagCommand.DETECTOR_NAME, run);
-            } catch (final ConditionsNotFoundException e) {
-                throw new RuntimeException(e);
-            }
-
-            // The unique conditions keys from this run.
-            final Set<String> keys = manager.getConditionsRecords().getConditionsKeys();
-
-            // Scan through all the unique keys.
-            for (final String key : keys) {
-
-                // Get the table meta data for the key.
-                final TableMetaData tableMetaData = manager.findTableMetaData(key);
-
-                // Get the ConditionsRecord from the collection.
-                final ConditionsRecordCollection records = manager.findConditionsRecords(key);
-                records.sortByUpdated();
-                final ConditionsRecord record = records.get(records.size() - 1);
-
-                manager.getCachedConditions(tableMetaData.getCollectionClass(), tableMetaData.getTableName())
-                        .getCachedData();
-
-                // Is this record already part of the new tag?
-                if (!addedIds.contains(record.getRowId())) {
-                    // Create a new record copied from the old one.
-                    final ConditionsRecord newRecord = new ConditionsRecord(record);
-
-                    // Set the tag value.
-                    newRecord.setFieldValue("tag", newTag);
-
-                    // Add the record to the tag.
-                    try {
-                        tagRecords.add(newRecord);
-                    } catch (final ConditionsObjectException e) {
-                        throw new RuntimeException(e);
-                    }
-
-                    // Flag the record's ID as used so it is only added once.
-                    addedIds.add(record.getRowId());
-                }
-            }
-        }
-
-        // Print out all the records that were found.
-        LOGGER.info("found ConditionsRecords for tag " + newTag + " ...");
-        for (final ConditionsRecord record : tagRecords) {
-            LOGGER.info(record.toString());
-        }
-
-        // Prompt user to verify with console input.
-        boolean makeTag = true;
-        if (!dontPrompt) {
-            LOGGER.info("Create conditions tag " + newTag + " in database?  (Y/N)");
+        // Starting run number (required).
+        int runStart = -1;
+        if (commandLine.hasOption("s")) {
+            runStart = Integer.parseInt(commandLine.getOptionValue("s"));
+            LOGGER.config("run start set to " + runStart);
+        } else {
+            throw new RuntimeException("missing require -s argument with starting run number");
+        }
+
+        // Ending run number (max integer is default).
+        int runEnd = Integer.MAX_VALUE;
+        if (commandLine.hasOption("e")) {
+            runEnd = Integer.parseInt(commandLine.getOptionValue("e"));
+            LOGGER.config("run end set to " + runEnd);
+        }
+
+        // Run end must be greater than or equal to run start.
+        if (runEnd < runStart) {
+            throw new IllegalArgumentException("runEnd < runStart");
+        }
+
+        // Action for disambiguating overlapping collections (default is to use the most recent creation date).
+        MultipleCollectionsAction multipleCollectionsAction = MultipleCollectionsAction.LAST_CREATED;
+        if (commandLine.hasOption("m")) {
+            multipleCollectionsAction = MultipleCollectionsAction
+                    .valueOf(commandLine.getOptionValue("m").toUpperCase());
+        }
+        LOGGER.config("multiple collections action set tco " + multipleCollectionsAction);
+
+        // Whether to prompt before tagging (default is yes).
+        boolean promptBeforeTagging = true;
+        if (commandLine.hasOption("d")) {
+            promptBeforeTagging = false;
+        }
+        LOGGER.config("prompt before tagging: " + promptBeforeTagging);
+
+        // Conditions system configuration.
+        this.getManager().setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
+        this.getManager().setLogLevel(Level.ALL);
+
+        // Find all the applicable conditions records by their run number ranges.
+        ConditionsRecordCollection tagConditionsRecordCollection = this.findConditionsRecords(runStart, runEnd);
+
+        LOGGER.info("found " + tagConditionsRecordCollection.size() + " conditions records for the tag");
+
+        // Build the collection of tag records to insert into the database.
+        final ConditionsTagCollection conditionsTagCollection = this.createConditionsTagCollection(
+                tagConditionsRecordCollection, tagName);
+
+        LOGGER.info("created " + conditionsTagCollection.size() + " tag records ..." + '\n' + conditionsTagCollection);
+
+        LOGGER.getHandlers()[0].flush();
+
+        // Prompt user to verify tag creation.
+        boolean createTag = true;
+        if (promptBeforeTagging) {
+            System.out.println("Create conditions tag '" + tagName + "' in the database?  (Y/N)");
             final String line = System.console().readLine();
             if (!line.equals("Y")) {
-                makeTag = false;
-            }
-        }
-
-        // Create the tag in the database if user verified or force option was present.
-        if (makeTag) {
+                createTag = false;
+            }
+        }
+
+        // Create the tag.
+        if (createTag) {
             try {
-                tagRecords.setConnection(manager.getConnection());
-                tagRecords.setTableMetaData(TableRegistry.getTableRegistry().findByTableName("conditions"));
-                tagRecords.insert();
+                LOGGER.info("creating tag " + tagName + " in the database ...");
+                conditionsTagCollection.insert();
             } catch (DatabaseObjectException | SQLException e) {
                 throw new RuntimeException(e);
             }
-        }
+        } else {
+            LOGGER.warning("user aborted tag operation!");
+        }
+
+        LOGGER.info("done!");
+    }
+   
+    /**
+     * Find all the conditions records that are applicable for the given run range.
+     * <p>
+     * Overlapping run numbers in conditions with the same key are not disambiguated.
+     * This must be done in the user's job at runtime; usually the most recently created 
+     * conditions record will be used if multiple one's are applicable to the current run.
+     *
+     * @param runStart the start run
+     * @param runEnd the end run (must be greater than or equal to <code>runStart</code>)
+     * @return the conditions records that fall in the run range
+     */
+    private ConditionsRecordCollection findConditionsRecords(final int runStart, final int runEnd) {
+        if (runStart > runEnd) {
+            throw new IllegalArgumentException("runStart > runEnd");
+        }
+        if (runStart < 0) {
+            throw new IllegalArgumentException("invalid runStart: " + runStart);
+        }
+        if (runEnd < 0) {
+            throw new IllegalArgumentException("invalid runEnd: " + runEnd);
+        }
+        final Connection connection = this.getManager().getConnection();
+        final ConditionsRecordCollection conditionsRecordCollection = new ConditionsRecordCollection();
+        final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName("conditions");
+        PreparedStatement statement = null;
+        try {
+            /*
+             * SQL statement handles 3 cases: 
+             * 1) condition's run_start in range 
+             * 2) condition's run_end in range 
+             * 3) condition's run_start and run_end enclose the range
+             */
+            statement = connection
+                    .prepareStatement("SELECT id FROM conditions WHERE (run_start >= ? and run_start <= ?) or (run_end >= ? and run_end <= ?)"
+                            + " or (run_start <= ? and run_end >= ?)");
+            statement.setInt(1, runStart);
+            statement.setInt(2, runEnd);
+            statement.setInt(3, runStart);
+            statement.setInt(4, runEnd);
+            statement.setInt(5, runStart);
+            statement.setInt(6, runEnd);
+
+            final ResultSet resultSet = statement.executeQuery();
+            while (resultSet.next()) {
+                final ConditionsRecord record = new ConditionsRecord();
+                record.setConnection(connection);
+                record.setTableMetaData(tableMetaData);
+                record.select(resultSet.getInt(1));
+                conditionsRecordCollection.add(record);
+            }
+        } catch (DatabaseObjectException | ConditionsObjectException | SQLException e) {
+            throw new RuntimeException(e);
+        } finally {
+            try {
+                if (statement != null) {
+                    statement.close();
+                }
+            } catch (final SQLException e) {
+                e.printStackTrace();
+            }
+        }
+        return conditionsRecordCollection;
     }
 }

Added: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java	(added)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/ConditionsTagConverter.java	Fri Jul 17 16:50:54 2015
@@ -0,0 +1,78 @@
+package org.hps.conditions.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.hps.conditions.api.AbstractConditionsObjectConverter;
+import org.hps.conditions.api.ConditionsObjectException;
+import org.hps.conditions.api.ConditionsTag;
+import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
+import org.lcsim.conditions.ConditionsManager;
+
+/**
+ * Convert records in the <i>conditions_tags</i> table to a conditions object collection. 
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+public class ConditionsTagConverter extends AbstractConditionsObjectConverter<ConditionsTagCollection>  {
+    
+    /**
+     * SQL SELECT string.
+     */
+    private static final String SELECT_SQL = "SELECT conditions_id, tag from conditions_tags where tag = ?";
+   
+    /**
+     * Get a {@link org.hps.conditions.api.ConditionsTagCollection} which specifies a group of collections
+     * that are tagged in the <i>conditions_tags</i> table in the database.
+     * <p>
+     * The run number is not used, and the <code>name</code> argument specifies the tag name.
+     *
+     * @param manager The current conditions manager.
+     * @param name The name of the conditions set.
+     * @return The matching ConditionsRecords.
+     */
+    @Override
+    public ConditionsTagCollection getData(final ConditionsManager manager, final String name) {
+
+        ConditionsTagCollection conditionsTagCollection = new ConditionsTagCollection();
+        DatabaseConditionsManager dbConditionsManager = DatabaseConditionsManager.class.cast(manager);
+        if (dbConditionsManager == null) {
+            throw new IllegalArgumentException("The conditions manager has the wrong type.");
+        }
+        boolean openedConnection = dbConditionsManager.openConnection();
+        Connection connection = DatabaseConditionsManager.getInstance().getConnection();
+        try {
+            PreparedStatement statement = connection.prepareStatement(SELECT_SQL);
+            statement.setString(1, name);
+            ResultSet resultSet = statement.executeQuery();
+            while (resultSet.next()) {
+                Integer conditionsId = resultSet.getInt(1);
+                String tag = resultSet.getString(2);
+                ConditionsTag record = new ConditionsTag(conditionsId, tag);
+                conditionsTagCollection.add(record);
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        } catch (ConditionsObjectException e) {
+            throw new RuntimeException(e);
+        } finally {
+            dbConditionsManager.closeConnection(openedConnection);
+        }
+        if (conditionsTagCollection.size() == 0) {
+            throw new IllegalArgumentException("The conditions tag " + name + " does not exist in the database.");
+        }
+        return conditionsTagCollection;
+    }
+
+    /**
+     * Get the type handled by this converter.
+     *
+     * @return The type handled by this converter, which is <code>ConditionsRecordCollection</code>.
+     */
+    @Override
+    public Class<ConditionsTagCollection> getType() {
+        return ConditionsTagCollection.class;
+    }    
+}

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/database/DatabaseConditionsManager.java	Fri Jul 17 16:50:54 2015
@@ -12,6 +12,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -21,10 +22,10 @@
 import org.hps.conditions.api.AbstractConditionsObjectConverter;
 import org.hps.conditions.api.ConditionsObject;
 import org.hps.conditions.api.ConditionsObjectCollection;
-import org.hps.conditions.api.ConditionsObjectException;
 import org.hps.conditions.api.ConditionsRecord;
 import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
 import org.hps.conditions.api.ConditionsSeries;
+import org.hps.conditions.api.ConditionsTag.ConditionsTagCollection;
 import org.hps.conditions.api.TableMetaData;
 import org.hps.conditions.api.TableRegistry;
 import org.hps.conditions.ecal.EcalConditions;
@@ -259,10 +260,20 @@
     private final TableRegistry tableRegistry = TableRegistry.getTableRegistry();
 
     /**
-     * The currently active conditions tag.
-     */
-    private String tag = null;
-
+     * The currently active conditions tag (empty collection means no tag is active).
+     */
+    private ConditionsTagCollection conditionsTagCollection = new ConditionsTagCollection();
+    
+    /**
+     * The current set of conditions for the run.
+     */
+    private ConditionsRecordCollection conditionsRecordCollection = null;
+    
+    /**
+     * The currently applied conditions tags.
+     */
+    private Set<String> tags = new HashSet<String>();
+    
     /**
      * Class constructor. Calling this will automatically register this manager as the global default.
      */
@@ -382,27 +393,7 @@
      * @return the set of matching conditions records
      */
     public ConditionsRecordCollection findConditionsRecords(final String name) {
-        final ConditionsRecordCollection runConditionsRecords = this.getCachedConditions(
-                ConditionsRecordCollection.class, "conditions").getCachedData();
-        logger.fine("searching for conditions with name " + name + " in " + runConditionsRecords.size() + " records");
-        final ConditionsRecordCollection foundConditionsRecords = new ConditionsRecordCollection();
-        for (final ConditionsRecord record : runConditionsRecords) {
-            if (record.getName().equals(name)) {
-                if (this.matchesTag(record)) {
-                    try {
-                        foundConditionsRecords.add(record);
-                    } catch (final ConditionsObjectException e) {
-                        throw new RuntimeException(e);
-                    }
-                    logger.finer("found matching conditions record " + record.getRowId());
-                } else {
-                    logger.finer("conditions record " + record.getRowId() + " rejected from non-matching tag "
-                            + record.getTag());
-                }
-            }
-        }
-        logger.fine("found " + foundConditionsRecords.size() + " conditions records matching tag " + this.tag);
-        return foundConditionsRecords;
+        return getConditionsRecords().findByKey(name);
     }
 
     /**
@@ -483,31 +474,30 @@
         collection.setCollectionId(collectionId);
         return collectionId;
     }
-
-    /**
-     * Get a list of all the {@link ConditionsRecord} objects.
-     *
-     * @return the list of all the {@link ConditionsRecord} objects
-     */
-    // FIXME: This should use a cache that is created during initialization, rather than look these up every time.
+    
+    /**
+     * Get the list of conditions records for the run, filtered by the current set of active tags.
+     * 
+     * @return the list of conditions records for the run
+     */
     public ConditionsRecordCollection getConditionsRecords() {
-        logger.finer("getting conditions records ...");
-        final ConditionsRecordCollection conditionsRecords = new ConditionsRecordCollection();
-        for (final TableMetaData tableMetaData : this.tableRegistry.values()) {
-            try {
-                final ConditionsRecordCollection foundConditionsRecords = this.findConditionsRecords(tableMetaData
-                        .getKey());
-                logger.finer("found " + foundConditionsRecords.size() + " collections with name "
-                        + tableMetaData.getKey());
-                conditionsRecords.addAll(foundConditionsRecords);
-            } catch (final Exception e) {
-                e.printStackTrace();
-                logger.warning(e.getMessage());
-            }
-        }
-        logger.finer("found " + conditionsRecords + " conditions records");
-        logger.getHandlers()[0].flush();
-        return conditionsRecords;
+        if (this.run == -1 || this.detectorName == null) {
+            throw new IllegalStateException("Conditions system is not initialized.");
+        } 
+        // If the collection is null then the new conditions records need to be retrieved from the database.
+        if (this.conditionsRecordCollection == null) {
+            
+            // Get the collection of conditions that are applicable for the current run.
+            this.conditionsRecordCollection =  
+                    this.getCachedConditions(ConditionsRecordCollection.class, "conditions").getCachedData();
+            
+            // If there is one or more tags enabled then filter the collection by the tag names.
+            if (this.conditionsTagCollection.size() > 0) {
+                this.conditionsRecordCollection = 
+                        this.conditionsTagCollection.filter(this.conditionsRecordCollection);
+            }
+        }
+        return this.conditionsRecordCollection;
     }
 
     /**
@@ -675,11 +665,14 @@
 
         // Open the database connection.
         this.openConnection();
-
+        
+        // Reset the conditions records to trigger a re-caching.
+        this.conditionsRecordCollection = null;
+        
         // Call the super class's setDetector method to construct the detector object and activate conditions listeners.
         logger.fine("activating default conditions manager");
         super.setDetector(detectorName, runNumber);
-
+        
         // Should all conditions sets be cached?
         if (this.cacheAllConditions) {
             // Cache the conditions sets of all registered converters.
@@ -811,24 +804,11 @@
     }
 
     /**
-     * Return <code>true</code> if the conditions record matches the current tag
-     *
-     * @param record the conditions record
-     * @return <code>true</code> if conditions record matches the currently used tag
-     */
-    private boolean matchesTag(final ConditionsRecord record) {
-        if (this.tag == null) {
-            // If there is no tag set then all records pass.
-            return true;
-        }
-        final String recordTag = record.getTag();
-        if (recordTag == null) {
-            // If there is a tag set but the record has no tag, it is rejected.
-            return false;
-        }
-        return this.tag.equals(recordTag);
-    }
-
+     * Create a new collection with the given type.
+     * 
+     * @param collectionType the collection type
+     * @return the new collection
+     */
     public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection(
             final Class<CollectionType> collectionType) {
         final List<TableMetaData> tableMetaDataList = TableRegistry.getTableRegistry().findByCollectionType(
@@ -849,6 +829,13 @@
         return collection;
     }
 
+    /**
+     * Create a new collection with the given type and table name.
+     * 
+     * @param collectionType the collection type
+     * @param tableName the table name
+     * @return the new collection
+     */
     public <CollectionType extends ConditionsObjectCollection<?>> CollectionType newCollection(
             final Class<CollectionType> collectionType, final String tableName) {
         final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName(tableName);
@@ -1044,13 +1031,40 @@
     }
 
     /**
-     * Set a tag used to filter the accessible conditions records
+     * Add a tag used to filter the accessible conditions records.
+     * <p>
+     * Multiple tags are OR'd together.
      *
      * @param tag the tag value used to filter returned conditions records
      */
-    public void setTag(final String tag) {
-        this.tag = tag;
-        logger.info("using conditions tag: " + tag);
+    public void addTag(final String tag) {
+        if (!this.tags.contains(tag)) {
+            logger.info("adding tag " + tag);
+            ConditionsTagCollection addConditionsTagCollection = this.getCachedConditions(ConditionsTagCollection.class, tag).getCachedData();
+            logger.info("adding conditions tag " + tag + " with " + conditionsTagCollection.size() + " records");
+            this.conditionsTagCollection.addAll(addConditionsTagCollection);                    
+        } else {
+            logger.warning("tag " + tag + " is already added");
+        }
+    }
+    
+    /**
+     * Add one or more tags for filtering records.
+     * 
+     * @param tags the <code>Set</code> of tags to add
+     */
+    public void addTags(final Set<String> tags) {
+        for (String tag : tags) {
+            this.addTag(tag);
+        }
+    }
+    
+    /**
+     * Clear the tags used to filter the {@link org.hps.conditons.api.ConditionsRecord}s.
+     */
+    public void clearTags() {
+        this.tags.clear();
+        this.conditionsTagCollection.clear();
     }
 
     /**

Modified: java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ecal/EcalPulseWidth.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ecal/EcalPulseWidth.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/main/java/org/hps/conditions/ecal/EcalPulseWidth.java	Fri Jul 17 16:50:54 2015
@@ -34,8 +34,8 @@
      * Get the signal pulse width.
      * @return the signal pulse width
      */
-    @Field(names = {"ecal_pulse_width"})
+    @Field(names = {"pulse_width"})
     public Double getPulseWidth() {
-        return this.getFieldValue("ecal_pulse_width");
+        return this.getFieldValue("pulse_width");
     }
 }

Modified: java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/EngRunConditionsTest.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/EngRunConditionsTest.java	(original)
+++ java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/EngRunConditionsTest.java	Fri Jul 17 16:50:54 2015
@@ -220,7 +220,7 @@
 
         final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
         DatabaseConditionsManager.getLogger().setLevel(Level.ALL);
-        manager.setTag("pass0");
+        manager.addTag("pass0");
         manager.setXmlConfig("/org/hps/conditions/config/conditions_database_engrun.xml");
 
         final FileCache cache = new FileCache();

Added: java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java
 =============================================================================
--- java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java	(added)
+++ java/branches/conditions-HPSJAVA-517/src/test/java/org/hps/conditions/api/ConditionsTagTest.java	Fri Jul 17 16:50:54 2015
@@ -0,0 +1,119 @@
+package org.hps.conditions.api;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection;
+import org.hps.conditions.database.DatabaseConditionsManager;
+import org.hps.conditions.ecal.EcalCalibration.EcalCalibrationCollection;
+import org.hps.conditions.ecal.EcalChannel.EcalChannelCollection;
+import org.hps.conditions.ecal.EcalGain.EcalGainCollection;
+import org.hps.conditions.ecal.EcalTimeShift.EcalTimeShiftCollection;
+import org.hps.conditions.svt.SvtAlignmentConstant.SvtAlignmentConstantCollection;
+import org.hps.conditions.svt.SvtCalibration.SvtCalibrationCollection;
+import org.hps.conditions.svt.SvtChannel.SvtChannelCollection;
+import org.hps.conditions.svt.SvtDaqMapping.SvtDaqMappingCollection;
+import org.hps.conditions.svt.SvtGain.SvtGainCollection;
+import org.hps.conditions.svt.SvtShapeFitParameters.SvtShapeFitParametersCollection;
+import org.hps.conditions.svt.SvtT0Shift.SvtT0ShiftCollection;
+import org.hps.conditions.svt.SvtTimingConstants.SvtTimingConstantsCollection;
+
+public class ConditionsTagTest extends TestCase {
+
+    private static final int[] RUNS = { 5037, 5038, 5066, 5076, 5139, 5149, 5174, 5181, 5200, 5218, 5236, 5251, 5253,
+        5263, 5299, 5310, 5375, 5388, 5389, 5400, 5404, 5533, 5538, 5558, 5575, 5596, 5601, 5603, 5610, 5623, 5640,
+        5641, 5642, 5673, 5686, 5711, 5712, 5713, 5714, 5722, 5747, 5748, 5779
+    };
+    
+    private static final String[] CONDITIONS = {
+        "ecal_calibrations",
+        "ecal_channels",
+        "ecal_gains",
+        "ecal_time_shifts",
+        "svt_alignments",
+        "svt_calibrations",
+        "svt_channels",
+        "svt_daq_map",
+        "svt_gains",
+        "svt_shape_fit_parameters",
+        "svt_t0_shifts",
+        "svt_timing_constants"
+    };
+    
+    private static final Class<?> TYPES[] = {
+        EcalCalibrationCollection.class,
+        EcalChannelCollection.class,
+        EcalGainCollection.class,
+        EcalTimeShiftCollection.class,
+        SvtAlignmentConstantCollection.class,
+        SvtCalibrationCollection.class,
+        SvtChannelCollection.class,
+        SvtDaqMappingCollection.class,
+        SvtGainCollection.class,
+        SvtShapeFitParametersCollection.class,
+        SvtT0ShiftCollection.class,
+        SvtTimingConstantsCollection.class
+    };
+    
+    private static DatabaseConditionsManager MANAGER;      
+    
+    @Override
+    public void setUp() {
+        // Configure the conditions system.
+        MANAGER = DatabaseConditionsManager.getInstance();
+        MANAGER.setConnectionResource("/org/hps/conditions/config/jeremym_dev_connection.prop");
+        MANAGER.setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
+        //MANAGER.setLogLevel(Level.WARNING);
+    }
+    
+    public void testConditionsTag() throws Exception {
+        MANAGER.addTag("pass1");
+        for (int run : RUNS) {
+            MANAGER.setDetector("HPS-conditions-test", run);
+            ConditionsRecordCollection conditionsRecordCollection = MANAGER.getConditionsRecords();
+            System.out.println("run " + run + " has " + conditionsRecordCollection.size());
+            System.out.println(conditionsRecordCollection);
+            for (int i = 0; i < CONDITIONS.length; i++) {
+                try {
+                    BaseConditionsObjectCollection<?> conditionsObjectCollection = 
+                            BaseConditionsObjectCollection.class.cast(
+                                    MANAGER.getCachedConditions(TYPES[i], CONDITIONS[i]).getCachedData());
+                System.out.println("got collection " + conditionsObjectCollection.getTableMetaData().getTableName() 
+                        + " with type " + conditionsObjectCollection.getTableMetaData().getCollectionClass().getName() 
+                        + " and " + conditionsObjectCollection.size() + " objects");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    
+    public void testMultipleConditionsTags() throws Exception {
+        Set<String> tags = new HashSet<String>();
+        tags.add("pass1");
+        tags.add("dev");
+        tags.add("eng_run");
+        tags.add("derp");
+        
+        for (int run : RUNS) {
+            MANAGER.setDetector("HPS-conditions-test", run);
+            ConditionsRecordCollection conditionsRecordCollection = MANAGER.getConditionsRecords();
+            System.out.println("run " + run + " has " + conditionsRecordCollection.size());
+            System.out.println(conditionsRecordCollection);
+            for (int i = 0; i < CONDITIONS.length; i++) {
+                try {
+                    BaseConditionsObjectCollection<?> conditionsObjectCollection = 
+                            BaseConditionsObjectCollection.class.cast(
+                                    MANAGER.getCachedConditions(TYPES[i], CONDITIONS[i]).getCachedData());
+                System.out.println("got collection " + conditionsObjectCollection.getTableMetaData().getTableName() 
+                        + " with type " + conditionsObjectCollection.getTableMetaData().getCollectionClass().getName() 
+                        + " and " + conditionsObjectCollection.size() + " objects");
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}

Top of Message | Previous Page | Permalink

Advanced Options


Options

Log In

Log In

Get Password

Get Password


Search Archives

Search Archives


Subscribe or Unsubscribe

Subscribe or Unsubscribe


Archives

November 2017
August 2017
July 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013

ATOM RSS1 RSS2



LISTSERV.SLAC.STANFORD.EDU

Secured by F-Secure Anti-Virus CataList Email List Search Powered by the LISTSERV Email List Manager

Privacy Notice, Security Notice and Terms of Use