// Path: httpsig/callout/src/main/java/com/google/apigee/util/TimeResolver.java
// public class TimeResolver {
//     private static final Pattern expiryPattern =
//         Pattern.compile("^([1-9][0-9]*)(s|m|h|d|w|)$", Pattern.CASE_INSENSITIVE);
//     private static final Map<String, Long> timeMultipliers;
//     private static String defaultUnit = "s";
// 
//     static {
//       Map<String, Long> m1 = new HashMap<String, Long>();
//       m1.put("s", 1L );
//       m1.put("m", 60L);
//       m1.put("h", 60L * 60 );
//       m1.put("d", 60L * 60 * 24 );
//       m1.put("w", 60L * 60 * 24 * 7 );
//       timeMultipliers = Collections.unmodifiableMap(m1);
//     }
// 
//     public static ZonedDateTime getExpiryDate(String expiresInString) {
//       Long milliseconds = resolveExpression(expiresInString);
//       Long seconds = milliseconds / 1000;
//       int secondsToAdd = seconds.intValue();
//       if (secondsToAdd <= 0) return null; /* no expiry */
//       ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
//       zdt = zdt.plusSeconds(secondsToAdd);
//       return zdt;
//     }
// 
//     /*
//      * Convert a simple time duration string, expressed in days, hours, minutes,
//      * or seconds, in a form like 30d, 12d, 8h, 24h, 45m, 30s, into a numeric
//      * quantity in seconds.  Eg, "10s" is converted to 10. "10m" is converted to 600.
//      *
//      * Default TimeUnit is s. Eg. the string "30" is treated as 30s.
//      */
//     public static Long resolveExpression(String subject) {
//       Matcher m = expiryPattern.matcher(subject);
//       if (m.find()) {
//         String key = m.group(2);
//         if (key.equals("")) key = defaultUnit;
//         return Long.parseLong(m.group(1), 10) * timeMultipliers.get(key);
//       }
//       return -1L;
//     }
//   }


import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.IOIntensive;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import com.google.apigee.util.TimeResolver;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
  }

  private String getRequiredHs2019Algorithm(MessageContext msgCtxt) throws Exception {
    String algorithm = (String) this.properties.get("hs2019-algorithm");
    if (algorithm == null) {
      throw new IllegalStateException("hs2019-algorithm is not specified.");
    }
    algorithm = algorithm.trim();
    if (algorithm.equals("")) {
      throw new IllegalStateException("hs2019-algorithm is not specified.");
    }

    algorithm = PackageUtils.resolvePropertyValue(algorithm, msgCtxt);
    if (algorithm == null || algorithm.equals("")) {
      throw new IllegalStateException("hs2019-algorithm resolves to an empty string.");
    }
    return algorithm;
  }

  private long getMaxTimeSkew(MessageContext msgCtxt) throws Exception {
    final long defaultMaxSkew = 60L;
    String timeskew = (String) this.properties.get("maxtimeskew");
    if (timeskew == null) {
      return defaultMaxSkew;
    }
    timeskew = timeskew.trim();
    if (timeskew.equals("")) {
      return defaultMaxSkew;
    }
    timeskew = PackageUtils.resolvePropertyValue(timeskew, msgCtxt);
// Path: httpsig/callout/src/main/java/com/google/apigee/util/TimeResolver.java
// public class TimeResolver {
//     private static final Pattern expiryPattern =
//         Pattern.compile("^([1-9][0-9]*)(s|m|h|d|w|)$", Pattern.CASE_INSENSITIVE);
//     private static final Map<String, Long> timeMultipliers;
//     private static String defaultUnit = "s";
// 
//     static {
//       Map<String, Long> m1 = new HashMap<String, Long>();
//       m1.put("s", 1L );
//       m1.put("m", 60L);
//       m1.put("h", 60L * 60 );
//       m1.put("d", 60L * 60 * 24 );
//       m1.put("w", 60L * 60 * 24 * 7 );
//       timeMultipliers = Collections.unmodifiableMap(m1);
//     }
// 
//     public static ZonedDateTime getExpiryDate(String expiresInString) {
//       Long milliseconds = resolveExpression(expiresInString);
//       Long seconds = milliseconds / 1000;
//       int secondsToAdd = seconds.intValue();
//       if (secondsToAdd <= 0) return null; /* no expiry */
//       ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
//       zdt = zdt.plusSeconds(secondsToAdd);
//       return zdt;
//     }
// 
//     /*
//      * Convert a simple time duration string, expressed in days, hours, minutes,
//      * or seconds, in a form like 30d, 12d, 8h, 24h, 45m, 30s, into a numeric
//      * quantity in seconds.  Eg, "10s" is converted to 10. "10m" is converted to 600.
//      *
//      * Default TimeUnit is s. Eg. the string "30" is treated as 30s.
//      */
//     public static Long resolveExpression(String subject) {
//       Matcher m = expiryPattern.matcher(subject);
//       if (m.find()) {
//         String key = m.group(2);
//         if (key.equals("")) key = defaultUnit;
//         return Long.parseLong(m.group(1), 10) * timeMultipliers.get(key);
//       }
//       return -1L;
//     }
//   }


// Path: httpsig/callout/src/main/java/com/google/apigee/callout/httpsignature/SignatureVerifierCallout.java
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.apigee.flow.execution.ExecutionContext;
import com.apigee.flow.execution.ExecutionResult;
import com.apigee.flow.execution.IOIntensive;
import com.apigee.flow.execution.spi.Execution;
import com.apigee.flow.message.MessageContext;
import com.google.apigee.util.TimeResolver;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;

  }

  private String getRequiredHs2019Algorithm(MessageContext msgCtxt) throws Exception {
    String algorithm = (String) this.properties.get("hs2019-algorithm");
    if (algorithm == null) {
      throw new IllegalStateException("hs2019-algorithm is not specified.");
    }
    algorithm = algorithm.trim();
    if (algorithm.equals("")) {
      throw new IllegalStateException("hs2019-algorithm is not specified.");
    }

    algorithm = PackageUtils.resolvePropertyValue(algorithm, msgCtxt);
    if (algorithm == null || algorithm.equals("")) {
      throw new IllegalStateException("hs2019-algorithm resolves to an empty string.");
    }
    return algorithm;
  }

  private long getMaxTimeSkew(MessageContext msgCtxt) throws Exception {
    final long defaultMaxSkew = 60L;
    String timeskew = (String) this.properties.get("maxtimeskew");
    if (timeskew == null) {
      return defaultMaxSkew;
    }
    timeskew = timeskew.trim();
    if (timeskew.equals("")) {
      return defaultMaxSkew;
    }
    timeskew = PackageUtils.resolvePropertyValue(timeskew, msgCtxt);
    Long durationInSeconds = TimeResolver.resolveExpression(timeskew);