示例#1
0
文件: ColorMap.java 项目: ethanrd/IDV
 /**
  * tokenize the pattern string as a numeric range
  *
  * @return min max range values
  * @throws Exception On badness
  */
 public Real[] getNumericRange() throws Exception {
   if (range == null) {
     range = new Real[] {null, null};
     List toks = StringUtil.split(pattern, ",");
     if (toks.size() == 0) {
       throw new IllegalStateException("Bad format for numeric range:" + pattern);
     }
     String tok1 = toks.get(0).toString();
     String tok2 = ((toks.size() == 1) ? tok1 : toks.get(1).toString());
     range[0] = ucar.visad.Util.toReal(tok1);
     range[1] = ucar.visad.Util.toReal(tok2);
   }
   return range;
 }
示例#2
0
 /**
  * Get the the scale unit.
  *
  * @return Unit used for scaleing values. May be <code>null</code>.
  */
 public Unit getScaleUnit() {
   if ((scaleUnit == null) && (scaleUnitName != null)) {
     try {
       scaleUnit = ucar.visad.Util.parseUnit(scaleUnitName);
     } catch (Exception exc) {
     }
   }
   return scaleUnit;
 }
示例#3
0
 /**
  * Get the the colorTable unit.
  *
  * @return Unit used for colorTableing values. May be <code>null</code>.
  */
 public Unit getColorTableUnit() {
   if ((colorTableUnit == null) && (colorTableUnitName != null)) {
     try {
       colorTableUnit = ucar.visad.Util.parseUnit(colorTableUnitName);
     } catch (Exception exc) {
     }
   }
   return colorTableUnit;
 }
示例#4
0
 /**
  * Get the the display unit.
  *
  * @return Unit used for displaying values. May be <code>null</code>.
  */
 public Unit getDisplayUnit() {
   if ((displayUnit == null) && (displayUnitName != null)) {
     try {
       displayUnit = ucar.visad.Util.parseUnit(displayUnitName);
     } catch (Exception exc) {
     }
   }
   return displayUnit;
 }
示例#5
0
  /**
   * Create the charts
   *
   * @throws RemoteException On badness
   * @throws VisADException On badness
   */
  public void loadData() throws VisADException, RemoteException {
    createChart();
    List dataChoiceWrappers = getDataChoiceWrappers();
    try {
      for (int dataSetIdx = 0; dataSetIdx < plot.getDatasetCount(); dataSetIdx++) {
        MyHistogramDataset dataset = (MyHistogramDataset) plot.getDataset(dataSetIdx);
        dataset.removeAllSeries();
      }

      //            dataset.removeAllSeries();
      Hashtable props = new Hashtable();
      props.put(TrackDataSource.PROP_TRACKTYPE, TrackDataSource.ID_TIMETRACE);

      for (int paramIdx = 0; paramIdx < dataChoiceWrappers.size(); paramIdx++) {
        DataChoiceWrapper wrapper = (DataChoiceWrapper) dataChoiceWrappers.get(paramIdx);

        DataChoice dataChoice = wrapper.getDataChoice();
        FlatField data = getFlatField((FieldImpl) dataChoice.getData(null, props));
        Unit unit = ucar.visad.Util.getDefaultRangeUnits((FlatField) data)[0];
        double[][] samples = data.getValues(false);
        double[] actualValues = filterData(samples[0], getTimeValues(samples, data))[0];
        NumberAxis domainAxis = new NumberAxis(wrapper.getLabel(unit));

        XYItemRenderer renderer;
        if (stacked) {
          renderer = new StackedXYBarRenderer();
        } else {
          renderer = new XYBarRenderer();
        }
        plot.setRenderer(paramIdx, renderer);
        Color c = wrapper.getColor(paramIdx);
        domainAxis.setLabelPaint(c);
        renderer.setSeriesPaint(0, c);

        MyHistogramDataset dataset = new MyHistogramDataset();
        dataset.setType(HistogramType.FREQUENCY);
        dataset.addSeries(dataChoice.getName() + " [" + unit + "]", actualValues, bins);
        plot.setDomainAxis(paramIdx, domainAxis, false);
        plot.mapDatasetToDomainAxis(paramIdx, paramIdx);
        plot.setDataset(paramIdx, dataset);
      }

    } catch (Exception exc) {
      LogUtil.logException("Error creating data set", exc);
      return;
    }
  }
