Example usage for java.io BufferedInputStream read

List of usage examples for java.io BufferedInputStream read

Introduction

In this page you can find the example usage for java.io BufferedInputStream read.

Prototype

public int read(byte b[]) throws IOException 

Source Link

Document

Reads up to b.length bytes of data from this input stream into an array of bytes.

Usage

From source file:com.glaf.core.util.ZipUtils.java

public static byte[] getZipBytes(Map<String, InputStream> dataMap) {
    byte[] bytes = null;
    try {//from   w  w  w  . jav  a2  s .  c  o m
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(baos);
        JarOutputStream jos = new JarOutputStream(bos);
        if (dataMap != null) {
            Set<Entry<String, InputStream>> entrySet = dataMap.entrySet();
            for (Entry<String, InputStream> entry : entrySet) {
                String name = entry.getKey();
                InputStream inputStream = entry.getValue();
                if (name != null && inputStream != null) {
                    BufferedInputStream bis = new BufferedInputStream(inputStream);
                    JarEntry jarEntry = new JarEntry(name);
                    jos.putNextEntry(jarEntry);

                    while ((len = bis.read(buf)) >= 0) {
                        jos.write(buf, 0, len);
                    }

                    bis.close();
                    jos.closeEntry();
                }
            }
        }
        jos.flush();
        jos.close();
        bos.flush();
        bos.close();
        bytes = baos.toByteArray();
        baos.close();
        return bytes;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

From source file:com.xiaomi.account.utils.SysHelper.java

public static File saveAsFile(Context context, InputStream imgStream, String filename) throws IOException {
    BufferedInputStream bis = new BufferedInputStream(imgStream);
    OutputStream os = new BufferedOutputStream(context.openFileOutput(filename, 0));
    byte[] buffer = new byte[1024];
    while (true) {
        try {/*from  w w  w.ja v a2 s. co m*/
            int count = bis.read(buffer);
            if (count == -1) {
                break;
            }
            os.write(buffer, 0, count);
        } finally {
            try {
                os.flush();
            } catch (IOException e) {
            }
            try {
                os.close();
            } catch (IOException e2) {
            }
        }
    }
    try {
        os.close();
    } catch (IOException e3) {
    }
    return context.getFileStreamPath(filename);
}

From source file:net.duckling.ddl.util.FileUtil.java

/**
 * Brief Intro Here/*from   w ww. ja v a2  s  .c o  m*/
 * ?
 * @param
 */
public static void copyFile(File sourceFile, File targetFile) throws IOException {
    // ?
    FileInputStream input = new FileInputStream(sourceFile);
    BufferedInputStream inBuff = new BufferedInputStream(input);

    // ?
    FileOutputStream output = new FileOutputStream(targetFile);
    BufferedOutputStream outBuff = new BufferedOutputStream(output);

    // 
    byte[] b = new byte[1024 * 5];
    int len;
    while ((len = inBuff.read(b)) != -1) {
        outBuff.write(b, 0, len);
    }
    // ?
    outBuff.flush();

    // ?
    inBuff.close();
    outBuff.close();
    output.close();
    input.close();
}

From source file:com.wabacus.system.dataimport.DataImportItem.java

public static void backupOrDeleteDataFile(File fileObj) {
    try {//w w w .j av  a  2s  .c o m
        if (fileObj == null || !fileObj.exists()) {
            return;
        }
        String backuppath = Config.getInstance().getSystemConfigValue("dataimport-backuppath", "");
        if (backuppath.equals("")) {
            log.debug("?" + fileObj.getAbsolutePath());
        } else {//?
            String filename = fileObj.getName();
            int idxdot = filename.lastIndexOf(".");
            if (idxdot > 0) {
                filename = filename.substring(0, idxdot) + "_"
                        + Tools.getStrDatetime("yyyyMMddHHmmss", new Date()) + filename.substring(idxdot);
            } else {
                filename = filename + "_" + Tools.getStrDatetime("yyyyMMddHHmmss", new Date());
            }
            File destFile = new File(
                    FilePathAssistant.getInstance().standardFilePath(backuppath + File.separator + filename));
            log.debug("?" + fileObj.getAbsolutePath() + "" + backuppath
                    + "");
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            try {
                bis = new BufferedInputStream(new FileInputStream(fileObj));
                bos = new BufferedOutputStream(new FileOutputStream(destFile));
                byte[] btmp = new byte[1024];
                while (bis.read(btmp) != -1) {
                    bos.write(btmp);
                }
            } catch (Exception e) {
                log.error("?" + fileObj.getAbsolutePath() + "", e);
            } finally {
                try {
                    if (bis != null)
                        bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (bos != null)
                        bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        fileObj.delete();
    } catch (Exception e) {
        log.error("?" + fileObj.getAbsolutePath() + "", e);
    }
}

From source file:net.iiit.siel.analysis.lang.NGramProfile.java

/**
 * Create a new Language profile from (preferably quite large) text file
 * /*w ww .j  a  v a2 s .  c o  m*/
 * @param name is thename of profile
 * @param is is the stream to read
 * @param encoding is the encoding of stream
 */
public static NGramProfile create(String name, InputStream is, String encoding) {

    NGramProfile newProfile = new NGramProfile(name, ABSOLUTE_MIN_NGRAM_LENGTH, ABSOLUTE_MAX_NGRAM_LENGTH);
    BufferedInputStream bis = new BufferedInputStream(is);

    byte buffer[] = new byte[4096];
    StringBuffer text = new StringBuffer();
    int len;

    try {
        while ((len = bis.read(buffer)) != -1) {
            text.append(new String(buffer, 0, len, encoding));
        }
    } catch (IOException e) {
        //e.printStackTrace(LogUtil.getWarnStream(LOG));
    }

    newProfile.analyze(text);
    return newProfile;
}

From source file:de.petermoesenthin.alarming.util.FileUtil.java

/**
 * Copies a file to the Alarming directory in the external storage
 *
 * @param context Application context/*from ww  w .jav a 2 s .co m*/
 * @param uri     Uri of file to copy
 */
public static void saveFileToExtAppStorage(final Context context, final Uri uri,
        final OnCopyFinishedListener op) {
    final File applicationDirectory = getApplicationDirectory();
    if (!applicationDirectory.exists()) {
        applicationDirectory.mkdirs();
    }
    File noMedia = new File(applicationDirectory.getPath() + File.separatorChar + ".nomedia");
    if (!noMedia.exists()) {
        try {
            noMedia.createNewFile();
            Log.e(DEBUG_TAG, "Created .nomedia file in: " + noMedia.getAbsolutePath());
        } catch (IOException e) {
            Log.e(DEBUG_TAG, "Unable to create .nomedia file", e);
        }
    }

    String fileName = getFilenameFromUriNoSpace(uri);
    final File destinationFile = new File(applicationDirectory.getPath() + File.separatorChar + fileName);

    Log.d(DEBUG_TAG, "Source file name: " + fileName);
    Log.d(DEBUG_TAG, "Source file uri: " + uri.toString());
    Log.d(DEBUG_TAG, "Destination file: " + destinationFile.getPath());

    Thread copyThread = new Thread(new Runnable() {
        @Override
        public void run() {
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            if (isExternalStorageWritable()) {
                try {
                    InputStream uriStream = context.getContentResolver().openInputStream(uri);
                    bis = new BufferedInputStream(uriStream);
                    bos = new BufferedOutputStream(new FileOutputStream(destinationFile.getPath(), false));
                    byte[] buf = new byte[1024];
                    while (bis.read(buf) != -1) {
                        bos.write(buf);
                    }
                } catch (IOException e) {
                    Log.e(DEBUG_TAG, "Unable to copy file from URI", e);

                } finally {
                    try {
                        if (bis != null)
                            bis.close();
                        if (bos != null)
                            bos.close();
                    } catch (IOException e) {
                        Log.e(DEBUG_TAG, "Unable to close buffers", e);
                    }
                }
            }
            if (op != null) {
                op.onOperationFinished();
            }
        }
    });
    copyThread.start();
}

From source file:com.mb.framework.util.property.PropertyUtilExt.java

/**
 * Copy property values from the origin bean to the destination bean for all
 * cases where the property names are the same. For each property, a
 * conversion is attempted as necessary. All combinations of standard
 * JavaBeans and DynaBeans as origin and destination are supported.
 * Properties that exist in the origin bean, but do not exist in the
 * destination bean (or are read-only in the destination bean) are silently
 * ignored./*www  . j  a v  a  2s .c  om*/
 * <p>
 * In addition to the method with the same name in the
 * <code>org.apache.commons.beanutils.PropertyUtils</code> class this method
 * can also copy properties of the following types:
 * <ul>
 * <li>java.lang.Integer</li>
 * <li>java.lang.Double</li>
 * <li>java.lang.Long</li>
 * <li>java.lang.Short</li>
 * <li>java.lang.Float</li>
 * <li>java.lang.String</li>
 * <li>java.lang.Boolean</li>
 * <li>java.sql.Date</li>
 * <li>java.sql.Time</li>
 * <li>java.sql.Timestamp</li>
 * <li>java.math.BigDecimal</li>
 * <li>a container-managed relations field.</li>
 * </ul>
 * 
 * @param dest
 *            Destination bean whose properties are modified
 * @param orig
 *            Origin bean whose properties are retrieved
 * @throws IllegalAccessException
 *             if the caller does not have access to the property accessor
 *             method
 * @throws InvocationTargetException
 *             if the property accessor method throws an exception
 * @throws NoSuchMethodException
 *             if an accessor method for this propety cannot be found
 * @throws ClassNotFoundException
 *             if an incorrect relations class mapping exists.
 * @throws InstantiationException
 *             if an object of the mapped relations class can not be
 *             constructed.
 */
public static void copyProperties(Object dest, Object orig)
        throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, Exception {
    PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);

    for (int i = 0; i < origDescriptors.length; i++) {
        String name = origDescriptors[i].getName();

        if (PropertyUtils.getPropertyDescriptor(dest, name) != null) {
            Object origValue = PropertyUtils.getSimpleProperty(orig, name);
            String origParamType = origDescriptors[i].getPropertyType().getName();
            try {
                // edited
                // if (origValue == null)throw new NullPointerException();

                PropertyUtils.setSimpleProperty(dest, name, origValue);
            } catch (Exception e) {
                try {
                    String destParamType = PropertyUtils.getPropertyType(dest, name).getName();

                    if (origValue instanceof String) {
                        if (destParamType.equals("java.lang.Integer")) {
                            Integer intValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                intValue = new Integer(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, intValue);
                        } else if (destParamType.equals("java.lang.Byte")) {
                            Byte byteValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                byteValue = new Byte(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, byteValue);
                        } else if (destParamType.equals("java.lang.Double")) {
                            Double doubleValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                doubleValue = new Double(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, doubleValue);
                        } else if (destParamType.equals("java.lang.Long")) {
                            Long longValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                longValue = new Long(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, longValue);
                        } else if (destParamType.equals("java.lang.Short")) {
                            Short shortValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                shortValue = new Short(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, shortValue);
                        } else if (destParamType.equals("java.lang.Float")) {
                            Float floatValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                floatValue = new Float(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, floatValue);
                        } else if (destParamType.equals("java.sql.Date")) {
                            java.sql.Date dateValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                dateValue = new java.sql.Date(DATE_FORMATTER.parse(sValue).getTime());
                            }
                            PropertyUtils.setSimpleProperty(dest, name, dateValue);
                        } else if (destParamType.equals("java.sql.Time")) {
                            java.sql.Time dateValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                dateValue = new java.sql.Time(TIME_FORMATTER.parse(sValue).getTime());
                            }
                            PropertyUtils.setSimpleProperty(dest, name, dateValue);
                        } else if (destParamType.equals("java.sql.Timestamp")) {
                            java.sql.Timestamp dateValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                dateValue = new java.sql.Timestamp(TIMESTAMP_FORMATTER.parse(sValue).getTime());
                            }
                            PropertyUtils.setSimpleProperty(dest, name, dateValue);
                        } else if (destParamType.equals("java.lang.Boolean")) {
                            Boolean bValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                bValue = Boolean.valueOf(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, bValue);
                        } else if (destParamType.equals("java.math.BigDecimal")) {
                            BigDecimal bdValue = null;
                            String sValue = ((String) origValue).trim();

                            if (sValue.length() > 0) {
                                bdValue = new BigDecimal(sValue);
                            }
                            PropertyUtils.setSimpleProperty(dest, name, bdValue);
                        }
                    } else if ((origValue != null) && (destParamType.equals("java.lang.String"))) {
                        // we're transferring a business-layer value object
                        // into a String-based Struts form bean..
                        if ("java.sql.Date".equals(origParamType)) {
                            PropertyUtils.setSimpleProperty(dest, name, DATE_FORMATTER.format(origValue));
                        } else if ("java.sql.Timestamp".equals(origParamType)) {
                            PropertyUtils.setSimpleProperty(dest, name, TIMESTAMP_FORMATTER.format(origValue));
                        } else if ("java.sql.Blob".equals(origParamType)) {
                            // convert a Blob to a String..
                            Blob blob = (Blob) origValue;
                            BufferedInputStream bin = null;
                            try {
                                int bytesRead;
                                StringBuffer result = new StringBuffer();
                                byte[] buffer = new byte[READ_BUFFER_LENGTH];
                                bin = new BufferedInputStream(blob.getBinaryStream());
                                do {
                                    bytesRead = bin.read(buffer);
                                    if (bytesRead != -1) {
                                        result.append(new String(buffer, 0, bytesRead));
                                    }
                                } while (bytesRead == READ_BUFFER_LENGTH);

                                PropertyUtils.setSimpleProperty(dest, name, result.toString());

                            } finally {
                                if (bin != null)
                                    try {
                                        bin.close();
                                    } catch (IOException ignored) {
                                    }
                            }

                        } else {
                            PropertyUtils.setSimpleProperty(dest, name, origValue.toString());
                        }
                    }
                } catch (Exception e2) {
                    throw e2;
                }
            }
        }
    }
}

From source file:com.volley.air.toolbox.HurlStack.java

/**
 * Perform a multipart request on a connection
 * //  w  w  w  .  j a v  a2 s  .c om
 * @param connection
 *            The Connection to perform the multi part request
 * @param request
 *            The params to add to the Multi Part request
 *            The files to upload
 * @throws ProtocolException
 */
private static void setConnectionParametersForMultipartRequest(HttpURLConnection connection, Request<?> request)
        throws IOException, ProtocolException {

    final String charset = ((MultiPartRequest<?>) request).getProtocolCharset();
    final int curTime = (int) (System.currentTimeMillis() / 1000);
    final String boundary = BOUNDARY_PREFIX + curTime;
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    connection.setRequestProperty(HEADER_CONTENT_TYPE, String.format(CONTENT_TYPE_MULTIPART, charset, curTime));

    Map<String, MultiPartParam> multipartParams = ((MultiPartRequest<?>) request).getMultipartParams();
    Map<String, String> filesToUpload = ((MultiPartRequest<?>) request).getFilesToUpload();

    if (((MultiPartRequest<?>) request).isFixedStreamingMode()) {
        int contentLength = getContentLengthForMultipartRequest(boundary, multipartParams, filesToUpload);

        connection.setFixedLengthStreamingMode(contentLength);
    } else {
        connection.setChunkedStreamingMode(0);
    }
    // Modified end

    ProgressListener progressListener;
    progressListener = (ProgressListener) request;

    PrintWriter writer = null;
    try {
        OutputStream out = connection.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(out, charset), true);

        for (Entry<String, MultiPartParam> entry : multipartParams.entrySet()) {
            MultiPartParam param = entry.getValue();

            writer.append(boundary).append(CRLF)
                    .append(String.format(HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA, entry.getKey()))
                    .append(CRLF).append(HEADER_CONTENT_TYPE + COLON_SPACE + param.contentType).append(CRLF)
                    .append(CRLF).append(param.value).append(CRLF).flush();
        }

        for (Entry<String, String> entry : filesToUpload.entrySet()) {

            File file = new File(entry.getValue());

            if (!file.exists()) {
                throw new IOException(String.format("File not found: %s", file.getAbsolutePath()));
            }

            if (file.isDirectory()) {
                throw new IOException(String.format("File is a directory: %s", file.getAbsolutePath()));
            }

            writer.append(boundary).append(CRLF)
                    .append(String.format(
                            HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA + SEMICOLON_SPACE + FILENAME,
                            entry.getKey(), file.getName()))
                    .append(CRLF).append(HEADER_CONTENT_TYPE + COLON_SPACE + CONTENT_TYPE_OCTET_STREAM)
                    .append(CRLF).append(HEADER_CONTENT_TRANSFER_ENCODING + COLON_SPACE + BINARY).append(CRLF)
                    .append(CRLF).flush();

            BufferedInputStream input = null;
            try {
                FileInputStream fis = new FileInputStream(file);
                int transferredBytes = 0;
                int totalSize = (int) file.length();
                input = new BufferedInputStream(fis);
                int bufferLength;

                byte[] buffer = new byte[1024];
                while ((bufferLength = input.read(buffer)) > 0) {
                    out.write(buffer, 0, bufferLength);
                    transferredBytes += bufferLength;
                    progressListener.onProgress(transferredBytes, totalSize);
                }
                out.flush(); // Important! Output cannot be closed. Close of
                             // writer will close
                             // output as well.
            } finally {
                if (input != null)
                    try {
                        input.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
            }
            writer.append(CRLF).flush(); // CRLF is important! It indicates
            // end of binary
            // boundary.
        }

        // End of multipart/form-data.
        writer.append(boundary + BOUNDARY_PREFIX).append(CRLF).flush();

    } catch (Exception e) {
        e.printStackTrace();

    } finally {
        if (writer != null) {
            writer.close();
        }
    }
}

From source file:moskitt4me.repositoryClient.core.util.RepositoryClientUtil.java

public static void addFileToZip(File file, ZipOutputStream zos) throws Exception {

    zos.putNextEntry(new ZipEntry(file.getName()));

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));

    long bytesRead = 0;
    byte[] bytesIn = new byte[1024];
    int read = 0;

    while ((read = bis.read(bytesIn)) != -1) {
        zos.write(bytesIn, 0, read);/*  w  w  w  .  j a  va2 s . co  m*/
        bytesRead += read;
    }

    zos.closeEntry();
    bis.close();
}

