anchor.diff:      int n;
   
       while ( ( n = reader.read(buffer)) != -1 ) {
  -        content.append(buffer, 0, n);
  +      content.append(buffer, 0, n);
       }
       reader.close();
   
       String strResponse = content.toString();
   
       return strResponse;
  -}
  -
  -private String getNewTokenIfCredentialsAreSpecified(ServerUrl su, String url) throws IOException{
  +  }
  +
  +  private String getNewTokenIfCredentialsAreSpecified(ServerUrl su, String url) throws IOException{
       String token = "";
       boolean isUserLogin = (su.getUsername() != null && !su.getUsername().isEmpty()) && (su.getPassword() != null && !su.getPassword().isEmpty());
       boolean isAppLogin = (su.getClientId() != null && !su.getClientId().isEmpty()) && (su.getClientSecret() != null && !su.getClientSecret().isEmpty());
       if (isUserLogin || isAppLogin) {
  -        _log(Level.INFO, "Matching credentials found in configuration file. OAuth 2.0 mode: " + isAppLogin);
  -        if (isAppLogin) {
  -            //OAuth 2.0 mode authentication
  -            //"App Login" - authenticating using client_id and client_secret stored in config
  -            if (su.getOAuth2Endpoint() == null || su.getOAuth2Endpoint().isEmpty()){
  -                su.setOAuth2Endpoint(DEFAULT_OAUTH);
  -            }
  -            if (su.getOAuth2Endpoint().charAt(su.getOAuth2Endpoint().length() - 1) != '/') {
  -                su.setOAuth2Endpoint(su.getOAuth2Endpoint() + "/");
  -            }
  -            _log(Level.INFO, "Service is secured by " + su.getOAuth2Endpoint() + ": getting new token...");
  -            String uri = su.getOAuth2Endpoint() + "token?client_id=" + su.getClientId() + "&client_secret=" + su.getClientSecret() + "&grant_type=client_credentials&f=json";
  +      _log(Level.INFO, "Matching credentials found in configuration file. OAuth 2.0 mode: " + isAppLogin);
  +      if (isAppLogin) {
  +        //OAuth 2.0 mode authentication
  +        //"App Login" - authenticating using client_id and client_secret stored in config
  +        if (su.getOAuth2Endpoint() == null || su.getOAuth2Endpoint().isEmpty()){
  +          su.setOAuth2Endpoint(DEFAULT_OAUTH);
  +        }
  +        if (su.getOAuth2Endpoint().charAt(su.getOAuth2Endpoint().length() - 1) != '/') {
  +          su.setOAuth2Endpoint(su.getOAuth2Endpoint() + "/");
  +        }
  +        _log(Level.INFO, "Service is secured by " + su.getOAuth2Endpoint() + ": getting new token...");
  +        String uri = su.getOAuth2Endpoint() + "token?client_id=" + URLEncoder.encode(su.getClientId(),"UTF-8") + "&client_secret=" + URLEncoder.encode(su.getClientSecret(), "UTF-8") + "&grant_type=client_credentials&f=json";
  +        String tokenResponse = webResponseToString(doHTTPRequest(uri, "POST"));
  +        token = extractToken(tokenResponse, "access_token");
  +        if (token != null && !token.isEmpty()) {
  +          token = exchangePortalTokenForServerToken(token, su);
  +        }
  +      } else {
  +        //standalone ArcGIS Server token-based authentication
  +
  +        //if a request is already being made to generate a token, just let it go
  +        if (url.toLowerCase().contains("/generatetoken")){
  +          String tokenResponse = webResponseToString(doHTTPRequest(url, "POST"));
  +          token = extractToken(tokenResponse, "token");
  +          return token;
  +        }
  +
  +        String infoUrl = "";
  +        //lets look for '/rest/' in the request url (could be 'rest/services', 'rest/community'...)
  +        if (url.toLowerCase().contains("/rest/")){
  +          infoUrl = url.substring(0, url.indexOf("/rest/"));
  +          infoUrl += "/rest/info?f=json";
  +          //if we don't find 'rest', lets look for the portal specific 'sharing' instead
  +        }else if (url.toLowerCase().contains("/sharing/")){
  +          infoUrl = url.substring(0, url.indexOf("sharing"));
  +          infoUrl += "/sharing/rest/info?f=json";
  +        }else
  +          return "-1"; //return -1, signaling that infourl can not be found
  +
  +        if (infoUrl != "") {
  +
  +          _log(Level.INFO, "[Info]: Querying security endpoint...");
  +
  +          String tokenServiceUri = su.getTokenServiceUri();
  +
  +          if (tokenServiceUri == null || tokenServiceUri.isEmpty()){
  +            _log(Level.INFO, "Token URL not cached.  Querying rest info page...");
  +            String infoResponse = webResponseToString(doHTTPRequest(infoUrl, "GET"));
  +            tokenServiceUri = getJsonValue(infoResponse, "tokenServicesUrl");
  +            su.setTokenServiceUri(tokenServiceUri);
  +          }
  +
  +          if (tokenServiceUri != null & !tokenServiceUri.isEmpty()){
  +            _log(Level.INFO, "[Info]: Service is secured by " + tokenServiceUri + ": getting new token...");
  +            String uri = tokenServiceUri + "?f=json&request=getToken&referer=" + URLEncoder.encode(PROXY_REFERER,"UTF-8") + "&expiration=60&username=" + URLEncoder.encode(su.getUsername(),"UTF-8") + "&password=" + URLEncoder.encode(su.getPassword(), "UTF-8");
               String tokenResponse = webResponseToString(doHTTPRequest(uri, "POST"));
  -            token = extractToken(tokenResponse, "access_token");
  -            if (token != null && !token.isEmpty()) {
  -                token = exchangePortalTokenForServerToken(token, su);
  -            }
  -        } else {
  -            //standalone ArcGIS Server token-based authentication
  -
  -            //if a request is already being made to generate a token, just let it go
  -            if (url.toLowerCase().contains("/generatetoken")){
  -                String tokenResponse = webResponseToString(doHTTPRequest(url, "POST"));
  -                token = extractToken(tokenResponse, "token");
  -                return token;
  -            }
  -
  -            String infoUrl = "";
  -            //lets look for '/rest/' in the request url (could be 'rest/services', 'rest/community'...)
  -            if (url.toLowerCase().contains("/rest/")){
  -                infoUrl = url.substring(0, url.indexOf("/rest/"));
  -                infoUrl += "/rest/info?f=json";
  -            //if we don't find 'rest', lets look for the portal specific 'sharing' instead
  -            }else if (url.toLowerCase().contains("/sharing/")){
  -                infoUrl = url.substring(0, url.indexOf("sharing"));
  -                infoUrl += "/sharing/rest/info?f=json";
  -            }else
  -                return "-1"; //return -1, signaling that infourl can not be found
  -
  -            if (infoUrl != "") {
  -
  -                _log(Level.INFO, "[Info]: Querying security endpoint...");
  -
  -                String tokenServiceUri = su.getTokenServiceUri();
  -
  -                if (tokenServiceUri == null || tokenServiceUri.isEmpty()){
  -                    _log(Level.INFO, "Token URL not cached.  Querying rest info page...");
  -                    String infoResponse = webResponseToString(doHTTPRequest(infoUrl, "GET"));
  -                    tokenServiceUri = getJsonValue(infoResponse, "tokenServicesUrl");
  -                    su.setTokenServiceUri(tokenServiceUri);
  -                }
  -
  -                 if (tokenServiceUri != null & !tokenServiceUri.isEmpty()){
  -                    _log(Level.INFO, "[Info]: Service is secured by " + tokenServiceUri + ": getting new token...");
  -                    String uri = tokenServiceUri + "?f=json&request=getToken&referer=" + PROXY_REFERER + "&expiration=60&username=" + su.getUsername() + "&password=" + su.getPassword();
  -                    String tokenResponse = webResponseToString(doHTTPRequest(uri, "POST"));
  -                    token = extractToken(tokenResponse, "token");
  -                 }
  -            }
  -        }
  +            token = extractToken(tokenResponse, "token");
  +          }
  +        }
  +      }
       }
       return token;
  -}
  -
  -private boolean checkReferer(String[] allowedReferers, String referer){
  +  }
  +
  +  private boolean checkReferer(String[] allowedReferers, String referer){
       if (allowedReferers != null && allowedReferers.length > 0){
  -        if (allowedReferers.length == 1 && allowedReferers[0].equals("*")) return true; //speed-up
  -        for (String allowedReferer : allowedReferers){
  -            allowedReferer = allowedReferer.replaceAll("\\s", "");
  -            if (referer.toLowerCase().equals(allowedReferer.toLowerCase())) return true; //return true if match
  -            else if (allowedReferer.contains("*")){ //try if the allowed referer contains wildcard for subdomain
  -                 if (checkWildcardSubdomain(allowedReferer, referer)) return true;//return true if match wildcard subdomain
  -            }
  -        }
  -        return false;//no-match
  +      if (allowedReferers.length == 1 && allowedReferers[0].equals("*")) return true; //speed-up
  +      for (String allowedReferer : allowedReferers){
  +        allowedReferer = allowedReferer.replaceAll("\\s", "");
  +        if (referer.toLowerCase().equals(allowedReferer.toLowerCase())) return true; //return true if match
  +        else if (allowedReferer.contains("*")){ //try if the allowed referer contains wildcard for subdomain
  +          if (checkWildcardSubdomain(allowedReferer, referer)) return true;//return true if match wildcard subdomain
  +        }
  +      }
  +      return false;//no-match
       }
       return true;//when allowedReferer is null, then allow everything
  -}
  -
  -
  -private boolean checkWildcardSubdomain(String allowedReferer, String referer){
  +  }
  +
  +
  +  private boolean checkWildcardSubdomain(String allowedReferer, String referer){
       String[] allowedRefererParts = allowedReferer.split("(\\.)");
       String[] refererParts = referer.split("(\\.)");
   
       int allowedIndex = allowedRefererParts.length-1;
       int refererIndex = refererParts.length-1;
       while(allowedIndex >= 0 && refererIndex >= 0){
  -        if (allowedRefererParts[allowedIndex].equalsIgnoreCase(refererParts[refererIndex])){
  -            allowedIndex = allowedIndex - 1;
  -            refererIndex = refererIndex - 1;
  -        }else{
  -            if(allowedRefererParts[allowedIndex].equals("*")){
  -                allowedIndex = allowedIndex - 1;
  -                refererIndex = refererIndex - 1;
  -                continue; //next
  -            }
  -            return false;
  -        }
  +      if (allowedRefererParts[allowedIndex].equalsIgnoreCase(refererParts[refererIndex])){
  +        allowedIndex = allowedIndex - 1;
  +        refererIndex = refererIndex - 1;
  +      }else{
  +        if(allowedRefererParts[allowedIndex].equals("*")){
  +          allowedIndex = allowedIndex - 1;
  +          refererIndex = refererIndex - 1;
  +          continue; //next
  +        }
  +        return false;
  +      }
       }
       return true;
  -}
  -
  -private String getFullUrl(String url){
  +  }
  +
  +  private String getFullUrl(String url){
       return url.startsWith("//") ? url.replace("//","https://") : url;
  -}
  -
  -private String exchangePortalTokenForServerToken(String portalToken, ServerUrl su) throws IOException{
  +  }
  +
  +  private String exchangePortalTokenForServerToken(String portalToken, ServerUrl su) throws IOException{
       String url = getFullUrl(su.getUrl());
       _log(Level.INFO, "[Info]: Exchanging Portal token for Server-specific token for " + url + "...");
       String uri = su.getOAuth2Endpoint().substring(0, su.getOAuth2Endpoint().toLowerCase().indexOf("/oauth2/")) +
  -         "/generateToken?token=" + portalToken + "&serverURL=" + url + "&f=json";
  +            "/generateToken?token=" + URLEncoder.encode(portalToken,"UTF-8") + "&serverURL=" + URLEncoder.encode(url,"UTF-8") + "&f=json";
       String tokenResponse = webResponseToString(doHTTPRequest(uri, "GET"));
       return extractToken(tokenResponse, "token");
  -}
  -
  -private String addTokenToUri(String uri, String token) {
  +  }
  +
  +  private String addTokenToUri(String uri, String token) {
       if (token != null && !token.isEmpty())
  -        uri += uri.contains("?") ? "&token=" + token : "?token=" + token;
  +      uri += uri.contains("?") ? "&token=" + token : "?token=" + token;
       return uri;
  -}
  -
  -private String extractToken(String tokenResponse, String key) {
  +  }
  +
  +  private String extractToken(String tokenResponse, String key) {
       String token = getJsonValue(tokenResponse, key);
       if (token == null || token.isEmpty()) {
  -        _log(Level.WARNING, "Token cannot be obtained: " + tokenResponse);
  +      _log(Level.WARNING, "Token cannot be obtained: " + tokenResponse);
       } else {
  -        _log(Level.INFO, "Token obtained: " + token);
  +      _log(Level.INFO, "Token obtained: " + token);
       }
       return token;
  -}
  -
  -private String getJsonValue(String text, String key) {
  +  }
  +
  +  private String getJsonValue(String text, String key) {
       _log(Level.FINE, "JSON Response: " + text);
       int i = text.indexOf(key);
       String value = "";
       if (i > -1) {
  -        value = text.substring(text.indexOf(':', i) + 1).trim();
  -        value = (value.length() > 0 && value.charAt(0) == '"') ?
  -            value.substring(1, value.indexOf('"', 1)) :
  -            value.substring(0, Math.max(0, Math.min(Math.min(value.indexOf(","), value.indexOf("]")), value.indexOf("}"))));
  +      value = text.substring(text.indexOf(':', i) + 1).trim();
  +      value = (value.length() > 0 && value.charAt(0) == '"') ?
  +              value.substring(1, value.indexOf('"', 1)) :
  +              value.substring(0, Math.max(0, Math.min(Math.min(value.indexOf(","), value.indexOf("]")), value.indexOf("}"))));
       }
       _log(Level.FINE, "Extracted Value: " + value);
       return value;
  -}
  -
  -private void cleanUpRatemap(ConcurrentHashMap<String, RateMeter> ratemap) {
  +  }
  +
  +  private void cleanUpRatemap(ConcurrentHashMap<String, RateMeter> ratemap) {
       Set<Map.Entry<String, RateMeter>> entrySet = ratemap.entrySet();
       for (Map.Entry<String,RateMeter> entry : entrySet){
  -        RateMeter rate = entry.getValue();
  -        if (rate.canBeCleaned())
  -            ratemap.remove(entry.getKey(), rate);
  -    }
  -}
  -
  -/**
  -* Static
  -*/
  -
  -    private static ProxyConfig getConfig()  throws IOException{
  -        ProxyConfig config = ProxyConfig.getCurrentConfig();
  -        if (config != null)
  -            return config;
  -        else
  -            throw new FileNotFoundException("The proxy configuration file");
  -    }
  -
  -    //writing Log file
  -    private static Object _lockobject = new Object();
  -    private static Logger logger = Logger.getLogger("ESRI_PROXY_LOGGER");
  -
  -    private boolean okToLog(){
  -        try{
  -            ProxyConfig proxyConfig = getConfig();
  -            String filename = proxyConfig.getLogFile();
  -            return filename != null && filename != "" && !filename.isEmpty() && logger != null;
  -        }catch (Exception e) {
  -            e.printStackTrace();
  -        }
  +      RateMeter rate = entry.getValue();
  +      if (rate.canBeCleaned())
  +        ratemap.remove(entry.getKey(), rate);
  +    }
  +  }
  +
  +  /**
  +   * Static
  +   */
  +
  +  private static ProxyConfig getConfig()  throws IOException{
  +    ProxyConfig config = ProxyConfig.getCurrentConfig();
  +    if (config != null)
  +      return config;
  +    else
  +      throw new FileNotFoundException("The proxy configuration file");
  +  }
  +
  +  //writing Log file
  +  private static Object _lockobject = new Object();
  +  private static Logger logger = Logger.getLogger("ESRI_PROXY_LOGGER");
  +
  +  private boolean okToLog(){
  +    try{
  +      ProxyConfig proxyConfig = getConfig();
  +      String filename = proxyConfig.getLogFile();
  +      return filename != null && filename != "" && !filename.isEmpty() && logger != null;
  +    }catch (Exception e) {
  +      e.printStackTrace();
  +    }
  +    return false;
  +  }
  +
  +  private static void _log(Level level, String s, Throwable thrown) {
  +    try {
  +
  +      ProxyConfig proxyConfig = getConfig();
  +      String filename = proxyConfig.getLogFile();
  +      boolean okToLog = filename != null && !filename.isEmpty() && logger != null;
  +      synchronized (_lockobject) {
  +
  +        if (okToLog) {
  +
  +          if (logger.getUseParentHandlers()){
  +            FileHandler fh = new FileHandler(filename, true);
  +            logger.addHandler(fh);
  +            SimpleFormatter formatter = new SimpleFormatter();
  +            fh.setFormatter(formatter);
  +            logger.setUseParentHandlers(false);
  +
  +            String logLevelStr = proxyConfig.getLogLevel();
  +            Level logLevel = Level.SEVERE;
  +
  +            if (logLevelStr != null){
  +              try {
  +                logLevel = Level.parse(logLevelStr);
  +              } catch (IllegalArgumentException e) {
  +                SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  +                System.err.println(dt.format(new Date()) + ": " + logLevelStr + " is not a valid logging level.  Defaulting to SEVERE.");
  +              }
  +            }
  +
  +            logger.setLevel(logLevel);
  +
  +            logger.info("Log handler configured and initialized.");
  +          }
  +
  +          if (thrown != null){
  +            logger.log(level, s, thrown);
  +          } else {
  +            logger.log(level, s);
  +          }
  +        }
  +      }
  +    }
  +    catch (Exception e) {
  +      SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  +      System.err.println("Error writing to log: ");
  +      System.err.println(dt.format(new Date()) + " " + s);
  +      e.printStackTrace();
  +    }
  +  }
  +
  +  private static void _log(String s, Throwable thrown){
  +    _log(Level.SEVERE, s, thrown);
  +  }
  +
  +  private static void _log(Level level, String s){
  +    _log(level, s, null);
  +  }
  +
  +  public static class ProxyConfig
  +  {
  +    public boolean canReadProxyConfig(){
  +      InputStream configFile = ProxyConfig.class.getClassLoader().getResourceAsStream("proxy.config");
  +      if (configFile != null)
  +        return true;
  +      else
           return false;
       }
   
  -    private static void _log(Level level, String s, Throwable thrown) {
  -        try {
  -
  -            ProxyConfig proxyConfig = getConfig();
  -            String filename = proxyConfig.getLogFile();
  -            boolean okToLog = filename != null && !filename.isEmpty() && logger != null;
  -            synchronized (_lockobject) {
  -
  -                if (okToLog) {
  -
  -                    if (logger.getUseParentHandlers()){
  -                        FileHandler fh = new FileHandler(filename, true);
  -                        logger.addHandler(fh);
  -                        SimpleFormatter formatter = new SimpleFormatter();
  -                        fh.setFormatter(formatter);
  -                        logger.setUseParentHandlers(false);
  -
  -                        String logLevelStr = proxyConfig.getLogLevel();
  -                        Level logLevel = Level.SEVERE;
  -
  -                        if (logLevelStr != null){
  -                            try {
  -                                logLevel = Level.parse(logLevelStr);
  -                            } catch (IllegalArgumentException e) {
  -                                SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  -                                System.err.println(dt.format(new Date()) + ": " + logLevelStr + " is not a valid logging level.  Defaulting to SEVERE.");
  -                            }
  -                        }
  -
  -                        logger.setLevel(logLevel);
  -
  -                        logger.info("Log handler configured and initialized.");
  -                    }
  -
  -                    if (thrown != null){
  -                        logger.log(level, s, thrown);
  -                    } else {
  -                        logger.log(level, s);
  -                    }
  +    public synchronized static ProxyConfig loadProxyConfig()  throws IOException{
  +      ProxyConfig config = null;
  +
  +      InputStream configFile = ProxyConfig.class.getClassLoader().getResourceAsStream("proxy.config");
  +      if (configFile != null) {
  +        BufferedReader reader = new BufferedReader( new InputStreamReader (configFile, "UTF-8"));
  +        String line = null;
  +        StringBuilder stringBuilder = new StringBuilder();
  +
  +        while( ( line = reader.readLine() ) != null ) {
  +          stringBuilder.append( line );
  +        }
  +
  +        String configFileStr = stringBuilder.toString();
  +        configFileStr = configFileStr.replaceAll("(?ms)<!\\-\\-(.+?)\\-\\->", "");
  +
  +        Pattern p = Pattern.compile("<\\s*ProxyConfig(.+?)>", Pattern.MULTILINE | Pattern.DOTALL);
  +        Matcher m = p.matcher(configFileStr);
  +        boolean found = m.find();
  +
  +        if (found){
  +
  +          String proxyConfigAttributes = m.group(1);
  +
  +          config = new ProxyConfig();
  +
  +          if (proxyConfigAttributes != null && !proxyConfigAttributes.isEmpty()){
  +            String mustMatch = ProxyConfig.getAttributeWithRegex("mustMatch", proxyConfigAttributes);
  +            if (mustMatch != null && !mustMatch.isEmpty()){
  +              config.setMustMatch(Boolean.parseBoolean(mustMatch));
  +            }
  +
  +            String allowedReferers = ProxyConfig.getAttributeWithRegex("allowedReferers", proxyConfigAttributes);
  +            if (allowedReferers != null && !allowedReferers.isEmpty()){
  +              config.setAllowedReferers(allowedReferers.split(","));
  +            }
  +
  +            String logFile = ProxyConfig.getAttributeWithRegex("logFile", proxyConfigAttributes);
  +            if (logFile != null && !logFile.isEmpty()){
  +              config.setLogFile(logFile);
  +            }
  +
  +            String logLevel = ProxyConfig.getAttributeWithRegex("logLevel", proxyConfigAttributes);
  +            if (logLevel != null && !logLevel.isEmpty()){
  +              config.setLogLevel(logLevel);
  +            }
  +
  +
  +            p = Pattern.compile("<\\s*serverUrls\\s*>(.+?)<\\s*/\\s*serverUrls\\s*>", Pattern.MULTILINE | Pattern.DOTALL);
  +            m = p.matcher(configFileStr);
  +            found = m.find();
  +
  +            if (found) {
  +              String serverUrls = m.group(1);
  +              if (serverUrls != null && !serverUrls.isEmpty()) {
  +                p = Pattern.compile("<\\s*serverUrl (.+?)((<\\s*/\\s*serverUrl\\s*)|/)>", Pattern.MULTILINE | Pattern.DOTALL);
  +                m = p.matcher(serverUrls);
  +
  +                ArrayList<ServerUrl> serverList = new ArrayList<ServerUrl>();
  +                while(m.find()){
  +                  String server = m.group(1);
  +                  String url = ProxyConfig.getAttributeWithRegex("url", server);
  +                  String matchAll = ProxyConfig.getAttributeWithRegex("matchAll", server);
  +                  String oauth2Endpoint = ProxyConfig.getAttributeWithRegex("oauth2Endpoint", server);
  +                  String username = ProxyConfig.getAttributeWithRegex("username", server);
  +                  String password = ProxyConfig.getAttributeWithRegex("password", server);
  +                  String clientId = ProxyConfig.getAttributeWithRegex("clientId", server);
  +                  String clientSecret = ProxyConfig.getAttributeWithRegex("clientSecret", server);
  +                  String rateLimit = ProxyConfig.getAttributeWithRegex("rateLimit", server);
  +                  String rateLimitPeriod = ProxyConfig.getAttributeWithRegex("rateLimitPeriod", server);
  +                  String tokenServiceUri = ProxyConfig.getAttributeWithRegex("tokenServiceUri", server);
  +
  +                  serverList.add(new ServerUrl(url, matchAll, oauth2Endpoint, username, password, clientId, clientSecret, rateLimit, rateLimitPeriod, tokenServiceUri));
                   }
  +
  +                config.setServerUrls(serverList.toArray(new ServerUrl[serverList.size()]));
  +              }
               }
  -        }
  -        catch (Exception e) {
  -            SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  -            System.err.println("Error writing to log: ");
  -            System.err.println(dt.format(new Date()) + " " + s);
  -            e.printStackTrace();
  -        }
  -    }
  -
  -    private static void _log(String s, Throwable thrown){
  -        _log(Level.SEVERE, s, thrown);
  -    }
  -
  -    private static void _log(Level level, String s){
  -        _log(level, s, null);
  -    }
  -
  -public static class ProxyConfig
  -{
  -    public boolean canReadProxyConfig(){
  -        InputStream configFile = ProxyConfig.class.getClassLoader().getResourceAsStream("proxy.config");
  -        if (configFile != null)
  -            return true;
  -        else
  -            return false;
  -    }
  -
  -    public synchronized static ProxyConfig loadProxyConfig()  throws IOException{
  -        ProxyConfig config = null;
  -
  -        InputStream configFile = ProxyConfig.class.getClassLoader().getResourceAsStream("proxy.config");
  -         if (configFile != null) {
  -             BufferedReader reader = new BufferedReader( new InputStreamReader (configFile, "UTF-8"));
  -             String line = null;
  -             StringBuilder stringBuilder = new StringBuilder();
  -
  -             while( ( line = reader.readLine() ) != null ) {
  -                 stringBuilder.append( line );
  -             }
  -
  -             String configFileStr = stringBuilder.toString();
  -             configFileStr = configFileStr.replaceAll("(?ms)<!\\-\\-(.+?)\\-\\->", "");
  -
  -             Pattern p = Pattern.compile("<\\s*ProxyConfig(.+?)>", Pattern.MULTILINE | Pattern.DOTALL);
  -             Matcher m = p.matcher(configFileStr);
  -             boolean found = m.find();
  -
  -             if (found){
  -
  -                 String proxyConfigAttributes = m.group(1);
  -
  -                 config = new ProxyConfig();
  -
  -                 if (proxyConfigAttributes != null && !proxyConfigAttributes.isEmpty()){
  -                    String mustMatch = ProxyConfig.getAttributeWithRegex("mustMatch", proxyConfigAttributes);
  -                    if (mustMatch != null && !mustMatch.isEmpty()){
  -                        config.setMustMatch(Boolean.parseBoolean(mustMatch));
  -                    }
  -
  -                    String allowedReferers = ProxyConfig.getAttributeWithRegex("allowedReferers", proxyConfigAttributes);
  -                    if (allowedReferers != null && !allowedReferers.isEmpty()){
  -                        config.setAllowedReferers(allowedReferers.split(","));
  -                    }
  -
  -                    String logFile = ProxyConfig.getAttributeWithRegex("logFile", proxyConfigAttributes);
  -                    if (logFile != null && !logFile.isEmpty()){
  -                        config.setLogFile(logFile);
  -                    }
  -
  -                    String logLevel = ProxyConfig.getAttributeWithRegex("logLevel", proxyConfigAttributes);
  -                    if (logLevel != null && !logLevel.isEmpty()){
  -                        config.setLogLevel(logLevel);
  -                    }
  -
  -
  -                    p = Pattern.compile("<\\s*serverUrls\\s*>(.+?)<\\s*/\\s*serverUrls\\s*>", Pattern.MULTILINE | Pattern.DOTALL);
  -                    m = p.matcher(configFileStr);
  -                    found = m.find();
  -
  -                    if (found) {
  -                        String serverUrls = m.group(1);
  -                        if (serverUrls != null && !serverUrls.isEmpty()) {
  -                            p = Pattern.compile("<\\s*serverUrl (.+?)((<\\s*/\\s*serverUrl\\s*)|/)>", Pattern.MULTILINE | Pattern.DOTALL);
  -                            m = p.matcher(serverUrls);
  -
  -                            ArrayList<ServerUrl> serverList = new ArrayList<ServerUrl>();
  -                            while(m.find()){
  -                                String server = m.group(1);
  -                                String url = ProxyConfig.getAttributeWithRegex("url", server);
  -                                String matchAll = ProxyConfig.getAttributeWithRegex("matchAll", server);
  -                                String oauth2Endpoint = ProxyConfig.getAttributeWithRegex("oauth2Endpoint", server);
  -                                String username = ProxyConfig.getAttributeWithRegex("username", server);
  -                                String password = ProxyConfig.getAttributeWithRegex("password", server);
  -                                String clientId = ProxyConfig.getAttributeWithRegex("clientId", server);
  -                                String clientSecret = ProxyConfig.getAttributeWithRegex("clientSecret", server);
  -                                String rateLimit = ProxyConfig.getAttributeWithRegex("rateLimit", server);
  -                                String rateLimitPeriod = ProxyConfig.getAttributeWithRegex("rateLimitPeriod", server);
  -                                String tokenServiceUri = ProxyConfig.getAttributeWithRegex("tokenServiceUri", server);
  -
  -                                serverList.add(new ServerUrl(url, matchAll, oauth2Endpoint, username, password, clientId, clientSecret, rateLimit, rateLimitPeriod, tokenServiceUri));
  -                            }
  -
  -                            config.setServerUrls(serverList.toArray(new ServerUrl[serverList.size()]));
  -                        }
  -                    }
  -                 }
  -
  -
  -             }
  -         }
  -         return config;
  +          }
  +
  +
  +        }
  +      }
  +      return config;
   
       }
   
       private static String getAttributeWithRegex(String property, String tag){
  -        Pattern p = Pattern.compile(property + "=\\s*\"\\s*(.+?)\\s*\"");
  -        Matcher m = p.matcher(tag);
  -        boolean found = m.find();
  -        String match = null;
  -        if (found){
  -            match = m.group(1);
  -        }
  -
  -        return match;
  +      Pattern p = Pattern.compile(property + "=\\s*\"\\s*(.+?)\\s*\"");
  +      Matcher m = p.matcher(tag);
  +      boolean found = m.find();
  +      String match = null;
  +      if (found){
  +        match = m.group(1);
  +      }
  +
  +      return match;
   
       }
   
  
positive.code:     String[] allowedReferers;
  
      public ServerUrl[] getServerUrls() {
         return this.serverUrls;
      }
      public void setServerUrls(ServerUrl[] value){
          this.serverUrls = value;
      }
  
      public boolean getMustMatch(){
          return this.mustMatch;
      }
      public void setMustMatch(boolean value){
          this.mustMatch = value;
      }
  
      public String[] getAllowedReferers(){
          return this.allowedReferers;
      }
      public void setAllowedReferers(String[] value){
          this.allowedReferers = value;
      }
  
      public String getLogFile(){
          return this.logFile;
      }
      public void setLogFile(String value){
          this.logFile = value;
      }
  
      public String getLogLevel(){
          return this.logLevel;
      }
      public void setLogLevel(String value){
          this.logLevel = value;
      }
  
      public ServerUrl getConfigServerUrl(String uri) {
          //split request URL to compare with allowed server URLs
          String[] uriParts = uri.split("(/)|(\\?)");
          String[] configUriParts = new String[] {};
  
          for (ServerUrl su : serverUrls) {
              //if a relative path is specified in the proxy configuration file, append what's in the request itself
              if (!su.getUrl().startsWith("http"))
                  su.setUrl(new StringBuilder(su.getUrl()).insert(0, uriParts[0]).toString());
  
              configUriParts = su.getUrl().split("/");
  
              //if the request has less parts than the config, don't allow
              if (configUriParts.length > uriParts.length) continue;
  
              int i = 1;
              //skip comparing the protocol, so that either http or https is considered valid
              for (i = 1; i < configUriParts.length; i++)
              {
                  if (!configUriParts[i].toLowerCase().equals(uriParts[i].toLowerCase()) ) break;
              }
              if (i == configUriParts.length)
              {
                  //if the urls don't match exactly, and the individual matchAll tag is 'false', don't allow
                  if (configUriParts.length == uriParts.length || su.getMatchAll())
                      return su;
              }
          }
  
          if (this.mustMatch)
              return null;//if nothing match and mustMatch is true, return null
        else
              return new ServerUrl(uri); //if mustMatch is false send the server URL back that is the same the uri to pass thru
      }
  
      public static boolean isUrlPrefixMatch(String prefix, String uri){
          return uri.toLowerCase().startsWith(prefix.toLowerCase()) ||
                  uri.toLowerCase().replace("https://","http://").startsWith(prefix.toLowerCase()) ||
                  uri.toLowerCase().substring(uri.indexOf("//")).startsWith(prefix.toLowerCase());
      }
  }
  
  public static class ServerUrl {
      String url;
      boolean matchAll;
      String oauth2Endpoint;
  
negative.code:             postBody.length > 0 ?
                      doHTTPRequest(uri, postBody, "POST", mapHeaderInfo) :
                      doHTTPRequest(uri, request.getMethod());
    }
  
    private boolean fetchAndPassBackToClient(HttpURLConnection con, HttpServletResponse clientResponse, boolean ignoreAuthenticationErrors) throws IOException{
      if (con!=null){
        Map<String, List<String>> headerFields = con.getHeaderFields();
  
        Set<String> headerFieldsSet = headerFields.keySet();
        Iterator<String> hearerFieldsIter = headerFieldsSet.iterator();
  
        while (hearerFieldsIter.hasNext()){
          String headerFieldKey = hearerFieldsIter.next();
          List<String> headerFieldValue = headerFields.get(headerFieldKey);
          StringBuilder sb = new StringBuilder();
          for (String value : headerFieldValue) {
            sb.append(value);
            sb.append("");
          }
          if (headerFieldKey != null) clientResponse.addHeader(headerFieldKey, sb.toString());
        }
  
        InputStream byteStream;
        if (con.getResponseCode() >= 400 && con.getErrorStream() != null){
          if (ignoreAuthenticationErrors && (con.getResponseCode() == 498 || con.getResponseCode() == 499)) return true;
          byteStream = con.getErrorStream();
        }else{
          byteStream = con.getInputStream();
        }
  
        clientResponse.setStatus(con.getResponseCode());
  
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        final int length = 5000;
  
        byte[] bytes = new byte[length];
        int bytesRead = 0;
  
        while ((bytesRead = byteStream.read(bytes, 0, length)) > 0) {
          buffer.write(bytes, 0, bytesRead);
        }
        buffer.flush();
  
        byte[] byteResponse = buffer.toByteArray();
        OutputStream ostream = clientResponse.getOutputStream();
        ostream.write(byteResponse);
        ostream.close();
        byteStream.close();
      }
      return false;
    }
  
    private boolean passHeadersInfo(Map mapHeaderInfo, HttpURLConnection con) {
      Iterator headerIterator = mapHeaderInfo.entrySet().iterator();
      while (headerIterator.hasNext()) {
        Map.Entry pair = (Map.Entry)headerIterator.next();
  