示例#6
0
  /**
   * Apply the properties
   *
   * @param compMap Optional map that holds components
   * @return Success
   * @throws RemoteException On badness
   * @throws VisADException On badness
   */
  protected boolean applyProperties(Hashtable compMap) throws VisADException, RemoteException {
    if (!super.applyProperties(compMap)) {
      return false;
    }
    setStartText(startTextFld.getText().trim());
    setEndText(endTextFld.getText().trim());
    try {
      if (maxDistanceFld != null) {
        Real oldMaxDataDistance = maxDataDistance;
        maxDataDistance = ucar.visad.Util.toReal(maxDistanceFld.getText().trim());
        tvm.setMaxDataDistance(maxDataDistance);
        updateLocation();
      }
    } catch (Exception exc) {
      LogUtil.userErrorMessage("Bad value:" + maxDistanceFld.getText().trim());
      return false;
    }

    return true;
  }
示例#7
0
    /**
     * Edit row
     *
     * @param paramInfo param info
     * @param removeOnCancel Should remove param info if user presses cancel_
     * @return ok
     */
    public boolean editRow(ParamInfo paramInfo, boolean removeOnCancel) {

      List comps = new ArrayList();
      ParamField nameFld = new ParamField(null, true);
      nameFld.setText(paramInfo.getName());
      JPanel topPanel = GuiUtils.hbox(GuiUtils.lLabel("Parameter:  "), nameFld);
      topPanel = GuiUtils.inset(topPanel, 5);

      comps.add(GuiUtils.inset(new JLabel("Defined"), new Insets(5, 0, 0, 0)));
      comps.add(GuiUtils.filler());
      comps.add(GuiUtils.filler());

      final JLabel ctPreviewLbl = new JLabel("");
      final JLabel ctLbl = new JLabel("");
      if (paramInfo.hasColorTableName()) {
        ctLbl.setText(paramInfo.getColorTableName());
        ColorTable ct =
            getIdv().getColorTableManager().getColorTable(paramInfo.getColorTableName());
        if (ct != null) {
          ctPreviewLbl.setIcon(ColorTableCanvas.getIcon(ct));
        } else {
          ctPreviewLbl.setIcon(null);
        }
      }
      String cbxLabel = "";
      final ArrayList menus = new ArrayList();
      getIdv()
          .getColorTableManager()
          .makeColorTableMenu(
              new ObjectListener(null) {
                public void actionPerformed(ActionEvent ae, Object data) {
                  ctLbl.setText(data.toString());
                  ColorTable ct = getIdv().getColorTableManager().getColorTable(ctLbl.getText());
                  if (ct != null) {
                    ctPreviewLbl.setIcon(ColorTableCanvas.getIcon(ct));
                  } else {
                    ctPreviewLbl.setIcon(null);
                  }
                }
              },
              menus);

      JCheckBox ctUseCbx = new JCheckBox(cbxLabel, paramInfo.hasColorTableName());
      final JButton ctPopup = new JButton("Change");
      ctPopup.addActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
              GuiUtils.showPopupMenu(menus, ctPopup);
            }
          });
      addEditComponents(
          comps,
          "Color Table:",
          ctUseCbx,
          GuiUtils.hbox(ctPopup, GuiUtils.vbox(ctLbl, ctPreviewLbl), 5));

      JCheckBox rangeUseCbx = new JCheckBox(cbxLabel, paramInfo.hasRange());
      JTextField minFld = new JTextField("" + paramInfo.getMin(), 4);
      JTextField maxFld = new JTextField("" + paramInfo.getMax(), 4);
      JPanel rangePanel = GuiUtils.hbox(minFld, maxFld, 5);
      addEditComponents(comps, "Range:", rangeUseCbx, rangePanel);

      JCheckBox unitUseCbx = new JCheckBox(cbxLabel, paramInfo.hasDisplayUnit());
      String unitLabel = "";
      Unit unit = null;
      if (paramInfo.hasDisplayUnit()) {
        unit = paramInfo.getDisplayUnit();
      }

      JComboBox unitFld = getIdv().getDisplayConventions().makeUnitBox(unit, null);
      //            JTextField unitFld = new JTextField(unitLabel, 15);
      addEditComponents(comps, "Unit:", unitUseCbx, unitFld);

      ContourInfo ci = paramInfo.getContourInfo();
      JCheckBox contourUseCbx = new JCheckBox(cbxLabel, ci != null);
      if (ci == null) {
        ci = new ContourInfo();
      }
      ContourInfoDialog contDialog =
          new ContourInfoDialog("Edit Contour Defaults", false, null, false);
      contDialog.setState(ci);
      addEditComponents(comps, "Contour:", contourUseCbx, contDialog.getContents());

      GuiUtils.tmpInsets = new Insets(5, 5, 5, 5);
      JComponent contents = GuiUtils.doLayout(comps, 3, GuiUtils.WT_NNY, GuiUtils.WT_N);

      contents = GuiUtils.topCenter(topPanel, contents);
      contents = GuiUtils.inset(contents, 5);
      while (true) {
        if (!GuiUtils.showOkCancelDialog(null, "Parameter Defaults", contents, null)) {
          if (removeOnCancel) {
            myParamInfos.remove(paramInfo);
            tableChanged();
          }
          return false;
        }
        String what = "";
        try {
          if (contourUseCbx.isSelected()) {
            what = "setting contour defaults";
            contDialog.doApply();
            ci.set(contDialog.getInfo());
            paramInfo.setContourInfo(ci);
          } else {
            paramInfo.clearContourInfo();
          }
          if (unitUseCbx.isSelected()) {
            what = "setting display unit";
            Object selected = unitFld.getSelectedItem();
            String unitName = TwoFacedObject.getIdString(selected);
            if ((unitName == null) || unitName.trim().equals("")) {
              paramInfo.setDisplayUnit(null);
            } else {
              paramInfo.setDisplayUnit(ucar.visad.Util.parseUnit(unitName));
            }
          } else {
            paramInfo.setDisplayUnit(null);
          }

          if (ctUseCbx.isSelected()) {
            paramInfo.setColorTableName(ctLbl.getText());
          } else {
            paramInfo.clearColorTableName();
          }

          if (rangeUseCbx.isSelected()) {
            what = "setting range";
            paramInfo.setRange(
                new Range(Misc.parseNumber(minFld.getText()), Misc.parseNumber(maxFld.getText())));
          } else {
            paramInfo.clearRange();
          }

          paramInfo.setName(nameFld.getText().trim());
          break;
        } catch (Exception exc) {
          errorMsg("An error occurred " + what + "\n " + exc.getMessage());
          //              exc.printStackTrace();
        }
      }
      repaint();
      saveData();
      return true;
    }
