Commit 49271f28 authored by ilex0208's avatar ilex0208

*)修改打包

parent 610db13b
......@@ -8,7 +8,6 @@ _mock
doc
src
node_modules
dist
.editorconfig
.eslintignore
.eslintrc.js
......
const gulp = require('gulp');
// gulp core function
const { src, dest, series, parallel, watch } = require('gulp');
// gulp compress js
const uglify = require('gulp-uglify');
// gulp judgment
const gulpif = require('gulp-if');
// gulp compress css
const cleanCSS = require('gulp-clean-css');
// Delete Files
const del = require('delete');
// Refresh the browser in real time
const browserSync = require('browser-sync').create();
const reload = browserSync.reload;
// proxy
const { createProxyMiddleware } = require('http-proxy-middleware');
// According to html reference, files are merged
// const useref = require('gulp-useref');
// File merge
const concat = require('gulp-concat');
// rollup packaging, processing es6 modules
const { rollup } = require('rollup');
// rollup looks for node_modules module
const { nodeResolve } = require('@rollup/plugin-node-resolve');
// rollup converts commonjs module to es6 module
const commonjs = require('@rollup/plugin-commonjs');
// rollup code compression
const terser = require('rollup-plugin-terser').terser;
// rollup babel plugin, support the latest ES grammar
const babel = require('@rollup/plugin-babel').default;
// const gulpBabel = require('gulp-babel');
// Distinguish development and production environments
const production = process.env.NODE_ENV === 'production' ? true : false;
const pkg = require('./package.json');
const banner = `/*! @preserve
* ${pkg.name}
* version: ${pkg.version}
* https://github.com/mengshukeji/Luckysheet
*/`;
// uglify js Compression configuration https://github.com/mishoo/UglifyJS#minify-options
const uglifyOptions = {
compress: {
drop_console: true
}
}
// babel config
const babelConfig = {
compact: false,
babelHelpers: 'bundled',
exclude: 'node_modules/**', // Only compile our source code
plugins: [
],
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3,
targets: {
chrome: 58,
ie: 11
}
}]
]
};
// file handler paths
const paths = {
// static resources,contains index.html, fonts and images,and extension plugins dependency
staticHtml: ['src/*.html'],
staticFonts: ['src/fonts/**'],
staticAssets: ['src/assets/**'],
staticImages: ['src/plugins/images/*.png'],
staticExpendPlugins: ['src/expendPlugins/**', '!src/expendPlugins/**/plugin.js'],
staticDemoData: ['src/demoData/*.js'],
staticCssImages: ['src/css/**', '!src/css/*.css'],
// static resources dest
destStaticHtml: ['dist'],
destStaticFonts: ['dist/fonts'],
destStaticAssets: ['dist/assets'],
destStaticImages: ['dist/plugins/images'],
destStaticExpendPlugins: ['dist/expendPlugins'],
destStaticDemoData: ['dist/demoData'],
destStaticCssImages: ['dist/css'],
//core es module
core: ['src/**/*.js', '!src/demoData/*.js', 'src/expendPlugins/**/plugin.js', '!src/plugins/js/*.js'],
//plugins src
pluginsCss: ['src/plugins/css/*.css'],
plugins: ['src/plugins/*.css'],
css: ['src/css/*.css', 'node_modules/flatpickr/dist/themes/light.css'],
pluginsJs: [
'node_modules/jquery/dist/jquery.min.js',
'node_modules/uuid/dist/umd/uuid.min.js',
'node_modules/exceljs/dist/exceljs.min.js',
'src/plugins/js/clipboard.min.js',
'src/plugins/js/spectrum.min.js',
'src/plugins/js/jquery-ui.min.js',
'src/plugins/js/jquery.mousewheel.min.js',
// 'src/plugins/js/numeral.min.js',
'src/plugins/js/html2canvas.min.js',
'src/plugins/js/localforage.min.js',
'src/plugins/js/lodash.min.js',
'src/plugins/js/jstat.min.js',
'src/plugins/js/crypto-api.min.js',
'src/plugins/js/jquery.sPage.min.js'
],
//plugins concat
concatPluginsCss: 'pluginsCss.css',
concatPlugins: 'plugins.css',
concatCss: 'luckysheet.css',
concatPluginsJs: 'plugin.js',
//plugins dest
destPluginsCss: ['dist/plugins/css'],
destPlugins: ['dist/plugins'],
destCss: ['dist/css'],
destPluginsJs: ['dist/plugins/js'],
// Package directory
dist: 'dist',
};
// Clear the dist directory
function clean() {
return del([paths.dist]);
}
// proxy middleware
const apiProxy = createProxyMiddleware('/luckysheet/', {
target: 'http://luckysheet.lashuju.com/', // set your server address
changeOrigin: true, // for vhosted sites
ws: true, // proxy websockets
});
// Static server
function serve(done) {
browserSync.init({
server: {
baseDir: paths.dist,
middleware: [apiProxy],//proxy
},
ghostMode: false, //默认true,滚动和表单在任何设备上输入将被镜像到所有设备里,会影响本地的协同编辑消息,故关闭
}, done)
}
// Monitoring file changes
function watcher(done) {
watch(paths.core, { delay: 500 }, series(core, reloadBrowser));
// watch plugins and css
watch(paths.pluginsCss, { delay: 500 }, series(pluginsCss, reloadBrowser));
watch(paths.plugins, { delay: 500 }, series(plugins, reloadBrowser));
watch(paths.css, { delay: 500 }, series(css, reloadBrowser));
watch(paths.pluginsJs, { delay: 500 }, series(pluginsJs, reloadBrowser));
// watch static
watch(paths.staticHtml, { delay: 500 }, series(copyStaticHtml, reloadBrowser));
watch(paths.staticFonts, { delay: 500 }, series(copyStaticFonts, reloadBrowser));
watch(paths.staticAssets, { delay: 500 }, series(copyStaticAssets, reloadBrowser));
watch(paths.staticImages, { delay: 500 }, series(copyStaticImages, reloadBrowser));
watch(paths.staticExpendPlugins, { delay: 500 }, series(copyStaticExpendPlugins, reloadBrowser));
watch(paths.staticDemoData, { delay: 500 }, series(copyStaticDemoData, reloadBrowser));
watch(paths.staticCssImages, { delay: 500 }, series(copyStaticCssImages, reloadBrowser));
done();
}
// Refresh browser
function reloadBrowser(done) {
reload();
done();
}
//Package the core code
async function core_rollup() {
const bundle = await rollup({
input: 'src/index.js',
plugins: [
nodeResolve(), // tells Rollup how to find date-fns in node_modules
commonjs(), // converts date-fns to ES modules
// postcss({
// plugins: [],
// extract: true,
// // minimize: isProductionEnv,
// }),
production && terser(), // minify, but only in production
babel(babelConfig)
],
});
bundle.write({
file: 'dist/luckysheet.umd.js',
format: 'umd',
name: 'luckysheet',
sourcemap: true,
inlineDynamicImports: true,
banner: banner
});
if (production) {
bundle.write({
file: 'dist/luckysheet.esm.js',
format: 'esm',
name: 'luckysheet',
sourcemap: true,
inlineDynamicImports: true,
banner: banner
});
}
}
async function core() {
await require('esbuild').buildSync({
format: 'iife',
globalName: 'luckysheet',
entryPoints: ['src/index.js'],
bundle: true,
minify: production,
banner: { js: banner },
target: ['es2020'],
sourcemap: true,
outfile: 'dist/luckysheet.umd.js',
})
}
// According to the build tag in html, package js and css
function pluginsCss() {
return src(paths.pluginsCss)
.pipe(concat(paths.concatPluginsCss))
.pipe(gulpif(production, cleanCSS()))
.pipe(dest(paths.destPluginsCss))
}
function plugins() {
return src(paths.plugins)
.pipe(concat(paths.concatPlugins))
.pipe(gulpif(production, cleanCSS()))
.pipe(dest(paths.destPlugins));
}
function css() {
return src(paths.css)
.pipe(concat(paths.concatCss))
.pipe(gulpif(production, cleanCSS()))
.pipe(dest(paths.destCss));
}
function pluginsJs() {
return src(paths.pluginsJs)
.pipe(concat(paths.concatPluginsJs))
.pipe(gulpif(production, uglify(uglifyOptions)))
.pipe(dest(paths.destPluginsJs));
}
// Copy static resources
function copyStaticHtml() {
return src(paths.staticHtml)
.pipe(dest(paths.destStaticHtml));
}
function copyStaticFonts() {
return src(paths.staticFonts)
.pipe(dest(paths.destStaticFonts));
}
function copyStaticAssets() {
return src(paths.staticAssets)
.pipe(dest(paths.destStaticAssets));
}
function copyStaticImages() {
return src(paths.staticImages)
.pipe(dest(paths.destStaticImages));
}
function copyStaticExpendPlugins() {
return src(paths.staticExpendPlugins)
.pipe(dest(paths.destStaticExpendPlugins));
}
function copyStaticDemoData() {
return src(paths.staticDemoData)
.pipe(dest(paths.destStaticDemoData));
// .pipe(gulpBabel({
// presets: ['@babel/env']
// }))
// .pipe(gulp.dest('dist'));
}
function copyStaticCssImages() {
return src(paths.staticCssImages)
.pipe(dest(paths.destStaticCssImages));
}
const dev = series(clean, parallel(pluginsCss, plugins, css, pluginsJs, copyStaticHtml, copyStaticFonts, copyStaticAssets, copyStaticImages, copyStaticExpendPlugins, copyStaticDemoData, copyStaticCssImages, core), watcher, serve);
const build = series(clean, parallel(pluginsCss, plugins, css, pluginsJs, copyStaticHtml, copyStaticFonts, copyStaticAssets, copyStaticImages, copyStaticExpendPlugins, copyStaticDemoData, copyStaticCssImages, core));
exports.dev = dev;
exports.build = build;
exports.default = dev;
const gulp = require('gulp');
const gulp = require("gulp");
// gulp core function
const { src, dest, series, parallel, watch } = require('gulp');
const { src, dest, series, parallel } = require("gulp");
// gulp compress js
const uglify = require('gulp-uglify');
const uglify = require("gulp-uglify");
// gulp judgment
const gulpif = require('gulp-if');
const gulpif = require("gulp-if");
// gulp compress css
const cleanCSS = require('gulp-clean-css');
const cleanCSS = require("gulp-clean-css");
// Delete Files
const del = require('delete');
const del = require("delete");
// Refresh the browser in real time
const browserSync = require('browser-sync').create();
const reload = browserSync.reload;
// proxy
const { createProxyMiddleware } = require('http-proxy-middleware');
// According to html reference, files are merged
// const useref = require('gulp-useref');
// File merge
const concat = require('gulp-concat');
// rollup packaging, processing es6 modules
const { rollup } = require('rollup');
// rollup looks for node_modules module
const { nodeResolve } = require('@rollup/plugin-node-resolve');
// rollup converts commonjs module to es6 module
const commonjs = require('@rollup/plugin-commonjs');
// rollup code compression
const terser = require('rollup-plugin-terser').terser;
// rollup babel plugin, support the latest ES grammar
const babel = require('@rollup/plugin-babel').default;
// const gulpBabel = require('gulp-babel');
// Distinguish development and production environments
const production = process.env.NODE_ENV === 'production' ? true : false;
const pkg = require('./package.json');
const banner = `/*! @preserve
* ${pkg.name}
* version: ${pkg.version}
* https://github.com/mengshukeji/Luckysheet
*/`;
const concat = require("gulp-concat");
const __ENV__ = require('amos-build/lib/tools/__ENV__');
const production = __ENV__ === "production" ? true : false;
// uglify js Compression configuration https://github.com/mishoo/UglifyJS#minify-options
const uglifyOptions = {
compress: {
drop_console: true
}
}
// babel config
const babelConfig = {
compact: false,
babelHelpers: 'bundled',
exclude: 'node_modules/**', // Only compile our source code
plugins: [
],
presets: [
['@babel/preset-env', {
useBuiltIns: 'usage',
corejs: 3,
targets: {
chrome: 58,
ie: 11
}
}]
]
drop_console: true,
},
};
// file handler paths
const paths = {
// static resources,contains index.html, fonts and images,and extension plugins dependency
staticHtml: ['src/*.html'],
staticFonts: ['src/fonts/**'],
staticAssets: ['src/assets/**'],
staticImages: ['src/plugins/images/*.png'],
staticExpendPlugins: ['src/expendPlugins/**', '!src/expendPlugins/**/plugin.js'],
staticDemoData: ['src/demoData/*.js'],
staticCssImages: ['src/css/**', '!src/css/*.css'],
staticHtml: ["src/*.html"],
staticFonts: ["src/fonts/**"],
staticAssets: ["src/assets/**"],
staticImages: ["src/plugins/images/*.png"],
staticExpendPlugins: [
"src/expendPlugins/**",
"!src/expendPlugins/**/plugin.js",
],
staticDemoData: ["src/demoData/*.js"],
staticCssImages: ["src/css/**", "!src/css/*.css"],
// static resources dest
destStaticHtml: ['dist'],
destStaticFonts: ['dist/fonts'],
destStaticAssets: ['dist/assets'],
destStaticImages: ['dist/plugins/images'],
destStaticExpendPlugins: ['dist/expendPlugins'],
destStaticDemoData: ['dist/demoData'],
destStaticCssImages: ['dist/css'],
destStaticHtml: ["dist"],
destStaticFonts: ["dist/fonts"],
destStaticAssets: ["dist/assets"],
destStaticImages: ["dist/plugins/images"],
destStaticExpendPlugins: ["dist/expendPlugins"],
destStaticDemoData: ["dist/demoData"],
destStaticCssImages: ["dist/css"],
//core es module
core: ['src/**/*.js', '!src/demoData/*.js', 'src/expendPlugins/**/plugin.js', '!src/plugins/js/*.js'],
core: [
"src/**/*.js",
"!src/demoData/*.js",
"src/expendPlugins/**/plugin.js",
"!src/plugins/js/*.js",
],
//plugins src
pluginsCss: ['src/plugins/css/*.css'],
plugins: ['src/plugins/*.css'],
css: ['src/css/*.css', 'node_modules/flatpickr/dist/themes/light.css'],
pluginsCss: ["src/plugins/css/*.css"],
plugins: ["src/plugins/*.css"],
css: ["src/css/*.css", "node_modules/flatpickr/dist/themes/light.css"],
pluginsJs: [
'node_modules/jquery/dist/jquery.min.js',
'node_modules/uuid/dist/umd/uuid.min.js',
'node_modules/exceljs/dist/exceljs.min.js',
'src/plugins/js/clipboard.min.js',
'src/plugins/js/spectrum.min.js',
'src/plugins/js/jquery-ui.min.js',
'src/plugins/js/jquery.mousewheel.min.js',
"node_modules/jquery/dist/jquery.min.js",
"node_modules/uuid/dist/umd/uuid.min.js",
"node_modules/exceljs/dist/exceljs.min.js",
"src/plugins/js/clipboard.min.js",
"src/plugins/js/spectrum.min.js",
"src/plugins/js/jquery-ui.min.js",
"src/plugins/js/jquery.mousewheel.min.js",
// 'src/plugins/js/numeral.min.js',
'src/plugins/js/html2canvas.min.js',
'src/plugins/js/localforage.min.js',
'src/plugins/js/lodash.min.js',
'src/plugins/js/jstat.min.js',
'src/plugins/js/crypto-api.min.js',
'src/plugins/js/jquery.sPage.min.js'
"src/plugins/js/html2canvas.min.js",
"src/plugins/js/localforage.min.js",
"src/plugins/js/lodash.min.js",
"src/plugins/js/jstat.min.js",
"src/plugins/js/crypto-api.min.js",
"src/plugins/js/jquery.sPage.min.js",
],
//plugins concat
concatPluginsCss: 'pluginsCss.css',
concatPlugins: 'plugins.css',
concatCss: 'luckysheet.css',
concatPluginsJs: 'plugin.js',
concatPluginsCss: "pluginsCss.css",
concatPlugins: "plugins.css",
concatCss: "luckysheet.css",
concatPluginsJs: "plugin.js",
//plugins dest
destPluginsCss: ['dist/plugins/css'],
destPlugins: ['dist/plugins'],
destCss: ['dist/css'],
destPluginsJs: ['dist/plugins/js'],
destPluginsCss: ["dist/plugins/css"],
destPlugins: ["dist/plugins"],
destCss: ["dist/css"],
destPluginsJs: ["dist/plugins/js"],
// Package directory
dist: 'dist',
dist: "dist",
};
// Clear the dist directory
......@@ -130,114 +97,12 @@ function clean() {
return del([paths.dist]);
}
// proxy middleware
const apiProxy = createProxyMiddleware('/luckysheet/', {
target: 'http://luckysheet.lashuju.com/', // set your server address
changeOrigin: true, // for vhosted sites
ws: true, // proxy websockets
});
// Static server
function serve(done) {
browserSync.init({
server: {
baseDir: paths.dist,
middleware: [apiProxy],//proxy
},
ghostMode: false, //默认true,滚动和表单在任何设备上输入将被镜像到所有设备里,会影响本地的协同编辑消息,故关闭
}, done)
}
// Monitoring file changes
function watcher(done) {
watch(paths.core, { delay: 500 }, series(core, reloadBrowser));
// watch plugins and css
watch(paths.pluginsCss, { delay: 500 }, series(pluginsCss, reloadBrowser));
watch(paths.plugins, { delay: 500 }, series(plugins, reloadBrowser));
watch(paths.css, { delay: 500 }, series(css, reloadBrowser));
watch(paths.pluginsJs, { delay: 500 }, series(pluginsJs, reloadBrowser));
// watch static
watch(paths.staticHtml, { delay: 500 }, series(copyStaticHtml, reloadBrowser));
watch(paths.staticFonts, { delay: 500 }, series(copyStaticFonts, reloadBrowser));
watch(paths.staticAssets, { delay: 500 }, series(copyStaticAssets, reloadBrowser));
watch(paths.staticImages, { delay: 500 }, series(copyStaticImages, reloadBrowser));
watch(paths.staticExpendPlugins, { delay: 500 }, series(copyStaticExpendPlugins, reloadBrowser));
watch(paths.staticDemoData, { delay: 500 }, series(copyStaticDemoData, reloadBrowser));
watch(paths.staticCssImages, { delay: 500 }, series(copyStaticCssImages, reloadBrowser));
done();
}
// Refresh browser
function reloadBrowser(done) {
reload();
done();
}
//Package the core code
async function core_rollup() {
const bundle = await rollup({
input: 'src/index.js',
plugins: [
nodeResolve(), // tells Rollup how to find date-fns in node_modules
commonjs(), // converts date-fns to ES modules
// postcss({
// plugins: [],
// extract: true,
// // minimize: isProductionEnv,
// }),
production && terser(), // minify, but only in production
babel(babelConfig)
],
});
bundle.write({
file: 'dist/luckysheet.umd.js',
format: 'umd',
name: 'luckysheet',
sourcemap: true,
inlineDynamicImports: true,
banner: banner
});
if (production) {
bundle.write({
file: 'dist/luckysheet.esm.js',
format: 'esm',
name: 'luckysheet',
sourcemap: true,
inlineDynamicImports: true,
banner: banner
});
}
}
async function core() {
await require('esbuild').buildSync({
format: 'iife',
globalName: 'luckysheet',
entryPoints: ['src/index.js'],
bundle: true,
minify: production,
banner: { js: banner },
target: ['es2020'],
sourcemap: true,
outfile: 'dist/luckysheet.umd.js',
})
}
// According to the build tag in html, package js and css
function pluginsCss() {
return src(paths.pluginsCss)
.pipe(concat(paths.concatPluginsCss))
.pipe(gulpif(production, cleanCSS()))
.pipe(dest(paths.destPluginsCss))
.pipe(dest(paths.destPluginsCss));
}
function plugins() {
......@@ -263,41 +128,48 @@ function pluginsJs() {
// Copy static resources
function copyStaticHtml() {
return src(paths.staticHtml)
.pipe(dest(paths.destStaticHtml));
return src(paths.staticHtml).pipe(dest(paths.destStaticHtml));
}
function copyStaticFonts() {
return src(paths.staticFonts)
.pipe(dest(paths.destStaticFonts));
return src(paths.staticFonts).pipe(dest(paths.destStaticFonts));
}
function copyStaticAssets() {
return src(paths.staticAssets)
.pipe(dest(paths.destStaticAssets));
return src(paths.staticAssets).pipe(dest(paths.destStaticAssets));
}
function copyStaticImages() {
return src(paths.staticImages)
.pipe(dest(paths.destStaticImages));
return src(paths.staticImages).pipe(dest(paths.destStaticImages));
}
function copyStaticExpendPlugins() {
return src(paths.staticExpendPlugins)
.pipe(dest(paths.destStaticExpendPlugins));
return src(paths.staticExpendPlugins).pipe(
dest(paths.destStaticExpendPlugins)
);
}
function copyStaticDemoData() {
return src(paths.staticDemoData)
.pipe(dest(paths.destStaticDemoData));
return src(paths.staticDemoData).pipe(dest(paths.destStaticDemoData));
// .pipe(gulpBabel({
// presets: ['@babel/env']
// }))
// .pipe(gulp.dest('dist'));
}
function copyStaticCssImages() {
return src(paths.staticCssImages)
.pipe(dest(paths.destStaticCssImages));
}
const dev = series(clean, parallel(pluginsCss, plugins, css, pluginsJs, copyStaticHtml, copyStaticFonts, copyStaticAssets, copyStaticImages, copyStaticExpendPlugins, copyStaticDemoData, copyStaticCssImages, core), watcher, serve);
const build = series(clean, parallel(pluginsCss, plugins, css, pluginsJs, copyStaticHtml, copyStaticFonts, copyStaticAssets, copyStaticImages, copyStaticExpendPlugins, copyStaticDemoData, copyStaticCssImages, core));
exports.dev = dev;
exports.build = build;
exports.default = dev;
return src(paths.staticCssImages).pipe(dest(paths.destStaticCssImages));
}
const buildAssets = series(
clean,
parallel(
pluginsCss,
plugins,
css,
pluginsJs,
copyStaticHtml,
copyStaticFonts,
copyStaticAssets,
copyStaticImages,
copyStaticExpendPlugins,
copyStaticDemoData,
copyStaticCssImages
)
);
gulp.task("assets", buildAssets);
{
"name": "@cloudqms/luckysheet",
"version": "2.1.20",
"version": "2.1.21",
"main": "lib/index.js",
"devDependencies": {
"@babel/runtime": "^7.12.1",
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@babel/runtime-corejs3": "^7.12.1",
"@commitlint/cli": "^9.1.1",
"@commitlint/config-conventional": "^9.1.1",
"@rollup/plugin-babel": "^5.2.1",
"@rollup/plugin-commonjs": "^13.0.0",
"@rollup/plugin-node-resolve": "^8.0.1",
"browser-sync": "^2.26.7",
"commitizen": "^4.1.2",
"cross-env": "^7.0.2",
"amos-build": "^5.x",
"tmp": "0.2.1",
"delete": "^1.1.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-if": "^3.0.0",
"gulp-uglify": "^3.0.2",
"gulp-useref": "^4.0.1",
"http-proxy-middleware": "^1.0.6",
"rollup": "^2.32.1",
"rollup-plugin-terser": "^6.1.0",
"standard-version": "^8.0.2",
"uuid": "^8.3.2",
"vuepress": "^1.5.0",
"esbuild": "^0.11.6",
"vuepress-plugin-baidu-autopush": "^1.0.1",
"vuepress-plugin-code-copy": "^1.0.6",
"vuepress-plugin-seo": "^0.1.4",
"vuepress-plugin-sitemap": "^2.3.1"
"gulp-useref": "^4.0.1"
},
"dependencies": {
"dayjs": "^1.9.6",
......@@ -42,16 +18,15 @@
"file-saver": "^2.0.5",
"flatpickr": "^4.0.9",
"jquery": "^2.2.4",
"uuid": "^8.3.2",
"jspdf": "^1.3.3",
"numeral": "^2.0.6",
"pako": "^1.0.11"
},
"scripts": {
"build": "ray-build react && ray-build stylescss",
"dev": "cross-env NODE_ENV=development gulp dev",
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs",
"release": "standard-version"
"assets": "gulp assets",
"pub": "npm run build && gulp assets && npm publish"
},
"publishConfig": {
"registry": "http://47.92.103.240:17358",
......
Markdown is supported
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