From source file:com.androidex.volley.toolbox.HurlStack.java

/**
 * Perform a multipart request on a connection
 * /* w  w  w  .  j av a  2  s  . com*/
 * @param connection
 *            The Connection to perform the multi part request
 * @param request
 *            The params to add to the Multi Part request
 *            The files to upload
 * @throws ProtocolException
 */
private static void setConnectionParametersForMultipartRequest(HttpURLConnection connection, Request<?> request)
        throws IOException, ProtocolException {

    final String charset = ((MultiPartRequest<?>) request).getProtocolCharset();
    final int curTime = (int) (System.currentTimeMillis() / 1000);
    final String boundary = BOUNDARY_PREFIX + curTime;
    connection.setRequestMethod("POST");
    connection.setDoOutput(true);
    connection.setRequestProperty(HEADER_CONTENT_TYPE, String.format(CONTENT_TYPE_MULTIPART, charset, curTime));

    Map<String, MultiPartParam> multipartParams = ((MultiPartRequest<?>) request).getMultipartParams();
    Map<String, String> filesToUpload = ((MultiPartRequest<?>) request).getFilesToUpload();

    if (((MultiPartRequest<?>) request).isFixedStreamingMode()) {
        int contentLength = getContentLengthForMultipartRequest(boundary, multipartParams, filesToUpload);

        connection.setFixedLengthStreamingMode(contentLength);
    } else {
        connection.setChunkedStreamingMode(0);
    }
    // Modified end

    ProgressListener progressListener;
    progressListener = (ProgressListener) request;

    PrintWriter writer = null;
    try {
        OutputStream out = connection.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(out, charset), true);

        for (String key : multipartParams.keySet()) {
            MultiPartParam param = multipartParams.get(key);

            writer.append(boundary).append(CRLF)
                    .append(String.format(HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA, key))
                    .append(CRLF).append(HEADER_CONTENT_TYPE + COLON_SPACE + param.contentType).append(CRLF)
                    .append(CRLF).append(param.value).append(CRLF).flush();
        }

        for (String key : filesToUpload.keySet()) {

            File file = new File(filesToUpload.get(key));

            if (!file.exists()) {
                throw new IOException(String.format("File not found: %s", file.getAbsolutePath()));
            }

            if (file.isDirectory()) {
                throw new IOException(String.format("File is a directory: %s", file.getAbsolutePath()));
            }

            writer.append(boundary).append(CRLF)
                    .append(String.format(
                            HEADER_CONTENT_DISPOSITION + COLON_SPACE + FORM_DATA + SEMICOLON_SPACE + FILENAME,
                            key, file.getName()))
                    .append(CRLF).append(HEADER_CONTENT_TYPE + COLON_SPACE + CONTENT_TYPE_OCTET_STREAM)
                    .append(CRLF).append(HEADER_CONTENT_TRANSFER_ENCODING + COLON_SPACE + BINARY).append(CRLF)
                    .append(CRLF).flush();

            BufferedInputStream input = null;
            try {
                FileInputStream fis = new FileInputStream(file);
                int transferredBytes = 0;
                int totalSize = (int) file.length();
                input = new BufferedInputStream(fis);
                int bufferLength = 0;

                byte[] buffer = new byte[1024];
                while ((bufferLength = input.read(buffer)) > 0) {
                    out.write(buffer, 0, bufferLength);
                    transferredBytes += bufferLength;
                    progressListener.onProgress(transferredBytes, totalSize);
                }
                out.flush(); // Important! Output cannot be closed. Close of
                             // writer will close
                             // output as well.
            } finally {
                if (input != null)
                    try {
                        input.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
            }
            writer.append(CRLF).flush(); // CRLF is important! It indicates
            // end of binary
            // boundary.
        }

        // End of multipart/form-data.
        writer.append(boundary + BOUNDARY_PREFIX).append(CRLF).flush();

    } catch (Exception e) {
        e.printStackTrace();

    } finally {
        if (writer != null) {
            writer.close();
        }
    }
}