示例#8
0
  /**
   * Create the param infos from the given xml root
   *
   * @param root The xml root
   * @return List of param infos
   */
  private List createParamInfoList(Element root) {

    List infos = new ArrayList();

    if (!root.getTagName().equals(TAG_PARAMS)) {
      try {
        Object obj = getIdv().getEncoderForRead().toObject(root);
        if (obj instanceof List) {
          infos.addAll((List) obj);
        } else {
          System.err.println("Unknown object type: " + obj.getClass().getName());
        }
      } catch (Exception exc) {
        System.err.println("Error reading param defaults");
      }
      return infos;
    }

    List nodes = XmlUtil.findChildren(root, TAG_PARAM);

    for (int i = 0; i < nodes.size(); i++) {
      Element child = (Element) nodes.get(i);
      Range range = null;
      Unit displayUnit = null;
      ContourInfo contourInfo = null;

      String paramName = XmlUtil.getAttribute(child, ATTR_NAME);
      String colorTableName = XmlUtil.getAttribute(child, ATTR_COLORTABLE, (String) null);
      String range_min = XmlUtil.getAttribute(child, ATTR_RANGE_MIN, (String) null);
      String range_max = XmlUtil.getAttribute(child, ATTR_RANGE_MAX, (String) null);

      String unitName = XmlUtil.getAttribute(child, ATTR_UNIT, (String) null);

      String ci_interval = XmlUtil.getAttribute(child, ATTR_CI_INTERVAL, (String) null);
      String ci_base = XmlUtil.getAttribute(child, ATTR_CI_BASE, (String) null);
      String ci_min = XmlUtil.getAttribute(child, ATTR_CI_MIN, range_min);
      String ci_max = XmlUtil.getAttribute(child, ATTR_CI_MAX, range_max);
      boolean ci_dash = XmlUtil.getAttribute(child, ATTR_CI_DASH, DFLT_CI_DASH);
      boolean ci_label = XmlUtil.getAttribute(child, ATTR_CI_LABEL, DFLT_CI_LABEL);
      String ci_width = XmlUtil.getAttribute(child, ATTR_CI_WIDTH, String.valueOf(DFLT_CI_WIDTH));

      if (unitName != null) {
        try {
          displayUnit = ucar.visad.Util.parseUnit(unitName);
        } catch (Exception e) {
          LogUtil.printException(log_, "Creating unit: " + unitName, e);
        }
      }

      if ((ci_interval != null) || (ci_base != null)) {
        if (ci_interval == null) {
          ci_interval = "NaN";
        }

        if (ci_base == null) {
          ci_base = "NaN";
        }
        if (ci_min == null) {
          ci_min = "NaN";
        }
        if (ci_max == null) {
          ci_max = "NaN";
        }
        if (ci_width == null) {
          ci_width = "1";
        }
        contourInfo =
            new ContourInfo(
                ci_interval,
                Misc.parseDouble(ci_base),
                Misc.parseDouble(ci_min),
                Misc.parseDouble(ci_max),
                ci_label,
                ci_dash,
                ContourInfo.DEFAULT_FILL,
                Misc.parseDouble(ci_width));
      }

      if ((ci_dash != DFLT_CI_DASH) || (ci_label != DFLT_CI_LABEL)) {
        if (contourInfo == null) {
          contourInfo = new ContourInfo(Double.NaN, Double.NaN, Double.NaN, Double.NaN);
          contourInfo.setIsLabeled(ci_label);
          contourInfo.setDashOn(ci_dash);
        }
      }

      if ((range_min != null) && (range_max != null)) {
        range = new Range(Misc.parseDouble(range_min), Misc.parseDouble(range_max));
      }

      ParamInfo paramInfo =
          new ParamInfo(paramName, colorTableName, range, contourInfo, displayUnit);
      infos.add(paramInfo);
    }
    return infos;
  }
