text:
const NAME = 'oauth4webapi';
const VERSION = 'v0.9.0';
const HOMEPAGE = 'https://github.com/panva/oauth4webapi';
const USER_AGENT = `${NAME}/${VERSION} (${HOMEPAGE})`;
const encoder = new TextEncoder();
const decoder = new TextDecoder();
function buf(input) {
    if (typeof input === 'string') {
        return encoder.encode(input);
    }
    return decoder.decode(input);
}
const CHUNK_SIZE = 0x8000;
function encodeBase64Url(input) {
    if (input instanceof ArrayBuffer) {
        input = new Uint8Array(input);
    }
    const arr = [];
    for (let i = 0; i < input.byteLength; i += CHUNK_SIZE) {
        arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
    }
    return btoa(arr.join('')).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}
function decodeBase64Url(input) {
    try {
        const binary = atob(input.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, ''));
        const bytes = new Uint8Array(binary.length);
        for (let i = 0; i < binary.length; i++) {
            bytes[i] = binary.charCodeAt(i);
        }
        return bytes;
    }
    catch {
        throw new TypeError('The input to be decoded is not correctly encoded.');
    }
}
function b64u(input) {
    if (typeof input === 'string') {
        return decodeBase64Url(input);
    }
    return encodeBase64Url(input);
}
class LRU {
    constructor(maxSize) {
        this.cache = new Map();
        this._cache = new Map();
        this.maxSize = maxSize;
    }
    get(key) {
        let v = this.cache.get(key);
        if (v) {
            return v;
        }
        if ((v = this._cache.get(key))) {
            this.update(key, v);
            return v;
        }
        return undefined;
    }
    has(key) {
        return this.cache.has(key) || this._cache.has(key);
    }
    set(key, value) {
        if (this.cache.has(key)) {
            this.cache.set(key, value);
        }
        else {
            this.update(key, value);
        }
        return this;
    }
    delete(key) {
        if (this.cache.has(key)) {
            return this.cache.delete(key);
        }
        if (this._cache.has(key)) {
            return this._cache.delete(key);
        }
        return false;
    }
    update(key, value) {
        this.cache.set(key, value);
        if (this.cache.size >= this.maxSize) {
            this._cache = this.cache;
            this.cache = new Map();
        }
    }
}
export class UnsupportedOperationError extends Error {
    constructor(message) {
        super(message ?? 'operation not supported');
        this.name = this.constructor.name;
        Error.captureStackTrace?.(this, this.constructor);
    }
}
export class OperationProcessingError extends Error {
    constructor(message) {
        super(message);
        this.name = this.constructor.name;
        Error.captureStackTrace?.(this, this.constructor);
    }
}
const OPE = OperationProcessingError;
const dpopNonces = new LRU(100);
function isCryptoKey(key) {
    return key instanceof CryptoKey;
}
function isPrivateKey(key) {
    return isCryptoKey(key) && key.type === 'private';
}
function isPublicKey(key) {
    return isCryptoKey(key) && key.type === 'public';
}
const SUPPORTED_JWS_ALGS = ['PS256', 'ES256', 'RS256'];
function preserveBodyStream(response) {
    assertReadableResponse(response);
    return response.clone();
}
function processDpopNonce(response) {
    const url = new URL(response.url);
    if (response.headers.has('dpop-nonce')) {
        dpopNonces.set(url.origin, response.headers.get('dpop-nonce'));
    }
    return response;
}
function normalizeTyp(value) {
    return value.toLowerCase().replace(/^application\//, '');
}
function isJsonObject(input) {
    if (input === null || typeof input !== 'object' || Array.isArray(input)) {
        return false;
    }
    return true;
}
function prepareHeaders(input) {
    if (input !== undefined && !(input instanceof Headers)) {
        throw new TypeError('"options.headers" must be an instance of Headers');
    }
    const headers = new Headers(input);
    if (!headers.has('user-agent')) {
        headers.set('user-agent', USER_AGENT);
    }
    if (headers.has('authorization')) {
        throw new TypeError('"options.headers" must not include the "authorization" header name');
    }
    if (headers.has('dpop')) {
        throw new TypeError('"options.headers" must not include the "dpop" header name');
    }
    return headers;
}
export async function discoveryRequest(issuerIdentifier, options) {
    if (!(issuerIdentifier instanceof URL)) {
        throw new TypeError('"issuer" must be an instance of URL');
    }
    if (issuerIdentifier.protocol !== 'https:' && issuerIdentifier.protocol !== 'http:') {
        throw new TypeError('"issuer.protocol" must be "https:" or "http:"');
    }
    const url = new URL(issuerIdentifier.href);
    switch (options?.algorithm) {
        case undefined:
        case 'oidc':
            url.pathname = `${url.pathname}/.well-known/openid-configuration`.replace('//', '/');
            break;
        case 'oauth2':
            if (url.pathname === '/') {
                url.pathname = `.well-known/oauth-authorization-server`;
            }
            else {
                url.pathname = `.well-known/oauth-authorization-server/${url.pathname}`.replace('//', '/');
            }
            break;
        default:
            throw new TypeError('"options.algorithm" must be "oidc" (default), or "oauth2"');
    }
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    return fetch(url.href, {
        headers,
        method: 'GET',
        redirect: 'manual',
        signal: options?.signal,
    }).then(processDpopNonce);
}
export async function processDiscoveryResponse(expectedIssuerIdentifier, response) {
    if (!(expectedIssuerIdentifier instanceof URL)) {
        throw new TypeError('"expectedIssuer" must be an instance of URL');
    }
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        throw new OPE('"response" is not a conform Authorization Server Metadata response');
    }
    let json;
    try {
        json = await preserveBodyStream(response).json();
    }
    catch {
        throw new OPE('failed to parse "response" body as JSON');
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (typeof json.issuer !== 'string' || json.issuer.length === 0) {
        throw new OPE('"response" body "issuer" property must be a non-empty string');
    }
    if (new URL(json.issuer).href !== expectedIssuerIdentifier.href) {
        throw new OPE('"response" body "issuer" does not match "expectedIssuer"');
    }
    return json;
}
function randomBytes() {
    return b64u(crypto.getRandomValues(new Uint8Array(32)));
}
export function generateRandomCodeVerifier() {
    return randomBytes();
}
export function generateRandomState() {
    return randomBytes();
}
export function generateRandomNonce() {
    return randomBytes();
}
export async function calculatePKCECodeChallenge(codeVerifier) {
    if (typeof codeVerifier !== 'string' || codeVerifier.length === 0) {
        throw new TypeError('"codeVerifier" must be a non-empty string');
    }
    return b64u(await crypto.subtle.digest('SHA-256', buf(codeVerifier)));
}
function getKeyAndKid(input) {
    if (input instanceof CryptoKey) {
        return { key: input };
    }
    if (!(input?.key instanceof CryptoKey)) {
        return {};
    }
    if (input.kid !== undefined && (typeof input.kid !== 'string' || input.kid.length === 0)) {
        throw new TypeError('"kid" must be a non-empty string');
    }
    return { key: input.key, kid: input.kid };
}
function formUrlEncode(token) {
    return encodeURIComponent(token).replace(/%20/g, '+');
}
function clientSecretBasic(clientId, clientSecret) {
    const username = formUrlEncode(clientId);
    const password = formUrlEncode(clientSecret);
    const credentials = btoa(`${username}:${password}`);
    return `Basic ${credentials}`;
}
function psAlg(key) {
    switch (key.algorithm.hash.name) {
        case 'SHA-256':
            return 'PS256';
        default:
            throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name');
    }
}
function rsAlg(key) {
    switch (key.algorithm.hash.name) {
        case 'SHA-256':
            return 'RS256';
        default:
            throw new UnsupportedOperationError('unsupported RsaHashedKeyAlgorithm hash name');
    }
}
function esAlg(key) {
    switch (key.algorithm.namedCurve) {
        case 'P-256':
            return 'ES256';
        default:
            throw new UnsupportedOperationError('unsupported EcKeyAlgorithm namedCurve');
    }
}
function determineJWSAlgorithm(key) {
    switch (key.algorithm.name) {
        case 'RSA-PSS':
            return psAlg(key);
        case 'RSASSA-PKCS1-v1_5':
            return rsAlg(key);
        case 'ECDSA':
            return esAlg(key);
        default:
            throw new UnsupportedOperationError('unsupported CryptoKey algorithm name');
    }
}
function epochTime() {
    return Math.floor(Date.now() / 1000);
}
function clientAssertion(as, client) {
    const now = epochTime();
    return {
        jti: randomBytes(),
        aud: [as.issuer, as.token_endpoint],
        exp: now + 60,
        iat: now,
        nbf: now,
        iss: client.client_id,
        sub: client.client_id,
    };
}
async function privateKeyJwt(as, client, key, kid) {
    return jwt({
        alg: determineJWSAlgorithm(key),
        kid,
    }, clientAssertion(as, client), key);
}
function assertIssuer(metadata) {
    if (typeof metadata !== 'object' || metadata === null) {
        throw new TypeError('"issuer" must be an object');
    }
    if (typeof metadata.issuer !== 'string' || metadata.issuer.length === 0) {
        throw new TypeError('"issuer.issuer" property must be a non-empty string');
    }
    return true;
}
function assertClient(metadata) {
    if (typeof metadata !== 'object' || metadata === null) {
        throw new TypeError('"client" must be an object');
    }
    if (typeof metadata.client_id !== 'string' || metadata.client_id.length === 0) {
        throw new TypeError('"client.client_id" property must be a non-empty string');
    }
    return true;
}
function assertClientSecret(clientSecret) {
    if (typeof clientSecret !== 'string' || clientSecret.length === 0) {
        throw new TypeError('"client.client_secret" property must be a non-empty string');
    }
    return clientSecret;
}
function assertNoClientPrivateKey(clientAuthMethod, clientPrivateKey) {
    if (clientPrivateKey !== undefined) {
        throw new TypeError(`"options.clientPrivateKey" property must not be provided when ${clientAuthMethod} client authentication method is used.`);
    }
}
function assertNoClientSecret(clientAuthMethod, clientSecret) {
    if (clientSecret !== undefined) {
        throw new TypeError(`"client.client_secret" property must not be provided when ${clientAuthMethod} client authentication method is used.`);
    }
}
async function clientAuthentication(as, client, body, headers, clientPrivateKey) {
    body.delete('client_secret');
    body.delete('client_assertion_type');
    body.delete('client_assertion');
    switch (client.token_endpoint_auth_method) {
        case undefined:
        case 'client_secret_basic': {
            assertNoClientPrivateKey('client_secret_basic', clientPrivateKey);
            headers.set('authorization', clientSecretBasic(client.client_id, assertClientSecret(client.client_secret)));
            break;
        }
        case 'client_secret_post': {
            assertNoClientPrivateKey('client_secret_post', clientPrivateKey);
            body.set('client_id', client.client_id);
            body.set('client_secret', assertClientSecret(client.client_secret));
            break;
        }
        case 'private_key_jwt': {
            assertNoClientSecret('private_key_jwt', client.client_secret);
            if (clientPrivateKey === undefined) {
                throw new TypeError('"options.clientPrivateKey" must be provided when "client.token_endpoint_auth_method" is "private_key_jwt"');
            }
            const { key, kid } = getKeyAndKid(clientPrivateKey);
            if (!isPrivateKey(key)) {
                throw new TypeError('"options.clientPrivateKey.key" must be a private CryptoKey');
            }
            body.set('client_id', client.client_id);
            body.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
            body.set('client_assertion', await privateKeyJwt(as, client, key, kid));
            break;
        }
        case 'none': {
            assertNoClientSecret('none', client.client_secret);
            assertNoClientPrivateKey('none', clientPrivateKey);
            body.set('client_id', client.client_id);
            break;
        }
        default:
            throw new UnsupportedOperationError('unsupported client token_endpoint_auth_method');
    }
}
async function jwt(header, claimsSet, key) {
    if (key.usages.includes('sign') === false) {
        throw new TypeError('private CryptoKey instances used for signing assertions must include "sign" in their "usages"');
    }
    const input = `${b64u(buf(JSON.stringify(header)))}.${b64u(buf(JSON.stringify(claimsSet)))}`;
    const signature = b64u(await crypto.subtle.sign(subtleAlgorithm(key), key, buf(input)));
    return `${input}.${signature}`;
}
export async function issueRequestObject(as, client, parameters, privateKey) {
    assertIssuer(as);
    assertClient(client);
    if (!(parameters instanceof URLSearchParams)) {
        throw new TypeError('"parameters" must be an instance of URLSearchParams');
    }
    parameters = new URLSearchParams(parameters);
    const { key, kid } = getKeyAndKid(privateKey);
    if (!isPrivateKey(key)) {
        throw new TypeError('"privateKey.key" must be a private CryptoKey');
    }
    parameters.set('client_id', client.client_id);
    const now = epochTime();
    const claims = {
        ...Object.fromEntries(parameters.entries()),
        jti: randomBytes(),
        aud: as.issuer,
        exp: now + 60,
        iat: now,
        nbf: now,
        iss: client.client_id,
    };
    let resource;
    if (parameters.has('resource') &&
        (resource = parameters.getAll('resource')) &&
        resource.length > 1) {
        claims.resource = resource;
    }
    return jwt({
        alg: determineJWSAlgorithm(key),
        typ: 'oauth-authz-req+jwt',
        kid,
    }, claims, key);
}
async function dpopProofJwt(headers, options, url, htm, accessToken) {
    const { privateKey, publicKey, nonce = dpopNonces.get(url.origin) } = options;
    if (!isPrivateKey(privateKey)) {
        throw new TypeError('"DPoP.privateKey" must be a private CryptoKey');
    }
    if (!isPublicKey(publicKey)) {
        throw new TypeError('"DPoP.publicKey" must be a public CryptoKey');
    }
    if (nonce !== undefined && (typeof nonce !== 'string' || nonce.length === 0)) {
        throw new TypeError('"DPoP.nonce" must be a non-empty string or undefined');
    }
    if (publicKey.extractable !== true) {
        throw new TypeError('"DPoP.publicKey.extractable" must be true');
    }
    const proof = await jwt({
        alg: determineJWSAlgorithm(privateKey),
        typ: 'dpop+jwt',
        jwk: await publicJwk(publicKey),
    }, {
        iat: epochTime(),
        jti: randomBytes(),
        htm,
        nonce,
        htu: `${url.origin}${url.pathname}`,
        ath: accessToken ? b64u(await crypto.subtle.digest('SHA-256', buf(accessToken))) : undefined,
    }, privateKey);
    headers.set('dpop', proof);
}
async function publicJwk(key) {
    const { kty, e, n, x, y, crv } = await crypto.subtle.exportKey('jwk', key);
    return { kty, crv, e, n, x, y };
}
export async function pushedAuthorizationRequest(as, client, parameters, options) {
    assertIssuer(as);
    assertClient(client);
    if (!(parameters instanceof URLSearchParams)) {
        throw new TypeError('"parameters" must be an instance of URLSearchParams');
    }
    if (typeof as.pushed_authorization_request_endpoint !== 'string') {
        throw new TypeError('"issuer.pushed_authorization_request_endpoint" must be a string');
    }
    const url = new URL(as.pushed_authorization_request_endpoint);
    const body = new URLSearchParams(parameters);
    body.set('client_id', client.client_id);
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    if (options?.DPoP !== undefined) {
        await dpopProofJwt(headers, options.DPoP, url, 'POST');
        body.set('dpop_jkt', await calculateJwkThumbprint(options.DPoP.publicKey));
    }
    return authenticatedRequest(as, client, 'POST', url, body, headers, options);
}
export function isOAuth2Error(input) {
    const value = input;
    if (typeof value !== 'object' || Array.isArray(value) || value === null) {
        return false;
    }
    return value.error !== undefined;
}
function unquote(value) {
    if (value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"') {
        return value.slice(1, -1);
    }
    return value;
}
const SPLIT_REGEXP = /((?:,|, )?[0-9a-zA-Z!#$%&'*+-.^_`|~]+=)/;
const SCHEMES_REGEXP = /(?:^|, ?)([0-9a-zA-Z!#$%&'*+\-.^_`|~]+)(?=$|[ ,])/g;
function wwwAuth(scheme, params) {
    const arr = params.split(SPLIT_REGEXP).slice(1);
    if (arr.length === 0) {
        return { scheme: scheme.toLowerCase(), parameters: {} };
    }
    arr[arr.length - 1] = arr[arr.length - 1].replace(/,$/, '');
    const parameters = {};
    for (let i = 1; i < arr.length; i += 2) {
        const idx = i;
        if (arr[idx][0] === '"') {
            while (arr[idx].slice(-1) !== '"' && ++i < arr.length) {
                arr[idx] += arr[i];
            }
        }
        const key = arr[idx - 1].replace(/^(?:, ?)|=$/g, '').toLowerCase();
        parameters[key] = unquote(arr[idx]);
    }
    return {
        scheme: scheme.toLowerCase(),
        parameters,
    };
}
export function parseWwwAuthenticateChallenges(response) {
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.headers.has('www-authenticate') === false) {
        return undefined;
    }
    const header = response.headers.get('www-authenticate');
    const result = [];
    for (const { 1: scheme, index } of header.matchAll(SCHEMES_REGEXP)) {
        result.push([scheme, index]);
    }
    if (result.length === 0) {
        return undefined;
    }
    const challenges = result.map(([scheme, indexOf], i, others) => {
        const next = others[i + 1];
        let parameters;
        if (next) {
            parameters = header.slice(indexOf, next[1]);
        }
        else {
            parameters = header.slice(indexOf);
        }
        return wwwAuth(scheme, parameters);
    });
    return challenges;
}
export async function processPushedAuthorizationResponse(as, client, response) {
    assertIssuer(as);
    assertClient(client);
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 201) {
        let err;
        if ((err = await handleOAuthBodyError(response))) {
            return err;
        }
        throw new OPE('"response" is not a conform Pushed Authorization Request Endpoint response');
    }
    let json;
    try {
        json = await preserveBodyStream(response).json();
    }
    catch {
        throw new OPE('failed to parse "response" body as JSON');
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (typeof json.request_uri !== 'string' || json.request_uri.length === 0) {
        throw new OPE('"response" body "request_uri" property must be a non-empty string');
    }
    if (typeof json.expires_in !== 'number' || json.expires_in <= 0) {
        throw new OPE('"response" body "expires_in" property must be a positive number');
    }
    return json;
}
export async function protectedResourceRequest(accessToken, method, url, headers, body, options) {
    if (typeof accessToken !== 'string' || accessToken.length === 0) {
        throw new TypeError('"accessToken" must be a non-empty string');
    }
    if (!(url instanceof URL)) {
        throw new TypeError('"url" must be an instance of URL');
    }
    headers = prepareHeaders(headers);
    if (options?.DPoP === undefined) {
        headers.set('authorization', `Bearer ${accessToken}`);
    }
    else {
        await dpopProofJwt(headers, options.DPoP, url, 'GET', accessToken);
        headers.set('authorization', `DPoP ${accessToken}`);
    }
    return fetch(url.href, {
        body,
        headers,
        method,
        redirect: 'manual',
        signal: options?.signal,
    }).then(processDpopNonce);
}
export async function userInfoRequest(as, client, accessToken, options) {
    assertIssuer(as);
    assertClient(client);
    if (typeof as.userinfo_endpoint !== 'string') {
        throw new TypeError('"issuer.userinfo_endpoint" must be a string');
    }
    const url = new URL(as.userinfo_endpoint);
    const headers = prepareHeaders(options?.headers);
    if (client.userinfo_signed_response_alg) {
        headers.set('accept', 'application/jwt');
    }
    else {
        headers.set('accept', 'application/json');
        headers.append('accept', 'application/jwt');
    }
    return protectedResourceRequest(accessToken, 'GET', url, headers, null, options);
}
const jwksCache = new LRU(20);
const cryptoKeyCaches = {};
async function getPublicSigKeyFromIssuerJwksUri(as, options, header) {
    const { alg, kid } = header;
    checkSupportedJwsAlg(alg);
    let jwks;
    let age;
    if (jwksCache.has(as.jwks_uri)) {
        ;
        ({ jwks, age } = jwksCache.get(as.jwks_uri));
        if (age >= 300) {
            jwksCache.delete(as.jwks_uri);
            return getPublicSigKeyFromIssuerJwksUri(as, options, header);
        }
    }
    else {
        jwks = await jwksRequest(as, options).then(processJwksResponse);
        age = 0;
        jwksCache.set(as.jwks_uri, {
            jwks,
            iat: epochTime(),
            get age() {
                return epochTime() - this.iat;
            },
        });
    }
    let kty;
    switch (alg[0]) {
        case 'R':
        case 'P':
            kty = 'RSA';
            break;
        case 'E':
            kty = 'EC';
            break;
        default:
            throw new UnsupportedOperationError();
    }
    const candidates = jwks.keys.filter((jwk) => {
        if (jwk.kty !== kty) {
            return false;
        }
        if (kid !== undefined && kid !== jwk.kid) {
            return false;
        }
        if (jwk.alg !== undefined && alg !== jwk.alg) {
            return false;
        }
        if (jwk.use !== undefined && jwk.use !== 'sig') {
            return false;
        }
        if (jwk.key_ops?.includes('verify') === false) {
            return false;
        }
        switch (alg) {
            case 'ES256':
                return jwk.crv === 'P-256';
            default:
                return true;
        }
    });
    const { 0: jwk, length } = candidates;
    if (length === 0) {
        if (age >= 60) {
            jwksCache.delete(as.jwks_uri);
            return getPublicSigKeyFromIssuerJwksUri(as, options, header);
        }
        throw new OPE('error when selecting a JWT verification key, no applicable keys found');
    }
    else if (length !== 1) {
        throw new OPE('error when selecting a JWT verification key, multiple applicable keys found, a "kid" JWT Header Parameter is required');
    }
    cryptoKeyCaches[alg] || (cryptoKeyCaches[alg] = new WeakMap());
    let key = cryptoKeyCaches[alg].get(jwk);
    if (!key) {
        key = await importJwk({ ...jwk, alg });
        if (key.type !== 'public') {
            throw new OPE('jwks_uri must only contain public keys');
        }
        cryptoKeyCaches[alg].set(jwk, key);
    }
    return key;
}
export const skipSubjectCheck = Symbol();
function getContentType(response) {
    return response.headers.get('content-type')?.split(';')[0];
}
export async function processUserInfoResponse(as, client, expectedSubject, response, options) {
    assertIssuer(as);
    assertClient(client);
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        throw new OPE('"response" is not a conform UserInfo Endpoint response');
    }
    let json;
    if (getContentType(response) === 'application/jwt') {
        if (typeof as.jwks_uri !== 'string') {
            throw new TypeError('"issuer.jwks_uri" must be a string');
        }
        const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.userinfo_signed_response_alg, as.userinfo_signing_alg_values_supported, 'RS256'), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
            .then(validateOptionalAudience.bind(undefined, client.client_id))
            .then(validateOptionalIssuer.bind(undefined, as.issuer));
        json = claims;
    }
    else {
        if (client.userinfo_signed_response_alg) {
            throw new OPE('JWT UserInfo Response expected');
        }
        try {
            json = await preserveBodyStream(response).json();
        }
        catch {
            throw new OPE('failed to parse "response" body as JSON');
        }
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (typeof json.sub !== 'string' || json.sub.length === 0) {
        throw new OPE('"response" body "sub" property must be a non-empty string');
    }
    switch (expectedSubject) {
        case skipSubjectCheck:
            break;
        default:
            if (typeof expectedSubject !== 'string' || expectedSubject.length === 0) {
                throw new OPE('"expectedSubject" must be a non-empty string');
            }
            if (json.sub !== expectedSubject) {
                throw new OPE('unexpected "response" body "sub" value');
            }
    }
    return json;
}
async function timingSafeEqual(a, b) {
    if (a.byteLength !== b.byteLength) {
        return false;
    }
    const len = a.byteLength;
    let out = 0;
    let i = -1;
    while (++i < len) {
        out |= a[i] ^ b[i];
    }
    return out === 0;
}
async function idTokenHash(alg, data) {
    let algorithm;
    switch (alg) {
        case 'RS256':
        case 'PS256':
        case 'ES256':
            algorithm = 'SHA-256';
            break;
        default:
            throw new UnsupportedOperationError();
    }
    const digest = await crypto.subtle.digest(algorithm, buf(data));
    return b64u(digest.slice(0, digest.byteLength / 2));
}
async function idTokenHashMatches(alg, data, actual) {
    const expected = await idTokenHash(alg, data);
    return timingSafeEqual(buf(actual), buf(expected));
}
async function authenticatedRequest(as, client, method, url, body, headers, options) {
    await clientAuthentication(as, client, body, headers, options?.clientPrivateKey);
    return fetch(url.href, {
        body,
        headers,
        method,
        redirect: 'manual',
        signal: options?.signal,
    }).then(processDpopNonce);
}
async function tokenEndpointRequest(as, client, grantType, parameters, options) {
    if (typeof as.token_endpoint !== 'string') {
        throw new TypeError('"issuer.token_endpoint" must be a string');
    }
    const url = new URL(as.token_endpoint);
    parameters.set('grant_type', grantType);
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    if (options?.DPoP !== undefined) {
        await dpopProofJwt(headers, options.DPoP, url, 'POST');
    }
    return authenticatedRequest(as, client, 'POST', url, parameters, headers, options);
}
export async function refreshTokenGrantRequest(as, client, refreshToken, options) {
    assertIssuer(as);
    assertClient(client);
    if (typeof refreshToken !== 'string' || refreshToken.length === 0) {
        throw new TypeError('"refreshToken" must be a non-empty string');
    }
    const parameters = new URLSearchParams(options?.additionalParameters);
    parameters.set('refresh_token', refreshToken);
    return tokenEndpointRequest(as, client, 'refresh_token', parameters, options);
}
const idTokenClaims = new WeakMap();
export function getValidatedIdTokenClaims(ref) {
    if (!idTokenClaims.has(ref)) {
        throw new TypeError('"ref" was already garbage collected or did not resolve from the proper sources');
    }
    return idTokenClaims.get(ref);
}
async function processGenericAccessTokenResponse(as, client, response, options, ignoreIdToken = false, ignoreRefreshToken = false) {
    assertIssuer(as);
    assertClient(client);
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        let err;
        if ((err = await handleOAuthBodyError(response))) {
            return err;
        }
        throw new OPE('"response" is not a conform Token Endpoint response');
    }
    let json;
    try {
        json = await preserveBodyStream(response).json();
    }
    catch {
        throw new OPE('failed to parse "response" body as JSON');
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (typeof json.access_token !== 'string' || json.access_token.length === 0) {
        throw new OPE('"response" body "access_token" property must be a non-empty string');
    }
    if (typeof json.token_type !== 'string' || json.token_type.length === 0) {
        throw new OPE('"response" body "token_type" property must be a non-empty string');
    }
    json.token_type = json.token_type.toLowerCase();
    if (json.expires_in !== undefined &&
        (typeof json.expires_in !== 'number' || json.expires_in <= 0)) {
        throw new OPE('"response" body "expires_in" property must be a positive number');
    }
    if (ignoreRefreshToken === false &&
        json.refresh_token !== undefined &&
        (typeof json.refresh_token !== 'string' || json.refresh_token.length === 0)) {
        throw new OPE('"response" body "refresh_token" property must be a non-empty string');
    }
    if (json.scope !== undefined && (typeof json.scope !== 'string' || json.scope.length === 0)) {
        throw new OPE('"response" body "scope" property must be a non-empty string');
    }
    if (ignoreIdToken === false) {
        if (json.id_token !== undefined &&
            (typeof json.id_token !== 'string' || json.id_token.length === 0)) {
            throw new OPE('"response" body "id_token" property must be a non-empty string');
        }
        if (json.id_token) {
            if (typeof as.jwks_uri !== 'string') {
                throw new TypeError('"issuer.jwks_uri" must be a string');
            }
            const { header, claims } = await validateJwt(json.id_token, checkSigningAlgorithm.bind(undefined, client.id_token_signed_response_alg, as.id_token_signing_alg_values_supported, 'RS256'), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
                .then(validatePresence.bind(undefined, [
                ['iss', 'issuer'],
                ['aud', 'audience'],
                ['sub', 'subject'],
                ['iat', 'issued at'],
                ['exp', 'expiration time'],
            ]))
                .then(validateIssuer.bind(undefined, as.issuer))
                .then(validateAudience.bind(undefined, client.client_id));
            if (Array.isArray(claims.aud) && claims.aud.length !== 1 && claims.azp !== client.client_id) {
                throw new OPE('unexpected ID Token "azp" (authorized party)');
            }
            if (client.require_auth_time && typeof claims.auth_time !== 'number') {
                throw new OPE('invalid ID Token "auth_time"');
            }
            if (claims.at_hash !== undefined) {
                if (typeof claims.at_hash !== 'string' ||
                    (await idTokenHashMatches(header.alg, json.access_token, claims.at_hash)) !== true) {
                    throw new OPE('invalid ID Token "at_hash"');
                }
            }
            idTokenClaims.set(json, claims);
        }
    }
    return json;
}
export async function processRefreshTokenResponse(as, client, response, options) {
    return processGenericAccessTokenResponse(as, client, response, options);
}
function validateOptionalAudience(expected, result) {
    if (result.claims.aud !== undefined) {
        return validateAudience(expected, result);
    }
    return result;
}
function validateAudience(expected, result) {
    if (Array.isArray(result.claims.aud)) {
        if (result.claims.aud.includes(expected) === false) {
            throw new OPE('unexpected JWT "aud" (audience)');
        }
    }
    else if (result.claims.aud !== expected) {
        throw new OPE('unexpected JWT "aud" (audience)');
    }
    return result;
}
function validateOptionalIssuer(expected, result) {
    if (result.claims.iss !== undefined) {
        return validateIssuer(expected, result);
    }
    return result;
}
function validateIssuer(expected, result) {
    if (result.claims.iss !== expected) {
        throw new OPE('unexpected JWT "iss" (issuer)');
    }
    return result;
}
export async function authorizationCodeGrantRequest(as, client, callbackParameters, redirectUri, codeVerifier, options) {
    assertIssuer(as);
    assertClient(client);
    if (!(callbackParameters instanceof CallbackParameters)) {
        throw new TypeError('"callbackParameters" must be an instance of CallbackParameters obtained from "validateAuthResponse()", or "validateJwtAuthResponse()');
    }
    if (typeof redirectUri !== 'string' || redirectUri.length === 0) {
        throw new TypeError('"redirectUri" must be a non-empty string');
    }
    if (typeof codeVerifier !== 'string' || codeVerifier.length === 0) {
        throw new TypeError('"codeVerifier" must be a non-empty string');
    }
    const code = getURLSearchParameter(callbackParameters, 'code');
    if (!code) {
        throw new OPE('no authorization code received');
    }
    const parameters = new URLSearchParams(options?.additionalParameters);
    parameters.set('redirect_uri', redirectUri);
    parameters.set('code_verifier', codeVerifier);
    parameters.set('code', code);
    return tokenEndpointRequest(as, client, 'authorization_code', parameters, options);
}
function validatePresence(required, result) {
    for (const [claim, name] of required) {
        if (result.claims[claim] === undefined) {
            throw new OPE(`missing JWT "${claim}" (${name})`);
        }
    }
    return result;
}
export const expectNoNonce = Symbol();
export const skipAuthTimeCheck = Symbol();
export async function processAuthorizationCodeOpenIDResponse(as, client, response, expectedNonce, maxAge, options) {
    const result = await processGenericAccessTokenResponse(as, client, response, options);
    if (isOAuth2Error(result)) {
        return result;
    }
    if (typeof result.id_token !== 'string' || result.id_token.length === 0) {
        throw new OPE('"response" body "id_token" property must be a non-empty string');
    }
    maxAge ?? (maxAge = client.default_max_age ?? skipAuthTimeCheck);
    const claims = getValidatedIdTokenClaims(result);
    if ((client.require_auth_time || maxAge !== skipAuthTimeCheck) &&
        claims.auth_time === undefined) {
        throw new OPE('missing ID Token "auth_time" claims');
    }
    if (maxAge !== skipAuthTimeCheck) {
        if (typeof maxAge !== 'number' || maxAge < 0) {
            throw new TypeError('"options.max_age" must be a non-negative number');
        }
        const now = epochTime();
        const tolerance = 30;
        if (claims.auth_time + maxAge < now - tolerance) {
            throw new OPE('too much time has elapsed since the last End-User authentication');
        }
    }
    switch (expectedNonce) {
        case undefined:
        case expectNoNonce:
            if (claims.nonce !== undefined) {
                throw new OPE('unexpected ID Token "nonce" claim value received');
            }
            break;
        default:
            if (typeof expectedNonce !== 'string' || expectedNonce.length === 0) {
                throw new TypeError('"expectedNonce" must be a non-empty string');
            }
            if (claims.nonce === undefined) {
                throw new OPE('ID Token "nonce" claim missing');
            }
            if (claims.nonce !== expectedNonce) {
                throw new OPE('unexpected ID Token "nonce" claim value received');
            }
    }
    return result;
}
export async function processAuthorizationCodeOAuth2Response(as, client, response) {
    const result = await processGenericAccessTokenResponse(as, client, response);
    if (isOAuth2Error(result)) {
        return result;
    }
    if (result.id_token !== undefined) {
        throw new OPE('Unexpected ID Token returned, use processAuthorizationCodeOpenIDResponse() for OpenID Connect callback processing');
    }
    return result;
}
function checkJwtType(expected, result) {
    if (typeof result.header.typ !== 'string' || normalizeTyp(result.header.typ) !== expected) {
        throw new OPE('unexpected JWT "typ" header parameter value');
    }
    return result;
}
export async function clientCredentialsGrantRequest(as, client, parameters, options) {
    assertIssuer(as);
    assertClient(client);
    return tokenEndpointRequest(as, client, 'client_credentials', new URLSearchParams(parameters), options);
}
export async function processClientCredentialsResponse(as, client, response) {
    const result = await processGenericAccessTokenResponse(as, client, response, undefined, true, true);
    if (isOAuth2Error(result)) {
        return result;
    }
    return result;
}
export async function revocationRequest(as, client, token, options) {
    assertIssuer(as);
    assertClient(client);
    if (typeof token !== 'string' || token.length === 0) {
        throw new TypeError('"token" must be a non-empty string');
    }
    if (typeof as.revocation_endpoint !== 'string') {
        throw new TypeError('"issuer.revocation_endpoint" must be a string');
    }
    const url = new URL(as.revocation_endpoint);
    const body = new URLSearchParams(options?.additionalParameters);
    body.set('token', token);
    const headers = prepareHeaders(options?.headers);
    headers.delete('accept');
    return authenticatedRequest(as, client, 'POST', url, body, headers, options);
}
export async function processRevocationResponse(response) {
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        let err;
        if ((err = await handleOAuthBodyError(response))) {
            return err;
        }
        throw new OPE('"response" is not a conform Revocation Endpoint response');
    }
    return undefined;
}
function assertReadableResponse(response) {
    if (response.bodyUsed === true) {
        throw new TypeError('"response" body has been used already');
    }
}
export async function introspectionRequest(as, client, token, options) {
    assertIssuer(as);
    assertClient(client);
    if (typeof token !== 'string' || token.length === 0) {
        throw new TypeError('"token" must be a non-empty string');
    }
    if (typeof as.introspection_endpoint !== 'string') {
        throw new TypeError('"issuer.introspection_endpoint" must be a string');
    }
    const url = new URL(as.introspection_endpoint);
    const body = new URLSearchParams(options?.additionalParameters);
    body.set('token', token);
    const headers = prepareHeaders(options?.headers);
    if (options?.requestJwtResponse ?? client.introspection_signed_response_alg) {
        headers.set('accept', 'application/token-introspection+jwt');
    }
    else {
        headers.set('accept', 'application/json');
    }
    return authenticatedRequest(as, client, 'POST', url, body, headers, options);
}
export async function processIntrospectionResponse(as, client, response, options) {
    assertIssuer(as);
    assertClient(client);
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        let err;
        if ((err = await handleOAuthBodyError(response))) {
            return err;
        }
        throw new OPE('"response" is not a conform Introspection Endpoint response');
    }
    let json;
    if (getContentType(response) === 'application/token-introspection+jwt') {
        if (typeof as.jwks_uri !== 'string') {
            throw new TypeError('"issuer.jwks_uri" must be a string');
        }
        const { claims } = await validateJwt(await preserveBodyStream(response).text(), checkSigningAlgorithm.bind(undefined, client.introspection_signed_response_alg, as.introspection_signing_alg_values_supported, 'RS256'), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
            .then(checkJwtType.bind(undefined, 'token-introspection+jwt'))
            .then(validatePresence.bind(undefined, [
            ['iss', 'issuer'],
            ['aud', 'audience'],
            ['iat', 'issued at'],
        ]))
            .then(validateIssuer.bind(undefined, as.issuer))
            .then(validateAudience.bind(undefined, client.client_id));
        json = claims.token_introspection;
        if (!isJsonObject(json)) {
            throw new OPE('JWT "token_introspection" claim must be a JSON object');
        }
    }
    else {
        try {
            json = await preserveBodyStream(response).json();
        }
        catch {
            throw new OPE('failed to parse "response" body as JSON');
        }
        if (!isJsonObject(json)) {
            throw new OPE('"response" body must be a top level object');
        }
    }
    if (typeof json.active !== 'boolean') {
        throw new OPE('"response" body "active" property must be a boolean');
    }
    return json;
}
export async function jwksRequest(as, options) {
    assertIssuer(as);
    if (typeof as.jwks_uri !== 'string') {
        throw new TypeError('"issuer.jwks_uri" must be a string');
    }
    const url = new URL(as.jwks_uri);
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    headers.append('accept', 'application/jwk-set+json');
    return fetch(url.href, {
        headers,
        method: 'GET',
        redirect: 'manual',
        signal: options?.signal,
    }).then(processDpopNonce);
}
export async function processJwksResponse(response) {
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        throw new OPE('"response" is not a conform JSON Web Key Set response');
    }
    let json;
    try {
        json = await preserveBodyStream(response).json();
    }
    catch {
        throw new OPE('failed to parse "response" body as JSON');
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (!Array.isArray(json.keys)) {
        throw new OPE('"response" body "keys" property must be an array');
    }
    if (!Array.prototype.every.call(json.keys, isJsonObject)) {
        throw new OPE('"response" body "keys" property members must be JWK formatted objects');
    }
    return json;
}
async function handleOAuthBodyError(response) {
    if (response.status > 399 && response.status < 500) {
        try {
            const json = await preserveBodyStream(response).json();
            if (isJsonObject(json) && typeof json.error === 'string' && json.error.length !== 0) {
                if (json.error_description !== undefined && typeof json.error_description !== 'string') {
                    delete json.error_description;
                }
                if (json.error_uri !== undefined && typeof json.error_uri !== 'string') {
                    delete json.error_uri;
                }
                if (json.algs !== undefined && typeof json.algs !== 'string') {
                    delete json.algs;
                }
                if (json.scope !== undefined && typeof json.scope !== 'string') {
                    delete json.scope;
                }
                return json;
            }
        }
        catch { }
    }
    return undefined;
}
function checkSupportedJwsAlg(alg) {
    if (SUPPORTED_JWS_ALGS.includes(alg) === false) {
        throw new UnsupportedOperationError('unsupported JWS `alg` identifier');
    }
    return alg;
}
function checkRsaKeyAlgorithm(algorithm) {
    if (typeof algorithm.modulusLength !== 'number' || algorithm.modulusLength < 2048) {
        throw new OPE(`${algorithm.name} modulusLength must be at least 2048 bits`);
    }
}
function subtleAlgorithm(key) {
    switch (key.algorithm.name) {
        case 'ECDSA':
            return { name: key.algorithm.name, hash: 'SHA-256' };
        case 'RSA-PSS':
            checkRsaKeyAlgorithm(key.algorithm);
            return {
                name: key.algorithm.name,
                saltLength: 256 >> 3,
            };
        case 'RSASSA-PKCS1-v1_5':
            checkRsaKeyAlgorithm(key.algorithm);
            return { name: key.algorithm.name };
    }
    throw new UnsupportedOperationError();
}
async function validateJwt(jws, checkAlg, getKey) {
    const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.');
    if (length === 5) {
        throw new UnsupportedOperationError('JWE structure JWTs are not supported');
    }
    if (length !== 3) {
        throw new OPE('Invalid JWT');
    }
    let header;
    try {
        header = JSON.parse(buf(b64u(protectedHeader)));
    }
    catch {
        throw new OPE('failed to parse JWT Header body as base64url encoded JSON');
    }
    if (!isJsonObject(header)) {
        throw new OPE('JWT Header must be a top level object');
    }
    checkAlg(header);
    if (header.crit !== undefined) {
        throw new OPE('unexpected JWT "crit" header parameter');
    }
    const key = await getKey(header);
    const input = `${protectedHeader}.${payload}`;
    const verified = await crypto.subtle.verify(subtleAlgorithm(key), key, b64u(signature), buf(input));
    if (verified !== true) {
        throw new OPE('JWT signature verification failed');
    }
    let claims;
    try {
        claims = JSON.parse(buf(b64u(payload)));
    }
    catch {
        throw new OPE('failed to parse JWT Payload body as base64url encoded JSON');
    }
    if (!isJsonObject(claims)) {
        throw new OPE('JWT Payload must be a top level object');
    }
    const now = epochTime();
    const tolerance = 30;
    if (claims.exp !== undefined) {
        if (typeof claims.exp !== 'number') {
            throw new OPE('invalid JWT "exp" (expiration time)');
        }
        if (claims.exp <= now - tolerance) {
            throw new OPE('JWT "exp" (expiration time) timestamp is <= now()');
        }
    }
    if (claims.iat !== undefined) {
        if (typeof claims.iat !== 'number') {
            throw new OPE('invalid JWT "iat" (issued at)');
        }
    }
    if (claims.iss !== undefined) {
        if (typeof claims.iss !== 'string') {
            throw new OPE('invalid JWT "iss" (issuer)');
        }
    }
    if (claims.nbf !== undefined) {
        if (typeof claims.nbf !== 'number') {
            throw new OPE('invalid JWT "nbf" (not before)');
        }
        if (claims.nbf > now + tolerance) {
            throw new OPE('JWT "nbf" (not before) timestamp is > now()');
        }
    }
    if (claims.aud !== undefined) {
        if (typeof claims.aud !== 'string' && !Array.isArray(claims.aud)) {
            throw new OPE('invalid JWT "aud" (audience)');
        }
    }
    return { header, claims };
}
export async function validateJwtAuthResponse(as, client, parameters, expectedState, options) {
    assertIssuer(as);
    assertClient(client);
    if (parameters instanceof URL) {
        parameters = parameters.searchParams;
    }
    if (!(parameters instanceof URLSearchParams)) {
        throw new TypeError('"parameters" must be an instance of URLSearchParams, or URL');
    }
    const response = getURLSearchParameter(parameters, 'response');
    if (!response) {
        throw new OPE('"parameters" does not contain a JARM response');
    }
    if (typeof as.jwks_uri !== 'string') {
        throw new TypeError('"issuer.jwks_uri" must be a string');
    }
    const { claims } = await validateJwt(response, checkSigningAlgorithm.bind(undefined, client.authorization_signed_response_alg, as.authorization_signing_alg_values_supported, 'RS256'), getPublicSigKeyFromIssuerJwksUri.bind(undefined, as, options))
        .then(validatePresence.bind(undefined, [
        ['iss', 'issuer'],
        ['aud', 'audience'],
        ['exp', 'expiration time'],
    ]))
        .then(validateIssuer.bind(undefined, as.issuer))
        .then(validateAudience.bind(undefined, client.client_id));
    const result = new URLSearchParams();
    for (const [key, value] of Object.entries(claims)) {
        if (typeof value === 'string' && key !== 'aud') {
            result.set(key, value);
        }
    }
    return validateAuthResponse(as, client, result, expectedState);
}
function checkSigningAlgorithm(client, issuer, fallback, header) {
    if (client !== undefined) {
        if (header.alg !== client) {
            throw new OPE('unexpected JWT "alg" header parameter');
        }
        return;
    }
    if (Array.isArray(issuer)) {
        if (issuer.includes(header.alg) === false) {
            throw new OPE('unexpected JWT "alg" header parameter');
        }
        return;
    }
    if (header.alg !== fallback) {
        throw new OPE('unexpected JWT "alg" header parameter');
    }
}
function getURLSearchParameter(parameters, name) {
    const { 0: value, length } = parameters.getAll(name);
    if (length > 1) {
        throw new OPE(`"${name}" parameter must be provided only once`);
    }
    return value;
}
export const skipStateCheck = Symbol();
export const expectNoState = Symbol();
class CallbackParameters extends URLSearchParams {
}
export function validateAuthResponse(as, client, parameters, expectedState) {
    assertIssuer(as);
    assertClient(client);
    if (parameters instanceof URL) {
        parameters = parameters.searchParams;
    }
    if (!(parameters instanceof URLSearchParams)) {
        throw new TypeError('"parameters" must be an instance of URLSearchParams, or URL');
    }
    if (getURLSearchParameter(parameters, 'response')) {
        throw new OPE('"parameters" contains a JARM response, use validateJwtAuthResponse() instead of validateAuthResponse()');
    }
    const iss = getURLSearchParameter(parameters, 'iss');
    const state = getURLSearchParameter(parameters, 'state');
    if (!iss && as.authorization_response_iss_parameter_supported === true) {
        throw new OPE('"iss" issuer parameter expected');
    }
    if (iss && iss !== as.issuer) {
        throw new OPE('unexpected "iss" issuer parameter value');
    }
    switch (expectedState) {
        case undefined:
        case expectNoState:
            if (state !== undefined) {
                throw new OPE('unexpected "state" parameter received');
            }
            break;
        case skipStateCheck:
            break;
        default:
            if (typeof expectedState !== 'string' || expectedState.length === 0) {
                throw new OPE('"expectedState" must be a non-empty string');
            }
            if (state === undefined) {
                throw new OPE('"state" callback parameter missing');
            }
            if (state !== expectedState) {
                throw new OPE('unexpected "state" parameter value received');
            }
    }
    const error = getURLSearchParameter(parameters, 'error');
    if (error) {
        return {
            error,
            error_description: getURLSearchParameter(parameters, 'error_description'),
            error_uri: getURLSearchParameter(parameters, 'error_uri'),
        };
    }
    const id_token = getURLSearchParameter(parameters, 'id_token');
    const token = getURLSearchParameter(parameters, 'token');
    if (id_token !== undefined || token !== undefined) {
        throw new UnsupportedOperationError('implicit and hybrid flows are not supported');
    }
    return new CallbackParameters(parameters);
}
async function importJwk(jwk) {
    const { alg, ext, key_ops, use, ...key } = jwk;
    let algorithm;
    switch (alg) {
        case 'PS256':
            algorithm = { name: 'RSA-PSS', hash: 'SHA-256' };
            break;
        case 'RS256':
            algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
            break;
        case 'ES256':
            algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
            break;
        default:
            throw new UnsupportedOperationError();
    }
    return crypto.subtle.importKey('jwk', key, algorithm, true, ['verify']);
}
export async function deviceAuthorizationRequest(as, client, parameters, options) {
    assertIssuer(as);
    assertClient(client);
    if (!(parameters instanceof URLSearchParams)) {
        throw new TypeError('"parameters" must be an instance of URLSearchParams');
    }
    if (typeof as.device_authorization_endpoint !== 'string') {
        throw new TypeError('"issuer.device_authorization_endpoint" must be a string');
    }
    const url = new URL(as.device_authorization_endpoint);
    const body = new URLSearchParams(parameters);
    body.set('client_id', client.client_id);
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    return authenticatedRequest(as, client, 'POST', url, body, headers, options);
}
export async function processDeviceAuthorizationResponse(as, client, response) {
    assertIssuer(as);
    assertClient(client);
    if (!(response instanceof Response)) {
        throw new TypeError('"response" must be an instance of Response');
    }
    if (response.status !== 200) {
        let err;
        if ((err = await handleOAuthBodyError(response))) {
            return err;
        }
        throw new OPE('"response" is not a conform Device Authorization Endpoint response');
    }
    let json;
    try {
        json = await preserveBodyStream(response).json();
    }
    catch {
        throw new OPE('failed to parse "response" body as JSON');
    }
    if (!isJsonObject(json)) {
        throw new OPE('"response" body must be a top level object');
    }
    if (typeof json.device_code !== 'string' || json.device_code.length === 0) {
        throw new OPE('"response" body "device_code" property must be a non-empty string');
    }
    if (typeof json.user_code !== 'string' || json.user_code.length === 0) {
        throw new OPE('"response" body "user_code" property must be a non-empty string');
    }
    if (typeof json.verification_uri !== 'string' || json.verification_uri.length === 0) {
        throw new OPE('"response" body "verification_uri" property must be a non-empty string');
    }
    if (typeof json.expires_in !== 'number' || json.expires_in <= 0) {
        throw new OPE('"response" body "expires_in" property must be a positive number');
    }
    if (json.verification_uri_complete !== undefined &&
        (typeof json.verification_uri_complete !== 'string' ||
            json.verification_uri_complete.length === 0)) {
        throw new OPE('"response" body "verification_uri_complete" property must be a non-empty string');
    }
    if (json.interval !== undefined && (typeof json.interval !== 'number' || json.interval <= 0)) {
        throw new OPE('"response" body "interval" property must be a positive number');
    }
    return json;
}
export async function deviceCodeGrantRequest(as, client, deviceCode, options) {
    assertIssuer(as);
    assertClient(client);
    if (typeof deviceCode !== 'string' || deviceCode.length === 0) {
        throw new TypeError('"deviceCode" must be a non-empty string');
    }
    const parameters = new URLSearchParams(options?.additionalParameters);
    parameters.set('device_code', deviceCode);
    return tokenEndpointRequest(as, client, 'urn:ietf:params:oauth:grant-type:device_code', parameters, options);
}
export async function processDeviceCodeResponse(as, client, response, options) {
    return processGenericAccessTokenResponse(as, client, response, options);
}
export async function generateKeyPair(alg, options) {
    let algorithm;
    if (typeof alg !== 'string' || alg.length === 0) {
        throw new TypeError('"alg" must be a non-empty string');
    }
    switch (alg) {
        case 'PS256':
            algorithm = {
                name: 'RSA-PSS',
                hash: 'SHA-256',
                modulusLength: options?.modulusLength ?? 2048,
                publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            };
            break;
        case 'RS256':
            algorithm = {
                name: 'RSASSA-PKCS1-v1_5',
                hash: 'SHA-256',
                modulusLength: options?.modulusLength ?? 2048,
                publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
            };
            break;
        case 'ES256':
            algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
            break;
        default:
            throw new UnsupportedOperationError();
    }
    return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, ['sign', 'verify']);
}
export async function calculateJwkThumbprint(key) {
    if (!isPublicKey(key) || key.extractable !== true) {
        throw new TypeError('"key" must be an extractable public CryptoKey');
    }
    determineJWSAlgorithm(key);
    const jwk = await crypto.subtle.exportKey('jwk', key);
    let components;
    switch (jwk.kty) {
        case 'EC':
            components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
            break;
        case 'RSA':
            components = { e: jwk.e, kty: jwk.kty, n: jwk.n };
            break;
        default:
            throw new UnsupportedOperationError();
    }
    return b64u(await crypto.subtle.digest('SHA-256', buf(JSON.stringify(components))));
}


text:
require 'travis/cli'

module Travis
  module CLI
    class Accounts < ApiCommand
      description "displays accounts and their subscription status"

      def run
        authenticate
        accounts.each do |account|
          color = account.subscribed? ? :green : :info
          say [
            color(account.login, [color, :bold]),
            color("(#{account.name || account.login.capitalize}):", color),
            account.subscribed?      ? "subscribed,"  : "not subscribed,",
            account.repos_count == 1 ? "1 repository" : "#{account.repos_count} repositories"
          ].join(" ")
        end
        unless accounts.all?(&:subscribed?) or session.config['host'].nil?
          say session.config['host'], "To set up a subscription, please visit %s."
        end
      end
    end
  end
end

redpajama_set_name: RedPajamaGithub


text:
"""The execution context for ClusterCoordinator."""

import contextlib
import threading

from tensorflow.python.util.lazy_loader import LazyLoader

# There is a circular dependency between this and the `cluster_coordinator`
# module. So we load it lazily to work around this.
cluster_coordinator = LazyLoader(
    "cluster_coordinator", globals(),
    "tensorflow.python.distribute.coordinator.cluster_coordinator"
)

_dispatch_context = threading.local()

def get_current_dispatch_context():
  try:
    return _dispatch_context.current
  except AttributeError:
    return None

@contextlib.contextmanager
def with_dispatch_context(worker_obj):
  previous_context = getattr(_dispatch_context, "current", None)
  _dispatch_context.current = DispatchContext(worker_obj)
  yield
  _dispatch_context.current = previous_context

class DispatchContext(object):
  """Context entered when executing a closure on a given worker."""

  def __init__(self, worker_obj):
    self._worker = worker_obj
    self._worker_index = worker_obj.worker_index

  @property
  def worker(self):
    return self._worker

  @property
  def worker_index(self):
    return self._worker_index

  def maybe_rebuild_remote_values(self, remote_value):
    e = (
        cluster_coordinator._maybe_rebuild_remote_values(  # pylint: disable=protected-access
            self._worker, remote_value))
    if e:
      if not isinstance(e, cluster_coordinator.InputError):
        e = cluster_coordinator.InputError(e)
      raise e

  def maybe_get_remote_value(self, ret):
    return cluster_coordinator._maybe_get_remote_value(ret)  # pylint: disable=protected-access


text:
namespace Gate2Camp.EVEBotLogic.Common
{
    public enum BotState
    {
        Active,
        Idle
    }
}


text:
package io.skysail.server.app.ref.one2many.resources;

import java.util.List;

import io.skysail.api.links.Link;
import io.skysail.server.ResourceContextId;
import io.skysail.server.app.ref.one2many.One2ManyApplication;
import io.skysail.server.app.ref.one2many.Todo;
import io.skysail.server.db.DbClassName;
import io.skysail.server.restlet.resources.ListServerResource;

public class TodoListsTodosResource extends ListServerResource<Todo> {

    private One2ManyApplication app;

    public TodoListsTodosResource() {
        super(TodoListsTodoResource.class);
        addToContext(ResourceContextId.LINK_GLYPH, "list");
        addToContext(ResourceContextId.LINK_TITLE, "list courses for this timetable");
    }

    @Override
    protected void doInit() {
        app = (One2ManyApplication) getApplication();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Todo> getEntity() {
        String sql = "select * from " + DbClassName.of(Todo.class) + " where #"+getAttribute("id")+" in IN(todos)";
        return (List<Todo>) app.getRepo().execute(Todo.class, sql);
    }

    @Override
    public List<Link> getLinks() {
        return super.getLinks(TodoListsTodosResource.class, PostTodoListToNewTodoRelationResource.class);
    }
}


text:
from msrest.paging import Paged

class ClusterCodeVersionsResultPaged(Paged):
    """
    A paging container for iterating over a list of :class:`ClusterCodeVersionsResult <azure.mgmt.servicefabric.models.ClusterCodeVersionsResult>` object
    """

    _attribute_map = {
        'next_link': {'key': 'nextLink', 'type': 'str'},
        'current_page': {'key': 'value', 'type': '[ClusterCodeVersionsResult]'}
    }

    def __init__(self, *args, **kwargs):

        super(ClusterCodeVersionsResultPaged, self).__init__(*args, **kwargs)


text:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

public partial class Code : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        this.CreateCheckCodeImage(GenerateCheckCode());

    }

    private string GenerateCheckCode()
    {
        int number;
        char code;
        string checkCode = String.Empty;

        System.Random random = new Random();

        for (int i = 0; i < 5; i++)
        {
            number = random.Next();

            if (number % 2 == 0)
                code = (char)('0' + (char)(number % 10));
            else
                code = (char)('A' + (char)(number % 26));

            checkCode += code.ToString();
        }

        Response.Cookies.Add(new HttpCookie("CheckCode", checkCode));
        Session["checkcode"] = checkCode;
        return checkCode;
    }

    private void CreateCheckCodeImage(string checkCode)
    {
        if (checkCode == null || checkCode.Trim() == String.Empty)
            return;

        System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 13.5)), 22);
        Graphics g = Graphics.FromImage(image);

        try
        {
            Random random = new Random();

            g.Clear(Color.White);

            for (int i = 0; i < 25; i++)
            {
                int x1 = random.Next(image.Width);
                int x2 = random.Next(image.Width);
                int y1 = random.Next(image.Height);
                int y2 = random.Next(image.Height);

                g.DrawLine(new Pen(Color.GreenYellow), x1, y1, x2, y2);
            }

            Font font = new System.Drawing.Font("Verdana", 12, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));
            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
            g.DrawString(checkCode, font, brush, 2, 2);

            //画图片的前景噪音点
            for (int i = 0; i < 80; i++)
            {
                int x = random.Next(image.Width);
                int y = random.Next(image.Height);

                image.SetPixel(x, y, Color.FromArgb(random.Next()));
            }

            //画图片的边框线
            g.DrawRectangle(new Pen(Color.Red), 0, 0, image.Width - 1, image.Height - 1);

            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
            Response.ClearContent();
            Response.ContentType = "image/Gif";
            Response.BinaryWrite(ms.ToArray());
        }
        finally
        {
            g.Dispose();
            image.Dispose();
        }
    }

}


