@Nonnull
    public MutableUserAgent parse(MutableUserAgent userAgent) {
        initializeMatchers();
        String useragentString = userAgent.getUserAgentString();
        if (useragentString != null && useragentString.length() > userAgentMaxLength) {
            setAsHacker(userAgent, 100);
            userAgent.setForced(HACKER_ATTACK_VECTOR, "Buffer overflow", 100);
            return userAgent;
        }

        synchronized (this) {
            // Reset all Matchers
            reset();

            if (userAgent.isDebug()) {
                for (Matcher matcher : allMatchers) {
                    matcher.setVerboseTemporarily(true);
                }
            }

            try {
                userAgent = flattener.parse(userAgent);

                inform(SYNTAX_ERROR, userAgent.getValue(SYNTAX_ERROR), null);

                if (verbose) {
                    LOG.info("=========== Checking all Touched Matchers: {}", touchedMatchers.size());
                }
                // Fire all Analyzers with any input
                for (Matcher matcher : touchedMatchers) {
                    matcher.analyze(userAgent);
                }

                if (verbose) {
                    LOG.info("=========== Checking all Zero Input Matchers: {}", zeroInputMatchers.size());
                }
                // Fire all Analyzers that should not get input
                for (Matcher matcher : zeroInputMatchers) {
                    matcher.analyze(userAgent);
                }

                userAgent.processSetAll();
            } catch (RuntimeException rte) {
                // If this occurs then someone has found a previously undetected problem.
                // So this is a safety for something that 'can' but 'should not' occur.
                userAgent.reset();
                setAsHacker(userAgent, 10000);
                userAgent.setForced(HACKER_ATTACK_VECTOR, "Yauaa Exploit", 10000);
            }
        }
        return userAgent;
    }
Parses and analyzes the useragent string provided in the MutableUserAgent instance.
NOTE: This method is internally synchronized because the way the analyzer works is not reentrant.
@param userAgent The MutableUserAgent instance that is to be parsed and that gets all results
@return An ImmutableUserAgent copy of the results that is suitable for further usage and caching.
analyzer/src/main/java/nl/basjes/parse/useragent/analyze/UserAgentStringMatchMaker.java