[kepler-dev] Help=>Modules Documentation

Derik Barseghian barseghian at nceas.ucsb.edu
Thu Aug 18 17:21:15 PDT 2011


Hi Lei and devs,

Just a note: if you'd like your module's docs/ documentation pdf to show up from within Kepler's Help=>Modules Documentation menu, you need to name it [your-modulename].pdf.
This is a silly restriction we should remove--that menu should be more flexible, allowing multiple docs per module--but until then that's how it works.

Derik


On Aug 18, 2011, at 5:01 PM, dou at ecoinformatics.org wrote:

> Author: dou
> Date: 2011-08-18 17:01:27 -0700 (Thu, 18 Aug 2011)
> New Revision: 28318
> 
> Added:
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder.java
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder2.java
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/DailyCollectingEventOutlierIdentificationService.java
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/ICollectingEventIdentificationService2.java
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/OutlierFinderResponseConstructor.java
>   trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/SpecimenRecordType.java
>   trunk/modules/kuration/workflows/OutlierIdentification/
>   trunk/modules/kuration/workflows/OutlierIdentification/OutlierIdentification.xml
>   trunk/modules/kuration/workflows/OutlierIdentification/data/
>   trunk/modules/kuration/workflows/OutlierIdentification/data/MissingGeo_TDWG11_Demo.csv
>   trunk/modules/kuration/workflows/OutlierIdentification/data/TDWG11_Demo.csv
> Modified:
>   trunk/modules/kuration/.classpath
>   trunk/modules/kuration/docs/Kuration Package User Manual.pdf
>   trunk/modules/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js
>   trunk/modules/kuration/workflows/SpecimenCuration/data/SpecimenRecord.js
>   trunk/modules/kuration/workflows/SpecimenCuration/function/visualization/SpecimenVisualization.html
> Log:
> add new demo OutlierIdentification for TDWG11
> 
> 
> Modified: trunk/modules/kuration/.classpath
> ===================================================================
> --- trunk/modules/kuration/.classpath	2011-08-18 23:56:34 UTC (rev 28317)
> +++ trunk/modules/kuration/.classpath	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -59,9 +59,6 @@
>   <classpathentry exported="true" kind="lib" path="lib\xoauth.jar"/>
>   <classpathentry combineaccessrules="false" kind="src" path="/koogle"/>
>   <classpathentry combineaccessrules="false" kind="src" path="/comad-exp"/>
> -  <classpathentry combineaccessrules="false" kind="src" path="/provenance-browser"/>
> -  <classpathentry combineaccessrules="false" kind="src" path="/prov-challenge-comad-actors"/>
> -  <classpathentry combineaccessrules="false" kind="src" path="/comad"/>
>   <classpathentry combineaccessrules="false" kind="src" path="/kepler"/>
>   <classpathentry combineaccessrules="false" kind="src" path="/outreach"/>
>   <classpathentry combineaccessrules="false" kind="src" path="/r"/>
> 
> Modified: trunk/modules/kuration/docs/Kuration Package User Manual.pdf
> ===================================================================
> (Binary files differ)
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,451 @@
> +/** Base class for coactors with one input and one output port.
> + *
> + * Copyright (c) 2008 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.math.RoundingMode;
> +import java.text.DecimalFormat;
> +import java.text.ParseException;
> +import java.text.SimpleDateFormat;
> +import java.util.Comparator;
> +import java.util.Date;
> +import java.util.Iterator;
> +import java.util.LinkedHashMap;
> +import java.util.LinkedList;
> +import java.util.TreeSet;
> +
> +import org.kepler.actor.SpecimenQC.util.CurationComment;
> +import org.kepler.actor.SpecimenQC.util.CurationComment.CurationStatus;
> +import org.kepler.coactors.ExtendedCollectionTransformer;
> +import org.kepler.demo.OutlierIdentification.SpecimenRecordType;
> +import org.kepler.exceptions.CollectionException;
> +import org.kepler.tokens.DataToken;
> +import org.kepler.util.AnnotationSet;
> +import org.kepler.util.CollectionManager;
> +import org.kepler.util.DependencySet;
> +import org.kepler.util.Parameters;
> +import org.kepler.util.TokenDisposition;
> +
> +import ptolemy.data.Token;
> +import ptolemy.data.IntToken;
> +import ptolemy.data.DoubleToken;
> +import ptolemy.data.OrderedRecordToken;
> +import ptolemy.data.RecordToken;
> +import ptolemy.data.StringToken;
> +import ptolemy.data.BooleanToken;
> +import ptolemy.data.expr.Parameter;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +
> +/**
> + * clustering on Collectors
> + * then clustering on Time
> + * then in each cluster, find out the outlier according to the lat/log (calculate distance between each two point)
> + * 
> + * @author fancy
> + *
> + */
> +public class CollectingEventOutlierFinder extends ExtendedCollectionTransformer{	
> +	
> +	public CollectingEventOutlierFinder(CompositeEntity container, String name)
> +		throws NameDuplicationException, IllegalActionException {
> +
> +		super(container, name);
> +		
> +		dataLabel = Parameters.stringParameter(this, "dataLabel", "");
> +		travelSpeedParam = Parameters.doubleParameter(this, "dailyTravelSpeed", 5.0); //km/day
> +		resultCollectionLabel = Parameters.stringParameter(this, "resultCollectionLabel", "");
> +		normalDataCollectionLabel = Parameters.stringParameter(this, "normalDataCollectionLabel", "");
> +		normalDataLabel = Parameters.stringParameter(this, "normalDataLabel", "");	
> +		outlierCommentLabel = Parameters.stringParameter(this, "outlierCommentLabel", "");
> +		outlierCollectionLabel = Parameters.stringParameter(this, "outlierCollectionLabel", "");
> +		outlierDataLabel = Parameters.stringParameter(this, "outlierDataLabel", "");		
> +		localComparatorDataLabel = Parameters.stringParameter(this, "localComparatorDataLabel", "");
> +		getRemoteEvidenceDataParam = Parameters.booleanParameter(this, "getRemoteEvidenceData", false);
> +		remoteComparatorDataLabel = Parameters.stringParameter(this, "remoteComparatorDataLabel", "");
> +    }
> +	
> +	public void initialize() throws IllegalActionException {
> +		super.initialize();		
> +		
> +		//parse dataLabel
> +		StringToken dataLabelToken = (StringToken)dataLabel.getToken();
> +	    if(dataLabelToken != null && dataLabelToken.stringValue()!=null){
> +	    	dataLabelStr = dataLabelToken.stringValue().trim();
> +	    }else{
> +	    	dataLabelStr = "";
> +	    }
> +	    
> +	    //parse max daily travel speed
> +	    Token travelSpeedToken = travelSpeedParam.getToken();
> +	    if(travelSpeedToken == null){
> +	    	travelSpeed = 5.0;
> +	    }else{
> +	    	travelSpeed = Double.valueOf(travelSpeedToken.toString());
> +	    } 	    
> +
> +		//parse output collection and data label
> +		StringToken resultCollectionLabelToken = (StringToken)resultCollectionLabel.getToken();
> +	    if(resultCollectionLabelToken != null && resultCollectionLabelToken.stringValue()!=null){
> +	    	resultCollectionLabelStr = resultCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	resultCollectionLabelStr = "";
> +	    }
> +
> +		StringToken normalDataCollectionLabelToken = (StringToken)normalDataCollectionLabel.getToken();
> +	    if(normalDataCollectionLabelToken != null && normalDataCollectionLabelToken.stringValue()!=null){
> +	    	normalDataCollectionLabelStr = normalDataCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	normalDataCollectionLabelStr = "";
> +	    }
> +	    
> +		StringToken outlierCommentLabelToken = (StringToken)outlierCommentLabel.getToken();
> +	    if(outlierCommentLabelToken != null && outlierCommentLabelToken.stringValue()!=null){
> +	    	outlierCommentLabelStr = outlierCommentLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierCommentLabelStr = "";
> +	    }	    
> +	    
> +		StringToken outlierCollectionLabelToken = (StringToken)outlierCollectionLabel.getToken();
> +	    if(outlierCollectionLabelToken != null && outlierCollectionLabelToken.stringValue()!=null){
> +	    	outlierCollectionLabelStr = outlierCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierCollectionLabelStr = "";
> +	    }
> +	    
> +		StringToken outlierDataLabelToken = (StringToken)outlierDataLabel.getToken();
> +	    if(outlierDataLabelToken != null && outlierDataLabelToken.stringValue()!=null){
> +	    	outlierDataLabelStr = outlierDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierDataLabelStr = "";
> +	    }
> +	    
> +		StringToken normalDataLabelToken = (StringToken)normalDataLabel.getToken();
> +	    if(normalDataLabelToken != null && normalDataLabelToken.stringValue()!=null){
> +	    	normalDataLabelStr = normalDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	normalDataLabelStr = "";
> +	    }	
> +	    
> +		StringToken localComparatorDataLabelToken = (StringToken)localComparatorDataLabel.getToken();
> +	    if(localComparatorDataLabelToken != null && localComparatorDataLabelToken.stringValue()!=null){
> +	    	localComparatorDataLabelStr = localComparatorDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	localComparatorDataLabelStr = "";
> +	    }
> +	    
> +	    getRemoteEvidence = ((BooleanToken)getRemoteEvidenceDataParam.getToken()).booleanValue();
> +	    
> +	    
> +		StringToken remoteComparatorDataLabelToken = (StringToken)remoteComparatorDataLabel.getToken();
> +	    if(remoteComparatorDataLabelToken != null && remoteComparatorDataLabelToken.stringValue()!=null){
> +	    	remoteComparatorDataLabelStr = remoteComparatorDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	remoteComparatorDataLabelStr = "";
> +	    }
> +	    
> +		//initialize required label
> +//		SpeicmenRecordTypeConf speicmenRecordTypeConf = SpeicmenRecordTypeConf.INSTANCE;		
> +		
> +	    CollectorLabel = "RecordedBy";
> +//		CollectorLabel = speicmenRecordTypeConf.getLabel("RecordedBy");
> +//		if(CollectorLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the RecordedBy label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +	    yearCollectedLabel = "YearCollected";
> +//		yearCollectedLabel = speicmenRecordTypeConf.getLabel("YearCollected");
> +//		if(yearCollectedLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the YearCollected label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +	    monthCollectedLabel = "MonthCollected";
> +//		monthCollectedLabel = speicmenRecordTypeConf.getLabel("MonthCollected");
> +//		if(monthCollectedLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the MonthCollected label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +	    dayCollectedLabel = "DayCollected";
> +//		dayCollectedLabel = speicmenRecordTypeConf.getLabel("DayCollected");
> +//		if(dayCollectedLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the DayCollected label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +	    latitudeLabel = "DecimalLatitude";
> +//		latitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLatitude");
> +//		if(latitudeLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the DecimalLatitude label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +	    longitudeLabel = "DecimalLongitude";
> +//		longitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLongitude");
> +//		if(longitudeLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the DecimalLongitude label of the SpecimenRecordType is not set.");
> +//		}	    
> +		
> +		collectingEventoutlierIdentificationService = new DailyCollectingEventOutlierIdentificationService(); 	    
> +	}	
> +
> +	public void handleScopeStart(CollectionManager collectionManager) throws IllegalActionException{
> +		inputObjList.clear();		
> +		inputDataMap.clear();
> +		
> +		recordWithGeoNum = 0;
> +	}		
> +	
> +  	public TokenDisposition handleData(CollectionManager collectionManager,Object object, AnnotationSet annotations) 
> +  		throws IllegalActionException, CollectionException {
> +  		if(dataLabelStr.equals(getCurrentToken().getLabel().toString())){  			
> +  			inputObjList.add((DataToken)getCurrentToken());
> +  			addDataToken((DataToken)getCurrentToken());
> +  		}  		
> +  		return TokenDisposition.FORWARD_TOKEN;
> +	}	
> +  	
> +	public void handleScopeEnd(CollectionManager collectionManager) throws IllegalActionException {
> +		if(inputObjList.size()==0 || inputDataMap.size()==0){
> +			return;
> +		}
> +		
> +		//find out outlier by using the service
> +		collectingEventoutlierIdentificationService.identifyOutlier(inputDataMap, travelSpeed, getRemoteEvidence);
> +
> +	    LinkedList<DataToken> noneOutlier = collectingEventoutlierIdentificationService.getNoneOutlier();
> +	    LinkedHashMap<DataToken,LinkedList<DataToken>> outlierLocalComparatorMap = collectingEventoutlierIdentificationService.getOutlierLocalComparatorMap();
> +	    LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>> outlierRemoteComparatorMap = collectingEventoutlierIdentificationService.getOutlierRemoteComparatorMap();		
> +		String comment = collectingEventoutlierIdentificationService.getComment();
> +		CurationStatus curationStatus = collectingEventoutlierIdentificationService.getCurationStatus();
> +	    
> +		//output		
> +		
> +		//calculate the percentage of records that has the complete geo-referencing information.
> +		DecimalFormat df = new DecimalFormat("#.##");
> +		df.setRoundingMode(RoundingMode.HALF_UP);
> +		double geoPercentage = Double.valueOf(df.format(Double.valueOf(recordWithGeoNum) / Double.valueOf(inputObjList.size())));
> +		
> +		if(curationStatus == CurationComment.UNABLE_DETERMINE_VALIDITY){
> +			AnnotationSet commentAn = new AnnotationSet();
> +			commentAn.addAnnotation(outlierCommentLabelStr, CurationComment.construct(curationStatus, comment, collectingEventoutlierIdentificationService.getServiceName()), getEmptyDependencySet());
> +//			commentAn.addAnnotation("GeoPercentage", new DoubleToken(geoPercentage), getEmptyDependencySet());
> +			
> +			CollectionManager topClusterCM = collectionManager.addCollection(getLabelManager().getLabel(resultCollectionLabelStr), getEmptyDependencySet(), commentAn);
> +			commentAn.setTarget(topClusterCM.getCollection(), collectionManager);
> +			
> +			for(int i=0;i<inputObjList.size();i++){
> +				DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +				cd.add(inputObjList.get(i));				
> +				topClusterCM.addData(inputObjList.get(i).getObject(), getLabelManager().getLabel(localComparatorDataLabelStr),cd, null);
> +			}
> +			
> +//			topClusterCM.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		}else if(curationStatus == CurationComment.CORRECT || curationStatus == CurationComment.UNABLE_CURATED){			
> +//			AnnotationSet topCommentAn = new AnnotationSet();
> +//			topCommentAn.addAnnotation("GeoPercentage", new DoubleToken(geoPercentage), getEmptyDependencySet());
> +			
> +			CollectionManager topClusterCM = collectionManager.addCollection(getLabelManager().getLabel(resultCollectionLabelStr), getEmptyDependencySet(), null);
> +			
> +			CollectionManager normalCM = topClusterCM.addCollection(getLabelManager().getLabel(normalDataCollectionLabelStr), getEmptyDependencySet(), null);
> +			for(int i=0;i<noneOutlier.size();i++){
> +				DataToken nontOutlier = noneOutlier.get(i);
> +				DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +				cd.add(nontOutlier);
> +				normalCM.addData(nontOutlier.getObject(), getLabelManager().getLabel(normalDataLabelStr), cd, null);			
> +			}
> +			
> +			if(curationStatus == CurationComment.UNABLE_CURATED){
> +				Iterator<DataToken> outlierIter = outlierLocalComparatorMap.keySet().iterator();
> +				while(outlierIter.hasNext()){
> +					DataToken outlier = outlierIter.next();
> +					LinkedList<DataToken> localComparatorList = outlierLocalComparatorMap.get(outlier);
> +					LinkedList<SpecimenRecordType> remoteComparatorList = null; 
> +					if(outlierRemoteComparatorMap.containsKey(outlier)){
> +						remoteComparatorList = outlierRemoteComparatorMap.get(outlier);
> +					}
> +					
> +					AnnotationSet commentAn = new AnnotationSet();
> +					commentAn.addAnnotation(outlierCommentLabelStr, CurationComment.construct(curationStatus, comment, collectingEventoutlierIdentificationService.getServiceName()), getEmptyDependencySet());
> +					
> +					CollectionManager outlierCM = topClusterCM.addCollection(getLabelManager().getLabel(outlierCollectionLabelStr), getEmptyDependencySet(), commentAn);
> +					commentAn.setTarget(outlierCM.getCollection(), topClusterCM);
> +
> +					DependencySet outlierDp = new DependencySet(collectionManager.getCoactor());
> +
> +					if(remoteComparatorList!=null){
> +						for(int j=0;j<remoteComparatorList.size();j++){
> +							OrderedRecordToken remoteComparator = remoteComparatorList.get(j);
> +							outlierCM.addData(remoteComparator, getLabelManager().getLabel(remoteComparatorDataLabelStr), getEmptyDependencySet(), null);
> +						}				
> +					}
> +					
> +					for(int j=0;j<localComparatorList.size();j++){
> +						DataToken localComparator = localComparatorList.get(j);
> +						DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +						cd.add(localComparator);
> +						outlierDp.add(localComparator);
> +						outlierCM.addData(localComparator.getObject(), getLabelManager().getLabel(localComparatorDataLabelStr), cd, null);
> +					}
> +					
> +					outlierDp.add(outlier);
> +					outlierCM.addData(outlier.getObject(), getLabelManager().getLabel(outlierDataLabelStr), outlierDp, null);			
> +				}				
> +			}
> +			
> +//			topClusterCM.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		}
> +		
> +		collectionManager.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		
> +		inputObjList.clear();
> +		inputDataMap.clear();
> +	}	
> +	
> +	private void addDataToken(DataToken dataToken){
> +		RecordToken recordToken = (RecordToken)dataToken.getObject();
> +		
> +		if(!hasCompleteGeo(recordToken)){
> +			return;
> +		}
> +		
> +		recordWithGeoNum++;
> +		
> +		String collector = ((StringToken)recordToken.get(CollectorLabel)).stringValue();
> +		
> +		TreeSet<DataToken> recordSet; 
> +		if(inputDataMap.containsKey(collector)){
> +			recordSet = inputDataMap.get(collector);
> +		}else{
> +			recordSet = new TreeSet<DataToken>(new SpecimenDataTokenComparator());
> +			inputDataMap.put(collector, recordSet);
> +		}
> +		recordSet.add(dataToken);
> +	}
> +	
> +	private boolean hasCompleteGeo(RecordToken r){
> +		Token latitudeToken = r.get(latitudeLabel);
> +		Token longitutdeToken = r.get(longitudeLabel);
> +		if(latitudeToken == null || longitutdeToken == null){
> +			return false;
> +		}else{
> +			return true;
> +		}
> +	}
> +	
> +	private class SpecimenDataTokenComparator implements Comparator<DataToken>{
> +		public int compare(DataToken o1, DataToken o2) {			
> +			RecordToken r1 = (RecordToken)o1.getObject();			
> +			int year1 = ((IntToken)r1.get(yearCollectedLabel)).intValue();
> +			int month1 = ((IntToken)r1.get(monthCollectedLabel)).intValue();
> +			int day1 = ((IntToken)r1.get(dayCollectedLabel)).intValue();
> +			long timestamp1 = getTimestamp(getFormatedDate(year1,month1,day1));
> +			
> +			RecordToken r2 = (RecordToken)o2.getObject();
> +			int year2 = ((IntToken)r2.get(yearCollectedLabel)).intValue();
> +			int month2 = ((IntToken)r2.get(monthCollectedLabel)).intValue();
> +			int day2 = ((IntToken)r2.get(dayCollectedLabel)).intValue();
> +			long timestamp2 = getTimestamp(getFormatedDate(year2,month2,day2));
> +			
> +			if(timestamp1>=timestamp2){
> +				return 1;
> +			}else{
> +				//if they're equal, they're treated as less
> +				return -1;
> +			}
> +		}	
> +	}	
> +
> +	private long getTimestamp(String dateStr){	
> +		//date is in format of mm-dd-yyyy
> +		SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy");
> +		Date date;
> +		try {
> +			date = format.parse(dateStr);
> +			return date.getTime();
> +		} catch (ParseException e) {
> +			// shouldn't happen
> +			e.printStackTrace();
> +		}
> +		return 0;
> +	}	
> +	
> +	private String getFormatedDate(int year, int month, int day){
> +		//assume year is four digit
> +		String yearStr = String.valueOf(year);
> +
> +		String monthStr = String.valueOf(month);		
> +		if(month<10){
> +			monthStr = "0"+monthStr;
> +		}
> +
> +		String dayStr = String.valueOf(day);		
> +		if(day<10){
> +			dayStr = "0"+dayStr;
> +		}
> +		
> +		return monthStr+"-"+dayStr+"-"+yearStr;
> +	}	
> +	
> +	public Parameter dataTypeParam; 
> +	public Parameter dataLabel; 
> +	public Parameter travelSpeedParam;
> +    public Parameter resultCollectionLabel;
> +    public Parameter normalDataCollectionLabel;
> +    public Parameter outlierCommentLabel;
> +    public Parameter outlierCollectionLabel;
> +    public Parameter outlierDataLabel;
> +    public Parameter normalDataLabel;
> +    public Parameter localComparatorDataLabel;
> +    public Parameter getRemoteEvidenceDataParam;
> +    public Parameter remoteComparatorDataLabel;
> +
> +    private String dataLabelStr = null;
> +    private double travelSpeed; 
> +    private String resultCollectionLabelStr = null;
> +    private String normalDataCollectionLabelStr = null;
> +    private String outlierCommentLabelStr = null;
> +    private String outlierCollectionLabelStr = null;
> +    private String outlierDataLabelStr = null;
> +    private String normalDataLabelStr = null;
> +    private String localComparatorDataLabelStr = null;
> +    private boolean getRemoteEvidence = false;
> +    private String remoteComparatorDataLabelStr = null;    
> +    
> +    private String CollectorLabel;
> +    private String yearCollectedLabel;
> +    private String monthCollectedLabel;
> +    private String dayCollectedLabel;
> +    private String latitudeLabel;
> +    private String longitudeLabel;
> +    
> +    DailyCollectingEventOutlierIdentificationService collectingEventoutlierIdentificationService = null;
> +    
> +    private LinkedList<DataToken> inputObjList = new LinkedList<DataToken>();
> +
> +    private LinkedHashMap<String,TreeSet<DataToken>> inputDataMap = new LinkedHashMap<String,TreeSet<DataToken>>();
> +        
> +    int recordWithGeoNum;
> +    
> +    private static final long serialVersionUID = 1L;
> +}
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder2.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder2.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/CollectingEventOutlierFinder2.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,474 @@
> +/** Base class for coactors with one input and one output port.
> + *
> + * Copyright (c) 2008 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> +
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.math.RoundingMode;
> +import java.text.DecimalFormat;
> +import java.text.ParseException;
> +import java.text.SimpleDateFormat;
> +import java.util.Comparator;
> +import java.util.Date;
> +import java.util.Iterator;
> +import java.util.LinkedHashMap;
> +import java.util.LinkedList;
> +import java.util.TreeSet;
> +
> +import org.kepler.actor.SpecimenQC.type.SpeicmenRecordTypeConf;
> +import org.kepler.actor.SpecimenQC.util.CurationComment;
> +import org.kepler.actor.SpecimenQC.util.CurationComment.CurationStatus;
> +import org.kepler.coactors.ExtendedCollectionTransformer;
> +import org.kepler.actor.SpecimenQC.type.SpecimenRecordType;
> +import org.kepler.exceptions.CollectionException;
> +import org.kepler.tokens.DataToken;
> +import org.kepler.util.AnnotationSet;
> +import org.kepler.util.ClassResolver;
> +import org.kepler.util.CollectionManager;
> +import org.kepler.util.DependencySet;
> +import org.kepler.util.Parameters;
> +import org.kepler.util.TokenDisposition;
> +
> +import ptolemy.data.Token;
> +import ptolemy.data.IntToken;
> +import ptolemy.data.DoubleToken;
> +import ptolemy.data.OrderedRecordToken;
> +import ptolemy.data.RecordToken;
> +import ptolemy.data.StringToken;
> +import ptolemy.data.BooleanToken;
> +import ptolemy.data.expr.Parameter;
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +
> +/**
> + * clustering on Collectors
> + * then clustering on Time
> + * then in each cluster, find out the outlier according to the lat/log (calculate distance between each two point)
> + * 
> + * @author fancy
> + *
> + */
> +public class CollectingEventOutlierFinder2 extends ExtendedCollectionTransformer{	
> +	
> +	public CollectingEventOutlierFinder2(CompositeEntity container, String name)
> +		throws NameDuplicationException, IllegalActionException {
> +
> +		super(container, name);
> +		
> +        serviceClassPathParam = Parameters.stringParameter(this, "ServiceClassPath", "");
> +        serviceClassQNParam = Parameters.stringParameter(this, "ServiceClassQN", "");
> +
> +		dataLabel = Parameters.stringParameter(this, "dataLabel", "");
> +		travelSpeedParam = Parameters.doubleParameter(this, "dailyTravelSpeed", 5.0); //km/day
> +		resultCollectionLabel = Parameters.stringParameter(this, "resultCollectionLabel", "");
> +		normalDataCollectionLabel = Parameters.stringParameter(this, "normalDataCollectionLabel", "");
> +		normalDataLabel = Parameters.stringParameter(this, "normalDataLabel", "");	
> +		outlierCommentLabel = Parameters.stringParameter(this, "outlierCommentLabel", "");
> +		outlierCollectionLabel = Parameters.stringParameter(this, "outlierCollectionLabel", "");
> +		outlierDataLabel = Parameters.stringParameter(this, "outlierDataLabel", "");		
> +		localComparatorDataLabel = Parameters.stringParameter(this, "localComparatorDataLabel", "");
> +		getRemoteEvidenceDataParam = Parameters.booleanParameter(this, "getRemoteEvidenceData", false);
> +		remoteComparatorDataLabel = Parameters.stringParameter(this, "remoteComparatorDataLabel", "");
> +    }
> +	
> +	public void initialize() throws IllegalActionException {
> +		super.initialize();		
> +		
> +		//parse dataLabel
> +		StringToken dataLabelToken = (StringToken)dataLabel.getToken();
> +	    if(dataLabelToken != null && dataLabelToken.stringValue()!=null){
> +	    	dataLabelStr = dataLabelToken.stringValue().trim();
> +	    }else{
> +	    	dataLabelStr = "";
> +	    }
> +	    
> +	    //parse max daily travel speed
> +	    Token travelSpeedToken = travelSpeedParam.getToken();
> +	    if(travelSpeedToken == null){
> +	    	travelSpeed = 5.0;
> +	    }else{
> +	    	travelSpeed = Double.valueOf(travelSpeedToken.toString());
> +	    } 	    
> +
> +		//parse output collection and data label
> +		StringToken resultCollectionLabelToken = (StringToken)resultCollectionLabel.getToken();
> +	    if(resultCollectionLabelToken != null && resultCollectionLabelToken.stringValue()!=null){
> +	    	resultCollectionLabelStr = resultCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	resultCollectionLabelStr = "";
> +	    }
> +
> +		StringToken normalDataCollectionLabelToken = (StringToken)normalDataCollectionLabel.getToken();
> +	    if(normalDataCollectionLabelToken != null && normalDataCollectionLabelToken.stringValue()!=null){
> +	    	normalDataCollectionLabelStr = normalDataCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	normalDataCollectionLabelStr = "";
> +	    }
> +	    
> +		StringToken outlierCommentLabelToken = (StringToken)outlierCommentLabel.getToken();
> +	    if(outlierCommentLabelToken != null && outlierCommentLabelToken.stringValue()!=null){
> +	    	outlierCommentLabelStr = outlierCommentLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierCommentLabelStr = "";
> +	    }	    
> +	    
> +		StringToken outlierCollectionLabelToken = (StringToken)outlierCollectionLabel.getToken();
> +	    if(outlierCollectionLabelToken != null && outlierCollectionLabelToken.stringValue()!=null){
> +	    	outlierCollectionLabelStr = outlierCollectionLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierCollectionLabelStr = "";
> +	    }
> +	    
> +		StringToken outlierDataLabelToken = (StringToken)outlierDataLabel.getToken();
> +	    if(outlierDataLabelToken != null && outlierDataLabelToken.stringValue()!=null){
> +	    	outlierDataLabelStr = outlierDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	outlierDataLabelStr = "";
> +	    }
> +	    
> +		StringToken normalDataLabelToken = (StringToken)normalDataLabel.getToken();
> +	    if(normalDataLabelToken != null && normalDataLabelToken.stringValue()!=null){
> +	    	normalDataLabelStr = normalDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	normalDataLabelStr = "";
> +	    }	
> +	    
> +		StringToken localComparatorDataLabelToken = (StringToken)localComparatorDataLabel.getToken();
> +	    if(localComparatorDataLabelToken != null && localComparatorDataLabelToken.stringValue()!=null){
> +	    	localComparatorDataLabelStr = localComparatorDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	localComparatorDataLabelStr = "";
> +	    }
> +	    
> +	    getRemoteEvidence = ((BooleanToken)getRemoteEvidenceDataParam.getToken()).booleanValue();
> +	    
> +	    
> +		StringToken remoteComparatorDataLabelToken = (StringToken)remoteComparatorDataLabel.getToken();
> +	    if(remoteComparatorDataLabelToken != null && remoteComparatorDataLabelToken.stringValue()!=null){
> +	    	remoteComparatorDataLabelStr = remoteComparatorDataLabelToken.stringValue().trim();
> +	    }else{
> +	    	remoteComparatorDataLabelStr = "";
> +	    }
> +	    
> +		//initialize required label
> +		SpeicmenRecordTypeConf speicmenRecordTypeConf = SpeicmenRecordTypeConf.INSTANCE;		
> +		
> +		CollectorLabel = speicmenRecordTypeConf.getLabel("RecordedBy");
> +		if(CollectorLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the RecordedBy label of the SpecimenRecordType is not set.");
> +		}
> +		
> +		yearCollectedLabel = speicmenRecordTypeConf.getLabel("YearCollected");
> +		if(yearCollectedLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the YearCollected label of the SpecimenRecordType is not set.");
> +		}
> +		
> +		monthCollectedLabel = speicmenRecordTypeConf.getLabel("MonthCollected");
> +		if(monthCollectedLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the MonthCollected label of the SpecimenRecordType is not set.");
> +		}
> +		
> +		dayCollectedLabel = speicmenRecordTypeConf.getLabel("DayCollected");
> +		if(dayCollectedLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the DayCollected label of the SpecimenRecordType is not set.");
> +		}
> +		
> +		latitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLatitude");
> +		if(latitudeLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the DecimalLatitude label of the SpecimenRecordType is not set.");
> +		}
> +		
> +		longitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLongitude");
> +		if(longitudeLabel == null){
> +			throw new IllegalActionException(getName()+" failed since the DecimalLongitude label of the SpecimenRecordType is not set.");
> +		}
> +	    
> +		//resolve service
> +		StringToken serviceClassPathToken =  (StringToken)serviceClassPathParam.getToken();
> +		if(serviceClassPathToken == null ||
> +				serviceClassPathToken.stringValue()==null ||
> +				serviceClassPathToken.stringValue().trim().equals("")){
> +			 throw new IllegalActionException(getName()+" failed since the ServiceClassPath parameter is not set.");
> +		}
> +		serviceClassPath = serviceClassPathToken.stringValue().trim();
> +		
> +		StringToken serviceClassQNToken =  (StringToken)serviceClassQNParam.getToken();
> +		if(serviceClassQNToken == null ||
> +				serviceClassQNToken.stringValue()==null ||
> +				serviceClassQNToken.stringValue().trim().equals("")){
> +			 throw new IllegalActionException(getName()+" failed since the ServiceClassPath parameter is not set.");
> +		}
> +		serviceClassQN = serviceClassQNToken.stringValue().trim();		
> +		
> +		collectingEventoutlierIdentificationService = (ICollectingEventIdentificationService2)ClassResolver.resolve(serviceClassPath, serviceClassQN, "org.kepler.demo.OutlierIdentification.ICollectingEventIdentificationService2");	    
> +	}	
> +
> +	public void handleScopeStart(CollectionManager collectionManager) throws IllegalActionException{
> +		inputObjList.clear();		
> +		inputDataMap.clear();
> +		
> +		recordWithGeoNum = 0;
> +	}		
> +	
> +  	public TokenDisposition handleData(CollectionManager collectionManager,Object object, AnnotationSet annotations) 
> +  		throws IllegalActionException, CollectionException {
> +  		if(dataLabelStr.equals(getCurrentToken().getLabel().toString())){  			
> +  			inputObjList.add((DataToken)getCurrentToken());
> +  			addDataToken((DataToken)getCurrentToken());
> +  		}  		
> +  		return TokenDisposition.FORWARD_TOKEN;
> +	}	
> +  	
> +	public void handleScopeEnd(CollectionManager collectionManager) throws IllegalActionException {
> +		if(inputObjList.size()==0 || inputDataMap.size()==0){
> +			return;
> +		}
> +		
> +		//find out outlier by using the service
> +		collectingEventoutlierIdentificationService.identifyOutlier(inputDataMap, travelSpeed, getRemoteEvidence);
> +
> +	    LinkedList<DataToken> noneOutlier = collectingEventoutlierIdentificationService.getNoneOutlier();
> +	    LinkedHashMap<DataToken,LinkedList<DataToken>> outlierLocalComparatorMap = collectingEventoutlierIdentificationService.getOutlierLocalComparatorMap();
> +	    LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>> outlierRemoteComparatorMap = collectingEventoutlierIdentificationService.getOutlierRemoteComparatorMap();		
> +		String comment = collectingEventoutlierIdentificationService.getComment();
> +		CurationStatus curationStatus = collectingEventoutlierIdentificationService.getCurationStatus();
> +	    
> +		//output		
> +		
> +		//calculate the percentage of records that has the complete geo-referencing information.
> +		DecimalFormat df = new DecimalFormat("#.##");
> +		df.setRoundingMode(RoundingMode.HALF_UP);
> +		double geoPercentage = Double.valueOf(df.format(Double.valueOf(recordWithGeoNum) / Double.valueOf(inputObjList.size())));
> +		
> +		if(curationStatus == CurationComment.UNABLE_DETERMINE_VALIDITY){
> +			AnnotationSet commentAn = new AnnotationSet();
> +			commentAn.addAnnotation(outlierCommentLabelStr, CurationComment.construct(curationStatus, comment, collectingEventoutlierIdentificationService.getServiceName()), getEmptyDependencySet());
> +//			commentAn.addAnnotation("GeoPercentage", new DoubleToken(geoPercentage), getEmptyDependencySet());
> +			
> +			CollectionManager topClusterCM = collectionManager.addCollection(getLabelManager().getLabel(resultCollectionLabelStr), getEmptyDependencySet(), commentAn);
> +			commentAn.setTarget(topClusterCM.getCollection(), collectionManager);
> +			
> +			for(int i=0;i<inputObjList.size();i++){
> +				DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +				cd.add(inputObjList.get(i));				
> +				topClusterCM.addData(inputObjList.get(i).getObject(), getLabelManager().getLabel(localComparatorDataLabelStr),cd, null);
> +			}
> +			
> +//			topClusterCM.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		}else if(curationStatus == CurationComment.CORRECT || curationStatus == CurationComment.UNABLE_CURATED){			
> +//			AnnotationSet topCommentAn = new AnnotationSet();
> +//			topCommentAn.addAnnotation("GeoPercentage", new DoubleToken(geoPercentage), getEmptyDependencySet());
> +			
> +			CollectionManager topClusterCM = collectionManager.addCollection(getLabelManager().getLabel(resultCollectionLabelStr), getEmptyDependencySet(), null);
> +			
> +			CollectionManager normalCM = topClusterCM.addCollection(getLabelManager().getLabel(normalDataCollectionLabelStr), getEmptyDependencySet(), null);
> +			for(int i=0;i<noneOutlier.size();i++){
> +				DataToken nontOutlier = noneOutlier.get(i);
> +				DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +				cd.add(nontOutlier);
> +				normalCM.addData(nontOutlier.getObject(), getLabelManager().getLabel(normalDataLabelStr), cd, null);			
> +			}
> +			
> +			if(curationStatus == CurationComment.UNABLE_CURATED){
> +				Iterator<DataToken> outlierIter = outlierLocalComparatorMap.keySet().iterator();
> +				while(outlierIter.hasNext()){
> +					DataToken outlier = outlierIter.next();
> +					LinkedList<DataToken> localComparatorList = outlierLocalComparatorMap.get(outlier);
> +					LinkedList<SpecimenRecordType> remoteComparatorList = null; 
> +					if(outlierRemoteComparatorMap.containsKey(outlier)){
> +						remoteComparatorList = outlierRemoteComparatorMap.get(outlier);
> +					}
> +					
> +					AnnotationSet commentAn = new AnnotationSet();
> +					commentAn.addAnnotation(outlierCommentLabelStr, CurationComment.construct(curationStatus, comment, collectingEventoutlierIdentificationService.getServiceName()), getEmptyDependencySet());
> +					
> +					CollectionManager outlierCM = topClusterCM.addCollection(getLabelManager().getLabel(outlierCollectionLabelStr), getEmptyDependencySet(), commentAn);
> +					commentAn.setTarget(outlierCM.getCollection(), topClusterCM);
> +
> +					DependencySet outlierDp = new DependencySet(collectionManager.getCoactor());
> +
> +					if(remoteComparatorList!=null){
> +						for(int j=0;j<remoteComparatorList.size();j++){
> +							OrderedRecordToken remoteComparator = remoteComparatorList.get(j);
> +							outlierCM.addData(remoteComparator, getLabelManager().getLabel(remoteComparatorDataLabelStr), getEmptyDependencySet(), null);
> +						}				
> +					}
> +					
> +					for(int j=0;j<localComparatorList.size();j++){
> +						DataToken localComparator = localComparatorList.get(j);
> +						DependencySet cd = new DependencySet(collectionManager.getCoactor());
> +						cd.add(localComparator);
> +						outlierDp.add(localComparator);
> +						outlierCM.addData(localComparator.getObject(), getLabelManager().getLabel(localComparatorDataLabelStr), cd, null);
> +					}
> +					
> +					outlierDp.add(outlier);
> +					outlierCM.addData(outlier.getObject(), getLabelManager().getLabel(outlierDataLabelStr), outlierDp, null);			
> +				}				
> +			}
> +			
> +//			topClusterCM.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		}
> +		
> +		collectionManager.addData(new DoubleToken(geoPercentage), getLabelManager().getLabel("GeoPercentage"), getEmptyDependencySet(), null);
> +		
> +		inputObjList.clear();
> +		inputDataMap.clear();
> +	}	
> +	
> +	private void addDataToken(DataToken dataToken){
> +		RecordToken recordToken = (RecordToken)dataToken.getObject();
> +		
> +		if(!hasCompleteGeo(recordToken)){
> +			return;
> +		}
> +		
> +		recordWithGeoNum++;
> +		
> +		String collector = ((StringToken)recordToken.get(CollectorLabel)).stringValue();
> +		
> +		TreeSet<DataToken> recordSet; 
> +		if(inputDataMap.containsKey(collector)){
> +			recordSet = inputDataMap.get(collector);
> +		}else{
> +			recordSet = new TreeSet<DataToken>(new SpecimenDataTokenComparator());
> +			inputDataMap.put(collector, recordSet);
> +		}
> +		recordSet.add(dataToken);
> +	}
> +	
> +	private boolean hasCompleteGeo(RecordToken r){
> +		Token latitudeToken = r.get(latitudeLabel);
> +		Token longitutdeToken = r.get(longitudeLabel);
> +		if(latitudeToken == null || longitutdeToken == null){
> +			return false;
> +		}else{
> +			return true;
> +		}
> +	}
> +	
> +	private class SpecimenDataTokenComparator implements Comparator<DataToken>{
> +		public int compare(DataToken o1, DataToken o2) {			
> +			RecordToken r1 = (RecordToken)o1.getObject();			
> +			int year1 = ((IntToken)r1.get(yearCollectedLabel)).intValue();
> +			int month1 = ((IntToken)r1.get(monthCollectedLabel)).intValue();
> +			int day1 = ((IntToken)r1.get(dayCollectedLabel)).intValue();
> +			long timestamp1 = getTimestamp(getFormatedDate(year1,month1,day1));
> +			
> +			RecordToken r2 = (RecordToken)o2.getObject();
> +			int year2 = ((IntToken)r2.get(yearCollectedLabel)).intValue();
> +			int month2 = ((IntToken)r2.get(monthCollectedLabel)).intValue();
> +			int day2 = ((IntToken)r2.get(dayCollectedLabel)).intValue();
> +			long timestamp2 = getTimestamp(getFormatedDate(year2,month2,day2));
> +			
> +			if(timestamp1>=timestamp2){
> +				return 1;
> +			}else{
> +				//if they're equal, they're treated as less
> +				return -1;
> +			}
> +		}	
> +	}	
> +
> +	private long getTimestamp(String dateStr){	
> +		//date is in format of mm-dd-yyyy
> +		SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy");
> +		Date date;
> +		try {
> +			date = format.parse(dateStr);
> +			return date.getTime();
> +		} catch (ParseException e) {
> +			// shouldn't happen
> +			e.printStackTrace();
> +		}
> +		return 0;
> +	}	
> +	
> +	private String getFormatedDate(int year, int month, int day){
> +		//assume year is four digit
> +		String yearStr = String.valueOf(year);
> +
> +		String monthStr = String.valueOf(month);		
> +		if(month<10){
> +			monthStr = "0"+monthStr;
> +		}
> +
> +		String dayStr = String.valueOf(day);		
> +		if(day<10){
> +			dayStr = "0"+dayStr;
> +		}
> +		
> +		return monthStr+"-"+dayStr+"-"+yearStr;
> +	}	
> +
> +	Parameter serviceClassPathParam;
> +	Parameter serviceClassQNParam;	
> +	public Parameter dataTypeParam; 
> +	public Parameter dataLabel; 
> +	public Parameter travelSpeedParam;
> +    public Parameter resultCollectionLabel;
> +    public Parameter normalDataCollectionLabel;
> +    public Parameter outlierCommentLabel;
> +    public Parameter outlierCollectionLabel;
> +    public Parameter outlierDataLabel;
> +    public Parameter normalDataLabel;
> +    public Parameter localComparatorDataLabel;
> +    public Parameter getRemoteEvidenceDataParam;
> +    public Parameter remoteComparatorDataLabel;
> +
> +	private String serviceClassPath;
> +	private String serviceClassQN;
> +    private String dataLabelStr = null;
> +    private double travelSpeed; 
> +    private String resultCollectionLabelStr = null;
> +    private String normalDataCollectionLabelStr = null;
> +    private String outlierCommentLabelStr = null;
> +    private String outlierCollectionLabelStr = null;
> +    private String outlierDataLabelStr = null;
> +    private String normalDataLabelStr = null;
> +    private String localComparatorDataLabelStr = null;
> +    private boolean getRemoteEvidence = false;
> +    private String remoteComparatorDataLabelStr = null;    
> +    
> +    private String CollectorLabel;
> +    private String yearCollectedLabel;
> +    private String monthCollectedLabel;
> +    private String dayCollectedLabel;
> +    private String latitudeLabel;
> +    private String longitudeLabel;
> +    
> +    ICollectingEventIdentificationService2 collectingEventoutlierIdentificationService = null;
> +    
> +    private LinkedList<DataToken> inputObjList = new LinkedList<DataToken>();
> +
> +    private LinkedHashMap<String,TreeSet<DataToken>> inputDataMap = new LinkedHashMap<String,TreeSet<DataToken>>();
> +//    private LinkedList<DataToken> noneOutlier = new LinkedList<DataToken>();
> +//    private LinkedHashMap<DataToken,LinkedList<DataToken>> outlierLocalComparatorMap = new LinkedHashMap<DataToken,LinkedList<DataToken>>();
> +//    private LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>> outlierRemoteComparatorMap = new LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>>();
> +        
> +    int recordWithGeoNum;
> +    
> +    private static final long serialVersionUID = 1L;
> +}
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/DailyCollectingEventOutlierIdentificationService.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/DailyCollectingEventOutlierIdentificationService.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/DailyCollectingEventOutlierIdentificationService.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,421 @@
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.text.ParseException;
> +import java.text.SimpleDateFormat;
> +import java.util.Date;
> +import java.util.HashMap;
> +import java.util.Iterator;
> +import java.util.LinkedHashMap;
> +import java.util.LinkedList;
> +import java.util.Map;
> +import java.util.Set;
> +import java.util.TreeSet;
> +
> +import org.kepler.actor.SpecimenQC.util.CurationComment;
> +import org.kepler.actor.SpecimenQC.util.FPQuery;
> +import org.kepler.actor.SpecimenQC.util.GEOUtil;
> +import org.kepler.actor.SpecimenQC.util.CurationComment.CurationStatus;
> +import org.kepler.demo.OutlierIdentification.SpecimenRecordType;
> +import org.kepler.tokens.DataToken;
> +
> +import ptolemy.data.IntToken;
> +import ptolemy.data.RecordToken;
> +import ptolemy.data.StringToken;
> +import ptolemy.data.Token;
> +import ptolemy.kernel.util.IllegalActionException;
> +
> +public class DailyCollectingEventOutlierIdentificationService{
> +
> +	public void identifyOutlier(
> +			LinkedHashMap<String, TreeSet<DataToken>> inputDataMap,
> +			double dailyTravelSpeed, 
> +			boolean doRemoteComparison) {
> +		noneOutlier.clear();
> +		outlierLocalComparatorMap.clear();
> +		outlierRemoteComparatorMap.clear();
> +		
> +		travelDistanceThreshold = dailyTravelSpeed;
> +		
> +		try{
> +			initializeLabel();
> +
> +			Iterator<String> inputDataMapIter = inputDataMap.keySet().iterator();
> +			while(inputDataMapIter.hasNext()){
> +				String collector = inputDataMapIter.next();
> +				TreeSet<DataToken> specimenRecordSet = inputDataMap.get(collector);
> +				
> +				LinkedList<DataToken> timeBasedCluster = new LinkedList<DataToken>();
> +				long previousTime = 0;
> +				Iterator<DataToken> specimenRecordSetIter = specimenRecordSet.iterator();
> +				while(specimenRecordSetIter.hasNext()){
> +					DataToken specimenRecordDataToken = specimenRecordSetIter.next();
> +					RecordToken currentSpecimenRecord = (RecordToken)specimenRecordDataToken.getObject();
> +					long currentTimestamp = getTimeStamp(currentSpecimenRecord);					
> +					
> +					if(previousTime!=0 && isTooLongInterval(previousTime,currentTimestamp)){
> +						//end of one time-based cluster
> +						findOutlier(timeBasedCluster, doRemoteComparison);
> +						timeBasedCluster.clear();
> +					}
> +					
> +					timeBasedCluster.add(specimenRecordDataToken);
> +					previousTime = currentTimestamp;
> +				}
> +				
> +				if(timeBasedCluster.size()>0){
> +					findOutlier(timeBasedCluster, doRemoteComparison);
> +				}			
> +			}
> +			
> +			if(outlierLocalComparatorMap.size()>0 || outlierRemoteComparatorMap.size()>0){
> +				curationStatus = CurationComment.UNABLE_CURATED;
> +				if(doRemoteComparison){
> +					comment = "It's an outlier of collecting events of a collector by comparing to the data in the dataset.";
> +				}else{
> +					comment = "It's an outlier of collecting events of a collector by comparing to both data in this dataset and data queried from Filtered-Push network.";
> +				}
> +			}else{
> +				curationStatus = CurationComment.CORRECT;
> +				comment = "There's no collecting event outlier.";
> +			}
> +			
> +		}catch(IllegalActionException ex){
> +			comment = ex.getMessage();
> +			curationStatus = CurationComment.UNABLE_DETERMINE_VALIDITY;
> +			return;
> +		}		
> +	}	
> +	
> +	public LinkedList<DataToken> getNoneOutlier() {
> +		return noneOutlier;
> +	}
> +
> +	public LinkedHashMap<DataToken, LinkedList<DataToken>> getOutlierLocalComparatorMap() {
> +		return outlierLocalComparatorMap;
> +	}
> +
> +	public LinkedHashMap<DataToken, LinkedList<SpecimenRecordType>> getOutlierRemoteComparatorMap() {
> +		return outlierRemoteComparatorMap;
> +	}	
> +	
> +	public void setCacheFile(String file) throws IllegalActionException {
> +	}	
> +	
> +	public String getComment(){
> +		return comment;
> +	}
> +	
> +	//can't return UNABLE_CURATED;
> +	public CurationStatus getCurationStatus() {
> +		return curationStatus;
> +	}
> +
> +	public void flushCacheFile() throws IllegalActionException {	
> +	}
> +
> +	public String getServiceName(){
> +		return serviceName;
> +	}
> +	
> +	private void initializeLabel() throws IllegalActionException{
> +//		SpeicmenRecordTypeConf speicmenRecordTypeConf = SpeicmenRecordTypeConf.INSTANCE;		
> +				
> +		CollectorLabel = "RecordedBy";
> +//		CollectorLabel = speicmenRecordTypeConf.getLabel("RecordedBy");
> +//		if(CollectorLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the RecordedBy label of the SpecimenRecordType is not set.");
> +//		}		
> +		
> +		yearCollectedLabel = "YearCollected";
> +//		yearCollectedLabel = speicmenRecordTypeConf.getLabel("YearCollected");
> +//		if(yearCollectedLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the YearCollected label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +		monthCollectedLabel = "MonthCollected";
> +//		monthCollectedLabel = speicmenRecordTypeConf.getLabel("MonthCollected");
> +//		if(monthCollectedLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the MonthCollected label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +		dayCollectedLabel = "DayCollected";
> +//		dayCollectedLabel = speicmenRecordTypeConf.getLabel("DayCollected");
> +//		if(dayCollectedLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the DayCollected label of the SpecimenRecordType is not set.");
> +//		}	
> +		
> +		latitudeLabel = "DecimalLatitude";
> +//		latitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLatitude");
> +//		if(latitudeLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the DecimalLatitude label of the SpecimenRecordType is not set.");
> +//		}
> +		
> +		longitudeLabel = "DecimalLongitude";
> +//		longitudeLabel = speicmenRecordTypeConf.getLabel("DecimalLongitude");
> +//		if(longitudeLabel == null){
> +//			throw new IllegalActionException(getClass().getName()+" failed since the DecimalLongitude label of the SpecimenRecordType is not set.");
> +//		}		
> +	}
> +	
> +	private long getTimeStamp(RecordToken record){
> +		int year = ((IntToken)record.get(yearCollectedLabel)).intValue();
> +		int month = ((IntToken)record.get(monthCollectedLabel)).intValue();
> +		int day = ((IntToken)record.get(dayCollectedLabel)).intValue();
> +		return getTimestamp(getFormatedDate(year,month,day));
> +	}
> +	
> +	private long getTimestamp(String dateStr){	
> +		//date is in format of mm-dd-yyyy
> +		SimpleDateFormat format = new SimpleDateFormat("MM-dd-yyyy");
> +		Date date;
> +		try {
> +			date = format.parse(dateStr);
> +			return date.getTime();
> +		} catch (ParseException e) {
> +			// shouldn't happen
> +			e.printStackTrace();
> +		}
> +		return 0;
> +	}
> +	
> +	private String getFormatedDate(int year, int month, int day){
> +		//assume year is four digit
> +		String yearStr = String.valueOf(year);
> +
> +		String monthStr = String.valueOf(month);		
> +		if(month<10){
> +			monthStr = "0"+monthStr;
> +		}
> +
> +		String dayStr = String.valueOf(day);		
> +		if(day<10){
> +			dayStr = "0"+dayStr;
> +		}
> +		
> +		return monthStr+"-"+dayStr+"-"+yearStr;
> +	}
> +	
> +	private boolean isTooLongInterval(long t1, long t2){
> +		long distance = t2 - t1;
> +		if(distance>=0 && (distance/day)>temporalDistanceThreshold){
> +			return true;
> +		}else{
> +			return false;
> +		}
> +	}	
> +	
> +	private void findOutlier(LinkedList<DataToken> timeBasedCluster, boolean doRemoteComparison) throws IllegalActionException{
> +		HashMap<DataToken, LinkedList<SpecimenRecordType>> outlierMap = new HashMap<DataToken, LinkedList<SpecimenRecordType>>();
> +		LinkedList<DataToken> localComparator = new LinkedList<DataToken>();
> +		for(int i=0;i<timeBasedCluster.size();i++){
> +			DataToken currentSpecimenDataToken = timeBasedCluster.get(i);
> +			RecordToken currentSpecimenRecord = (RecordToken)currentSpecimenDataToken.getObject();
> +			
> +			//test outlier by comparing backward
> +			boolean isOutlierBackward = false;
> +			if(i!=0){
> +				//find the nearest none outlier
> +				int j=i-1;
> +				DataToken previousDataToken = timeBasedCluster.get(j);
> +				while(outlierMap.containsKey(previousDataToken) && j>0){
> +					j = j-1;
> +					previousDataToken = timeBasedCluster.get(j);
> +				}
> +				
> +				if(!outlierMap.containsKey(previousDataToken)){
> +					isOutlierBackward = isTooFar((RecordToken)previousDataToken.getObject(), currentSpecimenRecord);
> +				}
> +			}
> +			
> +			//test outlier by comparing forward
> +			boolean isOutlierForward = false;
> +			if(i<timeBasedCluster.size()-1){
> +				RecordToken successiveRecord = (RecordToken)timeBasedCluster.get(i+1).getObject(); 
> +				
> +				if(isTooFar(currentSpecimenRecord,successiveRecord)){
> +					isOutlierForward = true;
> +				}
> +			}			
> +			
> +			boolean isOutlier = false;
> +			if(isOutlierBackward || isOutlierForward){				
> +				//It's a potential outlier				
> +				if(doRemoteComparison){
> +					//do further confirmation by using records quried from FP
> +					//once it's confirmed once, then we think it's an outlier no matter whether the other records come to the same result
> +					//since at least it's a highly suspicious record.
> +					//But if all the records got from FP agree that it's not an outlier and the number of the records exceed a threshold, we think it's not outlier so far.
> +					//this part should be refined in the future.
> +					boolean confirmedOutlier = false;
> +					LinkedList<SpecimenRecordType> specimenRecordsFromFP = getAdjacentRecordsFromFP(currentSpecimenRecord);
> +					for(int k=0;k<specimenRecordsFromFP.size();k++){
> +						if(isTooFar(currentSpecimenRecord,specimenRecordsFromFP.get(k))){
> +							confirmedOutlier = true;
> +							break;
> +						}
> +					}
> +					
> +					if(confirmedOutlier||
> +						!confirmedOutlier && specimenRecordsFromFP.size()<outlierDenyRecordNumberFromFP){
> +						isOutlier = true;		
> +						outlierMap.put(currentSpecimenDataToken, specimenRecordsFromFP);
> +					}	
> +				}else{
> +					isOutlier = true;
> +					outlierMap.put(currentSpecimenDataToken, null);
> +				}				
> +			}
> +			
> +			if(!isOutlier){
> +				noneOutlier.add(currentSpecimenDataToken);
> +				localComparator.add(currentSpecimenDataToken);
> +			}
> +		}
> +		
> +		if(outlierMap.size()>0){
> +			Iterator<DataToken> iter = outlierMap.keySet().iterator();
> +			while(iter.hasNext()){
> +				DataToken outlier = iter.next();				
> +				outlierLocalComparatorMap.put(outlier,localComparator);
> +				if(doRemoteComparison){
> +					outlierRemoteComparatorMap.put(outlier,outlierMap.get(outlier));
> +				}				
> +			}
> +		}
> +	}	
> +	
> +	private LinkedList<SpecimenRecordType> getAdjacentRecordsFromFP(RecordToken specimenRecord) throws IllegalActionException{				
> +		//add search conditions
> +		String collector = ((StringToken)specimenRecord.get(CollectorLabel)).stringValue();
> +		int year = ((IntToken)specimenRecord.get(yearCollectedLabel)).intValue();
> +		int month = ((IntToken)specimenRecord.get(monthCollectedLabel)).intValue();
> +		int day = ((IntToken)specimenRecord.get(dayCollectedLabel)).intValue();
> +		
> +		int previousYear = year;
> +		int previousMonth = month;
> +		int previousDay = day - 1;
> +		
> +		int successiveYear = year;
> +		int successiveMonth = month;
> +		int successiveDay = day + 1;		
> +		
> +		if(month==1 && day ==1){
> +			previousYear = year -1;
> +			previousMonth = 12;
> +			previousDay = 31;
> +		}else if(month==12 && day ==31){
> +			successiveYear = year + 1;
> +			successiveMonth = 1;
> +			successiveDay = 1;			
> +		}else if(day ==1){
> +			previousMonth = previousMonth -1;
> +			if(isBigMonth(previousMonth)){
> +				previousDay = 31;
> +			}else{
> +				previousDay = 30;
> +			}				
> +		}else if(isBigMonth(month) && day ==31 || !isBigMonth(month) && day ==30){
> +			successiveMonth = successiveMonth +1;
> +			successiveDay = 1;		
> +		}
> +		
> +		FPQuery fpQuery = new FPQuery();
> +		
> +		fpQuery.clearConditions();
> +		fpQuery.addCondition("collector", "Binary", 0.0, collector);
> +		fpQuery.addCondition("year", "Binary", 0.0, String.valueOf(previousYear));
> +		fpQuery.addCondition("month", "Binary", 0.0, String.valueOf(previousMonth));
> +		fpQuery.addCondition("day", "Binary", 0.0, String.valueOf(previousDay));
> +		//LinkedList<SpecimenRecordType> result = fpQuery.search();
> +		LinkedList<SpecimenRecordType> result = convertType(fpQuery.search());
> +				
> +		
> +		fpQuery.clearConditions();
> +		fpQuery.addCondition("collector", "Binary", 0.0, collector);
> +		fpQuery.addCondition("year", "Binary", 0.0, String.valueOf(year));
> +		fpQuery.addCondition("month", "Binary", 0.0, String.valueOf(month));
> +		fpQuery.addCondition("day", "Binary", 0.0, String.valueOf(day));		
> +		//result.addAll(fpQuery.search()); 
> +		result.addAll(convertType(fpQuery.search()));
> +				
> +		fpQuery.clearConditions();
> +		fpQuery.addCondition("collector", "Binary", 0.0, collector);
> +		fpQuery.addCondition("year", "Binary", 0.0, String.valueOf(successiveYear));
> +		fpQuery.addCondition("month", "Binary", 0.0, String.valueOf(successiveMonth));
> +		fpQuery.addCondition("day", "Binary", 0.0, String.valueOf(successiveDay));	
> +		//result.addAll(fpQuery.search());
> +		result.addAll(convertType(fpQuery.search()));
> +		
> +		return result;
> +	}
> +	
> +	private LinkedList<SpecimenRecordType> convertType(LinkedList<org.kepler.actor.SpecimenQC.type.SpecimenRecordType> records) throws IllegalActionException{
> +		LinkedList<SpecimenRecordType> result = new LinkedList<SpecimenRecordType>();
> +		for(int i=0;i<records.size();i++){			
> +			org.kepler.actor.SpecimenQC.type.SpecimenRecordType record = records.get(i);
> +			
> +			Map<String,Token> fieldMap = new HashMap<String,Token>();
> +			Set labels = record.labelSet();
> +			Iterator<String> iter = labels.iterator();
> +			while(iter.hasNext()){
> +				String label = iter.next();
> +				Token value = record.get(label);
> +				fieldMap.put(label, value);
> +			}
> +			
> +			try {
> +				result.add(new SpecimenRecordType(fieldMap));
> +			} catch (org.kepler.exceptions.ParseException e) {
> +				throw new IllegalActionException(getClass().getName()+" failed in convertType since "+e.getMessage());
> +			}
> +		}
> +		
> +		return result;
> +	}
> +	
> +	private boolean isBigMonth(int month){
> +		if(month==1 || month ==3 || month ==5 || month ==7 || month ==8 || month ==10 || month ==12){
> +			return true;
> +		}else{
> +			return false;
> +		}
> +	}	
> +	
> +	private boolean isTooFar(RecordToken r1, RecordToken r2){
> +		long timestamp1 = getTimeStamp(r1);
> +		double latitude1 = Double.valueOf(r1.get(latitudeLabel).toString());
> +		double longitutde1 = Double.valueOf(r1.get(longitudeLabel).toString());
> +		
> +		long timestamp2 = getTimeStamp(r2);
> +		double latitude2 = Double.valueOf(r2.get(latitudeLabel).toString());
> +		double longitutde2 = Double.valueOf(r2.get(longitudeLabel).toString());		
> +		
> +		double travelDistancePerDay = GEOUtil.getDistance(latitude1,longitutde1,latitude2,longitutde2)/(Math.abs(timestamp2 - timestamp1)/day+1);
> +		if(travelDistancePerDay>=travelDistanceThreshold){ 
> +			return true;
> +		}else{
> +			return false;
> +		}		
> +	}	
> +	
> +	private String CollectorLabel;
> +    private String yearCollectedLabel;
> +    private String monthCollectedLabel;
> +    private String dayCollectedLabel;
> +    private String latitudeLabel;
> +    private String longitudeLabel;  
> +	
> +	private CurationStatus curationStatus;
> +	private String comment = "";
> +
> +    private LinkedList<DataToken> noneOutlier = new LinkedList<DataToken>();
> +    private LinkedHashMap<DataToken,LinkedList<DataToken>> outlierLocalComparatorMap = new LinkedHashMap<DataToken,LinkedList<DataToken>>();
> +    private LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>> outlierRemoteComparatorMap = new LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>>();
> +    
> +    private final int temporalDistanceThreshold = 7; //in day
> +    private double travelDistanceThreshold = 1000; //in km/day
> +    private final int outlierDenyRecordNumberFromFP = 10; 
> +    private final int day = 86400000;    
> +	
> +	private final String serviceName = "Collecting Event Outlier Identification Service";
> +}
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/ICollectingEventIdentificationService2.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/ICollectingEventIdentificationService2.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/ICollectingEventIdentificationService2.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,26 @@
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.util.LinkedHashMap;
> +import java.util.LinkedList;
> +import java.util.TreeSet;
> +
> +import org.kepler.actor.SpecimenQC.ICurationService;
> +import org.kepler.actor.SpecimenQC.type.SpecimenRecordType;
> +import org.kepler.tokens.DataToken;
> +
> +public interface ICollectingEventIdentificationService2 extends ICurationService{
> +	
> +	//The key is the collector
> +	//The TreeSet is the events belonging to this collection and ordered by the collecting date	
> +	public void identifyOutlier(LinkedHashMap<String,TreeSet<DataToken>> inputDataMap, double dailyTravelSpeed, boolean doRemoteComparison);
> +	
> +	public LinkedList<DataToken> getNoneOutlier();
> +	
> +	//The key is the outlier
> +	//the linkedlist is the comparator data from the local dataset
> +	public LinkedHashMap<DataToken,LinkedList<DataToken>> getOutlierLocalComparatorMap();
> +	
> +	//The key is the outlier
> +	//the LinkedList is the comparator data queried remotely from the Filtered-push network
> +	public LinkedHashMap<DataToken,LinkedList<SpecimenRecordType>> getOutlierRemoteComparatorMap();
> +}
> \ No newline at end of file
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/OutlierFinderResponseConstructor.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/OutlierFinderResponseConstructor.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/OutlierFinderResponseConstructor.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,73 @@
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.util.List;
> +
> +import org.kepler.coactors.CollectionTransformer;
> +import org.kepler.util.DataBindingValueMap;
> +
> +import ptolemy.kernel.CompositeEntity;
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.kernel.util.NameDuplicationException;
> +
> +import ptolemy.data.Token;
> +import ptolemy.data.DoubleToken;
> +import ptolemy.data.StringToken;
> +import ptolemy.data.RecordToken;
> +
> +public class OutlierFinderResponseConstructor extends CollectionTransformer{
> +	public OutlierFinderResponseConstructor(CompositeEntity container, String name)
> +    	throws IllegalActionException, NameDuplicationException {
> +    
> +		super(container, name);
> +		
> +		createSignatureElementParameter("Outliers", "SpecimenRecordType*", true);
> +		createSignatureElementParameter("GeoRefPercentage", "DoubleToken", true);
> +		
> +		createSignatureElementParameter("Response", "StringToken", false);
> +	}
> +
> +	public void initialize() throws IllegalActionException {
> +		super.initialize();
> +		
> +		//initialize required label
> +//		SpeicmenRecordTypeConf speicmenRecordTypeConf = SpeicmenRecordTypeConf.INSTANCE;		
> +		
> +		catalogNumLabel = "CatalogNumber";
> +//		catalogNumLabel = speicmenRecordTypeConf.getLabel("CatalogNumber");
> +//		if(catalogNumLabel == null){
> +//			throw new IllegalActionException(getName()+" failed since the CatalogNumber label of the SpecimenRecordType is not set.");
> +//		}		
> +	}
> +	
> +	public DataBindingValueMap fireActor(DataBindingValueMap inputDataMap) throws IllegalActionException{
> +		List<?> outlierObjs = (List<?>)inputDataMap.get("Outliers");
> +		double geoRefPercentage = ((DoubleToken)inputDataMap.get("GeoRefPercentage")).doubleValue();
> +		
> +		String responseString = "{\"outliers\":["; 
> +		if(outlierObjs != null){
> +			for(int i=0;i<outlierObjs.size();i++){
> +				RecordToken record = (RecordToken)outlierObjs.get(i);
> +				Token catalogNumToken = record.get(catalogNumLabel);
> +				if(catalogNumToken != null){
> +					String catalogNum = catalogNumToken.toString();
> +					if(catalogNumToken instanceof StringToken){
> +						catalogNum = ((StringToken)catalogNumToken).stringValue();
> +					}				
> +					responseString = responseString+"\""+catalogNum+"\",";
> +				}
> +			}
> +			responseString = responseString.substring(0,responseString.length()-1);
> +		}
> +		
> +		responseString = responseString + "],\"geoRefPercentage\":"+String.valueOf(geoRefPercentage)+"}";
> +				
> +		//String responseString = "{\"outliers\":[\"2\",\"3\"],\"geoRefPercentage\":0.2}"; 
> +		
> +		DataBindingValueMap outputData = new DataBindingValueMap();
> +		outputData.put("Response", new StringToken(responseString)) ;
> +
> +		return outputData;
> +	}
> +	
> +	private String catalogNumLabel;
> +}
> 
> Added: trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/SpecimenRecordType.java
> ===================================================================
> --- trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/SpecimenRecordType.java	                        (rev 0)
> +++ trunk/modules/kuration/src/org/kepler/demo/OutlierIdentification/SpecimenRecordType.java	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,67 @@
> +/* Class representing SpeciemnRecord.
> + *
> + * Copyright (c) 2008 The Regents of the University of California.
> + * All rights reserved.
> + *
> + * Permission is hereby granted, without written agreement and without
> + * license or royalty fees, to use, copy, modify, and distribute this
> + * software and its documentation for any purpose, provided that the
> + * above copyright notice and the following two paragraphs appear in
> + * all copies of this software.
> + *
> + * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
> + * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
> + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
> + * IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY
> + * OF SUCH DAMAGE.
> + *
> + * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
> + * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY
> + * OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
> + * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
> + */
> + 
> +package org.kepler.demo.OutlierIdentification;
> +
> +import java.util.Map;
> +
> +import org.apache.commons.lang.StringEscapeUtils;
> +import org.kepler.exceptions.ParseException;
> +import org.kepler.types.DomainObject;
> +import org.kepler.util.Xml.Indentation;
> +import org.w3c.dom.Node;
> +
> +import ptolemy.kernel.util.IllegalActionException;
> +import ptolemy.data.OrderedRecordToken;
> +import ptolemy.data.Token;
> +import ptolemy.data.type.RecordType;
> +import ptolemy.data.type.Type;
> +
> +public class SpecimenRecordType extends OrderedRecordToken implements DomainObject{
> +	//the required constructor 
> +	public SpecimenRecordType(Node node) throws ParseException, IllegalActionException  {
> +		super(node.getTextContent());
> +	}
> +
> +	public SpecimenRecordType(Map<String,Token> fieldMap) throws ParseException, IllegalActionException  {
> +		super(fieldMap);	
> +	}	
> +
> +	public String getXmlContentString(Indentation indentation) {
> +		String str = toString();
> +		
> +		//replace the special character with the one that can't be processed by the XMLParser
> +		//escapte the string according to XML rule, like replace & with $amp;
> +		str = StringEscapeUtils.escapeXml(str);
> +		
> +		return str; 
> +	}
> +	
> +	public String toString() {
> +	    return super.toString();
> +	}
> +	
> +	private static final long serialVersionUID = 1L;	
> +}
> 
> Added: trunk/modules/kuration/workflows/OutlierIdentification/OutlierIdentification.xml
> ===================================================================
> --- trunk/modules/kuration/workflows/OutlierIdentification/OutlierIdentification.xml	                        (rev 0)
> +++ trunk/modules/kuration/workflows/OutlierIdentification/OutlierIdentification.xml	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,474 @@
> +<?xml version="1.0"?>
> +<!DOCTYPE entity PUBLIC "-//UC Berkeley//DTD MoML 1//EN"
> +    "http://ptolemy.eecs.berkeley.edu/xml/dtd/MoML_1.dtd">
> +<entity name="OutlierIdentification" class="org.kepler.moml.CompositeClassEntity">
> +<property name="class" value="org.kepler.moml.CompositeClassEntity" class="ptolemy.kernel.util.StringAttribute">
> +  <property name="id" value="null" class="ptolemy.kernel.util.StringAttribute"/>
> +</property>
> +
> +
> +
> +<property name="_createdBy" class="ptolemy.kernel.attributes.VersionAttribute" value="8.1.devel">
> +</property>
> +
> +<property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org/ns/:6867:97:99">
> +</property>
> +
> +<property name="ComadDirector" class="org.kepler.domains.ComadDirector">
> +    <property name="timeResolution" class="ptolemy.actor.parameters.SharedParameter" value="1E-10">
> +    </property>
> +    <property name="initialQueueCapacity" class="ptolemy.data.expr.Parameter" value="1">
> +    </property>
> +    <property name="maximumQueueCapacity" class="ptolemy.data.expr.Parameter" value="65536">
> +    </property>
> +    <property name="data driven mode" class="ptolemy.data.expr.Parameter" value="false">
> +    </property>
> +    <property name="output directory root" class="ptolemy.data.expr.Parameter" value="/tmp">
> +    </property>
> +    <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org:director:800:1">
> +    </property>
> +    <property name="class" class="ptolemy.kernel.util.StringAttribute" value="org.kepler.domains.ComadDirector">
> +        <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:director:800:1">
> +        </property>
> +    </property>
> +    <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Director">
> +    </property>
> +    <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Director">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="{130, 85}">
> +    </property>
> +</property>
> +
> +<property name="TypeSystem" class="org.kepler.types.TypeSystem">
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[155.0, 175.0]">
> +    </property>
> +    <property name="SpecimenRecordType" class="org.kepler.types.DataTypeParameter" value="org.kepler.demo.OutlierIdentification.SpecimenRecordType">
> +    </property>
> +</property>
> +
> +<property name="InputDataSet" class="ptolemy.data.expr.StringParameter" value="D:/project/Kepler/kepler.trunk/kuration/workflows/OutlierIdentification/data/TDWG11_Demo.csv">
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Edward A. Lee</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure><p>StringParameter specifies a persistent string. </p>

<p>Change the name of the StringParameter to better identify the specified value (right-click the parameter and select "Customize Name" from the menu). Other actors may refer to the StringParameter using the $NAME syntax (e.g. $Parameter).
</p></configure></property>
> +</property>    <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:93:1">
> +    </property>
> +    <property name="class" class="ptolemy.kernel.util.StringAttribute" value="ptolemy.data.expr.StringParameter">
> +        <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:class:1185:1">
> +        </property>
> +    </property>
> +    <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Parameter">
> +    </property>
> +    <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Parameter">
> +    </property>
> +    <property name="_hideName" class="ptolemy.kernel.util.SingletonAttribute">
> +    </property>
> +    <property name="_icon" class="ptolemy.vergil.icon.ValueIcon">
> +        <property name="_color" class="ptolemy.actor.gui.ColorAttribute" value="{1.0, 0.0, 0.0, 1.0}">
> +        </property>
> +    </property>
> +    <property name="_smallIconDescription" class="ptolemy.kernel.util.SingletonConfigurableAttribute">
> +        <configure>
> +        <svg>
> +          <text x="20" style="font-size:14; font-family:SansSerif; fill:red" y="20">-S-</text>
> +        </svg>
> +      </configure>
> +    </property>
> +    <property name="_editorFactory" class="ptolemy.vergil.toolbox.VisibleParameterEditorFactory">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="{215.0, 155.0}">
> +    </property>
> +    <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org:actor:421:1">
> +    </property>
> +</property>
> +
> +<property name="MaxTravelSpeed" class="ptolemy.data.expr.Parameter" value="5.0">
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +</property>    <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:3:2">
> +    </property>
> +    <property name="class" class="ptolemy.kernel.util.StringAttribute" value="ptolemy.data.expr.Parameter">
> +        <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:class:1184:1">
> +        </property>
> +    </property>
> +    <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Parameter">
> +    </property>
> +    <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Parameter">
> +    </property>
> +    <property name="_hideName" class="ptolemy.kernel.util.SingletonAttribute">
> +    </property>
> +    <property name="_icon" class="ptolemy.vergil.icon.ValueIcon">
> +        <property name="_color" class="ptolemy.actor.gui.ColorAttribute" value="{0.0, 0.0, 1.0, 1.0}">
> +        </property>
> +    </property>
> +    <property name="_smallIconDescription" class="ptolemy.kernel.util.SingletonConfigurableAttribute">
> +        <configure>
> +      <svg>
> +        <text x="20" style="font-size:14; font-family:SansSerif; fill:blue" y="20">-P-</text>
> +      </svg>
> +    </configure>
> +    </property>
> +    <property name="_editorFactory" class="ptolemy.vergil.toolbox.VisibleParameterEditorFactory">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[215.0, 175.0]">
> +    </property>
> +    <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org:actor:420:1">
> +    </property>
> +</property>
> +
> +
> +
> +
> +
> +<relation name="relation4" class="ptolemy.actor.TypedIORelation">
> +</relation>
> +
> +<relation name="relation2" class="ptolemy.actor.TypedIORelation">
> +</relation>
> +
> +<relation name="relation3" class="ptolemy.actor.TypedIORelation">
> +</relation>
> +
> +<entity name="CSVCollectionReader" class="org.kepler.coactors.CSVCollectionReader">
> +    <property name="ReadScope" class="ptolemy.data.expr.StringParameter" value="">
> +    </property>
> +    <property name="Signature" class="ptolemy.data.expr.StringParameter" value="">
> +    </property>
> +    <property name="File" class="ptolemy.data.expr.FileParameter" value="$InputDataSet">
> +    </property>
> +    <property name="Field Delimiter" class="org.kepler.types.ComadReaderDelimiterTypeChoice" value="comma">
> +    </property>
> +    <property name="Collection Label" class="ptolemy.data.expr.StringParameter" value="SpecimenRecords">
> +    </property>
> +    <property name="Row Label" class="ptolemy.data.expr.StringParameter" value="SpecimenRecord">
> +    </property>
> +    <property name="Data Organization Mode" class="org.kepler.types.ComadReaderDataOrganizationModeChoice" value="row as data">
> +    </property>
> +    <property name="rowDataType" class="ptolemy.data.expr.StringParameter" value="SpecimenRecordType">
> +    </property>
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Lei Dou</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>1.0</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The CSVCollectionReader actor imports external data from a file in CSV format into the COMAD workflow.</configure></property>
> +<property name="port:output" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The output port from where the data stream flows out of the actor</configure></property>
> +<property name="prop:Data Organization Mode" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>indicates how to organize each row. Two choices are available: ?row as data? and ?row as collection?. ?row as data? means each row is organized as a data in type of RecorToken or the type declared by ?rowDataType? parameter while ?row as collection? means each row is organized as a collection while each column is represented as a data inside the collection.</configure></property>
> +<property name="prop:Row Label" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>indicates the label for each row. If each row is organized as a collection while each column is represented as a data inside the collection, then the ?row label? is the label for the collection. If each row is organized as a data in type of RecorToken, then the ?row label? is the label for each RecordToken data.</configure></property>
> +<property name="prop:Field Delimiter" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>indicates what delimiter is used to separate different field. The available choices include comma, tab and semicolon.</configure></property>
> +<property name="prop:author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:ReadScope" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:Signature" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:File" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>full path of the input file</configure></property>
> +<property name="prop:Collection Label" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>indicates the label of root collection when the file format is CSV.</configure></property>
> +<property name="prop:rowDataType" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>If the ?Data Organization Mode? is set as ?row as data?, then the data representing each row will be created as the specified type. If this parameter doesn?t declare any data type, then the data will be simply created as a RecordToken.</configure></property>
> +</property>    <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:99:12">
> +    </property>
> +    <property name="class" class="ptolemy.kernel.util.StringAttribute" value="org.kepler.coactors.CSVCollectionReader">
> +        <property name="id" class="ptolemy.kernel.util.StringAttribute" value="null">
> +        </property>
> +    </property>
> +    <property name="semanticType" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#DataInput#Data Input">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[130.0, 290.0]">
> +    </property>
> +    <property name="author" class="ptolemy.kernel.util.ConfigurableAttribute">
> +        <configure>Lei Dou</configure>
> +    </property>
> +    <property name="" class="ptolemy.vergil.basic.DocAttribute">
> +        <property name="description" class="ptolemy.kernel.util.StringAttribute" value="The CSVCollectionReader actor imports external data from a file in CSV format into the COMAD workflow.">
> +        </property>
> +        <property name="author" class="ptolemy.kernel.util.StringAttribute" value="Lei Dou">
> +        </property>
> +        <property name="version" class="ptolemy.kernel.util.StringAttribute" value="1.0">
> +        </property>
> +        <property name="File (parameter)" class="ptolemy.data.expr.StringParameter" value="full path of the input file">
> +        </property>
> +        <property name="Field Delimiter (parameter)" class="ptolemy.data.expr.StringParameter" value="indicates what delimiter is used to separate different field. The available choices include comma, tab and semicolon.">
> +        </property>
> +        <property name="Collection Label (parameter)" class="ptolemy.data.expr.StringParameter" value="indicates the label of root collection when the file format is CSV.">
> +        </property>
> +        <property name="Row Label (parameter)" class="ptolemy.data.expr.StringParameter" value="indicates the label for each row. If each row is organized as a collection while each column is represented as a data inside the collection, then the ?row label? is the label for the collection. If each row is organized as a data in type of RecorToken, then the ?row label? is the label for each RecordToken data.">
> +        </property>
> +        <property name="Data Organization Mode (parameter)" class="ptolemy.data.expr.StringParameter" value="indicates how to organize each row. Two choices are available: ?row as data? and ?row as collection?. ?row as data? means each row is organized as a data in type of RecorToken or the type declared by ?rowDataType? parameter while ?row as collection? means each row is organized as a collection while each column is represented as a data inside the collection.">
> +        </property>
> +        <property name="rowDataType (parameter)" class="ptolemy.data.expr.StringParameter" value="If the ?Data Organization Mode? is set as ?row as data?, then the data representing each row will be created as the specified type. If this parameter doesn?t declare any data type, then the data will be simply created as a RecordToken.">
> +        </property>
> +        <property name="output (port)" class="ptolemy.kernel.util.StringAttribute" value="The output port from where the data stream flows out of the actor">
> +        </property>
> +        <property name="ReadScope (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="Signature (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="author (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +    </property>
> +    <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org/ns/:5882:274:2">
> +    </property>
> +</entity>
> +<entity name="CompositeCoactor" class="org.kepler.coactors.CompositeCoactor">
> +    <property name="ReadScope" class="ptolemy.data.expr.StringParameter" value="/">
> +    </property>
> +    <property name="Signature" class="ptolemy.data.expr.StringParameter" value="port:StringToken
->
">
> +    </property>
> +    <property name="DependencyMode" class="ptolemy.data.expr.Parameter" value="false">
> +        <display name="Depend on Firing"/>
> +    </property>
> +    <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:41:28">
> +    </property>
> +    <property name="class" class="ptolemy.kernel.util.StringAttribute" value="org.kepler.coactors.CompositeCoactor">
> +        <property name="id" class="ptolemy.kernel.util.StringAttribute" value="null">
> +        </property>
> +    </property>
> +    <property name="_createdBy" class="ptolemy.kernel.attributes.VersionAttribute" value="8.1.devel">
> +    </property>
> +    <property name="semanticType" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#DataOperation#Data Operation">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[675.0, 285.0]">
> +    </property>
> +    <property name="author" class="ptolemy.kernel.util.ConfigurableAttribute">
> +        <configure>Timothy M. McPhillips, Lei Dou</configure>
> +    </property>
> +    <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org:actor:804:1:urn:lsid:kepler-project.org/ns/:2945:854:3">
> +    </property>
> +    <property name="" class="ptolemy.vergil.basic.DocAttribute">
> +        <property name="description" class="ptolemy.kernel.util.StringAttribute" value="The CompositeCoactor actor is used to encapsulate a sub-workflow assembled from a group of kepler actors. The director for the sub-workflow can only be SDFDirector. 
<p/>
The input and output port of the nested workflow are actually the input and output data binding port of the CompositeCoactor. From these ports, the input data is bound and prepared to fire the inside workflow and the output is written into the data stream.  Please refer to chapter "COMAD Actor" for more details about how to use this actor. ">
> +        </property>
> +        <property name="author" class="ptolemy.kernel.util.StringAttribute" value="Timothy M. McPhillips, Lei Dou">
> +        </property>
> +        <property name="version" class="ptolemy.kernel.util.StringAttribute" value="2.0">
> +        </property>
> +        <property name="ReadScope (parameter)" class="ptolemy.data.expr.StringParameter" value="read scope path expression">
> +        </property>
> +        <property name="DependencyMode (parameter)" class="ptolemy.data.expr.StringParameter" value="If it's set true, then the dependency is generated only from the input data of the same firing.  Otherwise, the dependency is generated from all the input data in the invocation. Please refer to "Provenance Recording" in "COMAD Actor" chapter for more details.">
> +        </property>
> +        <property name="class (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="semanticType (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="derivedFrom (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="input (port)" class="ptolemy.kernel.util.StringAttribute" value="The input port from where the data stream flows into the actor.">
> +        </property>
> +        <property name="output (port)" class="ptolemy.kernel.util.StringAttribute" value="The output port from where the data stream flows out of the actor.">
> +        </property>
> +        <property name="Signature (parameter)" class="ptolemy.data.expr.StringParameter" value="displays the signature of the actor">
> +        </property>
> +        <property name="entityId (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +        <property name="author (parameter)" class="ptolemy.data.expr.StringParameter" value="">
> +        </property>
> +    </property>
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Timothy M. McPhillips, Lei Dou</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>2.0</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The CompositeCoactor actor is used to encapsulate a sub-workflow assembled from a group of kepler actors. The director for the sub-workflow can only be SDFDirector. 
<p/>
The input and output port of the nested workflow are actually the input and output data binding port of the CompositeCoactor. From these ports, the input data is bound and prepared to fire the inside workflow and the output is written into the data stream.  Please refer to chapter "COMAD Actor" for more details about how to use this actor. </configure></property>
> +<property name="port:input" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The input port from where the data stream flows into the actor.</configure></property>
> +<property name="port:output" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The output port from where the data stream flows out of the actor.</configure></property>
> +<property name="prop:Signature" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>displays the signature of the actor</configure></property>
> +<property name="prop:entityId" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:ReadScope" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>read scope path expression</configure></property>
> +<property name="prop:author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:semanticType" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:derivedFrom" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:class" class="ptolemy.kernel.util.ConfigurableAttribute"><configure></configure></property>
> +<property name="prop:DependencyMode" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>If it's set true, then the dependency is generated only from the input data of the same firing.  Otherwise, the dependency is generated from all the input data in the invocation. Please refer to "Provenance Recording" in "COMAD Actor" chapter for more details.</configure></property>
> +</property>    <property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
> +        <property name="iterations" class="ptolemy.data.expr.Parameter" value="0">
> +        </property>
> +        <property name="vectorizationFactor" class="ptolemy.data.expr.Parameter" value="1">
> +        </property>
> +        <property name="allowDisconnectedGraphs" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +        <property name="allowRateChanges" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +        <property name="constrainBufferSizes" class="ptolemy.data.expr.Parameter" value="true">
> +        </property>
> +        <property name="period" class="ptolemy.data.expr.Parameter" value="0.0">
> +        </property>
> +        <property name="synchronizeToRealTime" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +        <property name="timeResolution" class="ptolemy.actor.parameters.SharedParameter" value="1E-10">
> +        </property>
> +        <property name="Scheduler" class="ptolemy.domains.sdf.kernel.SDFScheduler">
> +            <property name="constrainBufferSizes" class="ptolemy.data.expr.Parameter" value="constrainBufferSizes">
> +            </property>
> +        </property>
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Steve Neuendorffer</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>
<p>The SDF Director is often used to oversee fairly simple, sequential workflows in which the director can determine the order of actor invocation from the workflow. Types of workflows that would run well under an SDF Director include processing and reformatting tabular data, converting one data type to another, and reading and plotting a series of data points. A workflow in which an image is read, processed (rotated, scaled, clipped, filtered, etc.), and then displayed, is also an example of a sequential workflow that requires a director simply to ensure that each actor fires in the proper order (i.e., that each actor executes only after it receives its required inputs).</p>

<p>The SDF Director is very efficient and will not tax system resources with overhead. However, this efficiency requires that certain conditions be met, namely that the da
> ta consumption and production rate of each actor in an SDF workflow be constant and declared. If an actor reads one piece of data and calculates and outputs a single result, it must always read and output a single token of data. This data rate cannot change during workflow execution and, in general, workflows that require dynamic scheduling and/or flow control cannot use this director. Additionally, the SDF Director has no understanding of passing time (at least by default), and actors that depend on a notion of time may not work as expected. For example, a TimedPlotter actor will plot all values at time zero when used in SDF. </p>

<p>By default, the SDF Director requires that all actors in its workflow be connected. Otherwise, the director cannot account for concurrency between disconnected workflow parts. Usually, a PN Director should be used for workflows that contain disconnected actors; however, the SDF Director's allowDisconnectedGraphs parameter m
> ay also be set to true. The SDF Director will then schedule each disconnected "island" independently. The director cannot infer the sequential relationship between disconnected actors (i.e., nothing forces the director to finish executing all actors on one island before firing actors on another). However, the order of execution within each island should be correct. Usually, disconnected graphs in an SDF model indicate an error.</p>
 
<p>Because SDF Directors schedule actors to fire only after they receive their inputs, workflows that require loops (feeding an actor's output back into its input port for further processing) can cause "deadlock" errors. The deadlock errors occur because the actor depends on its own output value as an initial input. To fix this problem, use a SampleDelay actor to generate and inject an initial input value into the workflow.</p>

<p>The SDF Director determines the order in which actors e
> xecute and how many times each actor needs to be fired to complete a single iteration of the workflow. This schedule is calculated BEFORE the director begins to iterate the workflow. Because the SDF Director calculates a schedule in advance, it is quite efficient. However, SDF workflows must be static. In other words, the same number of tokens must be consumed/produced at every iteration of the workflow. Workflows that require dynamic control structures, such as a BooleanSwitch actor that sends output on one of two ports depending on the value of a 'control', cannot be used with an SDF Director because the number of tokens on each output can change for each execution.</p>

<p>Unless otherwise specified, the SDF Director assumes that each actor consumes and produces exactly one token per channel on each firing. Actors that do not follow the one-token-per-channel firing convention (e.g., Repeat or Ramp) must declare the number of tokens they produce or cons
> ume via the appropriate parameters. </p>

<p>The number of times a workflow is iterated is controlled by the director's iterations parameter. By default, this parameter is set to "0". Note that "0" does not mean "no iterations." Rather, "0" means that the workflow will iterate forever. Values greater than zero specify the actual number of times the director should execute the entire workflow. A value of 1, meaning that the director will run the workflow once, is often the best setting when building an SDF workflow. </p>

<p>The amount of data processed by an SDF workflow is a function of both the number of times the workflow iterates and the value of the director's vectorizationFactor parameter. The vectorizationFactor is used to increase the efficiency of a workflow by increasing the number of times actors fire each time the workflow iterates. If the parameter is set to a positive integer (other
>  than 1), the director will fire each actor the specified number of times more than normal. The default is 1, indicating that no vectorization should be performed. Keep in mind that changing the vectorizationFactor parameter changes the meaning of a nested SDF workflow and may cause deadlock in a workflow that uses it. </p>

<p>The SDF Director has several advanced parameters that are generally only relevant when an SDF workflow contains composite components. In most cases the period, timeResolution, synchronizeToRealTime, allowRateChanges, timeResolution, and constrainBufferSizes parameters can be left at their default values.</p>

<p>For more information about the SDF Director, see the Ptolemy documentation (http://ptolemy.eecs.berkeley.edu/papers/05/ptIIdesign3-domains/ptIIdesign3-domains.pdf).</p>

</configure></property>
> +<property name="prop:allowDisconnectedGraphs" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether to allow disconnected actors in the workflow (by default, all actors are required to be connected). If disconnected actors are permitted, the SDF Director will schedule each disconnected 'island' independently. Nothing "forces" the director to finish executing all actors on one island before firing actors on another. However, the order of execution within each island should be correct. Usually, disconnected graphs in an SDF workflow indicate an error.</configure></property>
> +<property name="prop:allowRateChanges" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether dynamic rate changes are permitted or not. By default, rate changes are not permitted, and the director will perform a check to disallow such workflows. If the parameter is selected, then workflows that require rate parameters to be modified during execution are valid, and the SDF Director will dynamically compute a new schedule at runtime. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:timeResolution" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The time precision used by this director. All time values are rounded to the nearest multiple of this number. The value is a double that defaults to "1E-10" (which is 10-10). This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:constrainBufferSizes" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether buffer sizes are fixed. By default, buffers are fixed, and attempts to write to the buffer that cause the buffer to exceed its scheduled size result in an error. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:iterations" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify the number of times a workflow is iterated. By default, this parameter is set to "0". Note that "0" does not mean "no iterations." Rather, "0" means that the workflow will iterate forever. Values greater than zero specify the actual number of times the director should execute the entire workflow. A value of 1, meaning that the director will run the workflow once, is often the best setting when building an SDF workflow. </configure></property>
> +<property name="prop:vectorizationFactor" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The vectorizationFactor is used to increase the efficiency of a workflow by increasing the number of times actors fire each time the workflow iterates. If the parameter is set to a positive integer (other than 1), the director will fire each actor the specified number of times more than normal. The default is 1, indicating that no vectorization should be performed. Keep in mind that changing the vectorizationFactor parameter changes the meaning of a nested SDF workflow and may cause deadlock in a workflow that uses it. </configure></property>
> +<property name="prop:synchronizeToRealTime" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether the execution should synchronize to real time or not. By default, the director does not synchronize to real time. If synchronize is selected, the director will only process the workflow when elapsed real time matches the product of the period parameter and the iteration count. Note: if the period parameter has a value of 0.0 (the default), then selecting this parameter has no effect. This is an advanced parameter that can usually be left at its default value.</configure></property>
> +<property name="prop:period" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The time period of each iteration. The value is a double that defaults to 0.0, which means that the director does not increment workflow time. If the value greater than 0.0, the actor will increment workflow time each time it fires. This is an advanced parameter that can usually be left at its default value. </configure></property>
> +</property>        <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:28:2">
> +        </property>
> +        <property name="class" class="ptolemy.kernel.util.StringAttribute" value="ptolemy.domains.sdf.kernel.SDFDirector">
> +            <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:directorclass:1:2">
> +            </property>
> +        </property>
> +        <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#Director">
> +        </property>
> +        <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#Director">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="{50.0, 110.0}">
> +        </property>
> +        <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org:director:1:2">
> +        </property>
> +    </property>
> +    <property name="port" class="org.kepler.types.SignatureElementParameter" value="StringToken">
> +        <property name="_icon" class="ptolemy.vergil.icon.ValueIcon">
> +            <property name="_color" class="ptolemy.actor.gui.ColorAttribute" value="{0.0, 0.0, 1.0, 1.0}">
> +            </property>
> +        </property>
> +        <property name="_editorFactory" class="ptolemy.vergil.toolbox.VisibleParameterEditorFactory">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="{95.0, 235.0}">
> +        </property>
> +    </property>
> +    <property name="DB_port" class="org.kepler.types.DataBindingParameter" value="/StringToken[@label=="response"]">
> +        <display name="port"/>
> +    </property>
> +    <port name="input" class="ptolemy.actor.TypedIOPort">
> +        <property name="input"/>
> +        <property name="dataType" class="ptolemy.kernel.util.StringAttribute" value="general">
> +        </property>
> +        <property name="isMultiport" class="ptolemy.kernel.util.StringAttribute" value="false">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="{105.0, 185.0}">
> +        </property>
> +    </port>
> +    <port name="output" class="ptolemy.actor.TypedIOPort">
> +        <property name="output"/>
> +        <property name="multiport"/>
> +        <property name="dataType" class="ptolemy.kernel.util.StringAttribute" value="unknown">
> +        </property>
> +        <property name="isMultiport" class="ptolemy.kernel.util.StringAttribute" value="true">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="{590.0, 210.0}">
> +        </property>
> +    </port>
> +    <port name="port" class="ptolemy.actor.TypedIOPort">
> +        <property name="input"/>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="[205.0, 295.0]">
> +        </property>
> +        <property name="_type" class="ptolemy.actor.TypeAttribute" value="string">
> +        </property>
> +        <property name="_hide" class="ptolemy.data.expr.SingletonParameter" value="true">
> +        </property>
> +    </port>
> +    <entity name="File Writer" class="org.geon.FileWrite">
> +        <property name="fileName" class="ptolemy.actor.parameters.FilePortParameter" value="/tmp/response.txt">
> +        </property>
> +        <property name="append" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +        <property name="confirmOverwrite" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +        <property name="alwaysFlush" class="ptolemy.data.expr.Parameter" value="false">
> +        </property>
> +<property name="KeplerDocumentation" class="ptolemy.vergil.basic.KeplerDocumentationAttribute">
> +<property name="description" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="author" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>No author given</configure></property>
> +<property name="version" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>null</configure></property>
> +<property name="userLevelDocumentation" class="ptolemy.kernel.util.ConfigurableAttribute"><configure><p>The FileWriter actor reads a string and writes it to a file. The actor outputs the file path of the generated file.</p>

<p>Specify a destination file path with the fileName parameter. If the specified file does not exist, then the actor will create it.  If the file already exists, then the actor will ask for permission to overwrite it (unless the append parameter is selected, in which case the new content is appended to the existing content).</p>

<p>The actor is similar to the LineWriter, except that the FileWriter outputs the generated file path, while the LineWriter actor does not. FileWriter is also similar to TextFileWriter, except that the FileWriter actor adds line breaks, while the TextFileWriter does not.</p>
</configure></property>
> +<property name="port:input" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>An input port that receives a string to write to a file.</configure></property>
> +<property name="port:url" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>An output port that broadcasts the file name of the generated file.</configure></property>
> +<property name="prop:append" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether to append the input string to an existing, specified file. By default, the actor will overwrite any preexisting file.</configure></property>
> +<property name="prop:confirmOverwrite" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>Specify whether the actor should confirm before overwriting an existing file. By default, the actor will not ask for confirmation.</configure></property>
> +<property name="prop:fileName" class="ptolemy.kernel.util.ConfigurableAttribute"><configure>The name of the file to which to write. See FileParameter for more information about specifying file names. </configure></property>
> +</property>        <property name="entityId" class="org.kepler.moml.NamedObjId" value="urn:lsid:kepler-project.org/ns/:6867:27:15">
> +        </property>
> +        <property name="class" class="ptolemy.kernel.util.StringAttribute" value="org.geon.FileWrite">
> +            <property name="id" class="ptolemy.kernel.util.StringAttribute" value="urn:lsid:kepler-project.org:class:1003:1">
> +            </property>
> +        </property>
> +        <property name="semanticType00" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:1:1#WriterOutputActor">
> +        </property>
> +        <property name="semanticType11" class="org.kepler.sms.SemanticType" value="urn:lsid:localhost:onto:2:1#LocalOutput">
> +        </property>
> +        <property name="_location" class="ptolemy.kernel.util.Location" value="{355.0, 280.0}">
> +        </property>
> +        <property name="" class="ptolemy.vergil.basic.DocAttribute">
> +            <property name="description" class="ptolemy.kernel.util.StringAttribute" value="<p>The FileWriter actor reads a string and writes it to a file. The actor outputs the file path of the generated file.</p>

<p>Specify a destination file path with the fileName parameter. If the specified file does not exist, then the actor will create it.  If the file already exists, then the actor will ask for permission to overwrite it (unless the append parameter is selected, in which case the new content is appended to the existing content).</p>

<p>The actor is similar to the LineWriter, except that the FileWriter outputs the generated file path, while the LineWriter actor does not. FileWriter is also similar to TextFileWriter, except that the FileWriter actor adds line breaks, while the TextFileWriter does not.</p>
">
> +            </property>
> +            <property name="author" class="ptolemy.kernel.util.StringAttribute" value="No author given">
> +            </property>
> +            <property name="version" class="ptolemy.kernel.util.StringAttribute" value="null">
> +            </property>
> +            <property name="append (parameter)" class="ptolemy.data.expr.StringParameter" value="Specify whether to append the input string to an existing, specified file. By default, the actor will overwrite any preexisting file.">
> +            </property>
> +            <property name="confirmOverwrite (parameter)" class="ptolemy.data.expr.StringParameter" value="Specify whether the actor should confirm before overwriting an existing file. By default, the actor will not ask for confirmation.">
> +            </property>
> +            <property name="input (port)" class="ptolemy.kernel.util.StringAttribute" value="An input port that receives a string to write to a file.">
> +            </property>
> +            <property name="url (port)" class="ptolemy.kernel.util.StringAttribute" value="An output port that broadcasts the file name of the generated file.">
> +            </property>
> +            <property name="fileName (parameter)" class="ptolemy.data.expr.StringParameter" value="The name of the file to which to write. See FileParameter for more information about specifying file names. ">
> +            </property>
> +        </property>
> +        <property name="derivedFrom" class="org.kepler.moml.NamedObjIdReferralList" value="urn:lsid:kepler-project.org:actor:144:1">
> +        </property>
> +    </entity>
> +    <relation name="relation2" class="ptolemy.actor.TypedIORelation">
> +    </relation>
> +    <link port="port" relation="relation2"/>
> +    <link port="File Writer.input" relation="relation2"/>
> +</entity>
> +<entity name="OutlierFinderResponseConstructor" class="org.kepler.demo.OutlierIdentification.OutlierFinderResponseConstructor">
> +    <property name="ReadScope" class="ptolemy.data.expr.StringParameter" value="/">
> +    </property>
> +    <property name="DB_Outliers" class="org.kepler.types.DataBindingParameter" value="/OutlierResult//SpecimenRecordType[@label=="Outlier"]*">
> +        <display name="Outliers"/>
> +    </property>
> +    <property name="DB_GeoRefPercentage" class="org.kepler.types.DataBindingParameter" value="/DoubleToken[@label=="GeoPercentage"]">
> +        <display name="GeoRefPercentage"/>
> +    </property>
> +    <property name="DB_Response" class="org.kepler.types.DataBindingParameter" value="/StringToken[@label=="response"]">
> +        <display name="Response"/>
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[460.0, 290.0]">
> +    </property>
> +</entity>
> +<entity name="CollectingEventOutlierFinder" class="org.kepler.demo.OutlierIdentification.CollectingEventOutlierFinder">
> +    <property name="ReadScope" class="ptolemy.data.expr.StringParameter" value="//SpecimenRecords">
> +    </property>
> +    <property name="dataLabel" class="ptolemy.data.expr.StringParameter" value="SpecimenRecord">
> +    </property>
> +    <property name="dailyTravelSpeed" class="ptolemy.data.expr.Parameter" value="MaxTravelSpeed">
> +    </property>
> +    <property name="resultCollectionLabel" class="ptolemy.data.expr.StringParameter" value="OutlierResult">
> +    </property>
> +    <property name="normalDataCollectionLabel" class="ptolemy.data.expr.StringParameter" value="NoneOutlierCollection">
> +    </property>
> +    <property name="normalDataLabel" class="ptolemy.data.expr.StringParameter" value="NoneOutlier">
> +    </property>
> +    <property name="outlierCommentLabel" class="ptolemy.data.expr.StringParameter" value="OutlierIdentificationComment">
> +    </property>
> +    <property name="outlierCollectionLabel" class="ptolemy.data.expr.StringParameter" value="OutlierCollection">
> +    </property>
> +    <property name="outlierDataLabel" class="ptolemy.data.expr.StringParameter" value="Outlier">
> +    </property>
> +    <property name="localComparatorDataLabel" class="ptolemy.data.expr.StringParameter" value="LocalComparator">
> +    </property>
> +    <property name="remoteComparatorDataLabel" class="ptolemy.data.expr.StringParameter" value="RemoteComparator">
> +    </property>
> +    <property name="_location" class="ptolemy.kernel.util.Location" value="[290.0, 290.0]">
> +    </property>
> +</entity>
> +    <link port="CSVCollectionReader.output" relation="relation2"/>
> +    <link port="CompositeCoactor.input" relation="relation4"/>
> +    <link port="OutlierFinderResponseConstructor.input" relation="relation3"/>
> +    <link port="OutlierFinderResponseConstructor.output" relation="relation4"/>
> +    <link port="CollectingEventOutlierFinder.input" relation="relation2"/>
> +    <link port="CollectingEventOutlierFinder.output" relation="relation3"/>
> +</entity>
> 
> Added: trunk/modules/kuration/workflows/OutlierIdentification/data/MissingGeo_TDWG11_Demo.csv
> ===================================================================
> --- trunk/modules/kuration/workflows/OutlierIdentification/data/MissingGeo_TDWG11_Demo.csv	                        (rev 0)
> +++ trunk/modules/kuration/workflows/OutlierIdentification/data/MissingGeo_TDWG11_Demo.csv	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,10 @@
> +CatalogNumber ,RecordedBy,FieldNumber ,YearCollected,MonthCollected,DayCollected,DecimalLatitude ,DecimalLongitude ,GeodeticDatum ,Country,StateProvince,County,Locality,Family ,ScientificName ,ScientificNameAuthorship ,InstitutionCode ,CollectionCode ,DatasetName ,Id
> +100001,Mark Elvin,4457,2010,9,29,41.59805,-70.486307,WGS84,United States,Massachusetts,Barnstable,Woods Hole,Aquifoliaceae,Ilex glabra,(L.) A. Gray,TDWG,BioBlitz2011,TDWG2011,926137834
> +100002,Mark Elvin,4463,2010,9,29,,,WGS85,United States,Massachusetts,Barnstable,Woods Hole,Ericaceae,Vaccinium corymbosum,L.,TDWG,BioBlitz2012,TDWG2012,925533578
> +100003,Mark Elvin,4468,2010,9,29,41.593557,-70.486787,WGS86,United States,Massachusetts,Barnstable,Woods Hole,Dicranaceae,Dicranum bonjeanii,De Not.,TDWG,BioBlitz2010,TDWG2010,1024940716
> +100004,Mark Elvin,4514,2010,9,30,41.636582,-70.48562,WGS87,United States,Massachusetts,Barnstable,Mashpee,Sphagnaceae,Sphagnum fimbriatum,Wilson,TDWG,BioBlitz2013,TDWG2013,1024940765
> +100005,Mark Elvin,4515,2010,9,30,,,WGS88,United States,Massachusetts,Barnstable,Mashpee,Sphagnaceae,Sphagnum papillosum,Lindb.,TDWG,BioBlitz2015,TDWG2015,1024940674
> +100006,Mark Elvin,4527,2010,9,30,,,WGS89,United States,Massachusetts,Barnstable,Woods Hole,Aquifoliaceae,Ilex verticillata,(L.) A. Gray,TDWG,BioBlitz2018,TDWG2018,1024940053
> +100007,Mark Elvin,4539,2010,9,30,,,WGS90,United States,Massachusetts,Barnstable,Woods Hole,Asteraceae,Symphyotrichum tenuifolium,(L.) G.L. Nesom,TDWG,BioBlitz2019,TDWG2019,927140834
> +100008,Mark Elvin,4501,2010,9,30,,,WGS91,United States,Massachusetts,Barnstable,Mashpee,Liliaceae,Maianthemum racemosum,(L.) Link,TDWG,BioBlitz2016,TDWG2016,127140835
> +100009,Mark Elvin,4493,2010,9,30,,,WGS92,United States,Massachusetts,Barnstable,Mashpee,Asteraceae,Prenanthes trifoliolata,(Cass.) Fernald,TDWG,BioBlitz2017,TDWG2017,427140835
> 
> Added: trunk/modules/kuration/workflows/OutlierIdentification/data/TDWG11_Demo.csv
> ===================================================================
> --- trunk/modules/kuration/workflows/OutlierIdentification/data/TDWG11_Demo.csv	                        (rev 0)
> +++ trunk/modules/kuration/workflows/OutlierIdentification/data/TDWG11_Demo.csv	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -0,0 +1,10 @@
> +CatalogNumber ,RecordedBy,FieldNumber ,YearCollected,MonthCollected,DayCollected,DecimalLatitude ,DecimalLongitude ,GeodeticDatum ,Country,StateProvince,County,Locality,Family ,ScientificName ,ScientificNameAuthorship ,InstitutionCode ,CollectionCode ,DatasetName ,Id
> +100001,Mark Elvin,4457,2010,9,29,41.59805,-70.486307,WGS84,United States,Massachusetts,Barnstable,Woods Hole,Aquifoliaceae,Ilex glabra,(L.) A. Gray,TDWG,BioBlitz2011,TDWG2011,926137834
> +100002,Mark Elvin,4463,2010,9,29,41.596734,-70.486093,WGS85,United States,Massachusetts,Barnstable,Woods Hole,Ericaceae,Vaccinium corymbosum,L.,TDWG,BioBlitz2012,TDWG2012,925533578
> +100003,Mark Elvin,4468,2010,9,29,41.593557,-70.486787,WGS86,United States,Massachusetts,Barnstable,Woods Hole,Dicranaceae,Dicranum bonjeanii,De Not.,TDWG,BioBlitz2010,TDWG2010,1024940716
> +100004,Mark Elvin,4514,2010,9,30,41.636582,-70.48562,WGS87,United States,Massachusetts,Barnstable,Mashpee,Sphagnaceae,Sphagnum fimbriatum,Wilson,TDWG,BioBlitz2013,TDWG2013,1024940765
> +100005,Mark Elvin,4515,2010,9,30,41.568934,-70.491865,WGS88,United States,Massachusetts,Barnstable,Mashpee,Sphagnaceae,Sphagnum papillosum,Lindb.,TDWG,BioBlitz2015,TDWG2015,1024940674
> +100006,Mark Elvin,4527,2010,9,30,41.568057,-70.491777,WGS89,United States,Massachusetts,Barnstable,Woods Hole,Aquifoliaceae,Ilex verticillata,(L.) A. Gray,TDWG,BioBlitz2018,TDWG2018,1024940053
> +100007,Mark Elvin,4539,2010,9,30,41.567972,-70.491071,WGS90,United States,Massachusetts,Barnstable,Woods Hole,Asteraceae,Symphyotrichum tenuifolium,(L.) G.L. Nesom,TDWG,BioBlitz2019,TDWG2019,927140834
> +100008,Mark Elvin,4501,2010,9,30,41.566358,-70.491378,WGS91,United States,Massachusetts,Barnstable,Mashpee,Liliaceae,Maianthemum racemosum,(L.) Link,TDWG,BioBlitz2016,TDWG2016,127140835
> +100009,Mark Elvin,4493,2010,9,30,41.565403,-70.4918,WGS92,United States,Massachusetts,Barnstable,Mashpee,Asteraceae,Prenanthes trifoliolata,(Cass.) Fernald,TDWG,BioBlitz2017,TDWG2017,427140835
> 
> Modified: trunk/modules/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js
> ===================================================================
> --- trunk/modules/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js	2011-08-18 23:56:34 UTC (rev 28317)
> +++ trunk/modules/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -1,3 +1,3 @@
> onInvalidSNRecordJsonLoad({"InvalidSNRecords":[
> -]
> +	{"CatalogNumber":"100001"}]
> });
> \ No newline at end of file
> 
> Modified: trunk/modules/kuration/workflows/SpecimenCuration/data/SpecimenRecord.js
> ===================================================================
> --- trunk/modules/kuration/workflows/SpecimenCuration/data/SpecimenRecord.js	2011-08-18 23:56:34 UTC (rev 28317)
> +++ trunk/modules/kuration/workflows/SpecimenCuration/data/SpecimenRecord.js	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -1,10 +1,10 @@
> onSpecimenRecordJsonLoad({"SpecimenRecords":[
> -	{"CatalogNumber":"100001","RecordedBy":"Megan A. Jensen","FieldNumber":"126","YearCollected":"2007","MonthCollected":"6","DayCollected":"29","DecimalLatitude":"47.1384","DecimalLongitude":"-120.9263","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"Washington","County":"Chelan","Locality":"Wenatchee National Forest. South Cle Elum Ridge.","Family":"Asteraceae","ScientificName":"Taraxacum erythrospermum","ScientificNameAuthorship":"Andrz. ex Besser","IdentificationTaxon":"urn:lsid:ipni.org:names:249536-2","ReproductiveCondition":"Flower:March;April;May;June;July;August","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"926137834"},
> -	{"CatalogNumber":"100002","RecordedBy":"G. Rink","FieldNumber":"2503","YearCollected":"2003","MonthCollected":"7","DayCollected":"27","DecimalLatitude":"37.24972","DecimalLongitude":"-108.68333","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"Colorado","County":"","Locality":"Yucca House National Monument","Family":"Asteraceae","ScientificName":"Acroptilon repens","ScientificNameAuthorship":"(L.) DC.","IdentificationTaxon":"urn:lsid:ipni.org:names:174802-1","ReproductiveCondition":"Flower:March;April;May;June;July;August;September","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"925533578"},
> -	{"CatalogNumber":"100003","RecordedBy":"Mark Elvin","FieldNumber":"2938","YearCollected":"1990","MonthCollected":"5","DayCollected":"11","DecimalLatitude":"34.0","DecimalLongitude":"-117.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"San Bernardino","Locality":"400 m north of Cushenbury Springs","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","IdentificationTaxon":"urn:lsid:ipni.org:names:59071-2","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940716"},
> -	{"CatalogNumber":"100005","RecordedBy":"Mark Elvin","FieldNumber":"2940","YearCollected":"1990","MonthCollected":"5","DayCollected":"12","DecimalLatitude":"34.0","DecimalLongitude":"-117.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"San Bernardino","Locality":"l mi. NW of Lucerne Valley town center","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","IdentificationTaxon":"urn:lsid:ipni.org:names:59071-2","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940674"},
> -	{"CatalogNumber":"100006","RecordedBy":"Mark Elvin","FieldNumber":"1940","YearCollected":"1990","MonthCollected":"5","DayCollected":"20","DecimalLatitude":"36.0","DecimalLongitude":"-118.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"Kern","Locality":"Weldon Rancheria","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","IdentificationTaxon":"urn:lsid:ipni.org:names:59071-2","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940053"},
> -	{"CatalogNumber":"100004","RecordedBy":"Mark Elvin","FieldNumber":"3000","YearCollected":"1990","MonthCollected":"5","DayCollected":"21","DecimalLatitude":"37.0","DecimalLongitude":"-118.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"","Locality":"Northern end of The Owens Valle Bishop","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","IdentificationTaxon":"urn:lsid:ipni.org:names:59071-2","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940765"},
> -	{"CatalogNumber":"100008","RecordedBy":"Joseph P. Tracy","FieldNumber":"107702","YearCollected":"1973","MonthCollected":"7","DayCollected":"31","DecimalLatitude":"41.00083","DecimalLongitude":"-123.04722","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"","Locality":"Carlotta Northern Coast Ranges","Family":"Asteraceae","ScientificName":"Logfia gallica","ScientificNameAuthorship":"Coss. & Germ.","IdentificationTaxon":"urn:lsid:ipni.org:names:231064-1","ReproductiveCondition":"Flower:March;April;May;June;July;August","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"127140835"},
> -	{"catalognumber":"100007","collectioncode":"FilteredPush","country":"United States","county":"Honolulu","datasetname":"SPNHCDEMO","daycollected":"16","decimallatitude":"21.312","decimallongitude":"-157.8055","family":"Asteraceae","fieldnumber":"606","geodeticdatum":"WGS84","id":"927140834","identificationtaxon":"urn:lsid:ipni.org:names:256109-1","institutioncode":"DAV","locality":"Honolulu 3115 Kaloaluiki Place","monthcollected":"5","recordedby":"Mark Elvin","reproductivecondition":"Flower:April;May;June;July;August","scientificname":"Tragopogon porrifolius","scientificnameauthorship":"L.","stateprovince":"Hawaii","yearcollected":"1994"}]
> +	{"CatalogNumber":"100001","RecordedBy":"Megan A. Jensen","FieldNumber":"126","YearCollected":"2007","MonthCollected":"6","DayCollected":"29","DecimalLatitude":"47.1384","DecimalLongitude":"-120.9263","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"Washington","County":"Chelan","Locality":"Wenatchee National Forest. South Cle Elum Ridge.","Family":"Asteraceae","ScientificName":"Taraxacum erythrospermum","ScientificNameAuthorship":"auct.","ReproductiveCondition":"Flower:March;April;May;June;July;August","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"926137834"},
> +	{"CatalogNumber":"100002","RecordedBy":"G. Rink","FieldNumber":"2503","YearCollected":"2003","MonthCollected":"7","DayCollected":"27","DecimalLatitude":"-37.25","DecimalLongitude":"-108.68","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"Colorado","County":"","Locality":"Yucca House National Monument","Family":"Asteraceae","ScientificName":"Acroptilon repens","ScientificNameAuthorship":"(L.) DC.","ReproductiveCondition":"Flower:March;April;May;June;July;August;September","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"925533578"},
> +	{"CatalogNumber":"100003","RecordedBy":"Mark Elvin","FieldNumber":"2938","YearCollected":"1990","MonthCollected":"5","DayCollected":"11","DecimalLatitude":"34.0","DecimalLongitude":"-117.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"San Bernardino","Locality":"400 m north of Cushenbury Springs","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940716"},
> +	{"CatalogNumber":"100004","RecordedBy":"Mark Elvin","FieldNumber":"3000","YearCollected":"1990","MonthCollected":"5","DayCollected":"21","DecimalLatitude":"37.0","DecimalLongitude":"-118.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"","Locality":"Northern end of The Owens Valle Bishop","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940765"},
> +	{"CatalogNumber":"100005","RecordedBy":"Mark Elvin","FieldNumber":"2940","YearCollected":"1990","MonthCollected":"5","DayCollected":"12","DecimalLatitude":"34.0","DecimalLongitude":"-117.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"San Bernardino","Locality":"l mi. NW of Lucerne Valley town center","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940674"},
> +	{"CatalogNumber":"100006","RecordedBy":"Mark Elvin","FieldNumber":"1940","YearCollected":"1990","MonthCollected":"5","DayCollected":"20","DecimalLatitude":"36.0","DecimalLongitude":"-118.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"Kern","Locality":"Weldon Rancheria","Family":"Asteraceae","ScientificName":"Cirsium mohavense","ScientificNameAuthorship":"(Greene) Petr.","ReproductiveCondition":"Flower:June;July;August;September;October;November","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"1024940053"},
> +	{"CatalogNumber":"100007","RecordedBy":"Mark Elvin","FieldNumber":"606","YearCollected":"1990","MonthCollected":"5","DayCollected":"16","DecimalLatitude":"21.312","DecimalLongitude":"-157.8055","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"Hawaii","County":"Honolulu","Locality":"Honolulu 3115 Kaloaluiki Place","Family":"Asteraceae","ScientificName":"Tragopogon porrifolius","ScientificNameAuthorship":"L.","ReproductiveCondition":"Flower:April;May;June;July;August","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"927140834"},
> +	{"CatalogNumber":"100008","RecordedBy":"Joseph P. Tracy","FieldNumber":"107702","YearCollected":"1973","MonthCollected":"7","DayCollected":"31","DecimalLatitude":"40.0","DecimalLongitude":"-104.0","GeodeticDatum":"WGS84","Country":"United States","StateProvince":"California","County":"","Locality":"Carlotta Northern Coast Ranges","Family":"Asteraceae","ScientificName":"Logfia gallica","ScientificNameAuthorship":"Coss. & Germ.","ReproductiveCondition":"Flower:July;August; September","InstitutionCode":"DAV","CollectionCode":"FilteredPush","DatasetName":"SPNHCDEMO","Id":"127140835"}]
> });
> \ No newline at end of file
> 
> Modified: trunk/modules/kuration/workflows/SpecimenCuration/function/visualization/SpecimenVisualization.html
> ===================================================================
> --- trunk/modules/kuration/workflows/SpecimenCuration/function/visualization/SpecimenVisualization.html	2011-08-18 23:56:34 UTC (rev 28317)
> +++ trunk/modules/kuration/workflows/SpecimenCuration/function/visualization/SpecimenVisualization.html	2011-08-19 00:01:27 UTC (rev 28318)
> @@ -47,10 +47,10 @@
>         }
>     </script>
> 
> -    <script src="file:////Users/rie/dou/project/kepler.trunk/kuration/workflows/SpecimenCuration/data/SpecimenRecord.js"></script>
> -    <script src="file:///Users/rie/dou/project/kepler.trunk/kuration/workflows/SpecimenCuration/function/visualization/PhenologyRecord.js"></script>        
> -    <script src="file:///Users/rie/dou/project/kepler.trunk/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js"></script>
> -    <script src="file:///Users/rie/dou/project/kepler.trunk/kuration/workflows/SpecimenCuration/function/visualization/StateCoordinate.js"></script>   
> +    <script src="file://D:\project\Kepler/kepler.trunk/kuration\workflows\SpecimenCuration/data/SpecimenRecord.js"></script>
> +    <script src="file://D:\project\Kepler/kepler.trunk/kuration/workflows/SpecimenCuration/function/visualization/PhenologyRecord.js"></script>        
> +    <script src="file://D:\project\Kepler/kepler.trunk/kuration/workflows/SpecimenCuration/data/InvalidScientificNameRecord.js"></script>
> +    <script src="file://D:\project\Kepler/kepler.trunk/kuration/workflows/SpecimenCuration/function/visualization/StateCoordinate.js"></script>   
>     <script type="text/javascript" language="javascript" src="specimenvisualization/specimenvisualization.nocache.js"></script>
>   </head>
> 
> 
> _______________________________________________
> Kepler-cvs mailing list
> Kepler-cvs at kepler-project.org
> http://lists.nceas.ucsb.edu/kepler/mailman/listinfo/kepler-cvs



More information about the Kepler-dev mailing list