New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

rollup-plugin-htaccess

Package Overview
Dependencies
Maintainers
0
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rollup-plugin-htaccess - npm Package Compare versions

Comparing version 0.5.2 to 0.5.3

116

dist/rollup-plugin-htaccess.d.ts

@@ -26,23 +26,23 @@ import type { Plugin as Plugin_2 } from 'rollup';

export declare interface ContentSecurityPolicySources {
hashes?: {
sha256?: Array<string>;
sha384?: Array<string>;
sha512?: Array<string>;
};
hosts?: Array<string>;
"inline-speculation-rules"?: boolean;
nonces?: Array<string>;
"report-sample"?: boolean;
schemes?: {
blob?: boolean;
data?: boolean;
filesystem?: boolean;
mediastream?: boolean;
blob?: boolean;
filesystem?: boolean;
};
self?: boolean;
"strict-dynamic"?: boolean;
"unsafe-eval"?: boolean;
"wasm-unsafe-eval"?: boolean;
"unsafe-hashes"?: boolean;
"unsafe-inline"?: boolean;
nonces?: Array<string>;
hashes?: {
sha256?: Array<string>;
sha384?: Array<string>;
sha512?: Array<string>;
};
"strict-dynamic"?: boolean;
"report-sample"?: boolean;
"inline-speculation-rules"?: boolean;
"wasm-unsafe-eval"?: boolean;
}

@@ -53,4 +53,4 @@