text:
class AddParamHandler < YARD::Handlers::Ruby::MethodHandler

  handles method_call(:add_param)

  def process
    name = statement[1][0].source.gsub(/^:/, '')
    class_name = statement[1][1].source

    case class_name
      when "Strings"
        class_name = "Array<String>"
      when "Files"
        class_name = "Array<String> [Files]"
      when "Paths"
        class_name = "Array<String> [Paths]"
      when "Urls"
        class_name = "Array<String> [Urls]"
    end

    namespace.attributes[scope][name] ||= SymbolHash[:read => nil, :write => nil]

    {:read => name, :write => "#{name}="}.each do |type, meth|
        namespace.attributes[scope][name][type] = MethodObject.new(namespace, meth, scope) do |o|

          o.source = statement.source
          o.signature = method_signature(meth)
          o.docstring = statement.comments

          if type == :write
            o.parameters = [['value', nil]]
          else
            new_tag = YARD::Tags::Tag.new(:return, "An instance of #{class_name}", class_name)
            o.docstring.add_tag(new_tag)
          end

          o.visibility = visibility
        end
    end
  end

end


text:
https://webpack.js.org/guides/tree-shaking/

https://doc.webpack-china.org/guides/tree-shaking/

https://alexjoverm.github.io/2017/03/06/Tree-shaking-with-Webpack-2-TypeScript-and-Babel/

