Commit 0f685693 authored by Francois-Rene Rideau's avatar Francois-Rene Rideau

2.26.149: next release will be ASDF 3 after all, not ASDF 2.27.

Introduce some backward incompatibility with features unused in quicklisp:
* Don't create a temporary package every time you load a .asd;
 instead, load everything from same package ASDF-USER,
 that :use's asdf/common-lisp asdf/package asdf/interface
 That's the Common Lisp way, what with COMMON-LISP-USER.
 If you want a private package, use DEFPACKAGE or DEFINE-PACKAGE.
* operation-description is renamed action-description.
 No one was using it in quicklisp, and no one was specializing it
 except cl-protobufs, which I'll fix.
* component-properties and component-property are gone.
 If you want a new property, create your own subclass of component.

Also, have a load-asd function with name in keyword arguments,
rather than load-sysdef function that requires the name.
parent 360ff431
......@@ -43,7 +43,7 @@ XCL ?= xcl
header_lisp := header.lisp
driver_lisp := package.lisp common-lisp.lisp utility.lisp pathname.lisp stream.lisp os.lisp image.lisp run-program.lisp lisp-build.lisp configuration.lisp backward-driver.lisp driver.lisp
defsystem_lisp := upgrade.lisp component.lisp system.lisp stamp-cache.lisp find-system.lisp find-component.lisp operation.lisp action.lisp lisp-action.lisp plan.lisp operate.lisp output-translations.lisp source-registry.lisp backward-internals.lisp defsystem.lisp bundle.lisp concatenate-source.lisp backward-interface.lisp interface.lisp footer.lisp
defsystem_lisp := upgrade.lisp component.lisp system.lisp stamp-cache.lisp find-system.lisp find-component.lisp operation.lisp action.lisp lisp-action.lisp plan.lisp operate.lisp output-translations.lisp source-registry.lisp backward-internals.lisp defsystem.lisp bundle.lisp concatenate-source.lisp backward-interface.lisp interface.lisp user.lisp footer.lisp
# Making ASDF itself should be our first, default, target:
build/asdf.lisp: $(wildcard *.lisp)
......
* Resolve performance degradation issue reported by stassats and fe[nl]ix
** Is it the warnings feature taking too much resources?
** Is output-files and/or input-files being called too much? Cache it!
* fix upgrade on (abcl, clisp, cmucl)
** Extract minimal test case
* Bug found by fe[nl]ix: infinite loop if the definitions in an asd file
......
......@@ -9,7 +9,7 @@
(:intern #:stamp #:done-p)
(:export
#:action #:define-convenience-action-methods
#:explain #:operation-description
#:explain #:action-description
#:downward-operation #:upward-operation #:sibling-operation
#:component-depends-on #:component-self-dependencies
#:input-files #:output-files #:output-file #:operation-done-p
......@@ -65,27 +65,27 @@
;;;; self-description
(defgeneric* operation-description (operation component) ;; ASDF3: rename to action-description
(defgeneric* action-description (operation component)
(:documentation "returns a phrase that describes performing this operation
on this component, e.g. \"loading /a/b/c\".
You can put together sentences using this phrase."))
(defmethod operation-description (operation component)
(defmethod action-description (operation component)
(format nil (compatfmt "~@<~A on ~A~@:>")
(type-of operation) component))
(defgeneric* (explain) (operation component))
(defmethod explain ((o operation) (c component))
(asdf-message (compatfmt "~&~@<; ~@;~A~:>~%") (operation-description o c)))
(asdf-message (compatfmt "~&~@<; ~@;~A~:>~%") (action-description o c)))
(define-convenience-action-methods explain (operation component))
(defun* format-action (stream action &optional colon-p at-sign-p)
(assert (null colon-p)) (assert (null at-sign-p))
(destructuring-bind (operation . component) action
(princ (operation-description operation component) stream)))
(princ (action-description operation component) stream)))
;;;; Dependencies
(defgeneric* component-depends-on (operation component) ;; ASDF3: rename to component-dependencies
(defgeneric* component-depends-on (operation component) ;; ASDF4: rename to component-dependencies
(:documentation
"Returns a list of dependencies needed by the component to perform
the operation. A dependency has one of the following forms:
......@@ -132,7 +132,7 @@ You can put together sentences using this phrase."))
((upward-operation
:initform nil :initarg :downward-operation :reader upward-operation)))
;; For backward-compatibility reasons, a system inherits from module and is a child-component
;; so we must guard against this case. ASDF3: remove that.
;; so we must guard against this case. ASDF4: remove that.
(defmethod component-depends-on ((o upward-operation) (c child-component))
`(,@(if-let (p (component-parent c))
`((,(or (upward-operation o) o) ,p))) ,@(call-next-method)))
......@@ -203,11 +203,10 @@ You can put together sentences using this phrase."))
;;;; Done performing
(defgeneric* component-operation-time (operation component)) ;; ASDF3: hide it behind plan-action-stamp
(defgeneric* component-operation-time (operation component)) ;; ASDF4: hide it behind plan-action-stamp
(define-convenience-action-methods component-operation-time (operation component))
(defgeneric* mark-operation-done (operation component)) ;; ASDF3: hide it behind (setf plan-action-stamp)
(defgeneric* mark-operation-done (operation component)) ;; ASDF4: hide it behind (setf plan-action-stamp)
(defgeneric* compute-action-stamp (plan operation component &key just-done)
(:documentation "Has this action been successfully done already,
and at what known timestamp has it been done at or will it be done at?
......@@ -277,12 +276,12 @@ in some previous image, or T if it needs to be done.")
:report
(lambda (s)
(format s (compatfmt "~@<Retry ~A.~@:>")
(operation-description operation component))))
(action-description operation component))))
(accept ()
:report
(lambda (s)
(format s (compatfmt "~@<Continue, treating ~A as having been successful.~@:>")
(operation-description operation component)))
(action-description operation component)))
(mark-operation-done operation component)
(return)))))
......
......@@ -10,7 +10,7 @@
:description "Runtime support for Common Lisp programs"
:long-description "Basic general-purpose utilities that are in such a need
that you can't portably construct a complete program without using them."
#+asdf2.27 :version #+asdf2.27 (:read-file-form "version.lisp-expr")
#+asdf3 :version #+asdf3 (:read-file-form "version.lisp-expr")
:around-compile call-without-redefinition-warnings
:components
((:static-file "version.lisp-expr")
......
......@@ -9,7 +9,7 @@
(in-package :asdf)
#+asdf2.27
#+asdf3
(defsystem :asdf/header
;; Note that it's polite to sort the defsystem forms in dependency order,
;; and compulsory to sort them in defsystem-depends-on order.
......@@ -18,7 +18,7 @@
:components
((:file "header")))
#+asdf2.27
#+asdf3
(defsystem :asdf/defsystem
:licence "MIT"
:description "The defsystem part of ASDF"
......@@ -51,7 +51,8 @@
("defsystem" "concatenate-source"
"backward-interface" "backward-internals"
"output-translations" "source-registry"))
(:file "footer" :depends-on ("interface"))))
(:file "user" :depends-on ("interface"))
(:file "footer" :depends-on ("user"))))
(defsystem :asdf
:author ("Daniel Barlow")
......@@ -59,14 +60,14 @@
:licence "MIT"
:description "Another System Definition Facility"
:long-description "ASDF builds Common Lisp software organized into defined systems."
:version "2.26.148" ;; to be automatically updated by make bump-version
:version "2.26.149" ;; to be automatically updated by make bump-version
:depends-on ()
:components
((:module "build"
:components
(#-gcl2.6
(:file "asdf"
#-asdf2.27 :do-first #-asdf2.27 ((compile-op (load-source-op "asdf")))
#-asdf3 :do-first #-asdf3 ((compile-op (load-source-op "asdf")))
))))
:in-order-to
(#+asdf2.27 (compile-op (monolithic-load-concatenated-source-op asdf/defsystem))))
(#+asdf3 (compile-op (monolithic-load-concatenated-source-op asdf/defsystem))))
......@@ -4,12 +4,12 @@
(asdf/package:define-package :asdf/backward-interface
(:recycle :asdf/backward-interface :asdf)
(:use :asdf/common-lisp :asdf/driver :asdf/upgrade
:asdf/component :asdf/system :asdf/operation :asdf/action
:asdf/component :asdf/system :asdf/find-system :asdf/operation :asdf/action
:asdf/lisp-build :asdf/operate :asdf/output-translations)
(:export
#:*asdf-verbose*
#:operation-error #:compile-error #:compile-failed #:compile-warned
#:error-component #:error-operation
#:error-component #:error-operation #:load-sysdef
#:component-load-dependencies
#:enable-asdf-binary-locations-compatibility
#:operation-forced
......@@ -116,6 +116,11 @@ ASDF:ENABLE-ASDF-BINARY-LOCATIONS-COMPATIBILITY as documented in the manual;
call that function where you would otherwise have loaded and configured A-B-L.")))
;;;; load-sysdef
(defun* load-sysdef (name pathname)
(load-asd pathname name))
;;;; run-shell-command
;;
;; WARNING! The function below is dysfunctional and deprecated.
......@@ -132,3 +137,4 @@ Please use ASDF-DRIVER:RUN-PROGRAM instead."
(let ((command (apply 'format nil control-string args)))
(asdf-message "; $ ~A~%" command)
(run-program command :force-shell t :ignore-error-status t :output *verbose-out*)))
......@@ -17,7 +17,6 @@
#:component-if-feature #:around-compile-hook
#:component-description #:component-long-description
#:component-version #:version-satisfies
#:component-properties #:component-property ;; backward-compatibility only. DO NOT USE!
#:component-inline-methods ;; backward-compatibility only. DO NOT USE!
#:component-operation-times ;; For internal use only.
;; portable ASDF encoding and implementation-specific external-format
......@@ -49,9 +48,6 @@ interpreted relative to the pathname of that component's parent.
Despite the function's name, the return value may be an absolute
pathname, because an absolute pathname may be interpreted relative to
another pathname in a degenerate way."))
(defgeneric* component-property (component property))
#-gcl2.6
(defgeneric* (setf component-property) (new-value component property))
(defgeneric* component-external-format (component))
(defgeneric* component-encoding (component))
(defgeneric* version-satisfies (component version))
......@@ -104,10 +100,7 @@ another pathname in a degenerate way."))
:accessor component-operation-times)
(around-compile :initarg :around-compile)
(%encoding :accessor %component-encoding :initform nil :initarg :encoding)
;; ASDF3: get rid of these "component properties" ?
(properties :accessor component-properties :initarg :properties
:initform nil)
;; For backward-compatibility, this slot is part of component rather than child-component
;; For backward-compatibility, this slot is part of component rather than child-component. ASDF4: don't.
(parent :initarg :parent :initform nil :reader component-parent)
(build-operation
:initarg :build-operation :initform nil :reader component-build-operation)))
......@@ -230,20 +223,6 @@ another pathname in a degenerate way."))
(file-type component))
;;;; General component-property - ASDF3: remove? Define clean subclasses, not messy "properties".
(defmethod component-property ((c component) property)
(cdr (assoc property (slot-value c 'properties) :test #'equal)))
(defmethod (setf component-property) (new-value (c component) property)
(let ((a (assoc property (slot-value c 'properties) :test #'equal)))
(if a
(setf (cdr a) new-value)
(setf (slot-value c 'properties)
(acons property new-value (slot-value c 'properties)))))
new-value)
;;;; Encodings
(defmethod component-encoding ((c component))
......
cl-asdf (2:2.27-1) unstable; urgency=low
cl-asdf (2:3.0-1) unstable; urgency=low
* ASDF-BUNDLE was merged into ASDF.
This notably means fewer headaches for users of ECL;
......
......@@ -128,7 +128,7 @@
rest)))
(component (find-component parent name)))
(when weakly-depends-on
;; ASDF3: deprecate this feature and remove it.
;; ASDF4: deprecate this feature and remove it.
(appendf depends-on
(remove-if (complement #'(lambda (x) (find-system x nil))) weakly-depends-on)))
(when previous-serial-component
......@@ -154,7 +154,7 @@
:collect c
:when serial :do (setf previous-component name)))
(compute-children-by-name component))
;; Used by POIU. ASDF3: rename to component-depends-on
;; Used by POIU. ASDF4: rename to component-depends-on?
(setf (component-sibling-dependencies component) depends-on)
(%refresh-component-inline-methods component rest)
(when if-component-dep-fails
......
......@@ -8,14 +8,14 @@
(:export
#:remove-entry-from-registry #:coerce-entry-to-directory
#:coerce-name #:primary-system-name
#:find-system #:locate-system #:load-sysdef #:with-system-definitions
#:find-system #:locate-system #:load-asd #:with-system-definitions
#:system-registered-p #:register-system #:registered-systems #:clear-system #:map-systems
#:system-definition-error #:missing-component #:missing-requires #:missing-parent
#:formatted-system-definition-error #:format-control #:format-arguments #:sysdef-error
#:load-system-definition-error #:error-name #:error-pathname #:error-condition
#:*system-definition-search-functions* #:search-for-system-definition
#:*central-registry* #:probe-asd #:sysdef-central-registry-search
#:make-temporary-package #:find-system-if-being-defined #:*systems-being-defined*
#:find-system-if-being-defined #:*systems-being-defined*
#:contrib-sysdef-search #:sysdef-find-asdf ;; backward compatibility symbols, functions removed
#:system-find-preloaded-system #:register-preloaded-system #:*preloaded-systems*
#:make-defined-systems-table #:*defined-systems*
......@@ -223,9 +223,6 @@ Going forward, we recommend new users should be using the source-registry.
(list new)
(subseq *central-registry* (1+ position))))))))))
(defun* make-temporary-package ()
(make-package (fresh-package-name :prefix :asdf :index 0) :use '(:cl :asdf/interface)))
(defmethod find-system ((name null) &optional (error-p t))
(declare (ignorable name))
(when error-p
......@@ -250,26 +247,22 @@ Going forward, we recommend new users should be using the source-registry.
(defmacro with-system-definitions ((&optional) &body body)
`(call-with-system-definitions #'(lambda () ,@body)))
(defun* load-sysdef (name pathname)
(defun* load-asd (pathname &key name (external-format (encoding-external-format (detect-encoding pathname))))
;; Tries to load system definition with canonical NAME from PATHNAME.
(with-system-definitions ()
(let ((package (make-temporary-package))) ;; ASDF3: get rid of that.
(unwind-protect
(handler-bind
((error #'(lambda (condition)
(error 'load-system-definition-error
:name name :pathname pathname
:condition condition))))
(let ((*package* package)
(*default-pathname-defaults*
;; resolve logical-pathnames so they won't wreak havoc in parsing namestrings.
(pathname-directory-pathname (translate-logical-pathname pathname)))
(external-format (encoding-external-format (detect-encoding pathname))))
(asdf-message (compatfmt "~&~@<; ~@;Loading system definition from ~A into ~A~@:>~%")
pathname package)
(with-muffled-loader-conditions ()
(load* pathname :external-format external-format))))
(delete-package package)))))
(let ((*package* (find-package :asdf-user))
(*default-pathname-defaults*
;; resolve logical-pathnames so they won't wreak havoc in parsing namestrings.
(pathname-directory-pathname (translate-logical-pathname pathname))))
(handler-bind
((error #'(lambda (condition)
(error 'load-system-definition-error
:name name :pathname pathname
:condition condition))))
(asdf-message (compatfmt "~&~@<; ~@;Loading system definition~@[ for ~A~] from ~A~@:>~%")
name pathname)
(with-muffled-loader-conditions ()
(load* pathname :external-format external-format))))))
(defun* locate-system (name)
"Given a system NAME designator, try to locate where to load the system from.
......@@ -318,7 +311,7 @@ PREVIOUS-TIME when not null is the time at which the PREVIOUS system was loaded.
(translate-logical-pathname previous-pathname))))
(stamp<= (get-file-stamp pathname) previous-time))))
;; only load when it's a pathname that is different or has newer content
(load-sysdef name pathname)))
(load-asd pathname :name name)))
(let ((in-memory (system-registered-p name))) ; try again after loading from disk if needed
(return
(cond
......
......@@ -13,15 +13,14 @@
;;;; Hook ASDF into the implementation's REQUIRE and other entry points.
#+(or abcl clisp clozure cmu ecl mkcl sbcl)
(let ((x (and #+clisp (find-symbol* '#:*module-provider-functions* :custom nil))))
(when x
(eval `(pushnew 'module-provide-asdf
#+abcl sys::*module-provider-functions*
#+clisp ,x
#+clozure ccl:*module-provider-functions*
#+(or cmu ecl) ext:*module-provider-functions*
#+mkcl mk-ext:*module-provider-functions*
#+sbcl sb-ext:*module-provider-functions*))))
(if-let (x (and #+clisp (find-symbol* '#:*module-provider-functions* :custom nil)))
(eval `(pushnew 'module-provide-asdf
#+abcl sys::*module-provider-functions*
#+clisp ,x
#+clozure ccl:*module-provider-functions*
#+(or cmu ecl) ext:*module-provider-functions*
#+mkcl mk-ext:*module-provider-functions*
#+sbcl sb-ext:*module-provider-functions*)))
#+(or ecl mkcl)
(progn
......@@ -57,7 +56,7 @@
(when (boundp 'excl:*warn-on-nested-reader-conditionals*)
(setf excl:*warn-on-nested-reader-conditionals* asdf/common-lisp::*acl-warn-save*)))
(dolist (f '(:asdf :asdf2 :asdf2.27)) (pushnew f *features*))
(dolist (f '(:asdf :asdf2 :asdf3)) (pushnew f *features*))
(provide :asdf)
......
;; -*- mode: Common-Lisp; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
;;; This is ASDF 2.26.148: Another System Definition Facility.
;;; This is ASDF 2.26.149: Another System Definition Facility.
;;;
;;; Feedback, bug reports, and patches are all welcome:
;;; please mail to <asdf-devel@common-lisp.net>.
......@@ -56,7 +56,7 @@
#+(or abcl clisp cmu)
(eval-when (:load-toplevel :compile-toplevel :execute)
(unless (member :asdf2.27 *features*)
(unless (member :asdf3 *features*)
(let* ((existing-version
(when (find-package :asdf)
(or (symbol-value (find-symbol (string :*asdf-version*) :asdf))
......
......@@ -31,7 +31,7 @@
#:feature #:version #:version-satisfies #:upgrade-asdf
#:implementation-identifier #:implementation-type #:hostname
#:input-files #:output-files #:output-file #:perform
#:operation-done-p #:explain #:component-sibling-dependencies
#:operation-done-p #:explain #:action-description #:component-sibling-dependencies
#:needed-in-image-p
;; #:run-program ; we can't export it, because SB-GROVEL :use's both ASDF and SB-EXT.
#:component-load-dependencies #:run-shell-command ; deprecated, do not use
......@@ -61,7 +61,6 @@
#:component-name
#:component-version
#:component-parent
#:component-property
#:component-system
#:component-encoding
#:component-external-format
......@@ -81,8 +80,6 @@
#:system-relative-pathname
#:map-systems
#:operation-description
#:*system-definition-search-functions* ; variables
#:*central-registry*
#:*compile-file-warnings-behaviour*
......
......@@ -49,7 +49,7 @@
;;;; prepare-op, compile-op and load-op
;;; prepare-op
(defmethod operation-description ((o prepare-op) (c component))
(defmethod action-description ((o prepare-op) (c component))
(declare (ignorable o))
(format nil (compatfmt "~@<loading dependencies of ~3i~_~A~@:>") c))
(defmethod perform ((o prepare-op) (c component))
......@@ -63,10 +63,10 @@
(if-let (it (system-source-file s)) (list it)))
;;; compile-op
(defmethod operation-description ((o compile-op) (c component))
(defmethod action-description ((o compile-op) (c component))
(declare (ignorable o))
(format nil (compatfmt "~@<compiling ~3i~_~A~@:>") c))
(defmethod operation-description ((o compile-op) (c parent-component))
(defmethod action-description ((o compile-op) (c parent-component))
(declare (ignorable o))
(format nil (compatfmt "~@<completing compilation for ~3i~_~A~@:>") c))
(defgeneric* call-with-around-compile-hook (component thunk))
......@@ -159,13 +159,13 @@
(list (subpathname pathname (component-name c) :type "build-report")))))
;;; load-op
(defmethod operation-description ((o load-op) (c cl-source-file))
(defmethod action-description ((o load-op) (c cl-source-file))
(declare (ignorable o))
(format nil (compatfmt "~@<loading FASL for ~3i~_~A~@:>") c))
(defmethod operation-description ((o load-op) (c parent-component))
(defmethod action-description ((o load-op) (c parent-component))
(declare (ignorable o))
(format nil (compatfmt "~@<completing load for ~3i~_~A~@:>") c))
(defmethod operation-description ((o load-op) component)
(defmethod action-description ((o load-op) component)
(declare (ignorable o))
(format nil (compatfmt "~@<loading ~3i~_~A~@:>")
component))
......@@ -197,7 +197,7 @@
;;;; prepare-source-op, load-source-op
;;; prepare-source-op
(defmethod operation-description ((o prepare-source-op) (c component))
(defmethod action-description ((o prepare-source-op) (c component))
(declare (ignorable o))
(format nil (compatfmt "~@<loading source for dependencies of ~3i~_~A~@:>") c))
(defmethod input-files ((o prepare-source-op) (c component))
......@@ -211,10 +211,10 @@
nil)
;;; load-source-op
(defmethod operation-description ((o load-source-op) c)
(defmethod action-description ((o load-source-op) c)
(declare (ignorable o))
(format nil (compatfmt "~@<Loading source of ~3i~_~A~@:>") c))
(defmethod operation-description ((o load-source-op) (c parent-component))
(defmethod action-description ((o load-source-op) (c parent-component))
(declare (ignorable o))
(format nil (compatfmt "~@<Loaded source of ~3i~_~A~@:>") c))
(defmethod component-depends-on ((o load-source-op) (c component))
......
......@@ -230,7 +230,7 @@ the action of OPERATION on COMPONENT in the PLAN"))
(when (and just-done (not all-present))
(warn "~A completed without ~:[~*~;~*its input file~:p~2:*~{ ~S~}~*~]~
~:[~; or ~]~:[~*~;~*its output file~:p~2:*~{ ~S~}~*~]"
(operation-description o c)
(action-description o c)
missing-in (length missing-in) (and missing-in missing-out)
missing-out (length missing-out)))
;; Note that we use stamp<= instead of stamp< to play nice with generated files.
......
......@@ -36,7 +36,7 @@
((name) (source-file) #|(children) (children-by-names)|#))
(defclass system (module proto-system)
;; Backward-compatibility: inherit from module. ASDF3: only inherit from parent-component.
;; Backward-compatibility: inherit from module. ASDF4: only inherit from parent-component.
(;; {,long-}description is now inherited from component, but we add the legacy accessors
(description :accessor system-description)
(long-description :accessor system-long-description)
......
......@@ -4,7 +4,7 @@
:components
((:file "file1" :perform (load-op :before (o c)
(setf *a* t)
(format t "Method run before ~A~%" (operation-description o c))))))
(format t "Method run before ~A~%" (action-description o c))))))
(load-system :foo)
......
;;; -*- Lisp -*-
(asdf:defsystem test3
:properties ((:prop1 . "value"))
(defsystem test3
:components
((:file "file1" :if-feature :asdf)
(:file "file2" :if-feature (:not :asdf))))
;;; -*- Lisp -*-
(defparameter *fasl1* (test-fasl "file1.lisp"))
(defparameter *fasl2* (test-fasl "file2.lisp"))
(delete-file-if-exists *fasl1*)
(delete-file-if-exists *fasl2*)
(DBG "should load file1 but not file2")
(asdf:load-system :test3)
(load-system :test3)
(assert (probe-file *fasl1*))
(assert (not (probe-file *fasl2*)))
(assert (not (component-property (find-system 'test3) :foo)))
(assert (equal (component-property (find-system 'test3) :prop1) "value"))
(setf (component-property (find-system 'test3) :foo) "bar")
(assert (equal (component-property (find-system 'test3) :foo) "bar"))
......@@ -35,7 +35,7 @@
;; "2.345.6" would be a development version in the official upstream
;; "2.345.0.7" would be your seventh local modification of official release 2.345
;; "2.345.6.7" would be your seventh local modification of development version 2.345.6
(asdf-version "2.26.148")
(asdf-version "2.26.149")
(existing-asdf (find-class (find-symbol* :component :asdf nil) nil))
(existing-version *asdf-version*)
(already-there (equal asdf-version existing-version))
......
;;;; ---------------------------------------------------------------------------
;;;; ASDF-USER, where the action happens.
(asdf/package:define-package :asdf/user
(:nicknames :asdf-user)
(:use :asdf/common-lisp :asdf/package :asdf/interface))
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