*/
export declare type ContentSecurityPolicySpec = Partial<Record<ContentSecurityPolicySourceDirective, ContentSecurityPolicySources> & {
sandbox: ContentSecurityPolicySandboxValue;
export declare type ContentSecurityPolicySpec = Partial<{
"report-to": string;
/**

@@ -60,7 +60,7 @@ * @deprecated The report-uri directive is deprecated and it's recommended to send CSP reports using report-to instead.

"report-uri": Array<string>;
"report-to": string;
"require-trusted-types-for": "script";
sandbox: ContentSecurityPolicySandboxValue;
"trusted-types": ContentSecurityPolicyTrustedTypesValue;
"upgrade-insecure-requests": boolean;
"trusted-types": ContentSecurityPolicyTrustedTypesValue;
}>;
} & Record<ContentSecurityPolicySourceDirective, ContentSecurityPolicySources>>;

@@ -71,4 +71,4 @@ /**

export declare interface ContentSecurityPolicyTrustedTypesValue {
"allow-duplicates"?: boolean;
policies?: Array<string>;
"allow-duplicates"?: boolean;
}

@@ -86,4 +86,4 @@

enabled: true;
files: Array<string>;
htaccessFile?: string;
files: Array<string>;
}

@@ -94,5 +94,5 @@

*/
export declare type ExtractMetaCSPOptions = ExtractMetaCSPEnabledOptions | {
export declare type ExtractMetaCSPOptions = {
enabled: false;
};
} | ExtractMetaCSPEnabledOptions;

@@ -103,3 +103,2 @@ /**

export declare type HeaderSpec<T extends keyof HeaderValueSpecMap> = {
header: T;
always?: boolean;

@@ -112,2 +111,3 @@ condition?: {

};
header: T;
} & ({

@@ -120,4 +120,4 @@ action: "add" | "append" | "merge" | "set" | "setifempty";

action: "edit" | "edit*";
replacement: string;
value: string;
replacement: string;
});

@@ -162,4 +162,4 @@

env?: {
value: string | null;
variable: string;
value: string | null;
};

@@ -179,6 +179,6 @@ handler?: string;

export declare interface Options {
extractMetaCSP: ExtractMetaCSPOptions;
fileName: string;
spec: Spec;
template: string | undefined;
spec: Spec;
extractMetaCSP: ExtractMetaCSPOptions;
}

@@ -190,4 +190,4 @@

export declare type OptionsSpec = "None" | {
plus?: Array<OptionName>;
minus?: Array<OptionName>;
minus?: Array<OptionName> | undefined;
plus?: Array<OptionName> | undefined;
} | {

@@ -201,5 +201,5 @@ set: Array<OptionName>;

export declare type PermissionsPolicyAllowlist = "*" | {
origins?: Array<string>;
self?: boolean;
src?: boolean;
self?: boolean;
origins?: Array<string>;
};

@@ -226,9 +226,9 @@

export declare interface RewriteCondSpec {
testString: string;
conditionPattern: string;
flags?: {
nocase?: boolean;
novary?: boolean;
ornext?: boolean;
novary?: boolean;
};
testString: string;
}

@@ -240,11 +240,11 @@

export declare interface RewriteOptionsSpec {
AllowAnyURI?: boolean;
AllowNoSlash?: boolean;
IgnoreContextInfo?: boolean;
IgnoreInherit?: boolean;
Inherit?: boolean;
InheritDown?: boolean;
InheritDownBefore?: boolean;
IgnoreInherit?: boolean;
AllowNoSlash?: boolean;
AllowAnyURI?: boolean;
LegacyPrefixDocRoot?: boolean;
MergeBase?: boolean;
IgnoreContextInfo?: boolean;
LegacyPrefixDocRoot?: boolean;
}

@@ -256,5 +256,5 @@

export declare interface RewriteRuleCookieFlagMinimalSpec {
domain: string;
name: string;
value: string;
domain: string;
}

@@ -265,23 +265,23 @@

*/
export declare type RewriteRuleCookieFlagSpec = RewriteRuleCookieFlagMinimalSpec & ({
lifetime?: number;
path?: string;
secure?: boolean;
httponly?: boolean;
samesite?: "Lax" | "None" | "Strict";
export declare type RewriteRuleCookieFlagSpec = ({
httponly?: boolean | undefined;
lifetime?: number | undefined;
path?: string | undefined;
samesite?: "Lax" | "None" | "Strict" | undefined;
secure?: boolean | undefined;
} | {
lifetime?: number;
path?: string;
secure?: boolean;
httponly?: boolean;
httponly?: boolean | undefined;
lifetime?: number | undefined;
path?: string | undefined;
secure?: boolean | undefined;
} | {
lifetime?: number;
path?: string;
secure?: boolean;
lifetime?: number | undefined;
path?: string | undefined;
secure?: boolean | undefined;
} | {
lifetime?: number;
path?: string;
lifetime?: number | undefined;
path?: string | undefined;
} | {
lifetime?: number;
});
lifetime?: number | undefined;
}) & RewriteRuleCookieFlagMinimalSpec;

@@ -295,7 +295,7 @@ /**

} & ({
flags?: MetadataRewriteRuleFlags & StandardRewriteRuleFlags;
substitution: null;
flags?: MetadataRewriteRuleFlags & StandardRewriteRuleFlags;
} | {
flags?: StandardRewriteRuleFlags;
substitution: string;
flags?: StandardRewriteRuleFlags;
});

@@ -356,4 +356,4 @@

export declare interface StrictTransportSecuritySpec {
includeSubDomains?: boolean;
maxAge: number;
includeSubDomains?: boolean;
preload?: boolean;

@@ -360,0 +360,0 @@ }

import {findAll}from'domutils';import {parseDocument,ElementType}from'htmlparser2';import {join}from'path';import {readFile as readFile$1,writeFile as writeFile$1}from'fs';function escapeValue(value) {
return value.replace(/"/g, '\\"');
return value.replace(/"/gu, '\\"');
}

@@ -20,3 +20,3 @@ async function readFile(path) {

});
}let outputOptions = {};
}let outputOptions = undefined;
function renderStart(outputOptionsValue) {

@@ -34,4 +34,4 @@ outputOptions = outputOptionsValue;

const dom = parseDocument(fileContents, {
withEndIndices: true,
withStartIndices: true,
withEndIndices: true,
});

@@ -42,7 +42,9 @@ const cspMetaElems = findAll((elem) => elem.type === ElementType.Tag &&

elem.attribs["http-equiv"].toLowerCase() === "content-security-policy", dom.children);
const cspValues = cspMetaElems.map((elem) => elem.attribs.content);
const cspValues = cspMetaElems.map((elem) => elem.attribs["content"]);
for (const cspMetaElem of cspMetaElems) {
fileContents =
fileContents.substring(0, cspMetaElem.startIndex) +
fileContents.substring(cspMetaElem.endIndex + 1);
if (cspMetaElem.startIndex !== null && cspMetaElem.endIndex !== null) {
fileContents =
fileContents.substring(0, cspMetaElem.startIndex) +
fileContents.substring(cspMetaElem.endIndex + 1);
}
}

@@ -53,3 +55,3 @@ await writeFile(fileName, fileContents);

async function writeCSPValuesToHtaccessFile(context, cspValues, options, htaccessFileName) {
const path = options.htaccessFile ?? join(outputOptions.dir ?? "", htaccessFileName);
const path = options.htaccessFile ?? join(outputOptions?.dir ?? "", htaccessFileName);
let fileContents = "";

@@ -60,12 +62,7 @@ try {

catch {
context.warn('Could not read htaccess file at path "' +
path +
'", writing extracted CSP to new file.');
context.warn(`Could not read htaccess file at path "${path}", writing extracted CSP to new file.`);
}
fileContents +=
cspValues
.map((value) => 'Header always set Content-Security-Policy "' +
escapeValue(value) +
'"')
.join("\n") + "\n";
fileContents += `${cspValues
.map((value) => `Header always set Content-Security-Policy "${escapeValue(value)}"`)
.join("\n")}\n`;
await writeFile(path, fileContents);

@@ -75,4 +72,2 @@ }

return {
order: "post",
sequential: true,
async handler() {

@@ -86,2 +81,4 @@ let cspValues = (await Promise.all(options.files.map(async (file) => extractCSPValuesFromHTMLFile(file)))).flat();

},
order: "post",
sequential: true,
};

@@ -94,4 +91,4 @@ }

return {
closeBundle: closeBundle(options.extractMetaCSP, options.fileName),
renderStart,
closeBundle: closeBundle(options.extractMetaCSP, options.fileName),
};

@@ -101,6 +98,3 @@ }function buildAddOutputFilterByType(spec) {

for (const directive of spec) {
output.push("AddOutputFilterByType " +
directive.filters.join(";") +
" " +
directive.mediaTypes.join(" "));
output.push(`AddOutputFilterByType ${directive.filters.join(";")} ${directive.mediaTypes.join(" ")}`);
}

@@ -111,7 +105,10 @@ return output.join("\n");

for (const errorCode in spec) {
if (!Object.prototype.hasOwnProperty.call(spec, errorCode)) {
continue;
}
let doc = spec[errorCode];
if (doc.includes(" ")) {
doc = '"' + doc + '"';
doc = `"${doc}"`;
}
output.push("ErrorDocument " + errorCode + " " + doc);
output.push(`ErrorDocument ${errorCode} ${doc}`);
}

@@ -121,7 +118,5 @@ return output.join("\n");

if (valueSpec !== null) {
return "sandbox " + valueSpec;
return `sandbox ${valueSpec}`;
}
else {
return "sandbox";
}
return "sandbox";
}

@@ -148,3 +143,3 @@ function buildTrustedTypesPart(valueSpec) {

if (sourceSpec[source] === true) {
sources.push("'" + source + "'");
sources.push(`'${source}'`);
}

@@ -160,3 +155,3 @@ }

if (sourceSpec.schemes[scheme] === true) {
sources.push(scheme + ":");
sources.push(`${scheme}:`);
}

@@ -166,3 +161,3 @@ }

if (sourceSpec.nonces !== undefined) {
sources.push(...sourceSpec.nonces.map((nonce) => "'nonce-" + nonce + "'"));
sources.push(...sourceSpec.nonces.map((nonce) => `'nonce-${nonce}'`));
}

@@ -173,3 +168,3 @@ if (sourceSpec.hashes !== undefined) {

if (hashes !== undefined) {
sources.push(...hashes.map((hash) => "'" + algo + "-" + hash + "'"));
sources.push(...hashes.map((hash) => `'${algo}-${hash}'`));
}

@@ -184,18 +179,20 @@ }

}
return directive + " " + sources.join(" ");
return `${directive} ${sources.join(" ")}`;
}
function buildPart(directive, valueSpec) {
function buildPart(directive,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed to correctly infer value type
valueSpec) {
switch (directive) {
case "sandbox":
return buildSandboxPart(valueSpec);
case "report-to":
return `report-to ${valueSpec}`;
case "report-uri":
return ["report-uri", ...valueSpec].join(" ");
case "report-to":
return "report-to " + valueSpec;
case "require-trusted-types-for":
return "require-trusted-types-for 'script'";
case "sandbox":
return buildSandboxPart(valueSpec);
case "trusted-types":
return buildTrustedTypesPart(valueSpec);
case "upgrade-insecure-requests":
return "upgrade-insecure-requests";
case "trusted-types":
return buildTrustedTypesPart(valueSpec);
default:

@@ -208,2 +205,5 @@ return buildSourcePart(directive, valueSpec);

for (const directive in spec) {
if (!Object.prototype.hasOwnProperty.call(spec, directive)) {
continue;
}
parts.push(buildPart(directive, spec[directive]));

@@ -216,4 +216,3 @@ }

}
const list = allowlist.origins?.map((origin) => '\\"' + escapeValue(origin) + '\\"') ??
[];
const list = allowlist.origins?.map((origin) => `\\"${escapeValue(origin)}\\"`) ?? [];
if (allowlist.src === true) {

@@ -225,3 +224,3 @@ list.unshift("src");

}
return "(" + list.join(" ") + ")";
return `(${list.join(" ")})`;
}

@@ -231,3 +230,10 @@ function buildPermissionsPolicyValue(spec) {

for (const key in spec) {
parts.push(key + "=" + buildAllowlist(spec[key]));
if (!Object.prototype.hasOwnProperty.call(spec, key)) {
continue;
}
const allowlistSpec = spec[key];
if (allowlistSpec === undefined) {
continue;
}
parts.push(`${key}=${buildAllowlist(allowlistSpec)}`);
}

@@ -246,12 +252,9 @@ return parts.join(", ");

}
return ("max-age=" +
spec.maxAge.toString() +
(spec.includeSubDomains === true ? "; includeSubDomains" : "") +
(spec.preload === true ? "; preload" : ""));
return `max-age=${spec.maxAge.toString()}${spec.includeSubDomains === true ? "; includeSubDomains" : ""}${spec.preload === true ? "; preload" : ""}`;
}function buildXContentTypeOptionsValue() {
return "nosniff";
}// eslint-disable-next-line deprecation/deprecation -- Internal deprecation
}// eslint-disable-next-line @typescript-eslint/no-deprecated -- Internal deprecation
function buildXFrameOptionsValue(spec) {
return spec === "sameorigin" ? "SAMEORIGIN" : "DENY";
}// eslint-disable-next-line deprecation/deprecation -- Internal deprecation
}// eslint-disable-next-line @typescript-eslint/no-deprecated -- Internal deprecation
function buildXXssProtectionValue(spec) {

@@ -261,11 +264,14 @@ switch (spec.mode) {

return "1; mode=block";
case "disabled":
return "0";
case "sanitize":
if (spec.reportUri !== undefined) {
return "1; report=" + escapeValue(spec.reportUri);
return `1; report=${escapeValue(spec.reportUri)}`;
}
return "1";
default:
return "0";
}
}function buildHeaderValue(context, header, value) {
}// eslint-disable-next-line consistent-return -- Clashes with typescript unreachable code check
function buildHeaderValue(context, header,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed to correctly infer value type
value) {
switch (header) {

@@ -286,4 +292,5 @@ case "Content-Security-Policy":

return buildXXssProtectionValue(value);
default:
context.error(`Unknown header type "${header}".`);
}
context.error('Unknown header type "' + header + '".');
}

@@ -297,19 +304,14 @@ function buildHeader(context, spec) {

if (["add", "append", "merge", "set", "setifempty"].includes(spec.action)) {
parts.push('"' +
buildHeaderValue(context, spec.header, spec
.value) +
'"');
parts.push(`"${buildHeaderValue(context, spec.header, spec.value)}"`);
}
else if (["edit", "edit*"].includes(spec.action)) {
parts.push('"' + escapeValue(spec.value) + '"');
parts.push('"' + escapeValue(spec.replacement) + '"');
parts.push(`"${escapeValue(spec.value)}"`);
parts.push(`"${escapeValue(spec.replacement)}"`);
}
if (spec.condition !== undefined) {
if ("envVar" in spec.condition) {
parts.push("env=" +
(spec.condition.requireUnset === true ? "!" : "") +
spec.condition.envVar);
parts.push(`env=${spec.condition.requireUnset === true ? "!" : ""}${spec.condition.envVar}`);
}
else if ("expression" in spec.condition) {
parts.push('"expr=' + escapeValue(spec.condition.expression) + '"');
parts.push(`"expr=${escapeValue(spec.condition.expression)}"`);
}

@@ -327,6 +329,6 @@ }

if ("plus" in spec && spec.plus !== undefined) {
output.push(spec.plus.map((option) => "+" + option).join(" "));
output.push(spec.plus.map((option) => `+${option}`).join(" "));
}
if ("minus" in spec && spec.minus !== undefined) {
output.push(spec.minus.map((option) => "-" + option).join(" "));
output.push(spec.minus.map((option) => `-${option}`).join(" "));
}

@@ -338,3 +340,3 @@ return output.join(" ");

if (spec[option] === true) {
output.push("RewriteOptions " + option);
output.push(`RewriteOptions ${option}`);
}

@@ -355,8 +357,3 @@ }

}
return ('RewriteCond "' +
spec.testString +
'" "' +
spec.conditionPattern +
'"' +
(flags.length > 0 ? " [" + flags.join(",") + "]" : ""));
return `RewriteCond "${spec.testString}" "${spec.conditionPattern}"${flags.length > 0 ? ` [${flags.join(",")}]` : ""}`;
}

@@ -381,3 +378,3 @@ function buildRewriteRuleCookieFlag(spec) {

const containsColon = output.some((field) => field.includes(":"));
return ("CO=" + (containsColon ? ";" : "") + output.join(containsColon ? ";" : ":"));
return `CO=${containsColon ? ";" : ""}${output.join(containsColon ? ";" : ":")}`;
}

@@ -391,3 +388,3 @@ function buildRewriteRuleFlags(flags) {

if (typeof flags.B === "string") {
output.push("B=" + flags.B);
output.push(`B=${flags.B}`);
if (flags.B.includes(" ")) {

@@ -404,3 +401,3 @@ requireQuotes = true;

if (flags.BNE !== undefined) {
output.push("BNE=" + flags.BNE);
output.push(`BNE=${flags.BNE}`);
if (flags.BNE.includes(" ")) {

@@ -422,8 +419,8 @@ requireQuotes = true;

if (flags.env.value === null) {
envValue = "!" + envValue;
envValue = `!${envValue}`;
}
else if (flags.env.value !== "") {
envValue += ":" + flags.env.value;
envValue += `:${flags.env.value}`;
}
output.push("E=" + envValue);
output.push(`E=${envValue}`);
}

@@ -440,3 +437,3 @@ if (flags.END === true) {

if (flags.handler !== undefined) {
output.push("H=" + flags.handler);
output.push(`H=${flags.handler}`);
}

@@ -471,9 +468,9 @@ if (flags.last === true) {

if (flags.redirect !== undefined) {
output.push("R=" + flags.redirect.toString());
output.push(`R=${flags.redirect.toString()}`);
}
if (flags.skip !== undefined) {
output.push("S=" + flags.skip.toString());
output.push(`S=${flags.skip.toString()}`);
}
if (flags.type !== undefined) {
output.push("T=" + flags.type);
output.push(`T=${flags.type}`);
}

@@ -490,3 +487,3 @@ if (flags.UnsafeAllow3F === true) {

const quote = requireQuotes ? '"' : "";
return " " + quote + "[" + output.join(",") + "]" + quote;
return ` ${quote}[${output.join(",")}]${quote}`;
}

@@ -500,8 +497,3 @@ function buildRewriteRules(spec) {

const flags = rule.flags !== undefined ? buildRewriteRuleFlags(rule.flags) : "";
output.push('RewriteRule "' +
escapeValue(rule.pattern) +
'" "' +
escapeValue(rule.substitution ?? "-") +
'"' +
flags);
output.push(`RewriteRule "${escapeValue(rule.pattern)}" "${escapeValue(rule.substitution ?? "-")}"${flags}`);
}

@@ -513,3 +505,3 @@ return output;

if (spec.base !== undefined) {
output.push('RewriteBase "' + escapeValue(spec.base) + '"');
output.push(`RewriteBase "${escapeValue(spec.base)}"`);
}

@@ -529,15 +521,15 @@ if (spec.options !== undefined) {

if (spec.AddOutputFilterByType !== undefined) {
output += buildAddOutputFilterByType(spec.AddOutputFilterByType) + "\n";
output += `${buildAddOutputFilterByType(spec.AddOutputFilterByType)}\n`;
}
if (spec.ErrorDocument !== undefined) {
output += buildErrorDocument(spec.ErrorDocument) + "\n";
output += `${buildErrorDocument(spec.ErrorDocument)}\n`;
}
if (spec.Options !== undefined) {
output += buildOptions(spec.Options) + "\n";
output += `${buildOptions(spec.Options)}\n`;
}
for (const header of spec.Header ?? []) {
output += buildHeader(context, header) + "\n";
output += `${buildHeader(context, header)}\n`;
}
if (spec.rewrite !== undefined) {
output += buildRewrite(spec.rewrite) + "\n";
output += `${buildRewrite(spec.rewrite)}\n`;
}

@@ -551,6 +543,5 @@ return output;

catch (err) {
context.error("Could not read rollup-plugin-htaccess template file, Error: " +
err.message);
context.error(`Could not read rollup-plugin-htaccess template file, Error: ${err.message}`);
}
return fileContents.replace(/\r/g, "") + "\n";
return `${fileContents.replace(/\r/gu, "")}\n`;
}async function buildHtaccessFile(context, options, root) {

@@ -569,6 +560,6 @@ let output = "";

const options = {
extractMetaCSP: { enabled: false },
fileName: ".htaccess",
spec: {},
template: undefined,
spec: {},
extractMetaCSP: { enabled: false },
...opts,

@@ -578,3 +569,2 @@ };

const rollupPlugin = {
name: "htaccess",
configResolved: (config) => {

@@ -585,7 +575,8 @@ root = config.root;

this.emitFile({
type: "asset",
fileName: options.fileName,
source: await buildHtaccessFile(this, options, root),
type: "asset",
});
},
name: "htaccess",
...extractMetaCSP(options),

@@ -592,0 +583,0 @@ };

{
"name": "rollup-plugin-htaccess",
"version": "0.5.2",
"version": "0.5.3",
"description": "A rollup/vite plugin to generate .htaccess files",

@@ -68,16 +68,14 @@ "keywords": [

"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
"@eslint/js": "^9.9.1",
"@microsoft/api-extractor": "^7.47.2",
"@rollup/plugin-typescript": "^11.1.6",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.1",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.12.0",
"eslint": "^8.57.0",
"@rollup/plugin-typescript": "^12.1.0",
"@types/jest": "^29.5.13",
"@types/node": "^22.0.2",
"eslint": "^9.9.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-jest": "^28.5.0",
"eslint-plugin-prefer-arrow-functions": "^3.3.2",
"eslint-plugin-jest": "^28.8.0",
"eslint-plugin-perfectionist": "^3.2.0",
"eslint-plugin-prefer-arrow-functions": "^3.4.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-simple-import-sort": "^12.1.0",
"jest": "^29.7.0",

@@ -89,4 +87,5 @@ "prettier": "^3.3.0",

"typescript": "^5.3.3",
"typescript-eslint": "^8.2.0",
"vite": "^5.2.13"
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc