docs: def run(expnum,
          ccd,
          prefix='',
          version='p',
          sex_thresh=_SEX_THRESHOLD,
          wave_thresh=_WAVE_THRESHOLD,
          maxcount=_MAX_COUNT,
          dry_run=False, 
          force=True):
      """run the actual step1jmp/matt codes.
  
      expnum: the CFHT expousre to process
      ccd: which ccd in the mosaic to process
      fwhm: the image quality, FWHM, of the image.  In pixels.
      sex_thresh: the detection threhold to run sExtractor at
      wave_thresh: the detection threshold for wavelet
      maxcount: saturation level
  
      """
      message = storage.SUCCESS
  
      if storage.get_status(task, prefix, expnum, version, ccd) and not force:
          logging.info("{} completed successfully for {} {} {} {}".format(task, prefix, expnum, version, ccd))
          return
          
      with storage.LoggingManager(task, prefix, expnum, ccd, version, dry_run):
          try:        
              if not storage.get_status(dependency, prefix, expnum, version, ccd):
                  raise IOError(35, "Cannot start {} as {} not yet completed for {}{}{}{:02d}".format(
                      task, dependency, prefix, expnum, version, ccd))
              logging.info("Retrieving imaging and input parameters from VOSpace")    
              storage.get_file(expnum, ccd, prefix=prefix, version=version, ext='mopheader')
              filename = storage.get_image(expnum, ccd, version=version, prefix=prefix)
              fwhm = storage.get_fwhm(expnum, ccd, prefix=prefix, version=version)
              basename = os.path.splitext(filename)[0]
  
              _get_weight_map(filename, ccd)
              
              logging.info("Launching step1jmp")
              logging.info(util.exec_prog(['step1jmp',
                                           '-f', basename,
                                           '-t', str(wave_thresh),
                                           '-w', str(fwhm),
                                           '-m', str(maxcount)]))
  
              logging.info(util.exec_prog(['step1matt',
                                   '-f', basename,
                                   '-t', str(sex_thresh),
                                   '-w', str(fwhm),
                                   '-m', str(maxcount)]))
  
              if os.access('weight.fits', os.R_OK):
                  os.unlink('weight.fits')
              
              if not dry_run:
                  for ext in ['obj.jmp', 'obj.matt']:
                      obj_uri = storage.get_uri(expnum, ccd, version=version, ext=ext,
                                                prefix=prefix)
                      obj_filename = basename + "." + ext
                      count = 0
                      with open(obj_filename, 'r'):
                        while True:
                          try:
                              count += 1
                              logging.info("Attempt {} to copy {} -> {}".format(count, obj_filename, obj_uri))
                              storage.copy(obj_filename, obj_uri)
                              break
                          except Exception as ex:
                              if count > 10:
                                  raise ex
              logging.info(message)
          except Exception as ex:
              message = str(ex)
              logging.error(message)
  
          if not dry_run:
              storage.set_status(task, prefix, expnum, version, ccd, status=message)