docs: public History[] getHistory(int profileId, String clientUUID, int offset, int limit, boolean withResponseData, HashMap<String, String[]> searchFilter, boolean hasMessage) throws Exception {
          ArrayList<History> returnData = new ArrayList<History>();
          Statement query = null;
          ResultSet results = null;
  
          Script[] scripts = ScriptService.getInstance().getScripts(Constants.SCRIPT_TYPE_HISTORY);
          String sqlQuery = "SELECT * FROM " + Constants.DB_TABLE_HISTORY + " ";
  
          int totalSearchLimit = -1;
  
          // see if profileId is set or not (-1)
          if (profileId != -1) {
              sqlQuery += "WHERE " + Constants.GENERIC_PROFILE_ID + "=" + profileId + " ";
          }
  
          if (clientUUID != null && clientUUID.compareTo("") != 0) {
              sqlQuery += "AND " + Constants.GENERIC_CLIENT_UUID + "='" + clientUUID + "' ";
          }
  
          sqlQuery += " ORDER BY " + Constants.GENERIC_ID + " DESC ";
  
          if (searchFilter == null && limit != -1) {
              sqlQuery += "LIMIT " + limit + " ";
              sqlQuery += "OFFSET " + offset;
          }
  
          if (hasMessage) {
              totalSearchLimit = 1000;
          }
  
          sqlQuery += ";";
  
          logger.info("Query: {}", sqlQuery);
  
          try (Connection sqlConnection = sqlService.getConnection()) {
              int entriesMatched = 0;
              // loop through all of the results, process filters and build an array of the results to return
              query = sqlConnection.createStatement();
              results = query.executeQuery(sqlQuery);
              int itemsViewed = 0;
              while (results.next() && (itemsViewed < totalSearchLimit || totalSearchLimit == -1)) {
                  itemsViewed++;
                  if (hasMessage && historyFromSQLResult(results, withResponseData, scripts).getValid()) {
                      continue;
                  }
                  if (searchFilter != null) {
                      // iterate over searchFilter and try to match the source URI
                      if (searchFilter.containsKey(Constants.HISTORY_FILTER_SOURCE_URI)) {
                          String[] sourceURIFilters = searchFilter.get(Constants.HISTORY_FILTER_SOURCE_URI);
  
                          int numMatches = 0;
  
                          // this will loop through all filters and count up the # of matches
                          // an item will be removed if the # of matches doesn't equal the number of filters
                          for (String uriFilter : sourceURIFilters) {
                              Pattern pattern = Pattern.compile(uriFilter);
                              Matcher matcher = pattern.matcher(results.getString(Constants.HISTORY_REQUEST_URL) +
                                                                    "?" + results.getString(Constants.HISTORY_REQUEST_PARAMS));
  
                              if (matcher.find()) {
                                  numMatches++;
                              }
                          }
  
                          if (numMatches != sourceURIFilters.length) {
                              // skip this item
                              continue;
                          }
                      }
                  }
  
                  entriesMatched++;
  
                  if (offset < entriesMatched) {
                      returnData.add(historyFromSQLResult(results, withResponseData, scripts));
                      if (limit != -1 && returnData.size() >= limit) {
                          break;
                      }
                  }
              }
          } catch (Exception e) {
              throw e;
          } finally {
              try {
                  if (results != null) {
                      results.close();
                  }
              } catch (Exception e) {
              }
              try {
                  if (query != null) {
                      query.close();
                  }
              } catch (Exception e) {
              }
          }
  
          return returnData.toArray(new History[0]);
      }