http://2ality.com/2015/12/webpack-tree-shaking.html

https://medium.com/modus-create-front-end-development/webpack-2-tree-shaking-configuration-9f1de90f3233

Tree shaking 是一个术语,
通常用来描述移除 JavaScript 上下文中无用代码这个过程,或者更准确的说是按需引用代码,
它依赖于 ES2015 模块系统中 import/export 的静态结构特性。
这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。

webpack 2 原生支持ES6模块 (别名 harmony modules) ,并能检测出未使用的模块输出。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/export

https://rollupjs.org/

https://rollupjs.org/repl

https://github.com/rollup/rollup

https://github.com/rollup/rollup/wiki/JavaScript-API

# ES6 classes

> ES6类是语法糖,以提供更简单和更清晰的语法来创建对象并处理继承。

https://caniuse.com/#search=es6

## Exploring ES6 探索ES6

http://exploringjs.com/es6/
http://exploringjs.com/es6.html

## Exploring ES2016 and ES2017

http://exploringjs.com/es2016-es2017.html
http://exploringjs.com/es2016-es2017/index.html

## Setting up ES6
http://exploringjs.com/setting-up-es6.html

## Speaking JavaScript

http://speakingjs.com/
http://speakingjs.com/es5/index.html

http://2ality.com/2014/09/es6-modules-final.html
http://2ality.com/2015/02/es6-classes-final.html
http://2ality.com/2016/01/ecmascript-2016.html

