Example usage for javax.imageio ImageIO createImageOutputStream

List of usage examples for javax.imageio ImageIO createImageOutputStream

Introduction

In this page you can find the example usage for javax.imageio ImageIO createImageOutputStream.

Prototype

public static ImageOutputStream createImageOutputStream(Object output) throws IOException 

Source Link

Document

Returns an ImageOutputStream that will send its output to the given Object .

Usage

From source file:com.el.ecom.utils.ImageUtils.java

/**
 * ?//from  w  ww.j a v  a2s  . com
 * 
 * @param srcFile ?
 * @param destFile 
 * @param watermarkFile ?
 * @param watermarkPosition ??
 * @param alpha ??
 */
public static void addWatermark(File srcFile, File destFile, File watermarkFile,
        WatermarkPosition watermarkPosition, int alpha) {
    Assert.notNull(srcFile);
    Assert.state(srcFile.exists());
    Assert.state(srcFile.isFile());
    Assert.notNull(destFile);
    Assert.state(alpha >= 0);
    Assert.state(alpha <= 100);

    if (watermarkFile == null || !watermarkFile.exists() || !watermarkFile.isFile() || watermarkPosition == null
            || watermarkPosition == WatermarkPosition.no) {
        try {
            if (!StringUtils.equals(srcFile.getCanonicalPath(), destFile.getCanonicalPath())) {
                FileUtils.copyFile(srcFile, destFile);
            }
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        return;
    }
    if (type == Type.jdk) {
        Graphics2D graphics2D = null;
        ImageOutputStream imageOutputStream = null;
        ImageWriter imageWriter = null;
        try {
            BufferedImage srcBufferedImage = ImageIO.read(srcFile);
            int srcWidth = srcBufferedImage.getWidth();
            int srcHeight = srcBufferedImage.getHeight();
            BufferedImage destBufferedImage = new BufferedImage(srcWidth, srcHeight,
                    BufferedImage.TYPE_INT_RGB);
            graphics2D = destBufferedImage.createGraphics();
            graphics2D.setBackground(BACKGROUND_COLOR);
            graphics2D.clearRect(0, 0, srcWidth, srcHeight);
            graphics2D.drawImage(srcBufferedImage, 0, 0, null);
            graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha / 100F));

            BufferedImage watermarkBufferedImage = ImageIO.read(watermarkFile);
            int watermarkImageWidth = watermarkBufferedImage.getWidth();
            int watermarkImageHeight = watermarkBufferedImage.getHeight();
            int x = srcWidth - watermarkImageWidth;
            int y = srcHeight - watermarkImageHeight;
            if (watermarkPosition == WatermarkPosition.topLeft) {
                x = 0;
                y = 0;
            } else if (watermarkPosition == WatermarkPosition.topRight) {
                x = srcWidth - watermarkImageWidth;
                y = 0;
            } else if (watermarkPosition == WatermarkPosition.center) {
                x = (srcWidth - watermarkImageWidth) / 2;
                y = (srcHeight - watermarkImageHeight) / 2;
            } else if (watermarkPosition == WatermarkPosition.bottomLeft) {
                x = 0;
                y = srcHeight - watermarkImageHeight;
            } else if (watermarkPosition == WatermarkPosition.bottomRight) {
                x = srcWidth - watermarkImageWidth;
                y = srcHeight - watermarkImageHeight;
            }
            graphics2D.drawImage(watermarkBufferedImage, x, y, watermarkImageWidth, watermarkImageHeight, null);

            imageOutputStream = ImageIO.createImageOutputStream(destFile);
            imageWriter = ImageIO.getImageWritersByFormatName(FilenameUtils.getExtension(destFile.getName()))
                    .next();
            imageWriter.setOutput(imageOutputStream);
            ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
            imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            imageWriteParam.setCompressionQuality(DEST_QUALITY / 100F);
            imageWriter.write(null, new IIOImage(destBufferedImage, null, null), imageWriteParam);
            imageOutputStream.flush();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            if (graphics2D != null) {
                graphics2D.dispose();
            }
            if (imageWriter != null) {
                imageWriter.dispose();
            }
            try {
                if (imageOutputStream != null) {
                    imageOutputStream.close();
                }
            } catch (IOException e) {
            }
        }
    } else {
        String gravity = "SouthEast";
        if (watermarkPosition == WatermarkPosition.topLeft) {
            gravity = "NorthWest";
        } else if (watermarkPosition == WatermarkPosition.topRight) {
            gravity = "NorthEast";
        } else if (watermarkPosition == WatermarkPosition.center) {
            gravity = "Center";
        } else if (watermarkPosition == WatermarkPosition.bottomLeft) {
            gravity = "SouthWest";
        } else if (watermarkPosition == WatermarkPosition.bottomRight) {
            gravity = "SouthEast";
        }
        IMOperation operation = new IMOperation();
        operation.gravity(gravity);
        operation.dissolve(alpha);
        operation.quality((double) DEST_QUALITY);
        try {
            operation.addImage(watermarkFile.getCanonicalPath());
            operation.addImage(srcFile.getCanonicalPath());
            operation.addImage(destFile.getCanonicalPath());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        if (type == Type.graphicsMagick) {
            CompositeCmd compositeCmd = new CompositeCmd(true);
            if (graphicsMagickPath != null) {
                compositeCmd.setSearchPath(graphicsMagickPath);
            }
            try {
                compositeCmd.run(operation);
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (IM4JavaException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        } else {
            CompositeCmd compositeCmd = new CompositeCmd(false);
            if (imageMagickPath != null) {
                compositeCmd.setSearchPath(imageMagickPath);
            }
            try {
                compositeCmd.run(operation);
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (InterruptedException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (IM4JavaException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }
}

From source file:com.alkacon.opencms.v8.weboptimization.CmsOptimizationSprite.java

/**
 * Writes the given image as of the given type to the servlet output stream.<p>
 * // ww  w. j ava2 s .c  o  m
 * @param image the image to write
 * @param type the type
 * 
 * @throws IOException if something goes wrong
 */
protected void writeImage(BufferedImage image, String type) throws IOException {

    ImageWriter writer = (ImageWriter) ImageIO.getImageWritersByFormatName(type).next();
    ImageOutputStream stream = ImageIO.createImageOutputStream(getJspContext().getResponse().getOutputStream());
    writer.setOutput(stream);
    writer.write(image);
    // We must close the stream now because if we are wrapping a ServletOutputStream,
    // a future gc can commit a stream that used in another thread (very very bad)
    stream.flush();
    stream.close();
    writer.dispose();
}

From source file:com.aimluck.eip.fileupload.util.FileuploadUtils.java

/**
 * ???????//from   ww w  .  j a va2 s  .  c  o m
 * 
 * @param org_id
 * @param folderName
 * @param uid
 * @param fileBean
 * @param acceptExts
 * @param msgList
 * @return
 */
public static ShrinkImageSet getBytesShrinkFilebean(String org_id, String folderName, int uid,
        FileuploadLiteBean fileBean, String[] acceptExts, int width, int height, List<String> msgList,
        boolean isFixOrgImage) {

    byte[] result = null;
    byte[] fixResult = null;
    InputStream is = null;
    boolean fixed = false;

    try {

        String file_name = fileBean.getFileName();
        String ext = "";

        if (acceptExts != null && acceptExts.length > 0) {
            // ???
            // ????
            boolean isAccept = false;
            String tmpExt = null;
            int len = acceptExts.length;
            for (int i = 0; i < len; i++) {
                if (!acceptExts[i].startsWith(".")) {
                    tmpExt = "." + acceptExts[i];
                }
                if (file_name.toLowerCase().endsWith(tmpExt)) {
                    isAccept = true;
                    ext = tmpExt.replace(".", "");
                    ;
                    break;
                }
            }
            if (!isAccept) {
                // ???????null ?
                return null;
            }
        }

        is = ALStorageService.getFile(FOLDER_TMP_FOR_ATTACHMENT_FILES,
                uid + ALStorageService.separator() + folderName, String.valueOf(fileBean.getFileId()));

        byte[] imageInBytes = IOUtils.toByteArray(is);
        ImageInformation readImageInformation = readImageInformation(new ByteArrayInputStream(imageInBytes));
        BufferedImage bufferdImage = ImageIO.read(new ByteArrayInputStream(imageInBytes));
        if (readImageInformation != null) {
            bufferdImage = transformImage(bufferdImage, getExifTransformation(readImageInformation),
                    readImageInformation.orientation >= 5 ? bufferdImage.getHeight() : bufferdImage.getWidth(),
                    readImageInformation.orientation >= 5 ? bufferdImage.getWidth() : bufferdImage.getHeight());
            fixed = isFixOrgImage;
        }
        if (bufferdImage == null) {
            // ?bufferdImage???????????,null?.
            return null;
        }

        BufferedImage shrinkImage = FileuploadUtils.shrinkAndTrimImage(bufferdImage, width, height);
        Iterator<ImageWriter> writers = ImageIO.getImageWritersBySuffix("jpeg");
        ImageWriter writer = writers.next();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageOutputStream ios = ImageIO.createImageOutputStream(out);
        writer.setOutput(ios);
        writer.write(shrinkImage);

        result = out.toByteArray();

        if (fixed) {
            Iterator<ImageWriter> writers2 = ImageIO.getImageWritersBySuffix(ext);
            ImageWriter writer2 = writers2.next();

            ByteArrayOutputStream out2 = new ByteArrayOutputStream();
            ImageOutputStream ios2 = ImageIO.createImageOutputStream(out2);
            writer2.setOutput(ios2);
            writer2.write(bufferdImage);

            fixResult = out2.toByteArray();
        }

    } catch (Exception e) {
        logger.error("fileupload", e);
        result = null;
    } finally {
        try {
            if (is != null) {
                is.close();
            }
        } catch (Exception e) {
            logger.error("fileupload", e);
            result = null;
        }
    }

    return new ShrinkImageSet(result, fixed ? fixResult : null);
}

From source file:org.getobjects.appserver.publisher.JoDefaultRenderer.java

/**
 * Renders a java.awt.BufferedImage to the WOResponse of the given context.
 * Remember to configure:<pre>//from  w  ww  . jav  a 2 s  .  co  m
 *   -Djava.awt.headless=true</pre>
 * (thats the VM arguments of the run panel in Eclipse) 
 * 
 * @param _img   - the BufferedImage object to render
 * @param _ctx - the WOContext to render the image in
 * @return null if everything went fine, an Exception otherwise
 */
public Exception renderBufferedImage(BufferedImage _img, WOContext _ctx) {
    // TBD: this method could be improved a lot, but it works well enough for
    //      simple cases

    if (_img == null)
        return new JoInternalErrorException("got no image to render");

    /* find a proper image writer */

    String usedType = null;
    Iterator<ImageWriter> writers;
    ImageWriter writer = null;
    WORequest rq = _ctx.request();
    if (rq != null) {
        // TBD: just iterate over the accepted (image/) types (considering
        //      the value quality) and check each

        if (rq.acceptsContentType("image/png", false /* direct match */)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/png")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/png";
        }
        if (writer == null && rq.acceptsContentType("image/gif", false)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/gif")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/gif";
        }
        if (writer == null && rq.acceptsContentType("image/jpeg", false)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/jpeg")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/jpeg";
        }
    }
    if (writer == null) {
        if ((writers = ImageIO.getImageWritersByMIMEType("image/png")) != null)
            writer = writers.next();
        if (writer != null)
            usedType = "image/png";
    }
    if (writer == null)
        return new JoInternalErrorException("found no writer for image: " + _img);

    /* prepare WOResponse */

    WOResponse r = _ctx.response();
    r.setStatus(WOMessage.HTTP_STATUS_OK);
    r.setHeaderForKey("inline", "content-disposition");
    if (usedType != null)
        r.setHeaderForKey(usedType, "content-type");
    // TBD: do we know the content-length? If not, should we generate to a
    //      buffer to avoid confusing the browser (IE ...)
    r.enableStreaming();

    /* write */

    ImageOutputStream ios = null;
    try {
        ios = ImageIO.createImageOutputStream(rq.outputStream());
    } catch (IOException e) {
        log.warn("could not create image output stream: " + _img);
        return e;
    }

    writer.setOutput(ios);

    try {
        writer.write(null, new IIOImage(_img, null, null), null);
        ios.flush();
        writer.dispose();
        ios.close();
    } catch (IOException e) {
        log.warn("failed to write image to stream", e);
        return e;
    }

    return null; /* everything is awesome O */
}

From source file:org.getobjects.appserver.publisher.GoDefaultRenderer.java

/**
 * Renders a java.awt.BufferedImage to the WOResponse of the given context.
 * Remember to configure:<pre>//from w ww  .j av  a 2 s .  c  o  m
 *   -Djava.awt.headless=true</pre>
 * (thats the VM arguments of the run panel in Eclipse) 
 * 
 * @param _img   - the BufferedImage object to render
 * @param _ctx - the WOContext to render the image in
 * @return null if everything went fine, an Exception otherwise
 */
public Exception renderBufferedImage(BufferedImage _img, WOContext _ctx) {
    // TBD: this method could be improved a lot, but it works well enough for
    //      simple cases

    if (_img == null)
        return new GoInternalErrorException("got no image to render");

    /* find a proper image writer */

    String usedType = null;
    Iterator<ImageWriter> writers;
    ImageWriter writer = null;
    WORequest rq = _ctx.request();
    if (rq != null) {
        // TBD: just iterate over the accepted (image/) types (considering
        //      the value quality) and check each

        if (rq.acceptsContentType("image/png", false /* direct match */)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/png")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/png";
        }
        if (writer == null && rq.acceptsContentType("image/gif", false)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/gif")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/gif";
        }
        if (writer == null && rq.acceptsContentType("image/jpeg", false)) {
            if ((writers = ImageIO.getImageWritersByMIMEType("image/jpeg")) != null)
                writer = writers.next();
            if (writer != null)
                usedType = "image/jpeg";
        }
    }
    if (writer == null) {
        if ((writers = ImageIO.getImageWritersByMIMEType("image/png")) != null)
            writer = writers.next();
        if (writer != null)
            usedType = "image/png";
    }
    if (writer == null)
        return new GoInternalErrorException("found no writer for image: " + _img);

    /* prepare WOResponse */

    WOResponse r = _ctx.response();
    r.setStatus(WOMessage.HTTP_STATUS_OK);
    r.setHeaderForKey("inline", "content-disposition");
    if (usedType != null)
        r.setHeaderForKey(usedType, "content-type");
    // TBD: do we know the content-length? If not, should we generate to a
    //      buffer to avoid confusing the browser (IE ...)
    r.enableStreaming();

    /* write */

    ImageOutputStream ios = null;
    try {
        ios = ImageIO.createImageOutputStream(rq.outputStream());
    } catch (IOException e) {
        log.warn("could not create image output stream: " + _img);
        return e;
    }

    writer.setOutput(ios);

    try {
        writer.write(null, new IIOImage(_img, null, null), null);
        ios.flush();
        writer.dispose();
        ios.close();
    } catch (IOException e) {
        log.warn("failed to write image to stream", e);
        return e;
    }

    return null; /* everything is awesome O */
}

From source file:nl.b3p.imagetool.ImageTool.java

/**
 * Writes a JPEG, GIF or PNG image to the outputstream.
 *
 * @param bufferedImage BufferedImage created from the given images.
 * @param dw DataWrapper object in which the request object is stored.
 * @param extension String with the extension of the file
 *
 * @throws Exception//  w  ww. j a v  a2  s.  c om
 */
// <editor-fold defaultstate="" desc="writeOtherImage(BufferedImage bufferedImage, DataWrapper dw, String extension) method.">
private static void writeOtherImage(BufferedImage bufferedImage, OutputStream os, String extension)
        throws Exception {
    //log.info("Writing JPG, GIF or PNG using ImageIO.write");
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
    ImageIO.write(bufferedImage, extension, ios);
    os.write(baos.toByteArray());
    ios.flush();
    ios.close();
}

From source file:org.dcm4che.tool.dcm2jpg.Dcm2Jpg.java

public void convert(File src, File dest) throws IOException {
    ImageInputStream iis = ImageIO.createImageInputStream(src);
    try {// w ww.j  a  v  a 2s.  c  o  m
        BufferedImage bi = readImage(iis);
        bi = convert(bi);
        dest.delete();
        ImageOutputStream ios = ImageIO.createImageOutputStream(dest);
        try {
            writeImage(ios, bi);
        } finally {
            try {
                ios.close();
            } catch (IOException ignore) {
            }
        }
    } finally {
        try {
            iis.close();
        } catch (IOException ignore) {
        }
    }
}

From source file:org.apache.jetspeed.security.mfa.impl.CaptchaImageResource.java

/**
 * @param image//from w w  w . java2 s . c  o  m
 *            The image to turn into data
 * @return The image data for this dynamic image
 */
protected byte[] toImageData(final BufferedImage image) throws IOException {
    // Create output stream
    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    String format = config.getImageFormat().substring(1);
    // Get image writer for format
    // FIXME: config.getImageFormat()
    final ImageWriter writer = (ImageWriter) ImageIO.getImageWritersByFormatName(format).next();

    // Write out image
    writer.setOutput(ImageIO.createImageOutputStream(out));
    writer.write(image);

    // Return the image data
    return out.toByteArray();
}

From source file:org.eclipse.smarthome.ui.internal.chart.ChartServlet.java

@SuppressWarnings({ "null" })
@Override//ww  w. j  av  a 2s .c o m
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    logger.debug("Received incoming chart request: {}", req);

    int width = defaultWidth;
    String w = req.getParameter("w");
    if (w != null) {
        try {
            width = Integer.parseInt(w);
        } catch (NumberFormatException e) {
            logger.debug("Ignoring invalid value '{}' for HTTP request parameter 'w'", w);
        }
    }
    int height = defaultHeight;
    String h = req.getParameter("h");
    if (h != null) {
        try {
            Double d = Double.parseDouble(h) * scale;
            height = d.intValue();
        } catch (NumberFormatException e) {
            logger.debug("Ignoring invalid value '{}' for HTTP request parameter 'h'", h);
        }
    }

    // To avoid ambiguity you are not allowed to specify period, begin and end time at the same time.
    if (req.getParameter("period") != null && req.getParameter("begin") != null
            && req.getParameter("end") != null) {
        res.sendError(HttpServletResponse.SC_BAD_REQUEST,
                "Do not specify the three parameters period, begin and end at the same time.");
        return;
    }

    // Read out the parameter period, begin and end and save them.
    Date timeBegin = null;
    Date timeEnd = null;

    Long period = PERIODS.get(req.getParameter("period"));
    if (period == null) {
        // use a day as the default period
        period = PERIODS.get("D");
    }

    if (req.getParameter("begin") != null) {
        try {
            timeBegin = new SimpleDateFormat(DATE_FORMAT).parse(req.getParameter("begin"));
        } catch (ParseException e) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "Begin and end must have this format: " + DATE_FORMAT + ".");
            return;
        }
    }

    if (req.getParameter("end") != null) {
        try {
            timeEnd = new SimpleDateFormat(DATE_FORMAT).parse(req.getParameter("end"));
        } catch (ParseException e) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST,
                    "Begin and end must have this format: " + DATE_FORMAT + ".");
            return;
        }
    }

    // Set begin and end time and check legality.
    if (timeBegin == null && timeEnd == null) {
        timeEnd = new Date();
        timeBegin = new Date(timeEnd.getTime() - period);
        logger.debug("No begin or end is specified, use now as end and now-period as begin.");
    } else if (timeEnd == null) {
        timeEnd = new Date(timeBegin.getTime() + period);
        logger.debug("No end is specified, use begin + period as end.");
    } else if (timeBegin == null) {
        timeBegin = new Date(timeEnd.getTime() - period);
        logger.debug("No begin is specified, use end-period as begin");
    } else if (timeEnd.before(timeBegin)) {
        throw new ServletException("The end is before the begin.");
    }

    // If a persistence service is specified, find the provider
    String serviceName = req.getParameter("service");

    ChartProvider provider = getChartProviders().get(providerName);
    if (provider == null) {
        res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Could not get chart provider.");
        return;
    }

    // Read out the parameter 'dpi'
    Integer dpi = null;
    if (req.getParameter("dpi") != null) {
        try {
            dpi = Integer.valueOf(req.getParameter("dpi"));
        } catch (NumberFormatException e) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST, "dpi parameter is invalid");
            return;
        }
        if (dpi <= 0) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST, "dpi parameter is <= 0");
            return;
        }
    }

    // Read out parameter 'legend'
    Boolean legend = null;
    if (req.getParameter("legend") != null) {
        legend = BooleanUtils.toBoolean(req.getParameter("legend"));
    }

    if (maxWidth > 0 && width > maxWidth) {
        height = Math.round((float) height / (float) width * maxWidth);
        if (dpi != null) {
            dpi = Math.round((float) dpi / (float) width * maxWidth);
        }
        width = maxWidth;
    }

    // Set the content type to that provided by the chart provider
    res.setContentType("image/" + provider.getChartType());
    logger.debug("chart building with width {} height {} dpi {}", width, height, dpi);
    try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(res.getOutputStream())) {
        BufferedImage chart = provider.createChart(serviceName, req.getParameter("theme"), timeBegin, timeEnd,
                height, width, req.getParameter("items"), req.getParameter("groups"), dpi, legend);
        ImageIO.write(chart, provider.getChartType().toString(), imageOutputStream);
        logger.debug("Chart successfully generated and written to the response.");
    } catch (ItemNotFoundException e) {
        logger.debug("{}", e.getMessage());
        res.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
    } catch (IllegalArgumentException e) {
        logger.warn("Illegal argument in chart: {}", e.getMessage());
        res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Illegal argument in chart: " + e.getMessage());
    } catch (IIOException | EOFException e) {
        // this can happen if the request is terminated while the image is streamed, see
        // https://github.com/openhab/openhab-distro/issues/684
        logger.debug("Failed writing image to response stream", e);
    } catch (RuntimeException e) {
        if (logger.isDebugEnabled()) {
            // we also attach the stack trace
            logger.warn("Chart generation failed: {}", e.getMessage(), e);
        } else {
            logger.warn("Chart generation failed: {}", e.getMessage());
        }
        res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
    }
}