title: java.io.EOFException: premature end of stream in PartialInputStream - bouncy Castle
body: <p>I am getting below mentioned exception when trying to decrypt the file. Any help in this regard will be of great benefit. Code has been added below for reference. The Encryption is working fine so do is Decryption but when we have large files then Encryption works but Decryption gives below mentioned error.</p>
  
  <p>Thanks in advance</p>
  
  <pre><code>Exception in thread "Main Thread" java.io.EOFException: premature end of stream in PartialInputStream
      at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at java.io.InputStream.read(InputStream.java:82)
      at org.bouncycastle.crypto.io.CipherInputStream.nextChunk(Unknown Source)
      at org.bouncycastle.crypto.io.CipherInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at org.bouncycastle.openpgp.PGPEncryptedData$TruncatedStream.read(Unknown Source)
      at java.io.InputStream.read(InputStream.java:151)
      at org.bouncycastle.util.io.TeeInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at org.bouncycastle.openpgp.PGPCompressedData$1.fill(Unknown Source)
      at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:141)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
      at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
      at java.io.InputStream.read(InputStream.java:82)
  </code></pre>
  
  <p><strong>Code for Encryption/Decryption</strong></p>
  
  <p>public class PGPUtils {</p>
  
  <pre><code>private static int BUFFER_SIZE = 1 &lt;&lt; 24;
  private static final int KEY_FLAGS = 27;
  private static final int[] MASTER_KEY_CERTIFICATION_TYPES = new int[] { PGPSignature.POSITIVE_CERTIFICATION,
          PGPSignature.CASUAL_CERTIFICATION, PGPSignature.NO_CERTIFICATION, PGPSignature.DEFAULT_CERTIFICATION,
  
  };
  
  @SuppressWarnings("unchecked")
  public static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {
  
      PGPPublicKeyRingCollection keyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in),
              new BcKeyFingerprintCalculator());
  
      //
      // we just loop through the collection till we find a key suitable for
      // encryption, in the real
      // world you would probably want to be a bit smarter about this.
      //
      PGPPublicKey publicKey = null;
  
      //
      // iterate through the key rings.
      //
      Iterator&lt;PGPPublicKeyRing&gt; rIt = keyRingCollection.getKeyRings();
  
      while (publicKey == null &amp;&amp; rIt.hasNext()) {
          PGPPublicKeyRing kRing = rIt.next();
          Iterator&lt;PGPPublicKey&gt; kIt = kRing.getPublicKeys();
          while (publicKey == null &amp;&amp; kIt.hasNext()) {
              PGPPublicKey key = kIt.next();
              if (key.isEncryptionKey()) {
                  publicKey = key;
              }
          }
      }
  
      if (publicKey == null) {
          throw new IllegalArgumentException("Can't find public key in the key ring.");
      }
      if (!isForEncryption(publicKey)) {
          throw new IllegalArgumentException("KeyID " + publicKey.getKeyID() + " not flagged for encryption.");
      }
      in.close();
      return publicKey;
  }
  
  @SuppressWarnings("unchecked")
  public static PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException {
  
      PGPSecretKeyRingCollection keyRingCollection = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in),
              new BcKeyFingerprintCalculator());
  
      //
      // We just loop through the collection till we find a key suitable for
      // signing.
      // In the real world you would probably want to be a bit smarter about
      // this.
      //
      PGPSecretKey secretKey = null;
  
      Iterator&lt;PGPSecretKeyRing&gt; rIt = keyRingCollection.getKeyRings();
      while (secretKey == null &amp;&amp; rIt.hasNext()) {
          PGPSecretKeyRing keyRing = rIt.next();
          Iterator&lt;PGPSecretKey&gt; kIt = keyRing.getSecretKeys();
          while (secretKey == null &amp;&amp; kIt.hasNext()) {
              PGPSecretKey key = kIt.next();
              if (key.isSigningKey()) {
                  secretKey = key;
              }
          }
      }
  
      // Validate secret key
      if (secretKey == null) {
          throw new IllegalArgumentException("Can't find private key in the key ring.");
      }
      if (!secretKey.isSigningKey()) {
          throw new IllegalArgumentException("Private key does not allow signing.");
      }
      if (secretKey.getPublicKey().isRevoked()) {
          throw new IllegalArgumentException("Private key has been revoked.");
      }
      if (!hasKeyFlags(secretKey.getPublicKey(), KeyFlags.SIGN_DATA)) {
          throw new IllegalArgumentException("Key cannot be used for signing.");
      }
      in.close();
      return secretKey;
  }
  
  /**
   * Load a secret key ring collection from keyIn and find the private key
   * corresponding to keyID if it exists.
   *
   * @param keyIn
   *            input stream representing a key ring collection.
   * @param keyID
   *            keyID we want.
   * @param pass
   *            passphrase to decrypt secret key with.
   * @return
   * @throws IOException
   * @throws PGPException
   * @throws NoSuchProviderException
   */
  public static PGPPrivateKey findPrivateKey(InputStream keyIn, long keyID, char[] pass) throws IOException,
          PGPException, NoSuchProviderException {
      PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn),
              new BcKeyFingerprintCalculator());
      keyIn.close();
      return findPrivateKey(pgpSec.getSecretKey(keyID), pass);
  
  }
  
  /**
   * Load a secret key and find the private key in it
   * 
   * @param pgpSecKey
   *            The secret key
   * @param pass
   *            passphrase to decrypt secret key with
   * @return
   * @throws PGPException
   */
  public static PGPPrivateKey findPrivateKey(PGPSecretKey pgpSecKey, char[] pass) throws PGPException {
      if (pgpSecKey == null)
          return null;
  
      PBESecretKeyDecryptor decryptor = new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider())
              .build(pass);
      return pgpSecKey.extractPrivateKey(decryptor);
  }
  
  /**
   * decrypt the passed in message stream
   */
  @SuppressWarnings("unchecked")
  public static void decryptFile(InputStream in, OutputStream out, InputStream keyIn, char[] passwd) throws Exception {
      getProvider();
  
      in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);
  
      PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());
      PGPEncryptedDataList enc;
  
      Object o = pgpF.nextObject();
      //
      // the first object might be a PGP marker packet.
      //
      if (o instanceof PGPEncryptedDataList) {
          enc = (PGPEncryptedDataList) o;
      } else {
          enc = (PGPEncryptedDataList) pgpF.nextObject();
      }
  
      //
      // find the secret key
      //
      Iterator&lt;PGPPublicKeyEncryptedData&gt; it = enc.getEncryptedDataObjects();
      PGPPrivateKey sKey = null;
      PGPPublicKeyEncryptedData pbe = null;
  
      while (sKey == null &amp;&amp; it.hasNext()) {
          pbe = it.next();
  
          sKey = findPrivateKey(keyIn, pbe.getKeyID(), passwd);
      }
  
      if (sKey == null) {
          throw new IllegalArgumentException("Secret key for message not found.");
      }
  
      InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
  
      PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());
  
      Object message = plainFact.nextObject();
  
      if (message instanceof PGPCompressedData) {
          PGPCompressedData cData = (PGPCompressedData) message;
          PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());
  
          message = pgpFact.nextObject();
      }
  
      if (message instanceof PGPLiteralData) {
          PGPLiteralData ld = (PGPLiteralData) message;
  
          InputStream unc = ld.getInputStream();
          int ch;
  
          while ((ch = unc.read()) &gt;= 0) {
              out.write(ch);
          }
      } else if (message instanceof PGPOnePassSignature) {
          System.out.println("Instance of PGPOnePassSignature");
          PGPLiteralData ld = (PGPLiteralData) message;
  
          InputStream unc = ld.getInputStream();
          int ch;
  
          while ((ch = unc.read()) &gt;= 0) {
              out.write(ch);
          }
      }
  
      else if (message instanceof PGPOnePassSignatureList) {
          // throw new
          // PGPException("Encrypted message contains a signed message - not literal data.");
  
      } else {
          throw new PGPException("Message is not a simple encrypted file - type unknown.");
      }
  
      if (pbe.isIntegrityProtected()) {
          if (!pbe.verify()) {
              throw new PGPException("Message failed integrity check");
          }
      }
  }
  
  /**
   * decrypt the passed in signed message stream
   */
  @SuppressWarnings("unchecked")
  public static void decryptSignedFile(InputStream in, OutputStream out, InputStream keyIn, char[] passwd,
          InputStream signPublicKeyInputStream) throws Exception {
      getProvider();
  
      in = org.bouncycastle.openpgp.PGPUtil.getDecoderStream(in);
  
      // Reading a PGP object stream
      PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());
  
      PGPEncryptedDataList enc;
  
      Object o = pgpF.nextObject();
      //
      // the first object might be a PGP marker packet.
      //
      if (o instanceof PGPEncryptedDataList) {
          enc = (PGPEncryptedDataList) o;
      } else {
          enc = (PGPEncryptedDataList) pgpF.nextObject();
      }
  
      //
      // find the secret key
      //
      Iterator&lt;PGPPublicKeyEncryptedData&gt; it = enc.getEncryptedDataObjects();
      PGPPrivateKey sKey = null;
      PGPPublicKeyEncryptedData pbe = null;
  
      while (sKey == null &amp;&amp; it.hasNext()) {
          pbe = it.next();
  
          sKey = findPrivateKey(keyIn, pbe.getKeyID(), passwd);
      }
  
      if (sKey == null) {
          throw new IllegalArgumentException("Secret key for message not found.");
      }
      keyIn.close();
      // A decryptor factory for handling public key decryption operations
      InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
  
      PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());
  
      PGPObjectFactory objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(in),
              new BcKeyFingerprintCalculator());
      Object message = plainFact.nextObject();
  
      if (message instanceof PGPCompressedData) {
          System.out.println("PGPCompressedData");
  
          PGPCompressedData cData = (PGPCompressedData) message;
          objectFactory = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());
  
          message = objectFactory.nextObject();
      }
  
      if (message instanceof PGPOnePassSignature) {
          System.out.println("Instance of PGPOnePassSignature");
          PGPLiteralData ld = (PGPLiteralData) message;
  
          InputStream unc = ld.getInputStream();
          int ch;
  
          while ((ch = unc.read()) &gt;= 0) {
  
              out.write(ch);
          }
          unc.close();
  
      }
  
      if (message instanceof PGPOnePassSignatureList) {
  
          PGPOnePassSignature calculatedSignature = ((PGPOnePassSignatureList) message).get(0);
  
          PGPPublicKey signPublicKey = readPublicKey(signPublicKeyInputStream);
  
          calculatedSignature.init(new BcPGPContentVerifierBuilderProvider(), signPublicKey);
          message = objectFactory.nextObject();
  
      } else {
          throw new PGPException("Message is not a simple encrypted file - type unknown.");
      }
  
      if (message instanceof PGPLiteralData) {
          PGPLiteralData ld = (PGPLiteralData) message;
  
          InputStream uncPGLiteral = null;
          try {
              uncPGLiteral = ld.getDataStream();
              int ch1;
  
              byte[] buffDecrypt = new byte[PGPUtils.BUFFER_SIZE];
              int len;
              IOUtils.copy(uncPGLiteral, out);
              // while ((len = uncPGLiteral.read(buffDecrypt)) &gt; 0) {
              // out.write(buffDecrypt, 0, len);
              //
              // }
          } finally {
              if (uncPGLiteral != null) {
                  System.out.println("Going to close the input stream");
                  uncPGLiteral.close();
                  out.close();
  
              }
          }
  
      }
      if (pbe.isIntegrityProtected()) {
          if (!pbe.verify()) {
              throw new PGPException("Message failed integrity check");
          }
      }
      signPublicKeyInputStream.close();
      clear.close();
      in.close();
  }
  
  public static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey, boolean armor,
          boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException {
      getProvider();
  
      if (armor) {
          out = new ArmoredOutputStream(out);
      }
  
      ByteArrayOutputStream bOut = new ByteArrayOutputStream();
      PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
  
      PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
  
      comData.close();
  
      BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES);
      dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
      dataEncryptor.setSecureRandom(new SecureRandom());
  
      PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
      encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
  
      byte[] bytes = bOut.toByteArray();
      System.out.println("length is&gt;&gt;&gt;&gt;&gt;&gt;&gt;" + bytes.length);
      OutputStream cOut = encryptedDataGenerator.open(out, bytes.length);
      cOut.write(bytes);
      cOut.close();
      out.close();
  }
  
  @SuppressWarnings("unchecked")
  public static OutputStream signEncryptFile(String fileName, PGPPublicKey publicKey, PGPSecretKey secretKey,
          String password, boolean armor, boolean withIntegrityCheck) throws Exception {
      System.out.println("fileName:::" + fileName);
  
      // Initialize Bouncy Castle security provider
      getProvider();
      OutputStream compressedOut = null;
      try {
          File inputFile = new File(fileName);
  
          String outputFileName = fileName.concat(".pgp");
          OutputStream out = new FileOutputStream(outputFileName);
  
          if (armor) {
              out = new ArmoredOutputStream(out);
          }
  
          // Bouncy Castle lightweight API to implement cryptographic
          // primitives. Constructs a new data encryptor builder for a
          // specified cipher type
          BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.TRIPLE_DES);
          // Sets whether or not the resulting encrypted data will be
          // protected using an integrity packet i.e withIntegrityPacket -
          // true if an integrity packet is to be included, false otherwise
          dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);
          dataEncryptor.setSecureRandom(new SecureRandom());
  
          // A PGPEncryptedDataGenerator is used by configuring one or more
          // encryption methods, and then invoking one of the open functions
          // to create an OutputStream that raw data can be supplied to for
          // encryption
          PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);
          // Add a key encryption method to be used to encrypt the session
          // data associated with this encrypted data
          encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(publicKey));
  
          // Create an OutputStream based on the configured methods to write a
          // single encrypted object of known length
          OutputStream encryptedOut = encryptedDataGenerator.open(out, new byte[BUFFER_SIZE]);
  
          // Generator for producing compressed data packets. Initialize
          // compressed data generator
          PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(
                  PGPCompressedData.UNCOMPRESSED);
          compressedOut = compressedDataGenerator.open(encryptedOut);
  
          // Initialize signature generator
          PGPPrivateKey privateKey = findPrivateKey(secretKey, password.toCharArray());
  
          // Initialize Content Sign Builder parameters are {int keyAlgorithm,
          // int hashAlgorithm}
          PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(secretKey.getPublicKey()
                  .getAlgorithm(), HashAlgorithmTags.SHA1);
  
          // Create a signature generator built on the passed in
          // contentSignerBuilder
          PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signerBuilder);
          // Initialise the generator for signing
          signatureGenerator.init(PGPSignature.STAND_ALONE, privateKey);
  
          boolean firstTime = true;
          Iterator&lt;String&gt; it = secretKey.getPublicKey().getUserIDs();
          while (it.hasNext() &amp;&amp; firstTime) {
              PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
              spGen.setSignerUserID(false, it.next());
              signatureGenerator.setHashedSubpackets(spGen.generate());
              // Exit the loop after the first iteration
              firstTime = false;
          }
          signatureGenerator.generateOnePassVersion(false).encode(compressedOut);
  
          // Generator for producing literal data packets.A
          // PGPLiteralDataGenerator is usually used to wrap the OutputStream
          // obtained from a PGPEncryptedDataGenerator or a
          // PGPCompressedDataGenerator. Initialize literal data generator
          PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
          OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.UTF8, fileName,
                  inputFile.length(), new Date());
  
          // Main loop - read the "in" stream, compress, encrypt and write to
          // the
          // "out" stream
          InputStream in = new FileInputStream(fileName);
          byte[] buf = new byte[BUFFER_SIZE];
          int len;
          while ((len = in.read(buf)) &gt; 0) {
              literalOut.write(buf, 0, len);
              signatureGenerator.update(buf, 0, len);
          }
  
          in.close();
          literalOut.close();
          literalDataGenerator.close();
          // Generate the signature, compress, encrypt and write to the "out"
          // stream
  
          signatureGenerator.generate();
  
          compressedOut.close();
          compressedDataGenerator.close();
          encryptedOut.close();
          encryptedDataGenerator.close();
  
          if (armor) {
              out.close();
          }
      } catch (Exception e) {
          System.out.println("Error is::" + e.getMessage());
      }
  
      return compressedOut;
  }
  
  public static boolean verifyFile(InputStream in, InputStream keyIn, String extractContentFile) throws Exception {
      in = PGPUtil.getDecoderStream(in);
  
      PGPObjectFactory pgpFact = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());
      PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();
  
      pgpFact = new PGPObjectFactory(c1.getDataStream(), new BcKeyFingerprintCalculator());
  
      PGPOnePassSignatureList p1 = (PGPOnePassSignatureList) pgpFact.nextObject();
  
      PGPOnePassSignature ops = p1.get(0);
  
      PGPLiteralData p2 = (PGPLiteralData) pgpFact.nextObject();
  
      InputStream dIn = p2.getInputStream();
  
      IOUtils.copy(dIn, new FileOutputStream(extractContentFile));
  
      int ch;
      PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn),
              new BcKeyFingerprintCalculator());
  
      PGPPublicKey key = pgpRing.getPublicKey(ops.getKeyID());
  
      FileOutputStream out = new FileOutputStream(p2.getFileName());
  
      ops.init(new BcPGPContentVerifierBuilderProvider(), key);
  
      while ((ch = dIn.read()) &gt;= 0) {
          ops.update((byte) ch);
          out.write(ch);
      }
  
      out.close();
  
      PGPSignatureList p3 = (PGPSignatureList) pgpFact.nextObject();
      return ops.verify(p3.get(0));
  }
  
  /**
   * From LockBox Lobs PGP Encryption tools.
   * http://www.lockboxlabs.org/content/downloads
   *
   * I didn't think it was worth having to import a 4meg lib for three methods
   * 
   * @param key
   * @return
   */
  public static boolean isForEncryption(PGPPublicKey key) {
      if (key.getAlgorithm() == PublicKeyAlgorithmTags.RSA_SIGN || key.getAlgorithm() == PublicKeyAlgorithmTags.DSA
              || key.getAlgorithm() == PublicKeyAlgorithmTags.EC
              || key.getAlgorithm() == PublicKeyAlgorithmTags.ECDSA) {
          return false;
      }
  
      return hasKeyFlags(key, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE);
  }
  
  /**
   * From LockBox Lobs PGP Encryption tools.
   * http://www.lockboxlabs.org/content/downloads
   *
   * I didn't think it was worth having to import a 4meg lib for three methods
   * 
   * @param key
   * @return
   */
  @SuppressWarnings("unchecked")
  private static boolean hasKeyFlags(PGPPublicKey encKey, int keyUsage) {
      System.out.println("In hasKeyFlags+" + encKey.isMasterKey());
      if (encKey.isMasterKey()) {
          System.out.println("In Here" + PGPUtils.MASTER_KEY_CERTIFICATION_TYPES.length);
          for (int i = 0; i != PGPUtils.MASTER_KEY_CERTIFICATION_TYPES.length; i++) {
              for (Iterator&lt;PGPSignature&gt; eIt = encKey
                      .getSignaturesOfType(PGPUtils.MASTER_KEY_CERTIFICATION_TYPES[i]); eIt.hasNext();) {
                  PGPSignature sig = eIt.next();
                  if (!isMatchingUsage(sig, keyUsage)) {
                      return false;
                  }
              }
          }
      } else {
          for (Iterator&lt;PGPSignature&gt; eIt = encKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); eIt.hasNext();) {
              PGPSignature sig = eIt.next();
              if (!isMatchingUsage(sig, keyUsage)) {
                  return false;
              }
          }
      }
      return true;
  }
  
  /**
   * From LockBox Lobs PGP Encryption tools.
   * http://www.lockboxlabs.org/content/downloads
   *
   * I didn't think it was worth having to import a 4meg lib for three methods
   * 
   * @param key
   * @return
   */
  private static boolean isMatchingUsage(PGPSignature sig, int keyUsage) {
      System.out.println("isMatchingUsage::");
      if (sig.hasSubpackets()) {
          PGPSignatureSubpacketVector sv = sig.getHashedSubPackets();
          if (sv.hasSubpacket(PGPUtils.KEY_FLAGS)) {
              // code fix suggested by kzt (see comments)
              if ((sv.getKeyFlags() == 0) &amp;&amp; (keyUsage == 0)) {
                  return false;
              }
          }
      }
      return true;
  }
  
  private static Provider getProvider() {
      Provider provider = Security.getProvider("BC");
      if (provider == null) {
          provider = new BouncyCastleProvider();
          Security.addProvider(provider);
      }
      return provider;
  }
  </code></pre>
  
  <p>}</p>