# ES6 module

> 导入/导出在JavaScript模块上ES6

> Import/export modules in JavaScript in ES6

https://caniuse.com/#search=export

https://caniuse.com/#search=ES6%20module

http://exploringjs.com/es6/ch_modules.html#static-module-structure

# HTML Imports

> 在其他HTML文档中包含和重用HTML文档的方法。

https://caniuse.com/#search=import

https://svelte.technology/blog/frameworks-without-the-framework


text:
package main

import (
	"bufio"
	"bytes"
	"crypto"
	"flag"
	"os"
	"strings"

	"github.com/golang/glog"

	"github.com/google/trillian-examples/experimental/batchmap/sumdb/mapdb"
	"github.com/google/trillian-examples/experimental/batchmap/sumdb/verification"

	_ "github.com/mattn/go-sqlite3"
)

const hash = crypto.SHA512_256

var (
	sumFile      = flag.String("sum_file", "", "go.sum file to check for integrity.")
	mapDB        = flag.String("map_db", "", "sqlite DB containing the map tiles.")
	treeID       = flag.Int64("tree_id", 12345, "The ID of the tree. Used as a salt in hashing.")
	prefixStrata = flag.Int("prefix_strata", 2, "The number of strata of 8-bit strata before the final strata.")
)

func main() {
	flag.Parse()

	if *mapDB == "" {
		glog.Exitf("No map_dir provided")
	}
	if *sumFile == "" {
		glog.Exitf("No sum_file provided")
	}

	tiledb, err := mapdb.NewTileDB(*mapDB)
	if err != nil {
		glog.Exitf("Failed to open map DB at %q: %v", *mapDB, err)
	}
	var rev int
	var logRoot []byte
	if rev, logRoot, _, err = tiledb.LatestRevision(); err != nil {
		glog.Exitf("No revisions found in map DB at %q: %v", *mapDB, err)
	}

	mv := verification.NewMapVerifier(tiledb.Tile, *prefixStrata, *treeID, hash)

	// Open the go.sum file for reading a line at a time.
	file, err := os.Open(*sumFile)
	if err != nil {
		glog.Exitf("failed to read file %q: %q", *sumFile, err)
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)

	var root []byte
	var count int
	// Confirm that each entry in the go.sum file is committed to by the map.
	// NOTE:
	// This is optimized for clarity of demonstrating inclusion, not for performance.
	// This code leads to a lot of duplicate I/O and tile calculation, particularly
	// for the higher tiles in the map (e.g. the root tile will be read and verified
	// for every single line in the go.sum file).
	for scanner.Scan() {
		line := scanner.Text()
		split := strings.LastIndex(line, " ")
		key := line[:split]
		expectedString := line[split+1:]
		glog.V(1).Infof("checking key %q value %q", key, expectedString)
		newRoot, err := mv.CheckInclusion(rev, key, []byte(expectedString))
		if err != nil {
			glog.Exitf("inclusion check failed for key %q value %q: %q", key, expectedString, err)
		}
		if root != nil && !bytes.Equal(root, newRoot) {
			glog.Exitf("map root changed while verifying file")
		}
		root = newRoot
		count++
	}
	glog.Infof("Verified %d entries committed to by map rev %d root %x. Log checkpoint:\n%s", count, rev, root, logRoot)
}


text:
package com.example.android.supportv4.graphics;

import com.example.android.supportv4.R;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.widget.ImageView;
import android.widget.RadioGroup;

/**
 * Demonstrates use of a {@link DrawableCompat}'s ability to become circular.
 */
public class DrawableCompatActivity extends Activity {

    private static final int IMAGE_RES = R.drawable.ic_favorite;

    private ImageView mImageView;
    private Drawable mDrawable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drawable_compat);

        mImageView = (ImageView) findViewById(R.id.image);

        Drawable d = ContextCompat.getDrawable(this, IMAGE_RES);
        mDrawable = DrawableCompat.wrap(d.mutate());

        mImageView.setImageDrawable(mDrawable);

        RadioGroup rg = (RadioGroup) findViewById(R.id.drawable_compat_options);
        rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int id) {
                switch (id) {
                    case R.id.drawable_compat_no_tint:
                        clearTint();
                        break;
                    case R.id.drawable_compat_color:
                        setColorTint();
                        break;
                    case R.id.drawable_compat_state_list:
                        setColorStateListTint();
                        break;
                }
            }
        });
    }

    private void clearTint() {
        DrawableCompat.setTintList(mDrawable, null);
    }

    private void setColorTint() {
        DrawableCompat.setTint(mDrawable, Color.MAGENTA);
    }

    private void setColorStateListTint() {
        DrawableCompat.setTintList(mDrawable,
                ContextCompat.getColorStateList(this, R.color.tint_state_list));
    }

}


