docs: @Nonnull
    private static UserAgentElementList _decryptUserAgent (@Nonnull final String sUserAgent)
    {
      final UserAgentElementList ret = new UserAgentElementList ();
      final StringScanner aSS = new StringScanner (sUserAgent.trim ());
      while (true)
      {
        aSS.skipWhitespaces ();
        final int nIndex = aSS.findFirstIndex ('/', ' ', '[', '(');
        if (nIndex == -1)
          break;
  
        switch (aSS.getCharAtIndex (nIndex))
        {
          case '/':
          {
            // e.g. "a/b"
            final String sKey = aSS.getUntilIndex (nIndex);
            final String sValue = aSS.skip (1).getUntilWhiteSpace ();
            final String sFullValue = sKey + "/" + sValue;
            // Special handling of URLs :)
            if (URLProtocolRegistry.getInstance ().hasKnownProtocol (sFullValue))
              ret.add (sFullValue);
            else
              ret.add (Pair.create (sKey, sValue));
            break;
          }
          case ' ':
          {
            // e.g. "Opera 6.03"
            // e.g. "HTC_P3700 Opera/9.50 (Windows NT 5.1; U; de)"
            final String sText = aSS.getUntilIndex (nIndex).trim ();
            final Matcher aMatcher = RegExHelper.getMatcher ("([^\\s]+)\\s+([0-9]+\\.[0-9]+)", sText);
            if (aMatcher.matches ())
              ret.add (Pair.create (aMatcher.group (1), aMatcher.group (2)));
            else
              ret.add (sText);
            break;
          }
          case '[':
          {
            // e.g. "[en]"
            aSS.setIndex (nIndex).skip (1); // skip incl. "["
            ret.add (aSS.getUntil (']'));
            aSS.skip (1);
            break;
          }
          case '(':
          {
            // e.g. "(compatible; MSIE 5.0; Windows 2000)"
            aSS.setIndex (nIndex).skip (1); // skip incl. "("
            final String sParams = aSS.getUntilBalanced (1, '(', ')');
  
            // convert to ";" separated list
            final ICommonsList <String> aParams = StringHelper.getExploded (';', sParams);
            ret.add (aParams.getAllMapped (String::trim));
            break;
          }
          default:
            throw new IllegalStateException ("Invalid character: " + aSS.getCharAtIndex (nIndex));
        }
      }
  
      // add all remaining parts as is
      final String sRest = aSS.getRest ().trim ();
      if (sRest.length () > 0)
        ret.add (sRest);
      return ret;
    }