whole_func_string: async function (requestId, domainName, subjectAlternativeNames, hostedZoneId) {
    const crypto = require('crypto');
    const acm = new aws.ACM();
    const route53 = new aws.Route53();
    if (waiter) {
      // Used by the test suite, since waiters aren't mockable yet
      route53.waitFor = acm.waitFor = waiter;
    }
  
    console.log(`Requesting certificate for ${domainName}`);
  
    const reqCertResponse = await acm.requestCertificate({
      DomainName: domainName,
      SubjectAlternativeNames: subjectAlternativeNames,
      IdempotencyToken: crypto.createHash('sha256').update(requestId).digest('hex').substr(0, 32),
      ValidationMethod: 'DNS'
    }).promise();
  
    console.log(`Certificate ARN: ${reqCertResponse.CertificateArn}`);
  
    console.log('Waiting for ACM to provide DNS records for validation...');
  
    var describeCertResponse;
    let attempt = 0;
    do {
      // Exponential backoff with jitter based on 100ms base
      await sleep(Math.random() * (Math.pow(attempt, 2) * 100));
      describeCertResponse = await acm.describeCertificate({
        CertificateArn: reqCertResponse.CertificateArn
      }).promise();
    } while (describeCertResponse.Certificate.DomainValidationOptions < 1 ||
      'ResourceRecord' in describeCertResponse.Certificate.DomainValidationOptions[0] === false);
  
    const record = describeCertResponse.Certificate.DomainValidationOptions[0].ResourceRecord;
  
    console.log(`Upserting DNS record into zone ${hostedZoneId}: ${record.Name} ${record.Type} ${record.Value}`);
  
    const changeBatch = await route53.changeResourceRecordSets({
      ChangeBatch: {
        Changes: [{
          Action: 'UPSERT',
          ResourceRecordSet: {
            Name: record.Name,
            Type: record.Type,
            TTL: 60,
            ResourceRecords: [{
              Value: record.Value
            }]
          }
        }]
      },
      HostedZoneId: hostedZoneId
    }).promise();
  
    console.log('Waiting for DNS records to commit...');
    await route53.waitFor('resourceRecordSetsChanged', {
      // Wait up to 5 minutes
      $waiter: {
        delay: 30,
        maxAttempts: 10
      },
      Id: changeBatch.ChangeInfo.Id
    }).promise();
  
    console.log('Waiting for validation...');
    await acm.waitFor('certificateValidated', {
      // Wait up to 5 minutes
      $waiter: {
        delay: 30,
        maxAttempts: 10
      },
      CertificateArn: reqCertResponse.CertificateArn
    }).promise();
  
    return reqCertResponse.CertificateArn;
  }
func_code_string: async function (requestId, domainName, subjectAlternativeNames, hostedZoneId) {
    const crypto = require('crypto');
    const acm = new aws.ACM();
    const route53 = new aws.Route53();
    if (waiter) {
      // Used by the test suite, since waiters aren't mockable yet
      route53.waitFor = acm.waitFor = waiter;
    }
  
    console.log(`Requesting certificate for ${domainName}`);
  
    const reqCertResponse = await acm.requestCertificate({
      DomainName: domainName,
      SubjectAlternativeNames: subjectAlternativeNames,
      IdempotencyToken: crypto.createHash('sha256').update(requestId).digest('hex').substr(0, 32),
      ValidationMethod: 'DNS'
    }).promise();
  
    console.log(`Certificate ARN: ${reqCertResponse.CertificateArn}`);
  
    console.log('Waiting for ACM to provide DNS records for validation...');
  
    var describeCertResponse;
    let attempt = 0;
    do {
      // Exponential backoff with jitter based on 100ms base
      await sleep(Math.random() * (Math.pow(attempt, 2) * 100));
      describeCertResponse = await acm.describeCertificate({
        CertificateArn: reqCertResponse.CertificateArn
      }).promise();
    } while (describeCertResponse.Certificate.DomainValidationOptions < 1 ||
      'ResourceRecord' in describeCertResponse.Certificate.DomainValidationOptions[0] === false);
  
    const record = describeCertResponse.Certificate.DomainValidationOptions[0].ResourceRecord;
  
    console.log(`Upserting DNS record into zone ${hostedZoneId}: ${record.Name} ${record.Type} ${record.Value}`);
  
    const changeBatch = await route53.changeResourceRecordSets({
      ChangeBatch: {
        Changes: [{
          Action: 'UPSERT',
          ResourceRecordSet: {
            Name: record.Name,
            Type: record.Type,
            TTL: 60,
            ResourceRecords: [{
              Value: record.Value
            }]
          }
        }]
      },
      HostedZoneId: hostedZoneId
    }).promise();
  
    console.log('Waiting for DNS records to commit...');
    await route53.waitFor('resourceRecordSetsChanged', {
      // Wait up to 5 minutes
      $waiter: {
        delay: 30,
        maxAttempts: 10
      },
      Id: changeBatch.ChangeInfo.Id
    }).promise();
  
    console.log('Waiting for validation...');
    await acm.waitFor('certificateValidated', {
      // Wait up to 5 minutes
      $waiter: {
        delay: 30,
        maxAttempts: 10
      },
      CertificateArn: reqCertResponse.CertificateArn
    }).promise();
  
    return reqCertResponse.CertificateArn;
  }
func_documentation_string: Requests a public certificate from AWS Certificate Manager, using DNS validation.
  The hosted zone ID must refer to a **public** Route53-managed DNS zone that is authoritative
  for the suffix of the certificate's Common Name (CN).  For example, if the CN is
  `*.example.com`, the hosted zone ID must point to a Route 53 zone authoritative
  for `example.com`.
  
  @param {string} requestId the CloudFormation request ID
  @param {string} domainName the Common Name (CN) field for the requested certificate
  @param {string} hostedZoneId the Route53 Hosted Zone ID
  @returns {string} Validated certificate ARN