text:
<component name="InspectionProjectProfileManager">
  <profile version="1.0">
    <option name="myName" value="Project Default" />
    <inspection_tool class="ArrayEquality" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="BashFloatArithmetic" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
    <inspection_tool class="BashSimpleArrayUse" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
    <inspection_tool class="BashUnregisterGlobalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
    <inspection_tool class="ClassHasNoToStringMethod" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="excludeClassNames" value="" />
      <option name="excludeException" value="true" />
      <option name="excludeDeprecated" value="true" />
      <option name="excludeEnum" value="false" />
      <option name="excludeAbstract" value="false" />
      <option name="excludeTestCode" value="false" />
      <option name="excludeInnerClasses" value="false" />
    </inspection_tool>
    <inspection_tool class="CollectionContainsUrl" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="HtmlTagCanBeJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="IOResource" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader" />
      <option name="insideTryAllowed" value="false" />
    </inspection_tool>
    <inspection_tool class="IgnoreUnusedEntry" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
    <inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="JDBCResource" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="insideTryAllowed" value="false" />
    </inspection_tool>
    <inspection_tool class="JNDIResource" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="insideTryAllowed" value="false" />
    </inspection_tool>
    <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="MissingPackageInfo" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="PackageDotHtmlMayBePackageInfo" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="PackageInfoWithoutPackage" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="ProblematicWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="SocketResource" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="insideTryAllowed" value="false" />
    </inspection_tool>
    <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="StringReplaceableByStringBuffer" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="onlyWarnOnLoop" value="true" />
    </inspection_tool>
    <inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="UnnecessaryInheritDoc" enabled="true" level="WARNING" enabled_by_default="true" />
    <inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
      <option name="ignoreInlineLinkToSuper" value="false" />
    </inspection_tool>
    <inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" />
  </profile>
</component>