IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 9950


Ignore:
Timestamp:
Nov 13, 2006, 12:15:55 PM (19 years ago)
Author:
Paul Price
Message:

Adding FRINGE type to pmFPAfile, which reads from/writes to FITS tables at the cell level.

Location:
trunk/psModules/src/camera
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmFPAfile.c

    r9436 r9950  
    119119}
    120120
     121// select the cell from the named pmFPAfile; if the named file does not exist,
     122pmCell *pmFPAfileThisCell (psMetadata *files, const pmFPAview *view, const char *name)
     123{
     124    PS_ASSERT_PTR_NON_NULL(files, false);
     125    PS_ASSERT_PTR_NON_NULL(view, false);
     126    PS_ASSERT_PTR_NON_NULL(name, false);
     127    PS_ASSERT_INT_POSITIVE(strlen(name), false);
     128
     129    bool status;
     130
     131    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
     132    if (file == NULL) {
     133        return NULL;
     134    }
     135
     136    // internal files have the readout as a separate element:
     137    if (file->mode == PM_FPA_MODE_INTERNAL) {
     138        return NULL;
     139    }
     140
     141    pmCell *cell = pmFPAviewThisCell(view, file->fpa);
     142    return cell;
     143}
     144
     145// select the readout from the named pmFPAfile; if the named file does not exist,
     146pmChip *pmFPAfileThisChip (psMetadata *files, const pmFPAview *view, const char *name)
     147{
     148    PS_ASSERT_PTR_NON_NULL(files, false);
     149    PS_ASSERT_PTR_NON_NULL(view, false);
     150    PS_ASSERT_PTR_NON_NULL(name, false);
     151    PS_ASSERT_INT_POSITIVE(strlen(name), false);
     152
     153    bool status;
     154
     155    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
     156    if (file == NULL) {
     157        return NULL;
     158    }
     159
     160    // internal files have the readout as a separate element:
     161    if (file->mode == PM_FPA_MODE_INTERNAL) {
     162        return NULL;
     163    }
     164
     165    pmChip *chip = pmFPAviewThisChip (view, file->fpa);
     166    return chip;
     167}
     168
    121169// select the rule from the camera configuration, perform substitutions as needed
    122170char *pmFPAfileNameFromRule (char *rule, pmFPAfile *file, const pmFPAview *view)
     
    296344    return false;
    297345}
     346
     347
     348pmFPAfileType pmFPAfileTypeFromString(const char *type)
     349{
     350    PS_ASSERT_STRING_NON_EMPTY(type, PM_FPA_FILE_NONE);
     351
     352    if (!strcasecmp (type, "SX"))     {
     353        return PM_FPA_FILE_SX;
     354    }
     355    if (!strcasecmp (type, "OBJ"))     {
     356        return PM_FPA_FILE_OBJ;
     357    }
     358    if (!strcasecmp (type, "CMP"))     {
     359        return PM_FPA_FILE_CMP;
     360    }
     361    if (!strcasecmp (type, "CMF"))     {
     362        return PM_FPA_FILE_CMF;
     363    }
     364    if (!strcasecmp (type, "RAW"))     {
     365        return PM_FPA_FILE_RAW;
     366    }
     367    if (!strcasecmp (type, "IMAGE"))     {
     368        return PM_FPA_FILE_IMAGE;
     369    }
     370    if (!strcasecmp (type, "PSF"))     {
     371        return PM_FPA_FILE_PSF;
     372    }
     373    if (!strcasecmp (type, "JPEG"))     {
     374        return PM_FPA_FILE_JPEG;
     375    }
     376    if (!strcasecmp (type, "FRINGE")) {
     377        return PM_FPA_FILE_FRINGE;
     378    }
     379
     380    return PM_FPA_FILE_NONE;
     381}
     382
  • trunk/psModules/src/camera/pmFPAfile.h

    r9585 r9950  
    77*  @author EAM, IfA
    88*
    9 *  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
    10 *  @date $Date: 2006-10-17 00:41:05 $
     9*  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
     10*  @date $Date: 2006-11-13 22:15:55 $
    1111*
    1212*  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
     
    3737    PM_FPA_FILE_JPEG,
    3838    PM_FPA_FILE_MANAPLOT,
     39    PM_FPA_FILE_FRINGE,
    3940} pmFPAfileType;
    4041
     
    101102pmReadout *pmFPAfileThisReadout (psMetadata *files, const pmFPAview *view, const char *name);
    102103
     104// select the cell from the named pmFPAfile; if the named file does not exist,
     105pmCell *pmFPAfileThisCell (psMetadata *files, const pmFPAview *view, const char *name);
     106
     107// select the chip from the named pmFPAfile; if the named file does not exist,
     108pmChip *pmFPAfileThisChip (psMetadata *files, const pmFPAview *view, const char *name);
     109
    103110// add the specified filename info (value) to the files of the given mode using the given reference name
    104111bool pmFPAfileAddFileNames (psMetadata *files, char *name, char *value, int mode);
     
    111118bool pmFPAfileCopyStructureView (pmFPA *out, pmFPA *in, int xBin, int yBin, const pmFPAview *view);
    112119
     120// Return the file type enum from a string
     121pmFPAfileType pmFPAfileTypeFromString(const char *type);
     122
    113123# endif
  • trunk/psModules/src/camera/pmFPAfileDefine.c

    r9903 r9950  
    7171    file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
    7272
    73     file->type = PM_FPA_FILE_NONE;
    7473    type = psMetadataLookupStr (&status, data, "FILE.TYPE");
    75     if (type != NULL) {
    76         if (!strcasecmp (type, "SX"))     {
    77             file->type = PM_FPA_FILE_SX;
    78         } else if (!strcasecmp (type, "OBJ"))     {
    79             file->type = PM_FPA_FILE_OBJ;
    80         } else if (!strcasecmp (type, "CMP"))     {
    81             file->type = PM_FPA_FILE_CMP;
    82         } else if (!strcasecmp (type, "CMF"))     {
    83             file->type = PM_FPA_FILE_CMF;
    84         } else if (!strcasecmp (type, "RAW"))     {
    85             file->type = PM_FPA_FILE_RAW;
    86         } else if (!strcasecmp (type, "IMAGE"))     {
    87             file->type = PM_FPA_FILE_IMAGE;
    88         } else if (!strcasecmp (type, "PSF"))     {
    89             file->type = PM_FPA_FILE_PSF;
    90         } else if (!strcasecmp (type, "JPEG"))     {
    91             file->type = PM_FPA_FILE_JPEG;
    92         }
    93     }
     74    file->type = pmFPAfileTypeFromString(type);
    9475    if (file->type == PM_FPA_FILE_NONE) {
    9576        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
     
    167148    file->extxtra  = psMemIncrRefCounter(psMetadataLookupStr (&status, data, "EXTNAME.XTRA"));
    168149
    169     file->type = PM_FPA_FILE_NONE;
    170150    type = psMetadataLookupStr (&status, data, "FILE.TYPE");
    171     if (type != NULL) {
    172         if (!strcasecmp (type, "SX"))     {
    173             file->type = PM_FPA_FILE_SX;
    174         } else if (!strcasecmp (type, "OBJ"))     {
    175             file->type = PM_FPA_FILE_OBJ;
    176         } else if (!strcasecmp (type, "CMP"))     {
    177             file->type = PM_FPA_FILE_CMP;
    178         } else if (!strcasecmp (type, "CMF"))     {
    179             file->type = PM_FPA_FILE_CMF;
    180         } else if (!strcasecmp (type, "RAW"))     {
    181             file->type = PM_FPA_FILE_RAW;
    182         } else if (!strcasecmp (type, "IMAGE"))     {
    183             file->type = PM_FPA_FILE_IMAGE;
    184         } else if (!strcasecmp (type, "PSF"))     {
    185             file->type = PM_FPA_FILE_PSF;
    186         } else if (!strcasecmp (type, "JPEG"))     {
    187             file->type = PM_FPA_FILE_JPEG;
    188         }
    189     }
     151    file->type = pmFPAfileTypeFromString(type);
    190152    if (file->type == PM_FPA_FILE_NONE) {
    191153        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
  • trunk/psModules/src/camera/pmFPAfileFitsIO.c

    r9067 r9950  
    1616#include "pmFPAfile.h"
    1717#include "pmFPAfileFitsIO.h"
     18
     19// given an already-opened fits file, read the table corresponding to the specified view
     20bool pmFPAviewReadFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name)
     21{
     22    PS_ASSERT_PTR_NON_NULL(view, false);
     23    PS_ASSERT_PTR_NON_NULL(file, false);
     24
     25    pmFPA *fpa = file->fpa;             // FPA of interest
     26    psFits *fits = file->fits;          // FITS file
     27
     28    if (view->chip == -1) {
     29        return pmFPAReadTable(fpa, fits, name) > 0;
     30    }
     31
     32    if (view->cell == -1) {
     33        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
     34        return pmChipReadTable(chip, fits, name) > 0;
     35    }
     36
     37    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
     38    return pmCellReadTable(cell, fits, name) > 0;
     39}
     40
     41// given an already-opened fits file, write the table corresponding to the specified view
     42bool pmFPAviewWriteFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name)
     43{
     44    PS_ASSERT_PTR_NON_NULL(view, false);
     45    PS_ASSERT_PTR_NON_NULL(file, false);
     46
     47    pmFPA *fpa = file->fpa;             // FPA of interest
     48    psFits *fits = file->fits;          // FITS file
     49
     50    if (view->chip == -1) {
     51        return pmFPAWriteTable(fits, fpa, name) > 0;
     52    }
     53
     54    if (view->cell == -1) {
     55        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
     56        return pmChipWriteTable(fits, chip, name) > 0;
     57    }
     58
     59    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
     60    return pmCellWriteTable(fits, cell, name) > 0;
     61}
    1862
    1963// given an already-opened fits file, read the components corresponding
     
    226270}
    227271
     272
     273// Free the table within a cell
     274static void freeTable(pmCell *cell,     // Cell of interest
     275                      const char *name  // Name of table to free
     276                     )
     277{
     278    assert(cell);
     279    assert(name && strlen(name) > 0);
     280
     281    psString headerName = NULL;         // Name of header
     282    psStringAppend(&headerName, "%s.HEADER", name);
     283    if (psMetadataLookup(cell->analysis, headerName)) {
     284        psMetadataRemoveKey(cell->analysis, headerName);
     285    }
     286    psFree(headerName);
     287
     288    if (psMetadataLookup(cell->analysis, name)) {
     289        psMetadataRemoveKey(cell->analysis, name);
     290    }
     291
     292    return;
     293}
     294
     295// given a file, free the components corresponding to the specified view
     296bool pmFPAviewFreeFitsTable (const pmFPAview *view, pmFPAfile *file, const char *name)
     297{
     298    PS_ASSERT_PTR_NON_NULL(view, false);
     299    PS_ASSERT_PTR_NON_NULL(file, false);
     300
     301    pmFPA *fpa = file->fpa;
     302
     303    if (view->chip == -1) {
     304        psArray *chips = fpa->chips;    // Array of chips
     305        for (int i = 0; i < chips->n; i++) {
     306            pmChip *chip = chips->data[i]; // Chip of interest
     307            psArray *cells = chip->cells; // Array of cells
     308            for (int j = 0; j < cells->n; j++) {
     309                pmCell *cell = cells->data[j]; // Cell of interest
     310                freeTable(cell, name);
     311            }
     312        }
     313        return true;
     314    }
     315
     316    if (view->cell == -1) {
     317        pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest
     318        psArray *cells = chip->cells;   // Array of cells
     319        for (int i = 0; i < cells->n; i++) {
     320            pmCell *cell = cells->data[i]; // Cell of interest
     321            freeTable(cell, name);
     322        }
     323        return true;
     324    }
     325
     326    pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest
     327    freeTable(cell, name);
     328    return true;
     329}
     330
  • trunk/psModules/src/camera/pmFPAfileFitsIO.h

    r7589 r9950  
    77*  @author EAM, IfA
    88*
    9 *  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
    10 *  @date $Date: 2006-06-17 01:50:43 $
     9*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
     10*  @date $Date: 2006-11-13 22:15:55 $
    1111*
    1212*  Copyright 2004-2005 Institute for Astronomy, University of Hawaii
     
    2525bool pmFPAviewFreeFitsImage (const pmFPAview *view, pmFPAfile *file);
    2626
     27
     28// read a table into the current view
     29bool pmFPAviewReadFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
     30
     31// write the table for the specified view
     32bool pmFPAviewWriteFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
     33
     34// free the appropriate table containers
     35bool pmFPAviewFreeFitsTable(const pmFPAview *view, pmFPAfile *file, const char *name);
     36
    2737# endif
  • trunk/psModules/src/camera/pmFPAfileIO.c

    r9654 r9950  
    3030#include "pmDetrendDB.h"
    3131
     32// Open a file that contains an image
     33static bool openImage(pmFPAfile *file,  // File to open
     34                      const pmFPAview *view, // View pointing to open level
     35                      const char *mode,  // Open mode (for psFitsOpen)
     36                      pmConfig *config  // Configuration
     37                     )
     38{
     39    file->fits = psFitsOpen (file->filename, mode);
     40    if (file->fits == NULL) {
     41        psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
     42        return false;
     43    }
     44    file->state = PM_FPA_STATE_OPEN;
     45
     46    // In some cases, I need to call pmFPAAddSourceFromHeader after I've opened the file,
     47    // specifically if I have not called this function on startup.  This happens for the
     48    // images supplied by the detrend database, which are only identified here (above).
     49    // this is never true for the output images, which are constructed later
     50
     51    if (file->mode == PM_FPA_MODE_READ) {
     52        bool addSource = false;
     53        switch (file->fileLevel) {
     54        case PM_FPA_LEVEL_FPA:
     55            addSource = !file->fpa->hdu;
     56            break;
     57        case PM_FPA_LEVEL_CHIP: {
     58                pmChip *chip = pmFPAviewThisChip(view, file->fpa);
     59                if (!chip) {
     60                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
     61                    return false;
     62                }
     63                addSource = !chip->hdu;
     64                break;
     65            }
     66        case PM_FPA_LEVEL_CELL: {
     67                pmCell *cell = pmFPAviewThisCell(view, file->fpa);
     68                if (!cell) {
     69                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
     70                    return false;
     71                }
     72                addSource = !cell->hdu;
     73                break;
     74            }
     75        default:
     76            psAbort ("pmFPAfileIO", "fileLevel not correctly set");
     77            break;
     78        }
     79
     80        if (addSource) {
     81            psMetadata *phu = psFitsReadHeader (NULL, file->fits);
     82            if (!file->format) {
     83                file->format = pmConfigCameraFormatFromHeader (config, phu);
     84                if (!file->format) {
     85                    psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
     86                    psFree(phu);
     87                    return NULL;
     88                }
     89            } else {
     90                pmConfigValidateCameraFormat (file->format, phu);
     91            }
     92            pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
     93            psFree (thisView);
     94            psFree (phu);
     95            // XXX we can check the output view to be sure it corresponds to our current view
     96        }
     97    }
     98    if (file->mode == PM_FPA_MODE_WRITE) {
     99        switch (file->fileLevel) {
     100        case PM_FPA_LEVEL_FPA:
     101            pmFPAWrite (file->fpa, file->fits, NULL, true, false);
     102            break;
     103        case PM_FPA_LEVEL_CHIP: {
     104                pmChip *chip = pmFPAviewThisChip(view, file->fpa);
     105                pmChipWrite (chip, file->fits, NULL, true, false);
     106                break;
     107            }
     108        case PM_FPA_LEVEL_CELL: {
     109                pmCell *cell = pmFPAviewThisCell(view, file->fpa);
     110                pmCellWrite(cell, file->fits, NULL, true);
     111                break;
     112            }
     113        default:
     114            psAbort ("pmFPAfileIO", "fileLevel not correctly set");
     115            break;
     116        }
     117    }
     118
     119    return true;
     120
     121}
     122
     123
    32124// open file (if not already opened)
    33125bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
     
    133225        // open the FITS types:
    134226    case PM_FPA_FILE_IMAGE:
     227    case PM_FPA_FILE_FRINGE:
    135228        psTrace ("pmFPAfile", 5, "opening %s (type: %d)\n", file->filename, file->type);
    136         file->fits = psFitsOpen (file->filename, mode);
    137         if (file->fits == NULL) {
    138             psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
    139             return false;
    140         }
    141         file->state = PM_FPA_STATE_OPEN;
    142 
    143         // In some cases, I need to call pmFPAAddSourceFromHeader after I've opened the file,
    144         // specifically if I have not called this function on startup.  This happens for the
    145         // images supplied by the detrend database, which are only identified here (above).
    146         // this is never true for the output images, which are constructed later
    147 
    148         if (file->mode == PM_FPA_MODE_READ) {
    149             pmChip *chip;
    150             pmCell *cell;
    151             bool addSource = false;
    152             switch (file->fileLevel) {
    153             case PM_FPA_LEVEL_FPA:
    154                 addSource = !file->fpa->hdu;
    155                 break;
    156             case PM_FPA_LEVEL_CHIP:
    157                 chip = pmFPAviewThisChip(view, file->fpa);
    158                 if (!chip) {
    159                     psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
    160                     return false;
    161                 }
    162                 addSource = !chip->hdu;
    163                 break;
    164             case PM_FPA_LEVEL_CELL:
    165                 cell = pmFPAviewThisCell(view, file->fpa);
    166                 if (!cell) {
    167                     psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
    168                     return false;
    169                 }
    170                 addSource = !cell->hdu;
    171                 break;
    172             default:
    173                 psAbort ("pmFPAfileIO", "fileLevel not correctly set");
    174                 break;
    175             }
    176 
    177             if (addSource) {
    178                 psMetadata *phu = psFitsReadHeader (NULL, file->fits);
    179                 if (!file->format) {
    180                     file->format = pmConfigCameraFormatFromHeader (config, phu);
    181                     if (!file->format) {
    182                         psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
    183                         psFree(phu);
    184                         return NULL;
    185                     }
    186                 } else {
    187                     pmConfigValidateCameraFormat (file->format, phu);
    188                 }
    189                 pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
    190                 psFree (thisView);
    191                 psFree (phu);
    192                 // XXX we can check the output view to be sure it corresponds to our current view
    193             }
    194         }
    195         if (file->mode == PM_FPA_MODE_WRITE) {
    196             switch (file->fileLevel) {
    197             case PM_FPA_LEVEL_FPA:
    198                 pmFPAWrite (file->fpa, file->fits, NULL, true, false);
    199                 break;
    200             case PM_FPA_LEVEL_CHIP: {
    201                     pmChip *chip = pmFPAviewThisChip(view, file->fpa);
    202                     pmChipWrite (chip, file->fits, NULL, true, false);
    203                     break;
    204                 }
    205             case PM_FPA_LEVEL_CELL: {
    206                     pmCell *cell = pmFPAviewThisCell(view, file->fpa);
    207                     pmCellWrite(cell, file->fits, NULL, true);
    208                     break;
    209                 }
    210             default:
    211                 psAbort ("pmFPAfileIO", "fileLevel not correctly set");
    212                 break;
    213             }
    214         }
    215         break;
    216 
     229        if (!openImage(file, view, mode, config)) {
     230            psError(PS_ERR_UNKNOWN, false, "Unable to open image %s (type %d)\n", file->filename, file->type);
     231            return false;
     232        }
     233        break;
    217234        // open the FITS object files
    218235    case PM_FPA_FILE_CMF:
     
    294311    switch (file->type) {
    295312    case PM_FPA_FILE_IMAGE:
    296         if (pmFPAviewReadFitsImage (view, file)) {
    297             psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
    298         } else {
     313        if (!pmFPAviewReadFitsImage (view, file)) {
    299314            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
    300315            return false;
    301316        }
     317        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
     318        break;
     319    case PM_FPA_FILE_FRINGE:
     320        if (!pmFPAviewReadFitsImage (view, file)) {
     321            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
     322            return false;
     323        }
     324        psTrace ("pmFPAfile", 5, "reading %s (type: %d)\n", file->filename, file->type);
     325
     326        if (!pmFPAviewReadFitsTable(view, file, "FRINGE")) {
     327            psError(PS_ERR_UNKNOWN, false, "Unable to read fringe data from %s.\n", file->filename);
     328            return false;
     329        }
     330
    302331        break;
    303332
     
    365394        }
    366395        break;
     396    case PM_FPA_FILE_FRINGE:
     397        if (!pmFPAviewFreeFitsTable(view, file, "FRINGE")) {
     398            psError(PS_ERR_UNKNOWN, false, "Unable to free fringe data.\n");
     399            return false;
     400        }
     401        break;
    367402
    368403    case PM_FPA_FILE_SX:
     
    436471        pmFPAviewWriteFitsImage (view, file);
    437472        psTrace ("pmFPAfile", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
     473        break;
     474    case PM_FPA_FILE_FRINGE:
     475        pmFPAviewWriteFitsImage (view, file);
     476        psTrace ("pmFPAfile", 5, "wrote table %s (fpa: %p)\n", file->filename, file->fpa);
     477        pmFPAviewWriteFitsTable(view, file, "FRINGE");
     478        psTrace ("pmFPAfile", 5, "wrote fringe table %s (fpa: %p)\n", file->filename, file->fpa);
    438479        break;
    439480
     
    513554    switch (file->type) {
    514555    case PM_FPA_FILE_IMAGE:
    515 
     556    case PM_FPA_FILE_FRINGE:
    516557        // create FPA structure component based on view
    517558        pmFPAAddSourceFromView (file->fpa, view, file->format);
     
    567608        // check the FITS types
    568609    case PM_FPA_FILE_IMAGE:
     610    case PM_FPA_FILE_FRINGE:
    569611    case PM_FPA_FILE_CMF:
    570612        psFitsClose (file->fits);
Note: See TracChangeset for help on using the changeset viewer.