docs: private Decision internalEvaluate(
              Map<String, String> resource, Subject subject, String action,
              Set<Attribute> environment, List<AclRule> matchingRules
      )
      {
          long start = System.currentTimeMillis();
          if (matchingRules.size() < 1) {
              return authorize(
                      false,
                      "No context matches subject or environment",
                      Explanation.Code.REJECTED_NO_SUBJECT_OR_ENV_FOUND,
                      resource,
                      subject,
                      action,
                      environment,
                      System.currentTimeMillis() - start
              );
          }
          if (resource == null) {
              throw new IllegalArgumentException(
                      "Resource does not identify any resource because it's an empty resource property or null."
              );
          } else {
              for (Map.Entry<String, String> entry : resource.entrySet()) {
                  if (entry.getKey() == null) {
                      throw new IllegalArgumentException("Resource definition cannot contain null property name.");
                  }
                  if (entry.getValue() == null) {
                      throw new IllegalArgumentException(
                              "Resource definition cannot contain null value.  Corresponding key: " + entry.getKey()
                      );
                  }
              }
          }
  
          if (subject == null) {
              throw new IllegalArgumentException("Invalid subject, subject is null.");
          }
          if (action == null || action.length() <= 0) {
              return authorize(
                      false,
                      "No action provided.",
                      Explanation.Code.REJECTED_NO_ACTION_PROVIDED,
                      resource,
                      subject,
                      action,
                      environment,
                      System.currentTimeMillis() - start
              );
          }
          // environment can be null.
          if (environment == null) {
              environment = Collections.emptySet();
          }
  
  
          ContextDecision contextDecision = null;
          ContextDecision lastDecision = null;
  
          //long contextIncludeStart = System.currentTimeMillis();
          boolean granted = false;
          boolean denied = false;
          for (AclRule rule : matchingRules) {
              final ContextDecision includes = ruleIncludesResourceAction(rule, resource, action);
              if (Explanation.Code.REJECTED_DENIED == includes.getCode()) {
                  contextDecision = includes;
                  denied = true;
                  return createAuthorize(
                          false, contextDecision, resource, subject, action, environment,
                          System.currentTimeMillis() - start
                  );
              } else if (includes.granted()) {
                  contextDecision = includes;
                  granted = true;
              }
              lastDecision = includes;
          }
          if (granted) {
              return createAuthorize(
                      true, contextDecision, resource, subject, action, environment,
                      System.currentTimeMillis() - start
              );
          }
  
          if (lastDecision == null) {
              return authorize(
                      false,
                      "No resource or action matched.",
                      Explanation.Code.REJECTED_NO_RESOURCE_OR_ACTION_MATCH,
                      resource,
                      subject,
                      action,
                      environment,
                      System.currentTimeMillis() - start
              );
          } else {
              return createAuthorize(
                      false,
                      lastDecision,
                      resource,
                      subject,
                      action,
                      environment,
                      System.currentTimeMillis() - start
              );
          }
      }