示例#9
0
  /**
   * Actually get the data identified by the given DataChoce. The default is to call the
   * getDataInner that does not take the requestProperties. This allows other, non unidata.data
   * DataSource-s (that follow the old API) to work.
   *
   * @param dataChoice The data choice that identifies the requested data.
   * @param category The data category of the request.
   * @param dataSelection Identifies any subsetting of the data.
   * @param requestProperties Hashtable that holds any detailed request properties.
   * @return The visad.Data object
   * @throws RemoteException Java RMI problem
   * @throws VisADException VisAD problem
   */
  protected Data getDataInner(
      DataChoice dataChoice,
      DataCategory category,
      DataSelection dataSelection,
      Hashtable requestProperties)
      throws VisADException, RemoteException {

    loadId = JobManager.getManager().stopAndRestart(loadId, "WMSControl");
    Object myLoadId = loadId;

    if (requestProperties == null) {
      requestProperties = new Hashtable();
    }
    WmsSelection wmsInfo = (WmsSelection) dataChoice.getId();

    // Look if there was a layer that overrides the one in the data choice
    Object tfoLayer = requestProperties.get(PROP_LAYER);
    if ((tfoLayer != null) && (tfoLayer instanceof TwoFacedObject)) {
      String layer = ((TwoFacedObject) tfoLayer).getId().toString();
      for (int i = 0; i < wmsSelections.size(); i++) {
        WmsSelection tmpSelection = (WmsSelection) wmsSelections.get(i);
        if (Misc.equals(tmpSelection.getLayer(), layer)) {
          wmsInfo = tmpSelection;
          break;
        }
      }
    }

    GeoLocationInfo boundsToUse = (GeoLocationInfo) requestProperties.get(PROP_BOUNDS);

    Image image = null;
    FieldImpl xyData = null;
    byte[] imageContent = null;

    //        System.err.println(wmsInfo.getImageFile());
    if (wmsInfo.getImageFile() != null) {
      try {
        boundsToUse = new GeoLocationInfo(90, -180, -90, 180);
        InputStream is = IOUtil.getInputStream(wmsInfo.getImageFile());
        imageContent = IOUtil.readBytes(is, myLoadId);
        image = Toolkit.getDefaultToolkit().createImage(imageContent);
        //                javax.swing.JLabel l = new javax.swing.JLabel(new
        // javax.swing.ImageIcon(image));
        //                l.setBackground(Color.red);
        //                ucar.unidata.util.GuiUtils.showOkCancelDialog(null,null, l,null);
        xyData = ucar.visad.Util.makeField(image, 0, false, true);
      } catch (Exception iexc) {
        logException("There was an error accessing the image:\n" + wmsInfo.getImageFile(), iexc);
        return null;
      }
    } else {
      String writeFile = (String) requestProperties.get(PROP_WRITEFILE);

      int imageWidth = Misc.getProperty(requestProperties, PROP_IMAGEWIDTH, 800);
      int imageHeight = Misc.getProperty(requestProperties, PROP_IMAGEHEIGHT, -1);
      double resolution = Misc.getProperty(requestProperties, PROP_RESOLUTION, (float) 1.0);

      if (wmsInfo.getLegendIcon() != null) {
        requestProperties.put(PROP_ICONPATH, wmsInfo.getLegendIcon());
      }
      if (!wmsInfo.getAllowSubsets() || (boundsToUse == null)) {
        boundsToUse = wmsInfo.getBounds();
      } else {
        boundsToUse.rectify(wmsInfo.getBounds(), 0.0);
        boundsToUse.snapToGrid();
        boundsToUse.rectify(wmsInfo.getBounds(), 0.0);
      }

      double widthDegrees = boundsToUse.getMaxLon() - boundsToUse.getMinLon();
      double heightDegrees = boundsToUse.getMaxLat() - boundsToUse.getMinLat();

      if ((widthDegrees == 0) || (heightDegrees == 0)) {
        return null;
      }

      if (wmsInfo.getFixedWidth() > -1) {
        imageWidth = wmsInfo.getFixedWidth();
      }
      if (wmsInfo.getFixedHeight() > -1) {
        imageHeight = wmsInfo.getFixedHeight();
      } else {
        if (imageHeight < 0) {
          imageHeight =
              Math.abs((int) (imageWidth * boundsToUse.getDegreesY() / boundsToUse.getDegreesX()));
        }
      }
      imageWidth = Math.min(Math.max(imageWidth, 50), 2056);
      imageHeight = Math.min(Math.max(imageHeight, 50), 2056);

      if (maintainRatio) {
        imageHeight = (int) (imageWidth * (heightDegrees / widthDegrees));
      }

      double diff = Math.abs(boundsToUse.getMinLon() - boundsToUse.getMaxLon());
      String url =
          wmsInfo.assembleRequest(
              boundsToUse, (int) (imageWidth / resolution), (int) (imageHeight / resolution));

      String cacheGroup = "WMS";
      synchronized (cachedUrls) {
        if (writeFile == null) {
          for (int i = 0; i < cachedUrls.size(); i++) {
            if (url.equals(cachedUrls.get(i))) {
              image = (Image) cachedData.get(i);
              break;
            }
          }
        }
      }

      try {
        if (image == null) {
          if (Misc.equals(url, lastUrl) && (lastImageContent != null)) {
            imageContent = lastImageContent;
          } else {
          }

          if (imageContent == null) {
            long t1 = System.currentTimeMillis();
            //                    System.err.println("getting image:" + url);
            LogUtil.message("Reading WMS image: " + wmsInfo);
            // System.err.println ("url:" + url);

            InputStream is = IOUtil.getInputStream(url);
            long t2 = System.currentTimeMillis();
            imageContent = IOUtil.readBytes(is, myLoadId);
            long t3 = System.currentTimeMillis();
            LogUtil.message("");
            //                    System.err.println("Done");
          }
          // If it is null then there is another thread that is doing
          // a subsequent read
          lastImageContent = null;
          if (imageContent == null) {
            return null;
          }
          Trace.call2("Getting image");
          Trace.call1("Making image");
          image = Toolkit.getDefaultToolkit().createImage(imageContent);
          // Wait on the image
          image = ucar.unidata.ui.ImageUtils.waitOnImage(image);
          if (image == null) {
            throw new IllegalStateException();
          }

          Trace.call2("Making image");
          lastImageContent = imageContent;
          lastUrl = url;
          updateDetailsText();
          if (!JobManager.getManager().canContinue(myLoadId)) {
            Trace.call2("WMSControl.loadImage");
            return null;
          }
          synchronized (cachedUrls) {
            if (cachedUrls.size() > 5) {
              cachedUrls.remove(cachedUrls.size() - 1);
              cachedData.remove(cachedData.size() - 1);
            }
            // For now don't cache
            //      cachedUrls.add(0, url);
            //                    cachedData.add(0, image);
          }
        }
        ImageHelper ih = new ImageHelper();
        int width = image.getWidth(ih);
        if (ih.badImage) {
          throw new IllegalStateException();
        }
        long tt1 = System.currentTimeMillis();

        xyData = ucar.visad.Util.makeField(image, 0, false, true);
        long tt2 = System.currentTimeMillis();
        //      System.err.println("time to make field:" + (tt2-tt1));
      } catch (Exception iexc) {
        if (imageContent != null) {
          String msg = new String(imageContent);
          //  System.err.println ("msg:" + msg);
          /* Check to see if this is of the form:

          <?xml version='1.0' encoding="UTF-8" standalone="no" ?>
          <!DOCTYPE ServiceExceptionReport SYSTEM "http://www.digitalearth.gov/wmt/xml/exception_1_1_0.dtd ">
          <ServiceExceptionReport version="1.1.0">
           <ServiceException>
             Service denied due to system overload. Please try again later.
           </ServiceException>
          </ServiceExceptionReport>

          */
          if (msg.indexOf("<ServiceExceptionReport") >= 0) {
            try {
              StringBuffer errors = new StringBuffer();
              errors.append("\n");
              Element root = XmlUtil.getRoot(msg);
              List children = XmlUtil.findChildren(root, "ServiceException");
              for (int i = 0; i < children.size(); i++) {

                Element node = (Element) children.get(i);
                String code = XmlUtil.getAttribute(node, "code", (String) null);
                String body = XmlUtil.getChildText(node);
                if (code != null) {
                  errors.append(code + "\n");
                }
                errors.append(body.trim() + "\n");
              }
              LogUtil.userErrorMessage(
                  "Error accessing image with the url:\n" + url + "\nError:\n" + errors);
            } catch (Exception exc) {
              LogUtil.userErrorMessage(
                  "Error accessing image with the url:\n"
                      + url
                      + "\nError:\n"
                      + StringUtil.stripTags(msg));
            }
            return null;
          }

          msg = StringUtil.replace(msg, "\n", " ").toLowerCase();
          if (StringUtil.stringMatch(msg, "service\\s*exception")) {
            if (StringUtil.stringMatch(msg, "cannot\\s*be\\s*less\\s*than")) {
              return null;
            }
          }
          if (msg.indexOf("error") >= 0) {
            LogUtil.userErrorMessage(
                "There was an error accessing the image with the url:\n"
                    + url
                    + "\nError:\n"
                    + new String(imageContent));
            return null;
          }
        }
        logException("There was an error accessing the image with the url:\n" + url, iexc);
        return null;
      }

      if (writeFile != null) {
        try {
          ImageXmlDataSource.writeToFile(writeFile, boundsToUse, imageContent, wmsInfo.getFormat());
        } catch (Exception exc) {
          throw new IllegalArgumentException(
              "Error writing image xml file:" + writeFile + " " + exc);
        }
      }
    }

    Linear2DSet domain = (Linear2DSet) xyData.getDomainSet();
    Linear2DSet imageDomain =
        new Linear2DSet(
            RealTupleType.SpatialEarth2DTuple,
            boundsToUse.getMinLon(),
            boundsToUse.getMaxLon(),
            domain.getX().getLength(),
            boundsToUse.getMaxLat(),
            boundsToUse.getMinLat(),
            domain.getY().getLength());

    // System.err.println("image domain:" + imageDomain);

    /*
    new Linear2DSet(RealTupleType.SpatialEarth2DTuple,
                        boundsToUse.getMinLon(), boundsToUse.getMaxLon(),
                        domain.getX().getLength(),
                        boundsToUse.getMinLat() +diff, boundsToUse.getMinLat(),
                        domain.getY().getLength());*/

    FieldImpl field = GridUtil.setSpatialDomain(xyData, imageDomain, true);

    return field;
  }