def step(taskName, parameterByName, folderStore, options):
    # Get probabilityInformation
    probabilityName = parameterByName['probability name']
    probabilityPath = folderStore.getProbabilityPath(probabilityName)
    probabilityInformation = probability_store.Information(probabilityPath)
    # Get imageInformation
    imageName = probabilityInformation.getImageName()
    imageInformation = folderStore.getImageInformation(imageName)
    # Get parameters
    positiveLocationPath = imageInformation.getPositiveLocationPath()
    multispectralImage = imageInformation.getMultispectralImage()
    spatialReference = multispectralImage.getSpatialReference()
    evaluationRadiusInMeters = parameterByName['evaluation radius in meters']
    evaluationDiameterInMeters = evaluationRadiusInMeters * 2
    iterationCountPerBurst = parameterByName['iteration count per burst']
    maximumDiameterInMeters = parameterByName['maximum diameter in meters']
    minimumDiameterInMeters = parameterByName['minimum diameter in meters']
    # Run
    targetLocationPath = folderStore.fillLocationPath(taskName)
    targetFolderPath = os.path.dirname(targetLocationPath)
    locationInformation = {
        'location': {
            'path': targetLocationPath, 
            'spatial reference': spatialReference,
        },
        'probability': {
            'name': probabilityName,
            'path': probabilityPath,
        },
        'parameters': {
            'iteration count per burst': iterationCountPerBurst, 
            'maximum diameter in meters': maximumDiameterInMeters,
            'minimum diameter in meters': minimumDiameterInMeters,
            'evaluation radius in meters': evaluationRadiusInMeters,
        },
    }
    if not options.is_test:
        # Cluster
        print 'Clustering locations...'
        probability_process.cluster(targetLocationPath, probabilityPath, iterationCountPerBurst, maximumDiameterInMeters, minimumDiameterInMeters)
        # If scanning has finished,
        if probabilityInformation.hasPerformance():
            print 'Evaluating locations...'
            # Load regions
            regionPath = probabilityInformation.getRegionPath()
            regionGeoFrames = region_store.loadShapefile(regionPath, multispectralImage, withGeoToPixelConversion=False)
            # Evaluate locations
            locationInformation['performance'] = evaluation_process.evaluateLocations(targetFolderPath, evaluationDiameterInMeters, positiveLocationPath, targetLocationPath, regionGeoFrames)
    # Record
    store.saveInformation(targetLocationPath, locationInformation)
def defineRegions(targetRegionPath, multispectralImagePath, panchromaticImagePath, parameterByName, options=None):
    # Load
    targetTestRegionPath = targetRegionPath + '-test'
    multispectralImage = image_store.load(str(multispectralImagePath))
    panchromaticImage = image_store.load(str(panchromaticImagePath))
    regionPath = parameterByName.get('region path')
    multispectralRegionFrames = parameterByName.get('multispectral region frames')
    windowLengthInMeters = parameterByName.get('window length in meters')
    regionLengthInWindows = parameterByName.get('region length in windows')
    testFractionPerRegion = parameterByName['test fraction per region']
    coverageFraction = parameterByName.get('coverage fraction', 1)
    coverageFrequency = int(1 / coverageFraction)
    coverageOffset = parameterByName.get('coverage offset', 0)
    # If regionPath is defined, use it
    if regionPath:
        regionGenerator = (x for x in region_store.loadShapefile(regionPath, multispectralImage))
    # If multispectralRegionFrames are defined, use them
    elif multispectralRegionFrames:
        regionGenerator = (x for x in multispectralRegionFrames)
    # Otherwise, prepare regionGenerator
    else:
        regionGenerator = region_store.makeRegionGenerator(multispectralImage, panchromaticImage, regionLengthInWindows, windowLengthInMeters)
    # Save regions
    regionDataset = region_store.create(targetRegionPath)
    testRegionDataset = region_store.create(targetTestRegionPath)
    if options and not options.is_test:
        for regionIndex, regionWindow in itertools.izip(itertools.count(1), regionGenerator):
            if (regionIndex + coverageOffset) % coverageFrequency == 0:
                regionDataset.addRegion(regionWindow)
                regionFrame = region_store.getMultispectralPixelFrame(regionWindow)
                testRegionDataset.addFrame(region_process.placeTestRegion(regionFrame, testFractionPerRegion))
    # Save as shapefiles
    regionDataset.saveShapefile(targetRegionPath, multispectralImage)
    testRegionDataset.saveShapefile(targetTestRegionPath, multispectralImage)
    # Prepare information
    information = {
        'parameters': {
            'multispectral image path': multispectralImagePath,
            'panchromatic image path': panchromaticImagePath,
            'test fraction per region': testFractionPerRegion,
            'window length in meters': windowLengthInMeters,
        },
        'regions': {
            'path': regionDataset.getPath(),
            'count': regionDataset.count(),
        },
        'test regions': {
            'path': testRegionDataset.getPath(),
            'count': testRegionDataset.count(),
        },
    }
    if regionPath:
        information['parameters'].update({
            'region path': regionPath,
        })
    elif multispectralRegionFrames: 
        information['parameters'].update({
            'multispectral region frames': store.stringifyNestedList(multispectralRegionFrames),
        })
    else:
        information['parameters'].update({
            'region length in windows': regionLengthInWindows,
            'coverage fraction': coverageFraction,
            'coverage offset': coverageOffset,
        })
    # Save information
    store.saveInformation(targetRegionPath, information)