class QQProfileDefinition extends OAuthProfileDefinition {

    /** Constant <code>OPENID_REGEX</code> */
    public static final Pattern OPENID_REGEX = Pattern.compile("\"openid\"\\s*:\\s*\"(\\S*?)\"");

    /** Constant <code>RET="ret"</code> */
    public static final String RET = "ret";

    /** Constant <code>MSG="msg"</code> */
    public static final String MSG = "msg";

    /** Constant <code>NICKNAME="nickname"</code> */
    public static final String NICKNAME = "nickname";

    /** Constant <code>PROVINCE="province"</code> */
    public static final String PROVINCE = "province";

    /** Constant <code>CITY="city"</code> */
    public static final String CITY = "city";

    /** Constant <code>YEAR="year"</code> */
    public static final String YEAR = "year";

    /** Constant <code>FIGUREURL="figureurl"</code> */
    public static final String FIGUREURL = "figureurl";

    /** Constant <code>FIGUREURL_1="figureurl_1"</code> */
    public static final String FIGUREURL_1 = "figureurl_1";

    /** Constant <code>FIGUREURL_2="figureurl_2"</code> */
    public static final String FIGUREURL_2 = "figureurl_2";

    /** Constant <code>FIGUREURL_QQ_1="figureurl_qq_1"</code> */
    public static final String FIGUREURL_QQ_1 = "figureurl_qq_1";

    /** Constant <code>FIGUREURL_QQ_2="figureurl_qq_2"</code> */
    public static final String FIGUREURL_QQ_2 = "figureurl_qq_2";

    /**
     * <p>Constructor for QQProfileDefinition.</p>
     */
    public QQProfileDefinition() {
        Arrays.stream(new String[]{
            MSG,
            NICKNAME,
            PROVINCE,
            CITY,
            YEAR
        }).forEach(a -> primary(a, Converters.STRING));
        Arrays.stream(new String[]{
            FIGUREURL,
            FIGUREURL_1,
            FIGUREURL_2,
            FIGUREURL_QQ_1,
            FIGUREURL_QQ_2
        }).forEach(a -> primary(a, Converters.URL));
        primary(RET, Converters.INTEGER);
        primary(GENDER, new GenderConverter("男", "女"));
        primary(YEAR, new DateConverter("yyyy"));
    }

    /**
     * <p>getOpenidUrl.</p>
     *
     * @param accessToken a {@link OAuth2AccessToken} object
     * @param configuration a {@link OAuth20Configuration} object
     * @return a {@link String} object
     */
    public String getOpenidUrl(OAuth2AccessToken accessToken, OAuth20Configuration configuration) {
        return "https://graph.qq.com/oauth2.0/me";
    }

    /** {@inheritDoc} */
    @Override
    public String getProfileUrl(final Token accessToken, final OAuthConfiguration configuration) {
        return "https://graph.qq.com/user/get_user_info";
    }

    /** {@inheritDoc} */
    @Override
    public QQProfile extractUserProfile(String body) {
        val profile = new QQProfile();
        val json = JsonHelper.getFirstNode(body);
        if (json != null) {
            for (val attribute : getPrimaryAttributes()) {
                convertAndAdd(profile, PROFILE_ATTRIBUTE, attribute,
                    JsonHelper.getElement(json, attribute));
            }
        } else {
            raiseProfileExtractionJsonError(body);
        }
        return profile;
    }

    /**
     * <p>extractOpenid.</p>
     *
     * @param body a {@link String} object
     * @return a {@link String} object
     */
    public String extractOpenid(String body) {
        var openid = extractParameter(body, OPENID_REGEX, true);
        return openid;
    }

    /**
     * <p>extractParameter.</p>
     *
     * @param response a {@link String} object
     * @param regexPattern a {@link Pattern} object
     * @param required a boolean
     * @return a {@link String} object
     * @throws OAuthException if any.
     */
    protected static String extractParameter(CharSequence response, Pattern regexPattern,
                                             boolean required)
        throws OAuthException {<FILL_FUNCTION_BODY>}
}

        val matcher = regexPattern.matcher(response);
        if (matcher.find()) {
            return matcher.group(1);
        }

        if (required) {
            throw new OAuthException(
                "Response body is incorrect. Can't extract a '" + regexPattern.pattern()
                    + "' from this: '" + response + "'", null);
        }

        return null;
    
<methods>public void <init>() ,public void <init>(org.pac4j.core.profile.factory.ProfileFactory) ,public abstract org.pac4j.core.profile.CommonProfile extractUserProfile(java.lang.String) ,public abstract java.lang.String getProfileUrl(com.github.scribejava.core.model.Token, org.pac4j.oauth.config.OAuthConfiguration) ,public com.github.scribejava.core.model.Verb getProfileVerb() <variables>