Commit ac419aba authored by Cholgrrr's avatar Cholgrrr
Browse files

.gitignore, settings.json und 14061 weitere dateien aktualisiert...

parent ed14b8b4
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.semverMin = exports.isBrowsersQueryValid = void 0;
function _browserslist() {
const data = _interopRequireDefault(require("browserslist"));
_browserslist = function () {
return data;
};
return data;
}
function _invariant() {
const data = _interopRequireDefault(require("invariant"));
_invariant = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
var _utils = require("./utils");
var _normalizeOptions = require("./normalize-options");
var _builtInModules = _interopRequireDefault(require("../data/built-in-modules.json"));
var _options = require("./options");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const browserslistDefaults = _browserslist().default.defaults;
const validateTargetNames = (validTargets, targets) => {
for (const target in targets) {
if (!_options.TargetNames[target]) {
const validOptions = (0, _utils.getValues)(_options.TargetNames);
throw new Error(`Invalid Option: '${target}' is not a valid target
Maybe you meant to use '${(0, _utils.findSuggestion)(validOptions, target)}'?`);
}
}
};
const browserNameMap = {
and_chr: "chrome",
android: "android",
chrome: "chrome",
edge: "edge",
firefox: "firefox",
ie: "ie",
ios_saf: "ios",
node: "node",
opera: "opera",
safari: "safari"
};
const isBrowsersQueryValid = browsers => typeof browsers === "string" || Array.isArray(browsers);
exports.isBrowsersQueryValid = isBrowsersQueryValid;
const validateBrowsers = browsers => {
(0, _invariant().default)(typeof browsers === "undefined" || isBrowsersQueryValid(browsers), `Invalid Option: '${browsers}' is not a valid browserslist query`);
return browsers;
};
const semverMin = (first, second) => {
return first && _semver().default.lt(first, second) ? first : second;
};
exports.semverMin = semverMin;
const mergeBrowsers = (fromQuery, fromTarget) => {
return Object.keys(fromTarget).reduce((queryObj, targKey) => {
if (targKey !== _options.TargetNames.browsers) {
queryObj[targKey] = fromTarget[targKey];
}
return queryObj;
}, fromQuery);
};
const getLowestVersions = browsers => {
return browsers.reduce((all, browser) => {
const [browserName, browserVersion] = browser.split(" ");
const normalizedBrowserName = browserNameMap[browserName];
if (!normalizedBrowserName) {
return all;
}
try {
const splitVersion = browserVersion.split("-")[0].toLowerCase();
const isSplitUnreleased = (0, _utils.isUnreleasedVersion)(splitVersion, browserName);
if (!all[normalizedBrowserName]) {
all[normalizedBrowserName] = isSplitUnreleased ? splitVersion : (0, _utils.semverify)(splitVersion);
return all;
}
const version = all[normalizedBrowserName];
const isUnreleased = (0, _utils.isUnreleasedVersion)(version, browserName);
if (isUnreleased && isSplitUnreleased) {
all[normalizedBrowserName] = (0, _utils.getLowestUnreleased)(version, splitVersion, browserName);
} else if (isUnreleased) {
all[normalizedBrowserName] = (0, _utils.semverify)(splitVersion);
} else if (!isUnreleased && !isSplitUnreleased) {
const parsedBrowserVersion = (0, _utils.semverify)(splitVersion);
all[normalizedBrowserName] = semverMin(version, parsedBrowserVersion);
}
} catch (e) {}
return all;
}, {});
};
const outputDecimalWarning = decimalTargets => {
if (!decimalTargets || !decimalTargets.length) {
return;
}
console.log("Warning, the following targets are using a decimal version:");
console.log("");
decimalTargets.forEach(({
target,
value
}) => console.log(` ${target}: ${value}`));
console.log("");
console.log("We recommend using a string for minor/patch versions to avoid numbers like 6.10");
console.log("getting parsed as 6.1, which can lead to unexpected behavior.");
console.log("");
};
const semverifyTarget = (target, value) => {
try {
return (0, _utils.semverify)(value);
} catch (error) {
throw new Error(`Invalid Option: '${value}' is not a valid value for 'targets.${target}'.`);
}
};
const targetParserMap = {
__default: (target, value) => {
const version = (0, _utils.isUnreleasedVersion)(value, target) ? value.toLowerCase() : semverifyTarget(target, value);
return [target, version];
},
node: (target, value) => {
const parsed = value === true || value === "current" ? process.versions.node : semverifyTarget(target, value);
return [target, parsed];
}
};
const getTargets = (targets = {}, options = {}) => {
const targetOpts = {};
validateTargetNames(targets);
if (targets.esmodules) {
const supportsESModules = _builtInModules.default["es6.module"];
targets.browsers = Object.keys(supportsESModules).map(browser => `${browser} ${supportsESModules[browser]}`).join(", ");
}
const browsersquery = validateBrowsers(targets.browsers);
const shouldParseBrowsers = !!targets.browsers;
const shouldSearchForConfig = !options.ignoreBrowserslistConfig && !Object.keys(targets).length;
if (shouldParseBrowsers || shouldSearchForConfig) {
_browserslist().default.defaults = (0, _normalizeOptions.objectToBrowserslist)(targets);
const browsers = (0, _browserslist().default)(browsersquery, {
path: options.configPath
});
const queryBrowsers = getLowestVersions(browsers);
targets = mergeBrowsers(queryBrowsers, targets);
_browserslist().default.defaults = browserslistDefaults;
}
const parsed = Object.keys(targets).filter(value => value !== _options.TargetNames.esmodules).sort().reduce((results, target) => {
if (target !== _options.TargetNames.browsers) {
const value = targets[target];
if (typeof value === "number" && value % 1 !== 0) {
results.decimalWarnings.push({
target,
value
});
}
const parser = targetParserMap[target] || targetParserMap.__default;
const [parsedTarget, parsedValue] = parser(target, value);
if (parsedValue) {
results.targets[parsedTarget] = parsedValue;
}
}
return results;
}, {
targets: targetOpts,
decimalWarnings: []
});
outputDecimalWarning(parsed.decimalWarnings);
return parsed.targets;
};
var _default = getTargets;
exports.default = _default;
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _debug = require("./debug");
var _utils = require("./utils");
function _default({
types: t
}) {
function replaceWithPolyfillImports(path, polyfills, regenerator) {
if (regenerator) {
(0, _utils.createImport)(path, "regenerator-runtime");
}
const items = Array.isArray(polyfills) ? new Set(polyfills) : polyfills;
for (const p of Array.from(items).reverse()) {
(0, _utils.createImport)(path, p);
}
path.remove();
}
const isPolyfillImport = {
ImportDeclaration(path, state) {
if (path.node.specifiers.length === 0 && (0, _utils.isPolyfillSource)(path.node.source.value)) {
this.importPolyfillIncluded = true;
replaceWithPolyfillImports(path, state.opts.polyfills, state.opts.regenerator);
}
},
Program(path, state) {
path.get("body").forEach(bodyPath => {
if ((0, _utils.isRequire)(t, bodyPath)) {
replaceWithPolyfillImports(bodyPath, state.opts.polyfills, state.opts.regenerator);
}
});
}
};
return {
name: "transform-polyfill-require",
visitor: isPolyfillImport,
pre() {
this.numPolyfillImports = 0;
this.importPolyfillIncluded = false;
},
post() {
const {
debug,
onDebug,
polyfills
} = this.opts;
if (debug) {
(0, _debug.logEntryPolyfills)(this.importPolyfillIncluded, polyfills, this.file.opts.filename, onDebug);
}
}
};
}
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _builtInDefinitions = require("./built-in-definitions");
var _debug = require("./debug");
var _utils = require("./utils");
function has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
function getType(target) {
if (Array.isArray(target)) return "array";
return typeof target;
}
function _default({
types: t
}) {
function addImport(path, builtIn, builtIns) {
if (builtIn && !builtIns.has(builtIn)) {
builtIns.add(builtIn);
(0, _utils.createImport)(path, builtIn);
}
}
function addUnsupported(path, polyfills, builtIn, builtIns) {
if (Array.isArray(builtIn)) {
for (const i of builtIn) {
if (polyfills.has(i)) {
addImport(path, i, builtIns);
}
}
} else {
if (polyfills.has(builtIn)) {
addImport(path, builtIn, builtIns);
}
}
}
const addAndRemovePolyfillImports = {
ImportDeclaration(path) {
if (path.node.specifiers.length === 0 && (0, _utils.isPolyfillSource)(path.node.source.value)) {
console.warn(`
When setting \`useBuiltIns: 'usage'\`, polyfills are automatically imported when needed.
Please remove the \`import '@babel/polyfill'\` call or use \`useBuiltIns: 'entry'\` instead.`);
path.remove();
}
},
Program: {
enter(path) {
path.get("body").forEach(bodyPath => {
if ((0, _utils.isRequire)(t, bodyPath)) {
console.warn(`
When setting \`useBuiltIns: 'usage'\`, polyfills are automatically imported when needed.
Please remove the \`require('@babel/polyfill')\` call or use \`useBuiltIns: 'entry'\` instead.`);
bodyPath.remove();
}
});
}
},
ReferencedIdentifier(path, state) {
const {
node,
parent,
scope
} = path;
if (t.isMemberExpression(parent)) return;
if (!has(_builtInDefinitions.definitions.builtins, node.name)) return;
if (scope.getBindingIdentifier(node.name)) return;
const builtIn = _builtInDefinitions.definitions.builtins[node.name];
addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
},
CallExpression(path) {
if (path.node.arguments.length) return;
const callee = path.node.callee;
if (!t.isMemberExpression(callee)) return;
if (!callee.computed) return;
if (!path.get("callee.property").matchesPattern("Symbol.iterator")) {
return;
}
addImport(path, "web.dom.iterable", this.builtIns);
},
BinaryExpression(path) {
if (path.node.operator !== "in") return;
if (!path.get("left").matchesPattern("Symbol.iterator")) return;
addImport(path, "web.dom.iterable", this.builtIns);
},
YieldExpression(path) {
if (!path.node.delegate) return;
addImport(path, "web.dom.iterable", this.builtIns);
},
MemberExpression: {
enter(path, state) {
if (!path.isReferenced()) return;
const {
node
} = path;
const obj = node.object;
const prop = node.property;
if (!t.isReferenced(obj, node)) return;
let instanceType;
let evaluatedPropType = obj.name;
let propName = prop.name;
if (node.computed) {
if (t.isStringLiteral(prop)) {
propName = prop.value;
} else {
const res = path.get("property").evaluate();
if (res.confident && res.value) {
propName = res.value;
}
}
}
if (path.scope.getBindingIdentifier(obj.name)) {
const result = path.get("object").evaluate();
if (result.value) {
instanceType = getType(result.value);
} else if (result.deopt && result.deopt.isIdentifier()) {
evaluatedPropType = result.deopt.node.name;
}
}
if (has(_builtInDefinitions.definitions.staticMethods, evaluatedPropType)) {
const staticMethods = _builtInDefinitions.definitions.staticMethods[evaluatedPropType];
if (has(staticMethods, propName)) {
const builtIn = staticMethods[propName];
addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
}
}
if (has(_builtInDefinitions.definitions.instanceMethods, propName)) {
let builtIn = _builtInDefinitions.definitions.instanceMethods[propName];
if (instanceType) {
builtIn = builtIn.filter(item => item.includes(instanceType));
}
addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
}
},
exit(path, state) {
if (!path.isReferenced()) return;
const {
node
} = path;
const obj = node.object;
if (!has(_builtInDefinitions.definitions.builtins, obj.name)) return;
if (path.scope.getBindingIdentifier(obj.name)) return;
const builtIn = _builtInDefinitions.definitions.builtins[obj.name];
addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
}
},
VariableDeclarator(path, state) {
if (!path.isReferenced()) return;
const {
node
} = path;
const obj = node.init;
if (!t.isObjectPattern(node.id)) return;
if (!t.isReferenced(obj, node)) return;
if (obj && path.scope.getBindingIdentifier(obj.name)) return;
for (let prop of node.id.properties) {
prop = prop.key;
if (!node.computed && t.isIdentifier(prop) && has(_builtInDefinitions.definitions.instanceMethods, prop.name)) {
const builtIn = _builtInDefinitions.definitions.instanceMethods[prop.name];
addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
}
}
},
Function(path, state) {
if (!this.usesRegenerator && (path.node.generator || path.node.async)) {
this.usesRegenerator = true;
if (state.opts.regenerator) {
addImport(path, "regenerator-runtime", this.builtIns);
}
}
}
};
return {
name: "use-built-ins",
pre() {
this.builtIns = new Set();
this.usesRegenerator = false;
},
post() {
const {
debug,
onDebug
} = this.opts;
if (debug) {
(0, _debug.logUsagePolyfills)(this.builtIns, this.file.opts.filename, onDebug);
}
},
visitor: addAndRemovePolyfillImports
};
}
\ No newline at end of file
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isRequire = exports.createImport = exports.getModulePath = exports.isPolyfillSource = exports.filterStageFromList = exports.getLowestUnreleased = exports.isUnreleasedVersion = exports.prettifyTargets = exports.prettifyVersion = exports.findSuggestion = exports.getValues = exports.semverify = void 0;
function _invariant() {
const data = _interopRequireDefault(require("invariant"));
_invariant = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function _jsLevenshtein() {
const data = _interopRequireDefault(require("js-levenshtein"));
_jsLevenshtein = function () {
return data;
};
return data;
}
function _helperModuleImports() {
const data = require("@babel/helper-module-imports");
_helperModuleImports = function () {
return data;
};
return data;
}
var _unreleasedLabels = _interopRequireDefault(require("../data/unreleased-labels"));
var _targetsParser = require("./targets-parser");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const versionRegExp = /^(\d+|\d+.\d+)$/;
const semverify = version => {
if (typeof version === "string" && _semver().default.valid(version)) {
return version;
}
(0, _invariant().default)(typeof version === "number" || typeof version === "string" && versionRegExp.test(version), `'${version}' is not a valid version`);
const split = version.toString().split(".");
while (split.length < 3) {
split.push("0");
}
return split.join(".");
};
exports.semverify = semverify;
const getValues = object => Object.keys(object).map(key => object[key]);
exports.getValues = getValues;
const findSuggestion = (options, option) => {
let levenshteinValue = Infinity;
return options.reduce((suggestion, validOption) => {
const value = (0, _jsLevenshtein().default)(validOption, option);
if (value < levenshteinValue) {
levenshteinValue = value;
return validOption;
}
return suggestion;
}, undefined);
};
exports.findSuggestion = findSuggestion;
const prettifyVersion = version => {
if (typeof version !== "string") {
return version;
}
const parts = [_semver().default.major(version)];
const minor = _semver().default.minor(version);
const patch = _semver().default.patch(version);
if (minor || patch) {
parts.push(minor);
}
if (patch) {
parts.push(patch);
}
return parts.join(".");
};
exports.prettifyVersion = prettifyVersion;
const prettifyTargets = targets => {
return Object.keys(targets).reduce((results, target) => {
let value = targets[target];
const unreleasedLabel = _unreleasedLabels.default[target];
if (typeof value === "string" && unreleasedLabel !== value) {
value = prettifyVersion(value);
}
results[target] = value;
return results;
}, {});
};
exports.prettifyTargets = prettifyTargets;
const isUnreleasedVersion = (version, env) => {
const unreleasedLabel = _unreleasedLabels.default[env];
return !!unreleasedLabel && unreleasedLabel === version.toString().toLowerCase();
};
exports.isUnreleasedVersion = isUnreleasedVersion;
const getLowestUnreleased = (a, b, env) => {
const unreleasedLabel = _unreleasedLabels.default[env];
const hasUnreleased = [a, b].some(item => item === unreleasedLabel);
if (hasUnreleased) {
return a === hasUnreleased ? b : a || b;
}
return (0, _targetsParser.semverMin)(a, b);
};
exports.getLowestUnreleased = getLowestUnreleased;
const filterStageFromList = (list, stageList) => {
return Object.keys(list).reduce((result, item) => {
if (!stageList[item]) {
result[item] = list[item];
}
return result;
}, {});
};
exports.filterStageFromList = filterStageFromList;
const isPolyfillSource = source => source === "@babel/polyfill" || source === "core-js";
exports.isPolyfillSource = isPolyfillSource;
const modulePathMap = {
"regenerator-runtime": "regenerator-runtime/runtime"
};
const getModulePath = mod => modulePathMap[mod] || `core-js/modules/${mod}`;
exports.getModulePath = getModulePath;
const createImport = (path, mod) => (0, _helperModuleImports().addSideEffect)(path, getModulePath(mod));
exports.createImport = createImport;
const isRequire = (t, path) => t.isExpressionStatement(path.node) && t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "require" && path.node.expression.arguments.length === 1 && t.isStringLiteral(path.node.expression.arguments[0]) && isPolyfillSource(path.node.expression.arguments[0].value);
exports.isRequire = isRequire;
\ No newline at end of file
{
"name": "@babel/preset-env",
"version": "7.3.4",
"description": "A Babel preset for each environment.",
"author": "Henry Zhu <hi@henryzoo.com>",
"homepage": "https://babeljs.io/",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"repository": "https://github.com/babel/babel/tree/master/packages/babel-preset-env",
"main": "lib/index.js",
"scripts": {
"build-data": "node ./scripts/build-data.js; node ./scripts/build-modules-support.js"
},
"dependencies": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-proposal-async-generator-functions": "^7.2.0",
"@babel/plugin-proposal-json-strings": "^7.2.0",
"@babel/plugin-proposal-object-rest-spread": "^7.3.4",
"@babel/plugin-proposal-optional-catch-binding": "^7.2.0",
"@babel/plugin-proposal-unicode-property-regex": "^7.2.0",
"@babel/plugin-syntax-async-generators": "^7.2.0",
"@babel/plugin-syntax-json-strings": "^7.2.0",
"@babel/plugin-syntax-object-rest-spread": "^7.2.0",
"@babel/plugin-syntax-optional-catch-binding": "^7.2.0",
"@babel/plugin-transform-arrow-functions": "^7.2.0",
"@babel/plugin-transform-async-to-generator": "^7.3.4",
"@babel/plugin-transform-block-scoped-functions": "^7.2.0",
"@babel/plugin-transform-block-scoping": "^7.3.4",
"@babel/plugin-transform-classes": "^7.3.4",
"@babel/plugin-transform-computed-properties": "^7.2.0",
"@babel/plugin-transform-destructuring": "^7.2.0",
"@babel/plugin-transform-dotall-regex": "^7.2.0",
"@babel/plugin-transform-duplicate-keys": "^7.2.0",
"@babel/plugin-transform-exponentiation-operator": "^7.2.0",
"@babel/plugin-transform-for-of": "^7.2.0",
"@babel/plugin-transform-function-name": "^7.2.0",
"@babel/plugin-transform-literals": "^7.2.0",
"@babel/plugin-transform-modules-amd": "^7.2.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/plugin-transform-modules-systemjs": "^7.3.4",
"@babel/plugin-transform-modules-umd": "^7.2.0",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0",
"@babel/plugin-transform-new-target": "^7.0.0",
"@babel/plugin-transform-object-super": "^7.2.0",
"@babel/plugin-transform-parameters": "^7.2.0",
"@babel/plugin-transform-regenerator": "^7.3.4",
"@babel/plugin-transform-shorthand-properties": "^7.2.0",
"@babel/plugin-transform-spread": "^7.2.0",
"@babel/plugin-transform-sticky-regex": "^7.2.0",
"@babel/plugin-transform-template-literals": "^7.2.0",
"@babel/plugin-transform-typeof-symbol": "^7.2.0",
"@babel/plugin-transform-unicode-regex": "^7.2.0",
"browserslist": "^4.3.4",
"invariant": "^2.2.2",
"js-levenshtein": "^1.1.3",
"semver": "^5.3.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.3.4",
"@babel/helper-fixtures": "^7.2.0",
"@babel/helper-plugin-test-runner": "^7.0.0",
"caniuse-db": "1.0.30000851",
"compat-table": "kangax/compat-table#1e7b377fbdda9243cf9602872fcb493cdbdd565f",
"electron-to-chromium": "1.3.79"
},
"gitHead": "1f6454cc90fe33e0a32260871212e2f719f35741"
}
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @babel/runtime-corejs2
> babel's modular runtime helpers with core-js@2 polyfilling
See our website [@babel/runtime-corejs2](https://babeljs.io/docs/en/next/babel-runtime-corejs2.html) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/runtime-corejs2
```
or using yarn:
```sh
yarn add @babel/runtime-corejs2 --dev
```
module.exports = require("core-js/library/fn/array/from");
\ No newline at end of file
module.exports = require("core-js/library/fn/array/is-array");
\ No newline at end of file
module.exports = require("core-js/library/fn/array/of");
\ No newline at end of file
module.exports = require("core-js/library/fn/clear-immediate");
\ No newline at end of file
module.exports = require("core-js/library/fn/date/now");
\ No newline at end of file
module.exports = require("core-js/library/fn/get-iterator");
\ No newline at end of file
module.exports = require("core-js/library/fn/is-iterable");
\ No newline at end of file
module.exports = require("core-js/library/fn/json/stringify");
\ No newline at end of file
module.exports = require("core-js/library/fn/map");
\ No newline at end of file
module.exports = require("core-js/library/fn/math/acosh");
\ No newline at end of file
module.exports = require("core-js/library/fn/math/asinh");
\ No newline at end of file
module.exports = require("core-js/library/fn/math/atanh");
\ No newline at end of file
module.exports = require("core-js/library/fn/math/cbrt");
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment