@angular/build
Advanced tools
Comparing version
{ | ||
"name": "@angular/build", | ||
"version": "20.0.0-next.0", | ||
"version": "20.0.0-next.1", | ||
"description": "Official build system for Angular", | ||
@@ -26,12 +26,12 @@ "keywords": [ | ||
"@ampproject/remapping": "2.3.0", | ||
"@angular-devkit/architect": "0.2000.0-next.0", | ||
"@babel/core": "7.26.9", | ||
"@angular-devkit/architect": "0.2000.0-next.1", | ||
"@babel/core": "7.26.10", | ||
"@babel/helper-annotate-as-pure": "7.25.9", | ||
"@babel/helper-split-export-declaration": "7.24.7", | ||
"@babel/plugin-syntax-import-attributes": "7.26.0", | ||
"@inquirer/confirm": "5.1.6", | ||
"@inquirer/confirm": "5.1.7", | ||
"@vitejs/plugin-basic-ssl": "2.0.0", | ||
"beasties": "0.2.0", | ||
"browserslist": "^4.23.0", | ||
"esbuild": "0.25.0", | ||
"esbuild": "0.25.1", | ||
"https-proxy-agent": "7.0.6", | ||
@@ -45,3 +45,3 @@ "istanbul-lib-instrument": "6.0.3", | ||
"piscina": "4.8.0", | ||
"rollup": "4.34.9", | ||
"rollup": "4.35.0", | ||
"sass": "1.85.1", | ||
@@ -51,3 +51,3 @@ "semver": "7.7.1", | ||
"tinyglobby": "0.2.12", | ||
"vite": "6.2.0", | ||
"vite": "6.2.1", | ||
"watchpack": "2.4.2" | ||
@@ -64,3 +64,3 @@ }, | ||
"@angular/service-worker": "^20.0.0 || ^20.0.0-next.0", | ||
"@angular/ssr": "^20.0.0-next.0", | ||
"@angular/ssr": "^20.0.0-next.1", | ||
"karma": "^6.4.0", | ||
@@ -71,3 +71,3 @@ "less": "^4.2.0", | ||
"tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", | ||
"typescript": ">=5.5 <5.9" | ||
"typescript": ">=5.8 <5.9" | ||
}, | ||
@@ -107,2 +107,3 @@ "peerDependenciesMeta": { | ||
}, | ||
"packageManager": "pnpm@9.15.6", | ||
"engines": { | ||
@@ -109,0 +110,0 @@ "node": "^20.11.1 || >=22.0.0", |
@@ -139,11 +139,39 @@ "use strict"; | ||
if (options.externalPackages || bundlingResult.externalConfiguration) { | ||
const { externalConfiguration, externalImports: { browser, server }, } = bundlingResult; | ||
const implicitBrowser = browser ? [...browser] : []; | ||
const implicitServer = server ? [...server] : []; | ||
// TODO: Implement wildcard externalConfiguration filtering | ||
executionResult.setExternalMetadata(externalConfiguration | ||
? implicitBrowser.filter((value) => !externalConfiguration.includes(value)) | ||
: implicitBrowser, externalConfiguration | ||
? implicitServer.filter((value) => !externalConfiguration.includes(value)) | ||
: implicitServer, externalConfiguration); | ||
const { externalConfiguration = [], externalImports: { browser = [], server = [] }, } = bundlingResult; | ||
// Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*, | ||
// which matches import paths like @foo/bar/baz. | ||
// This means all paths within the @foo/bar package are also marked as external. | ||
const exclusionsPrefixes = externalConfiguration.map((exclusion) => exclusion + '/'); | ||
const exclusions = new Set(externalConfiguration); | ||
const explicitExternal = new Set(); | ||
const isExplicitExternal = (dep) => { | ||
if (exclusions.has(dep)) { | ||
return true; | ||
} | ||
for (const prefix of exclusionsPrefixes) { | ||
if (dep.startsWith(prefix)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
const implicitBrowser = []; | ||
for (const dep of browser) { | ||
if (isExplicitExternal(dep)) { | ||
explicitExternal.add(dep); | ||
} | ||
else { | ||
implicitBrowser.push(dep); | ||
} | ||
} | ||
const implicitServer = []; | ||
for (const dep of server) { | ||
if (isExplicitExternal(dep)) { | ||
explicitExternal.add(dep); | ||
} | ||
else { | ||
implicitServer.push(dep); | ||
} | ||
} | ||
executionResult.setExternalMetadata(implicitBrowser, implicitServer, [...explicitExternal]); | ||
} | ||
@@ -150,0 +178,0 @@ const { metafile, initialFiles, outputFiles } = bundlingResult; |
@@ -111,2 +111,5 @@ /** | ||
externalDependencies: string[] | undefined; | ||
externalPackages: boolean | { | ||
exclude: string[] | undefined; | ||
} | undefined; | ||
extractLicenses: boolean | undefined; | ||
@@ -119,5 +122,2 @@ inlineStyleLanguage: string; | ||
progress: boolean; | ||
externalPackages: boolean | { | ||
exclude: string[]; | ||
} | undefined; | ||
preserveSymlinks: boolean; | ||
@@ -124,0 +124,0 @@ stylePreprocessorOptions: import("./schema").StylePreprocessorOptions | undefined; |
@@ -256,3 +256,9 @@ "use strict"; | ||
crossOrigin, | ||
externalDependencies, | ||
externalDependencies: normalizeExternals(externalDependencies), | ||
externalPackages: typeof externalPackages === 'object' | ||
? { | ||
...externalPackages, | ||
exclude: normalizeExternals(externalPackages.exclude), | ||
} | ||
: externalPackages, | ||
extractLicenses, | ||
@@ -265,3 +271,2 @@ inlineStyleLanguage, | ||
progress, | ||
externalPackages, | ||
preserveSymlinks, | ||
@@ -452,1 +457,19 @@ stylePreprocessorOptions, | ||
} | ||
/** | ||
* Normalizes an array of external dependency paths by ensuring that | ||
* wildcard patterns (`/*`) are removed from package names. | ||
* | ||
* This avoids the need to handle this normalization repeatedly in our plugins, | ||
* as esbuild already treats `--external:@foo/bar` as implicitly including | ||
* `--external:@foo/bar/*`. By standardizing the input, we ensure consistency | ||
* and reduce redundant checks across our plugins. | ||
* | ||
* @param value - An optional array of dependency paths to normalize. | ||
* @returns A new array with wildcard patterns removed from package names, or `undefined` if input is `undefined`. | ||
*/ | ||
function normalizeExternals(value) { | ||
if (!value) { | ||
return undefined; | ||
} | ||
return [...new Set(value.map((d) => (d.endsWith('/*') ? d.slice(0, -2) : d)))]; | ||
} |
@@ -65,3 +65,5 @@ /** | ||
* Exclude the listed external dependencies from being bundled into the bundle. Instead, the | ||
* created bundle relies on these dependencies to be available during runtime. | ||
* created bundle relies on these dependencies to be available during runtime. Note: | ||
* `@foo/bar` marks all paths within the `@foo/bar` package as external, including sub-paths | ||
* like `@foo/bar/baz`. | ||
*/ | ||
@@ -68,0 +70,0 @@ externalDependencies?: string[]; |
@@ -199,3 +199,3 @@ { | ||
"externalDependencies": { | ||
"description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime.", | ||
"description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime. Note: `@foo/bar` marks all paths within the `@foo/bar` package as external, including sub-paths like `@foo/bar/baz`.", | ||
"type": "array", | ||
@@ -202,0 +202,0 @@ "items": { |
@@ -36,6 +36,2 @@ "use strict"; | ||
const { builderName, normalizedOptions } = await initialize(options, projectName, context); | ||
// Warn if the initial options provided by the user enable prebundling but caching is disabled | ||
if (options.prebundle && !normalizedOptions.cacheOptions.enabled) { | ||
context.logger.warn(`Prebundling has been configured but will not be used because caching has been disabled.`); | ||
} | ||
yield* (0, vite_server_1.serveWithVite)(normalizedOptions, builderName, (options, context, plugins) => (0, internal_1.buildApplicationInternal)(options, context, { codePlugins: plugins }), context, { indexHtml: extensions?.indexHtmlTransformer }, extensions); | ||
@@ -42,0 +38,0 @@ } |
@@ -107,5 +107,7 @@ /** | ||
* List of package imports that should not be prebundled by the development server. The | ||
* packages will be bundled into the application code itself. | ||
* packages will be bundled into the application code itself. Note: specifying `@foo/bar` | ||
* marks all paths within the `@foo/bar` package as excluded, including sub-paths like | ||
* `@foo/bar/baz`. | ||
*/ | ||
exclude: string[]; | ||
}; |
@@ -118,3 +118,3 @@ { | ||
"exclude": { | ||
"description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself.", | ||
"description": "List of package imports that should not be prebundled by the development server. The packages will be bundled into the application code itself. Note: specifying `@foo/bar` marks all paths within the `@foo/bar` package as excluded, including sub-paths like `@foo/bar/baz`.", | ||
"type": "array", | ||
@@ -121,0 +121,0 @@ "items": { "type": "string" } |
@@ -674,2 +674,3 @@ "use strict"; | ||
resetComponentUpdates: () => templateUpdates.clear(), | ||
projectRoot: serverOptions.projectRoot, | ||
}), | ||
@@ -676,0 +677,0 @@ (0, plugins_1.createRemoveIdPrefixPlugin)(externalMetadata.explicitBrowser), |
@@ -105,3 +105,3 @@ "use strict"; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
checkFileSystem, extractionResult.messages, 'warning', | ||
checkFileSystem, extractionResult.messages, normalizedOptions.i18nOptions.i18nDuplicateTranslation || 'warning', | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
@@ -108,0 +108,0 @@ extractionResult.basePath); |
@@ -17,3 +17,2 @@ "use strict"; | ||
const node_assert_1 = __importDefault(require("node:assert")); | ||
const node_url_1 = require("node:url"); | ||
/** | ||
@@ -30,11 +29,5 @@ * A babel plugin factory function for adding istanbul instrumentation. | ||
enter(path, state) { | ||
const inputSourceMap = // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
state.file.inputMap?.toObject(); | ||
// istanbul does not support URL as sources. | ||
if (inputSourceMap?.sources) { | ||
inputSourceMap.sources = inputSourceMap.sources.map((s) => s.startsWith('file://') ? (0, node_url_1.fileURLToPath)(s) : s); | ||
} | ||
const visitor = (0, istanbul_lib_instrument_1.programVisitor)(core_1.types, state.filename, { | ||
// Babel returns a Converter object from the `convert-source-map` package | ||
inputSourceMap, | ||
inputSourceMap: state.file.inputMap?.toObject(), | ||
}); | ||
@@ -41,0 +34,0 @@ visitors.set(path, visitor); |
@@ -50,3 +50,2 @@ "use strict"; | ||
const path = __importStar(require("node:path")); | ||
const node_url_1 = require("node:url"); | ||
const environment_options_1 = require("../../../utils/environment-options"); | ||
@@ -547,6 +546,2 @@ const compilation_1 = require("../../angular/compilation"); | ||
noEmitOnError: false, | ||
// Using the path as a URL is necessary here; otherwise, esbuild will not generate source maps correctly. | ||
// https://github.com/evanw/esbuild/issues/4070 | ||
// https://github.com/evanw/esbuild/issues/4075 | ||
outDir: absWorkingDir ? (0, node_url_1.pathToFileURL)(absWorkingDir + '/').href : undefined, | ||
inlineSources: !!pluginOptions.sourcemap, | ||
@@ -553,0 +548,0 @@ inlineSourceMap: !!pluginOptions.sourcemap, |
@@ -279,11 +279,9 @@ "use strict"; | ||
for (const { imports } of Object.values(result.metafile.outputs)) { | ||
for (const importData of imports) { | ||
if (!importData.external || | ||
utils_1.SERVER_GENERATED_EXTERNALS.has(importData.path) || | ||
(importData.kind !== 'import-statement' && | ||
importData.kind !== 'dynamic-import' && | ||
importData.kind !== 'require-call')) { | ||
for (const { external, kind, path } of imports) { | ||
if (!external || | ||
utils_1.SERVER_GENERATED_EXTERNALS.has(path) || | ||
(kind !== 'import-statement' && kind !== 'dynamic-import' && kind !== 'require-call')) { | ||
continue; | ||
} | ||
externalImports.add(importData.path); | ||
externalImports.add(path); | ||
} | ||
@@ -290,0 +288,0 @@ } |
@@ -77,3 +77,3 @@ /** | ||
*/ | ||
setExternalMetadata(implicitBrowser: string[], implicitServer: string[], explicit: string[] | undefined): void; | ||
setExternalMetadata(implicitBrowser: string[], implicitServer: string[], explicit: string[]): void; | ||
get output(): { | ||
@@ -80,0 +80,0 @@ success: boolean; |
@@ -89,3 +89,3 @@ "use strict"; | ||
setExternalMetadata(implicitBrowser, implicitServer, explicit) { | ||
this.externalMetadata = { implicitBrowser, implicitServer, explicit: explicit ?? [] }; | ||
this.externalMetadata = { implicitBrowser, implicitServer, explicit }; | ||
} | ||
@@ -92,0 +92,0 @@ get output() { |
@@ -21,3 +21,10 @@ "use strict"; | ||
function createExternalPackagesPlugin(options) { | ||
const exclusions = options?.exclude?.length ? new Set(options.exclude) : undefined; | ||
const exclusions = new Set(options?.exclude); | ||
// Similar to esbuild, --external:@foo/bar automatically implies --external:@foo/bar/*, | ||
// which matches import paths like @foo/bar/baz. | ||
// This means all paths within the @foo/bar package are also marked as external. | ||
const exclusionsPrefixes = options?.exclude?.map((exclusion) => exclusion + '/') ?? []; | ||
const seenExclusions = new Set(); | ||
const seenExternals = new Set(); | ||
const seenNonExclusions = new Set(); | ||
return { | ||
@@ -33,3 +40,3 @@ name: 'angular-external-packages', | ||
// Safe to use native packages external option if no loader options or exclusions present | ||
if (!exclusions && !loaderOptionKeys?.length) { | ||
if (!exclusions.size && !loaderOptionKeys?.length) { | ||
build.initialOptions.packages = 'external'; | ||
@@ -44,5 +51,17 @@ return; | ||
} | ||
if (exclusions?.has(args.path)) { | ||
if (seenExternals.has(args.path)) { | ||
return { external: true }; | ||
} | ||
if (exclusions.has(args.path) || seenExclusions.has(args.path)) { | ||
return null; | ||
} | ||
if (!seenNonExclusions.has(args.path)) { | ||
for (const exclusion of exclusionsPrefixes) { | ||
if (args.path.startsWith(exclusion)) { | ||
seenExclusions.add(args.path); | ||
return null; | ||
} | ||
} | ||
seenNonExclusions.add(args.path); | ||
} | ||
const { importer, kind, resolveDir, namespace, pluginData = {} } = args; | ||
@@ -57,6 +76,11 @@ pluginData[EXTERNAL_PACKAGE_RESOLUTION] = true; | ||
}); | ||
// Return result if unable to resolve or explicitly marked external (externalDependencies option) | ||
if (!result.path || result.external) { | ||
// Return result if unable to resolve | ||
if (!result.path) { | ||
return result; | ||
} | ||
// Return if explicitly marked external (externalDependencies option) | ||
if (result.external) { | ||
seenExternals.add(args.path); | ||
return { external: true }; | ||
} | ||
// Allow customized loaders to run against configured paths regardless of location | ||
@@ -68,6 +92,4 @@ if (loaderFileExtensions.has((0, node_path_1.extname)(result.path))) { | ||
if (/[\\/]node_modules[\\/]/.test(result.path)) { | ||
return { | ||
path: args.path, | ||
external: true, | ||
}; | ||
seenExternals.add(args.path); | ||
return { external: true }; | ||
} | ||
@@ -74,0 +96,0 @@ // Otherwise return original result |
@@ -45,4 +45,2 @@ "use strict"; | ||
const promises_1 = require("node:fs/promises"); | ||
const node_path_1 = require("node:path"); | ||
const node_url_1 = require("node:url"); | ||
/** | ||
@@ -121,3 +119,3 @@ * The lazy-loaded instance of the less stylesheet preprocessor. | ||
try { | ||
const { imports, map, css } = await less.render(data, { | ||
const { imports, css } = await less.render(data, { | ||
filename, | ||
@@ -130,3 +128,3 @@ paths: options.includePaths, | ||
? { | ||
sourceMapFileInline: false, | ||
sourceMapFileInline: true, | ||
outputSourceFiles: true, | ||
@@ -137,5 +135,3 @@ } | ||
return { | ||
// There can be cases where `less` will return an undefined `map` even | ||
// though the types do not specify this as a possibility. | ||
contents: map ? `${css}\n${sourceMapToUrlComment(map)}` : css, | ||
contents: css, | ||
loader: 'css', | ||
@@ -193,11 +189,1 @@ watchFiles: [filename, ...imports], | ||
} | ||
function sourceMapToUrlComment(sourceMap) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const map = JSON.parse(sourceMap); | ||
// Using file URLs instead of paths ensures that esbuild correctly resolves the source map. | ||
// https://github.com/evanw/esbuild/issues/4070 | ||
// https://github.com/evanw/esbuild/issues/4075 | ||
map.sources = map.sources.map((source) => source && (0, node_path_1.isAbsolute)(source) ? (0, node_url_1.pathToFileURL)(source).href : source); | ||
const urlSourceMap = Buffer.from(JSON.stringify(map), 'utf-8').toString('base64'); | ||
return `/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${urlSourceMap} */`; | ||
} |
@@ -51,2 +51,3 @@ "use strict"; | ||
const tinyglobby_1 = require("tinyglobby"); | ||
const error_1 = require("../../../utils/error"); | ||
const load_result_cache_1 = require("../load-result-cache"); | ||
@@ -317,4 +318,13 @@ /** | ||
} | ||
throw error; | ||
else { | ||
(0, error_1.assertIsError)(error); | ||
return { | ||
errors: [ | ||
{ | ||
text: error.message, | ||
}, | ||
], | ||
}; | ||
} | ||
} | ||
} |
@@ -14,1 +14,2 @@ /** | ||
export { createAngularComponentMiddleware } from './component-middleware'; | ||
export { createChromeDevtoolsMiddleware } from './chrome-devtools-middleware'; |
@@ -10,3 +10,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.createAngularComponentMiddleware = exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0; | ||
exports.createChromeDevtoolsMiddleware = exports.createAngularComponentMiddleware = exports.createAngularHeadersMiddleware = exports.createAngularSsrInternalMiddleware = exports.createAngularSsrExternalMiddleware = exports.createAngularIndexHtmlMiddleware = exports.angularHtmlFallbackMiddleware = exports.createAngularAssetsMiddleware = void 0; | ||
var assets_middleware_1 = require("./assets-middleware"); | ||
@@ -25,1 +25,3 @@ Object.defineProperty(exports, "createAngularAssetsMiddleware", { enumerable: true, get: function () { return assets_middleware_1.createAngularAssetsMiddleware; } }); | ||
Object.defineProperty(exports, "createAngularComponentMiddleware", { enumerable: true, get: function () { return component_middleware_1.createAngularComponentMiddleware; } }); | ||
var chrome_devtools_middleware_1 = require("./chrome-devtools-middleware"); | ||
Object.defineProperty(exports, "createChromeDevtoolsMiddleware", { enumerable: true, get: function () { return chrome_devtools_middleware_1.createChromeDevtoolsMiddleware; } }); |
@@ -26,3 +26,3 @@ "use strict"; | ||
} | ||
const escapedExternals = externals.map(escapeRegexSpecialChars); | ||
const escapedExternals = externals.map((e) => escapeRegexSpecialChars(e) + '(?:/.+)?'); | ||
const prefixedExternalRegex = new RegExp(`${resolvedConfig.base}${VITE_ID_PREFIX}(${escapedExternals.join('|')})`, 'g'); | ||
@@ -29,0 +29,0 @@ // @ts-expect-error: Property 'push' does not exist on type 'readonly Plugin<any>[]' |
@@ -42,4 +42,5 @@ /** | ||
resetComponentUpdates: () => void; | ||
projectRoot: string; | ||
} | ||
export declare function createAngularSetupMiddlewaresPlugin(options: AngularSetupMiddlewaresPluginOptions): Plugin; | ||
export {}; |
@@ -54,2 +54,3 @@ "use strict"; | ||
server.middlewares.use((0, middlewares_1.createAngularAssetsMiddleware)(server, assets, outputFiles, componentStyles, await createEncapsulateStyle())); | ||
server.middlewares.use((0, middlewares_1.createChromeDevtoolsMiddleware)(server.config.cacheDir, options.projectRoot)); | ||
extensionMiddleware?.forEach((middleware) => server.middlewares.use(middleware)); | ||
@@ -56,0 +57,0 @@ // Returning a function, installs middleware after the main transform middleware but |
@@ -8,2 +8,3 @@ /** | ||
*/ | ||
import { DiagnosticHandlingStrategy } from '@angular/localize/tools'; | ||
import type { TranslationLoader } from './load-translations'; | ||
@@ -28,2 +29,3 @@ export interface LocaleDescription { | ||
hasDefinedSourceLocale?: boolean; | ||
i18nDuplicateTranslation?: DiagnosticHandlingStrategy; | ||
} | ||
@@ -30,0 +32,0 @@ export declare function createI18nOptions(projectMetadata: { |
@@ -13,3 +13,3 @@ "use strict"; | ||
/** Version placeholder is replaced during the build process with actual package version */ | ||
const VERSION = '20.0.0-next.0'; | ||
const VERSION = '20.0.0-next.1'; | ||
function hasCacheMetadata(value) { | ||
@@ -16,0 +16,0 @@ return (!!value && |
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1132789
0.44%345
0.58%25888
0.49%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated
Updated