I have an app (Vite + React) that depends on a library that makes use of dynamic imports in the form of:
const { T } = useLocale(({ locale }) => require(`./i18n/${locale}.json`));
Unfortunately, I can't seem to be able to build my app due to this line. When I attempt to build with Vite, I get errors such as:
Not supported dynamic import, file:/Users/borne/Work/prototype/node_modules/#internal/top-navigation/es/Navigation.js
I added the legacy plugin to my configs, as well as the CommonJs solution as described here:
https://www.npmjs.com/package/#originjs/vite-plugin-commonjs
But it didn't seem to change anything.
This is my config:
import {defineConfig} from 'vite';
import react from '#vitejs/plugin-react';
import babel from 'vite-plugin-babel';
import { viteCommonjs, esbuildCommonjs } from '#originjs/vite-plugin-commonjs';
import legacy from '#vitejs/plugin-legacy';
const fs = require('fs');
export default defineConfig({
plugins: [
viteCommonjs(),
babel(),
react({
babel: {
parserOpts: {
plugins: ['decorators-legacy']
}
},
}),
legacy({
targets: ['defaults', 'not IE 11']
}),
],
optimizeDeps: {
esbuildOptions: {
plugins: [
esbuildCommonjs([
'#internal/top-navigation',
]),
],
},
},
server: {
hmr: {
clientPort: 443,
},
https: {
key: fs.readFileSync('./.cert/key.pem'),
cert: fs.readFileSync('./.cert/cert.pem'),
},
},
define: {
'process.env': {},
'global': {}
}
})
What am I missing?
I made an tiny math library (tinycas) which I published to npm as an esm module.
Here is the package.json :
{
"name": "tinycas",
"version": "0.8.9",
"description": "A Simple CAS",
"keywords": [
"cas",
"math"
],
"module": "./dist/tinycas.mjs",
"type": "module",
"author": "Zahara-Nour",
"repository": "github:Zahara-Nour/tinycas",
"scripts": {
"dist": "rollup -c",
"test": "jest --coverage --colors",
"testw": "jest --watch --colors",
"start": "node src/index.js",
},
"license": "ISC",
"devDependencies": {
......
},
"dependencies": {
"decimal.js": "^10.2.1"
}
}
I made the package with rollup :
// rollup.config.js
// import { nodeResolve } from '#rollup/plugin-node-resolve';
export default [
{
external: ['decimal.js'],
input: './src/index.js',
output:
{
file: './dist/tinycas.mjs',
format: 'es',
},
// plugins: [nodeResolve()]
},
]
Then I used this library in a sveltekit project. In dev mode, no problem, the library is imported and I can use it. But when I want to make a production build to test it before deploying it to Vercel, vite seems not to find my library :
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '/Users/david/Coding/js/ubumaths/node_modules/tinycas/' imported from /Users/david/Coding/js/ubumaths/.svelte-kit/output/server/entries/pages/index.svelte.js
at new NodeError (node:internal/errors:371:5)
at legacyMainResolve (node:internal/modules/esm/resolve:336:9)
at packageResolve (node:internal/modules/esm/resolve:919:14)
at moduleResolve (node:internal/modules/esm/resolve:978:18)
at defaultResolve (node:internal/modules/esm/resolve:1080:11)
at ESMLoader.resolve (node:internal/modules/esm/loader:530:30)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:251:18)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:79:40)
at link (node:internal/modules/esm/module_job:78:36)
> 500 /
at file:///Users/david/Coding/js/ubumaths/node_modules/#sveltejs/kit/dist/chunks/index2.js:1043:11
at save (file:///Users/david/Coding/js/ubumaths/node_modules/#sveltejs/kit/dist/chunks/index2.js:1262:4)
at visit (file:///Users/david/Coding/js/ubumaths/node_modules/#sveltejs/kit/dist/chunks/index2.js:1153:3)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
However, my library is installed. Is it because I didn't package my library in a good way ? Maybe I have to also provide a cjs version for the production build?
I would like to trigger EMR spark job with python code through AWS Lambda after trigger the s3 event.I appreciate if any one can share the configuration/command to invoke the EMR spark job from AWS Lambda function.
Since this question is very generic, I will try to give an example code for doing this. You will have to change certain parameters based upon your actual value.
The way I generally do this is I place the main handler function in one file say named as lambda_handler.py and all the configuration and steps of the EMR in a file named as emr_configuration_and_steps.py.
Please check the code snippet below for lambda_handler.py
import boto3
import emr_configuration_and_steps
import logging
import traceback
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
def create_emr(name):
try:
emr = boto3.client('emr')
cluster_id = emr.run_job_flow(
Name=name,
VisibleToAllUsers=emr_configuration_and_steps.visible_to_all_users,
LogUri=emr_configuration_and_steps.log_uri,
ReleaseLabel=emr_configuration_and_steps.release_label,
Applications=emr_configuration_and_steps.applications,
Tags=emr_configuration_and_steps.tags,
Instances=emr_configuration_and_steps.instances,
Steps=emr_configuration_and_steps.steps,
Configurations=emr_configuration_and_steps.configurations,
ScaleDownBehavior=emr_configuration_and_steps.scale_down_behavior,
ServiceRole=emr_configuration_and_steps.service_role,
JobFlowRole=emr_configuration_and_steps.job_flow_role
)
logger.info("EMR is created successfully")
return cluster_id['JobFlowId']
except Exception as e:
traceback.print_exc()
raise Exception(e)
def lambda_handler(event, context):
logger.info("starting the lambda function for spawning EMR")
try:
emr_cluster_id = create_emr('Name of Your EMR')
logger.info("emr_cluster_id is = " + emr_cluster_id)
except Exception as e:
logger.error("Exception at some step in the process " + str(e))
Now the second file(emr_configuration_and_steps.py) that has all the configuration would look like this.
visible_to_all_users = True
log_uri = 's3://your-s3-log-path-here/'
release_label = 'emr-5.29.0'
applications = [{'Name': 'Spark'}, {'Name': 'Hadoop'}]
tags = [
{'Key': 'Project', 'Value': 'Your-Project Name'},
{'Key': 'Service', 'Value': 'Your-Service Name'},
{'Key': 'Environment', 'Value': 'Development'}
]
instances = {
'Ec2KeyName': 'Your-key-name',
'Ec2SubnetId': 'your-subnet-name',
'InstanceFleets': [
{
"InstanceFleetType": "MASTER",
"TargetOnDemandCapacity": 1,
"TargetSpotCapacity": 0,
"InstanceTypeConfigs": [
{
"WeightedCapacity": 1,
"BidPriceAsPercentageOfOnDemandPrice": 100,
"InstanceType": "m3.xlarge"
}
],
"Name": "Master Node"
},
{
"InstanceFleetType": "CORE",
"TargetSpotCapacity": 8,
"InstanceTypeConfigs": [
{
"WeightedCapacity": 8,
"BidPriceAsPercentageOfOnDemandPrice": 50,
"InstanceType": "m3.xlarge"
}
],
"Name": "Core Node"
},
],
'KeepJobFlowAliveWhenNoSteps': False
}
steps = [
{
'Name': 'Setup Hadoop Debugging',
'ActionOnFailure': 'TERMINATE_CLUSTER',
'HadoopJarStep': {
'Jar': 'command-runner.jar',
'Args': ['state-pusher-script']
}
},
{
"Name": "Active Marker for digital panel",
"ActionOnFailure": 'TERMINATE_CLUSTER',
'HadoopJarStep': {
"Jar": "command-runner.jar",
"Args": [
"spark-submit",
"--deploy-mode",
"cluster",
"--driver-memory", "4g",
"--executor-memory", "4g",
"--executor-cores", "2",
"--class", "your-main-class-full-path-name",
"s3://your-jar-path-SNAPSHOT-jar-with-dependencies.jar"
]
}
}
]
configurations = [
{
"Classification": "spark-log4j",
"Properties": {
"log4j.logger.root": "INFO",
"log4j.logger.org": "INFO",
"log4j.logger.com": "INFO"
}
}
]
scale_down_behavior = 'TERMINATE_AT_TASK_COMPLETION'
service_role = 'EMR_DefaultRole'
job_flow_role = 'EMR_EC2_DefaultRole'
Please adjust the certain path and name according to your use case. To deploy this you need to install boto3 and package/zip these 2 files in a zip file and upload this to your lambda function. By this you should be able to spawn the EMR.
This question is similar to Disable logging in gunicorn for a specific request / URL / endpoint except that my question is concerned with disabling gunicorn healthcheck logging in a Django app.
How do I disable gunicorn logging in a Django app?
I'm also using syslog, so the settings.LOGGING dictionary is something like this:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "default",
},
"syslog": {
"level": "DEBUG",
"class": "logging.handlers.SysLogHandler",
"formatter": "default",
"facility": SysLogHandler.LOG_LOCAL2,
"address": syslog_address,
},
},
"loggers": {
"django": {"handlers": ["console", "syslog"], "propagate": True},
"apps": {"handlers": ["console", "syslog"], "level": "DEBUG"},
"utils": {"handlers": ["console", "syslog"], "level": "DEBUG"},
"gunicorn.access": {"handlers": ["console", "syslog"], "level": "INFO"},
"gunicorn.error": {"handlers": ["console", "syslog"], "level": "INFO"},
},
}
Note that I explicitly added the gunicorn.access logger for use with syslog (see: https://github.com/benoitc/gunicorn/issues/2016).
I'm answering my own question.
Once I added the gunicorn.access logger to deal with syslog, I could not simply add a pre_request hook in my gunicorn.conf file (as per this solution).
You have to provide your own custom logging class by subclassing gunicorn.glogging.Logger as stated in the docs.
Create a logging module and add:
from gunicorn import glogging
class CustomGunicornLogger(glogging.Logger):
def access(self, resp, req, environ, request_time):
# disable healthcheck logging
if req.path in ["/healthcheck"]:
return
super().access(resp, req, environ, request_time)
In your gunicorn.conf file, add:
logger_class = 'your_module.CustomGunicornLogger'
Use your gunicorn.conf file when using gunicorn:
gunicorn --config=gunicorn.conf your_django_app.wsgi:application
Another solution was inspired by this gunicorn answer: How to filter logs from gunicorn?
class HealthCheckFilter(logging.Filter):
def filter(self, record):
return record.getMessage().find('/healthcheck') == -1
Add the healthcheck to the custom logger:
class CustomGunicornLogger(glogging.Logger):
def setup(self, cfg):
super().setup(cfg)
# Add filters to Gunicorn logger
logger = logging.getLogger("gunicorn.access")
logger.addFilter(HealthCheckFilter())
I am running a Windows 7 Professional PC, using Visual Studio 2017 version 15.4.5. When I created a .Net Core 2.0 project and selected the type of Angular, it ran fine out of the box.
Then I added font awesome and primeng (https://www.primefaces.org/primeng/#/) in what I think is the standard way, i.e., adding references to the package.json file, then to the nonTreeShakableModules section of the webpack.config.vendor.js file, then adding modules to app.module.shared.ts. This was primeng version 5.0.2 and font-awesome version 4.7.0.
In development, all is good - everything is running fine. However, when I try to publish, I see the following lines in the Output window:
npm install
removed 3 packages in 3.389s
node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod
What? Why would it remove 3 packages?
And then the publish attempt fails. After the failure, I see that 3 of my npm packages have been UNINSTALLED:
1) #types/jquery
2) font-awesome
3) primeng
And I see a bunch of "Module not found" errors - of course they are not found, because they were just removed!
I looked at the .csproj file, and I see the following:
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec Command="npm install" />
<Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
<Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />
So, as far as I can tell, the "npm install" command, or something triggered by that command, is removing these modules. I have to re-install them after every Publish attempt.
So, my question: Why are these packages being removed, and what can I do about it?
My package.json file:
{
"name": "CaseManagementReporting",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"dependencies": {
"#angular/animations": "4.2.5",
"#angular/common": "4.2.5",
"#angular/compiler": "4.2.5",
"#angular/compiler-cli": "4.2.5",
"#angular/core": "4.2.5",
"#angular/forms": "4.2.5",
"#angular/http": "4.2.5",
"#angular/platform-browser": "4.2.5",
"#angular/platform-browser-dynamic": "4.2.5",
"#angular/platform-server": "4.2.5",
"#angular/router": "4.2.5",
"#ngtools/webpack": "1.5.0",
"#types/webpack-env": "1.13.0",
"angular2-template-loader": "0.6.2",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.1",
"awesome-typescript-loader": "3.2.1",
"bootstrap": "3.3.7",
"css": "2.2.1",
"css-loader": "0.28.4",
"es6-shim": "0.35.3",
"event-source-polyfill": "0.0.9",
"expose-loader": "0.7.3",
"extract-text-webpack-plugin": "2.1.2",
"file-loader": "0.11.2",
"font-awesome": "4.7.0",
"html-loader": "0.4.5",
"isomorphic-fetch": "2.2.1",
"jquery": "3.2.1",
"json-loader": "0.5.4",
"preboot": "4.5.2",
"primeng": "5.0.2",
"raw-loader": "0.5.1",
"reflect-metadata": "0.1.10",
"rxjs": "5.4.2",
"style-loader": "0.18.2",
"to-string-loader": "1.1.5",
"typescript": "2.4.1",
"url-loader": "0.5.9",
"webpack": "2.5.1",
"webpack-hot-middleware": "2.18.2",
"webpack-merge": "4.1.0",
"zone.js": "0.8.12"
},
"devDependencies": {
"#types/chai": "4.0.1",
"#types/jasmine": "2.5.53",
"#types/jquery": "3.2.1",
"chai": "4.0.2",
"jasmine-core": "2.6.4",
"karma": "1.7.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.3"
}
}
My tsconfig.json file:
{
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipDefaultLibCheck": true,
"skipLibCheck": true, // Workaround for https://github.com/angular/angular/issues/17863. Remove this if you upgrade to a fixed version of Angular.
"strict": true,
"lib": [ "es6", "dom" ],
"types": [ "webpack-env", "jquery" ]
},
"exclude": [ "bin", "node_modules" ],
"atom": { "rewriteTsconfig": false }
}
My webpack.config.vendor.js file:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const merge = require('webpack-merge');
const treeShakableModules = [
'#angular/animations',
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/forms',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router',
'zone.js'
];
const nonTreeShakableModules = [
'bootstrap',
'bootstrap/dist/css/bootstrap.css',
'es6-promise',
'es6-shim',
'event-source-polyfill',
'jquery',
'font-awesome/css/font-awesome.css',
'primeng/resources/themes/bootstrap/theme.css',
'primeng/resources/primeng.min.css',
'primeng/primeng'
];
const allModules = treeShakableModules.concat(nonTreeShakableModules);
module.exports = (env) => {
const extractCSS = new ExtractTextPlugin('vendor.css');
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
resolve: { extensions: [ '.js' ] },
module: {
rules: [
{ test: /\.(png|woff|woff2|eot|ttf|svg|jpg|jpeg|gif)(\?|$)/, use: 'url-loader?limit=100000' }
]
},
output: {
publicPath: 'dist/',
filename: '[name].js',
library: '[name]_[hash]'
},
plugins: [
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
new webpack.ContextReplacementPlugin(/\#angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)#angular/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898
new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
]
};
const clientBundleConfig = merge(sharedConfig, {
entry: {
// To keep development builds fast, include all vendor dependencies in the vendor bundle.
// But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle.
vendor: isDevBuild ? allModules : nonTreeShakableModules
},
output: { path: path.join(__dirname, 'wwwroot', 'dist') },
module: {
rules: [
{ test: /\.css(\?|$)/, use: extractCSS.extract({ use: isDevBuild ? 'css-loader' : 'css-loader?minimize' }) }
]
},
plugins: [
extractCSS,
new webpack.DllPlugin({
path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin()
])
});
const serverBundleConfig = merge(sharedConfig, {
target: 'node',
resolve: { mainFields: ['main'] },
entry: { vendor: allModules.concat(['aspnet-prerendering']) },
output: {
path: path.join(__dirname, 'ClientApp', 'dist'),
libraryTarget: 'commonjs2',
},
module: {
rules: [
{ test: /\.css(\?|$)/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize'] }
]
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'),
name: '[name]_[hash]'
})
]
});
return [clientBundleConfig, serverBundleConfig];
}
My webpack.config.js file:
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
I found a solution for this problem (which sadly just led to another, but...).
I believe that this was/is a bug in the version of NPM which I was using. I had npm version 5.0.3 installed. After hours of searching, I came across this GitHub discussion: here in which many people complained about the npm install command actually removing modules. I downgraded my npm instance from 5.0.3 to 3.10.3 (which is what my home environment was using), and I found that the packages were no longer removed. (Why anybody would write something that would remove packages with a command like "npm install" is utterly beyond me, but read the linked article and you will see the frustration this has caused!)
As a .Net developer, of course, I did not even know how to downgrade my npm instance, so I had to look that up. For those who might be helped, the command is: npm install -g npm#3.10.3. I found that here
So, now my publish process runs without deleting packages, which is what I asked about in my question. That issue is resolved, so I am treating this as an answer.
But this is not to say that the downgrade solved all of my problems. When I attempted to publish, I got new errors, which I think are unrelated to the npm version:
Can't resolve './../$$_gendir/ClientApp/app/app.module.browser.ngfactory' in 'C:\Projects\ForthrightProjects\CaseManagementReporting\CaseManagementReporting\ClientApp' CaseManagementReporting Module not found 0
Can't resolve './../$$_gendir/ClientApp/app/app.module.server.ngfactory' in 'C:\Projects\ForthrightProjects\CaseManagementReporting\CaseManagementReporting\ClientApp' CaseManagementReporting Module not found 0
Yet more Googling found this article: here
which suggests commenting out this line in the webpack.config.js file:
// { test: /.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '#ngtools/webpack' },
Or, alternatively, changing it to this:
{ test: /.ts$/, include: /ClientApp/, use: ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] },
I tried both options, and both of them worked to get past the errors above. HOWEVER, I now am faced with yet another error in attempting to publish:
ERROR in Metadata version mismatch for module: C:/Projects/ForthrightProjects/CaseManagementReporting/CaseManagementReporting/node_modules/primeng/components/dom/domhandler.d.ts, found version 4, expected 3
So, after some additional searching and trials and errors, I came across this link: here
One of the suggestions there was to change the primeng entry in the project.json file to this: "primeng": "^4.2.4"
Amazingly enough, this actually worked. I am now able to publish. Hopefully successful deployment of the published files will not be so terribly painful.
To .Net developers: Remember back when you just added a package with NuGet, and everything just worked? Sigh...