emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] /srv/bzr/emacs/trunk r110861: Provide new `defalias-fset-f


From: Stefan Monnier
Subject: [Emacs-diffs] /srv/bzr/emacs/trunk r110861: Provide new `defalias-fset-function' symbol property.
Date: Fri, 09 Nov 2012 17:20:47 -0500
User-agent: Bazaar (2.5.0)

------------------------------------------------------------
revno: 110861
committer: Stefan Monnier <address@hidden>
branch nick: trunk
timestamp: Fri 2012-11-09 17:20:47 -0500
message:
  Provide new `defalias-fset-function' symbol property.
  * src/lisp.h (AUTOLOADP): New macro.
  * src/eval.c (Fautoload): Don't attach to loadhist, call Fdefalias instead.
  * src/data.c (Ffset): Remove special ad-advice-info handling.
  (Fdefalias): Handle autoload definitions and new Qdefalias_fset_function.
  (Fsubr_arity): CSE.
  (Finteractive_form): Simplify.
  (Fquo): Don't insist on having at least 2 arguments.
  (Qdefalias_fset_function): New var.
  * lisp/emacs-lisp/advice.el (ad-set-advice-info): Set defalias-fset-function.
  (ad--defalias-fset): New function.
  (ad-safe-fset): Remove.
  (ad-make-freeze-definition): Use cl-letf*.
modified:
  etc/NEWS
  lisp/ChangeLog
  lisp/emacs-lisp/advice.el
  src/ChangeLog
  src/data.c
  src/eval.c
  src/lisp.h
=== modified file 'etc/NEWS'
--- a/etc/NEWS  2012-11-09 20:45:10 +0000
+++ b/etc/NEWS  2012-11-09 22:20:47 +0000
@@ -38,6 +38,9 @@
 ** Docstrings can be made dynamic by adding a `dynamic-docstring-function'
 text-property on the first char.
 
+** The `defalias-fset-function' property lets you catch calls to defalias
+and redirect them to your own function instead of `fset'.
+
 * Changes in Emacs 24.4 on non-free operating systems
 
 

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2012-11-09 20:45:10 +0000
+++ b/lisp/ChangeLog    2012-11-09 22:20:47 +0000
@@ -1,5 +1,12 @@
 2012-11-09  Stefan Monnier  <address@hidden>
 
+       * emacs-lisp/advice.el (ad-set-advice-info): Set defalias-fset-function.
+       (ad--defalias-fset): New function.
+       (ad-safe-fset): Remove.
+       (ad-make-freeze-definition): Use cl-letf*.
+
+2012-11-09  Stefan Monnier  <address@hidden>
+
        * subr.el (dolist): Don't bind VAR in RESULT.
 
        * emacs-lisp/advice.el: Miscellaneous cleanup.  Use lexical-binding.

=== modified file 'lisp/emacs-lisp/advice.el'
--- a/lisp/emacs-lisp/advice.el 2012-11-09 20:41:03 +0000
+++ b/lisp/emacs-lisp/advice.el 2012-11-09 22:20:47 +0000
@@ -1846,8 +1846,12 @@
 (defmacro ad-get-advice-info-macro (function)
   `(get ,function 'ad-advice-info))
 
-(defmacro ad-set-advice-info (function advice-info)
-  `(put ,function 'ad-advice-info ,advice-info))
+(defsubst ad-set-advice-info (function advice-info)
+  (cond
+   (advice-info (put function 'defalias-fset-function #'ad--defalias-fset))
+   ((get function 'defalias-fset-function)
+    (put function 'defalias-fset-function nil)))
+  (put function 'ad-advice-info advice-info))
 
 (defmacro ad-copy-advice-info (function)
   `(copy-tree (get ,function 'ad-advice-info)))
@@ -1954,18 +1958,10 @@
 ;; @@ Dealing with automatic advice activation via `fset/defalias':
 ;; ================================================================
 
-;; Since Emacs 19.26 the built-in versions of `fset' and `defalias'
-;; take care of automatic advice activation, hence, we don't have to
-;; hack it anymore by advising `fset/defun/defmacro/byte-code/etc'.
+;; Automatic activation happens when a function gets defined via `defalias',
+;; which calls the `defalias-fset-function' (which we set to
+;; `ad--defalias-fset') instead of `fset', if non-nil.
 
-;; The functionality of the new `fset' is as follows:
-;;
-;;     fset(sym,newdef)
-;;       assign NEWDEF to SYM
-;;       if (get SYM 'ad-advice-info)
-;;          ad-activate-internal(SYM, nil)
-;;       return (symbol-function SYM)
-;;
 ;; Whether advised definitions created by automatic activations will be
 ;; compiled depends on the value of `ad-default-compilation-action'.
 
@@ -1977,6 +1973,10 @@
 ;; to `ad-activate' by using `ad-with-auto-activation-disabled' where
 ;; appropriate, especially in a safe version of `fset'.
 
+(defun ad--defalias-fset (function definition)
+  (fset function definition)
+  (ad-activate-internal function nil))
+
 ;; For now define `ad-activate-internal' to the dummy definition:
 (defun ad-activate-internal (_function &optional _compile)
   "Automatic advice activation is disabled. `ad-start-advice' enables it."
@@ -1994,12 +1994,6 @@
   `(let ((ad-activate-on-top-level nil))
     ,@body))
 
-(defun ad-safe-fset (symbol definition)
-  "A safe `fset' which will never call `ad-activate-internal' recursively."
-  (ad-with-auto-activation-disabled
-   (fset symbol definition)))
-
-
 ;; @@ Access functions for original definitions:
 ;; ============================================
 ;; The advice-info of an advised function contains its `origname' which is
@@ -2019,8 +2013,7 @@
         (symbol-function origname))))
 
 (defmacro ad-set-orig-definition (function definition)
-  `(ad-safe-fset
-    (ad-get-advice-info-field ,function 'origname) ,definition))
+  `(fset (ad-get-advice-info-field ,function 'origname) ,definition))
 
 (defmacro ad-clear-orig-definition (function)
   `(fmakunbound (ad-get-advice-info-field ,function 'origname)))
@@ -3151,7 +3144,7 @@
       (ad-set-advice-info function old-advice-info)
       ;; Don't `fset' function to nil if it was previously unbound:
       (if function-defined-p
-         (ad-safe-fset function old-definition)
+         (fset function old-definition)
        (fmakunbound function)))))
 
 
@@ -3182,61 +3175,54 @@
       (error
        "ad-make-freeze-definition: `%s' is not yet defined"
        function))
-  (let* ((name (ad-advice-name advice))
-        ;; With a unique origname we can have multiple freeze advices
-        ;; for the same function, each overloading the previous one:
-        (unique-origname
-         (intern (format "%s-%s-%s" (ad-make-origname function) class name)))
-        (orig-definition
-         ;; If FUNCTION is already advised, we'll use its current origdef
-         ;; as the original definition of the frozen advice:
-         (or (ad-get-orig-definition function)
-             (symbol-function function)))
-        (old-advice-info
-         (if (ad-is-advised function)
-             (ad-copy-advice-info function)))
-        (real-docstring-fn
-         (symbol-function 'ad-make-advised-definition-docstring))
-        (real-origname-fn
-         (symbol-function 'ad-make-origname))
-        (frozen-definition
-         (unwind-protect
-               (progn
-                 ;; Make sure we construct a proper docstring:
-                 (ad-safe-fset 'ad-make-advised-definition-docstring
-                               'ad-make-freeze-docstring)
-                 ;; Make sure `unique-origname' is used as the origname:
-                 (ad-safe-fset 'ad-make-origname (lambda (_x) unique-origname))
-                 ;; No we reset all current advice information to nil and
-                 ;; generate an advised definition that's solely determined
-                 ;; by ADVICE and the current origdef of FUNCTION:
-                 (ad-set-advice-info function nil)
-                 (ad-add-advice function advice class position)
-                 ;; The following will provide proper real docstrings as
-                 ;; well as a definition that will make the compiler happy:
-                 (ad-set-orig-definition function orig-definition)
-                 (ad-make-advised-definition function))
-           ;; Restore the old advice state:
-           (ad-set-advice-info function old-advice-info)
-           ;; Restore functions:
-           (ad-safe-fset
-            'ad-make-advised-definition-docstring real-docstring-fn)
-           (ad-safe-fset 'ad-make-origname real-origname-fn))))
+  (cl-letf*
+      ((name (ad-advice-name advice))
+       ;; With a unique origname we can have multiple freeze advices
+       ;; for the same function, each overloading the previous one:
+       (unique-origname
+        (intern (format "%s-%s-%s" (ad-make-origname function) class name)))
+       (orig-definition
+        ;; If FUNCTION is already advised, we'll use its current origdef
+        ;; as the original definition of the frozen advice:
+        (or (ad-get-orig-definition function)
+            (symbol-function function)))
+       (old-advice-info
+        (if (ad-is-advised function)
+            (ad-copy-advice-info function)))
+       ;; Make sure we construct a proper docstring:
+       ((symbol-function 'ad-make-advised-definition-docstring)
+        #'ad-make-freeze-docstring)
+       ;; Make sure `unique-origname' is used as the origname:
+       ((symbol-function 'ad-make-origname) (lambda (_x) unique-origname))
+       (frozen-definition
+        (unwind-protect
+            (progn
+              ;; No we reset all current advice information to nil and
+              ;; generate an advised definition that's solely determined
+              ;; by ADVICE and the current origdef of FUNCTION:
+              (ad-set-advice-info function nil)
+              (ad-add-advice function advice class position)
+              ;; The following will provide proper real docstrings as
+              ;; well as a definition that will make the compiler happy:
+              (ad-set-orig-definition function orig-definition)
+              (ad-make-advised-definition function))
+          ;; Restore the old advice state:
+          (ad-set-advice-info function old-advice-info))))
     (if frozen-definition
        (let* ((macro-p (ad-macro-p frozen-definition))
               (body (cdr (if macro-p
                              (ad-lambdafy frozen-definition)
-                              frozen-definition))))
+                            frozen-definition))))
          `(progn
-            (if (not (fboundp ',unique-origname))
-                (fset ',unique-origname
-                      ;; avoid infinite recursion in case the function
-                      ;; we want to freeze is already advised:
-                      (or (ad-get-orig-definition ',function)
-                          (symbol-function ',function))))
-            (,(if macro-p 'defmacro 'defun)
-             ,function
-             ,@body))))))
+             (if (not (fboundp ',unique-origname))
+                 (fset ',unique-origname
+                       ;; avoid infinite recursion in case the function
+                       ;; we want to freeze is already advised:
+                       (or (ad-get-orig-definition ',function)
+                           (symbol-function ',function))))
+             (,(if macro-p 'defmacro 'defun)
+              ,function
+              ,@body))))))
 
 
 ;; @@ Activation and definition handling:
@@ -3269,7 +3255,7 @@
   (let ((verified-cached-definition
         (if (ad-verify-cache-id function)
             (ad-get-cache-definition function))))
-    (ad-safe-fset function
+    (fset function
                  (or verified-cached-definition
                      (ad-make-advised-definition function)))
     (if (ad-should-compile function compile)
@@ -3311,7 +3297,7 @@
                    (error "ad-handle-definition (see its doc): `%s' %s"
                           function "invalidly redefined")
                  (if (eq ad-redefinition-action 'discard)
-                     (ad-safe-fset function original-definition)
+                     (fset function original-definition)
                    (ad-set-orig-definition function current-definition)
                    (if (eq ad-redefinition-action 'warn)
                        (message "ad-handle-definition: `%s' got redefined"
@@ -3386,7 +3372,7 @@
           (if (not (ad-get-orig-definition function))
               (error "ad-deactivate: `%s' has no original definition"
                      function)
-            (ad-safe-fset function (ad-get-orig-definition function))
+            (fset function (ad-get-orig-definition function))
             (ad-set-advice-info-field function 'active nil)
             (eval (ad-make-hook-form function 'deactivation))
             function)))))
@@ -3424,7 +3410,7 @@
          (completing-read "Recover advised function: " obarray nil t))))
   (cond ((ad-is-advised function)
         (cond ((ad-get-orig-definition function)
-               (ad-safe-fset function (ad-get-orig-definition function))
+               (fset function (ad-get-orig-definition function))
                (ad-clear-orig-definition function)))
         (ad-set-advice-info function nil)
         (ad-pop-advised-function function))))
@@ -3658,8 +3644,7 @@
                 (setq index -1)
                 (mapcar (lambda (function)
                           (setq index (1+ index))
-                          `(ad-safe-fset
-                            ',function
+                           `(fset ',function
                             (or (ad-get-orig-definition ',function)
                                 ,(car (nth index current-bindings)))))
                         functions))
@@ -3670,8 +3655,7 @@
            (setq index -1)
            (mapcar (lambda (function)
                      (setq index (1+ index))
-                     `(ad-safe-fset
-                       ',function
+                       `(fset ',function
                        ,(car (nth index current-bindings))))
                    functions))))))
 
@@ -3684,7 +3668,7 @@
   (interactive)
   ;; Advising `ad-activate-internal' means death!!
   (ad-set-advice-info 'ad-activate-internal nil)
-  (ad-safe-fset 'ad-activate-internal 'ad-activate))
+  (fset 'ad-activate-internal 'ad-activate))
 
 (defun ad-stop-advice ()
   "Stop the automatic advice handling magic.
@@ -3692,7 +3676,7 @@
   (interactive)
   ;; Advising `ad-activate-internal' means death!!
   (ad-set-advice-info 'ad-activate-internal nil)
-  (ad-safe-fset 'ad-activate-internal 'ad-activate-internal-off))
+  (fset 'ad-activate-internal 'ad-activate-internal-off))
 
 (defun ad-recover-normality ()
   "Undo all advice related redefinitions and unadvises everything.
@@ -3700,7 +3684,7 @@
   (interactive)
   ;; Advising `ad-activate-internal' means death!!
   (ad-set-advice-info 'ad-activate-internal nil)
-  (ad-safe-fset 'ad-activate-internal 'ad-activate-internal-off)
+  (fset 'ad-activate-internal 'ad-activate-internal-off)
   (ad-recover-all)
   (ad-do-advised-functions (function)
     (message "Oops! Left over advised function %S" function)

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2012-11-09 19:47:28 +0000
+++ b/src/ChangeLog     2012-11-09 22:20:47 +0000
@@ -1,3 +1,14 @@
+2012-11-09  Stefan Monnier  <address@hidden>
+
+       * lisp.h (AUTOLOADP): New macro.
+       * eval.c (Fautoload): Don't attach to loadhist, call Fdefalias instead.
+       * data.c (Ffset): Remove special ad-advice-info handling.
+       (Fdefalias): Handle autoload definitions and new 
Qdefalias_fset_function.
+       (Fsubr_arity): CSE.
+       (Finteractive_form): Simplify.
+       (Fquo): Don't insist on having at least 2 arguments.
+       (Qdefalias_fset_function): New var.
+
 2012-11-09  Jan Djärv  <address@hidden>
 
        * image.c (xpm_make_color_table_h): Change to hashtest_equal.
@@ -26,7 +37,7 @@
 
 2012-11-09  Jan Djärv  <address@hidden>
 
-       * nsfont.m (ns_descriptor_to_entity): Qcondesed and Qexpanded has
+       * nsfont.m (ns_descriptor_to_entity): Qcondensed and Qexpanded has
        been removed, so remove them here also.
 
 2012-11-09  Stefan Monnier  <address@hidden>

=== modified file 'src/data.c'
--- a/src/data.c        2012-09-23 08:44:20 +0000
+++ b/src/data.c        2012-11-09 22:20:47 +0000
@@ -80,7 +80,7 @@
 Lisp_Object Qfont_spec, Qfont_entity, Qfont_object;
 static Lisp_Object Qdefun;
 
-Lisp_Object Qinteractive_form;
+Lisp_Object Qinteractive_form, Qdefalias_fset_function;
 
 static void swap_in_symval_forwarding (struct Lisp_Symbol *, struct 
Lisp_Buffer_Local_Value *);
 
@@ -444,7 +444,7 @@
 }
 
 
-/* Extract and set components of lists */
+/* Extract and set components of lists.  */
 
 DEFUN ("car", Fcar, Scar, 1, 1, 0,
        doc: /* Return the car of LIST.  If arg is nil, return nil.
@@ -608,27 +608,18 @@
   (register Lisp_Object symbol, Lisp_Object definition)
 {
   register Lisp_Object function;
-
   CHECK_SYMBOL (symbol);
-  if (NILP (symbol) || EQ (symbol, Qt))
-    xsignal1 (Qsetting_constant, symbol);
 
   function = XSYMBOL (symbol)->function;
 
   if (!NILP (Vautoload_queue) && !EQ (function, Qunbound))
     Vautoload_queue = Fcons (Fcons (symbol, function), Vautoload_queue);
 
-  if (CONSP (function) && EQ (XCAR (function), Qautoload))
+  if (AUTOLOADP (function))
     Fput (symbol, Qautoload, XCDR (function));
 
   set_symbol_function (symbol, definition);
-  /* Handle automatic advice activation.  */
-  if (CONSP (XSYMBOL (symbol)->plist)
-      && !NILP (Fget (symbol, Qad_advice_info)))
-    {
-      call2 (Qad_activate_internal, symbol, Qnil);
-      definition = XSYMBOL (symbol)->function;
-    }
+
   return definition;
 }
 
@@ -642,15 +633,32 @@
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (CONSP (XSYMBOL (symbol)->function)
-      && EQ (XCAR (XSYMBOL (symbol)->function), Qautoload))
-    LOADHIST_ATTACH (Fcons (Qt, symbol));
   if (!NILP (Vpurify_flag)
       /* If `definition' is a keymap, immutable (and copying) is wrong.  */
       && !KEYMAPP (definition))
     definition = Fpurecopy (definition);
-  definition = Ffset (symbol, definition);
-  LOADHIST_ATTACH (Fcons (Qdefun, symbol));
+
+  {
+    bool autoload = AUTOLOADP (definition);
+    if (NILP (Vpurify_flag) || !autoload)
+      { /* Only add autoload entries after dumping, because the ones before are
+          not useful and else we get loads of them from the loaddefs.el.  */
+
+       if (AUTOLOADP (XSYMBOL (symbol)->function))
+         /* Remember that the function was already an autoload.  */
+         LOADHIST_ATTACH (Fcons (Qt, symbol));
+       LOADHIST_ATTACH (Fcons (autoload ? Qautoload : Qdefun, symbol));
+      }
+  }
+
+  { /* Handle automatic advice activation.  */
+    Lisp_Object hook = Fget (symbol, Qdefalias_fset_function);
+    if (!NILP (hook))
+      call2 (hook, symbol, definition);
+    else
+      Ffset (symbol, definition);
+  }
+
   if (!NILP (docstring))
     Fput (symbol, Qfunction_documentation, docstring);
   /* We used to return `definition', but now that `defun' and `defmacro' expand
@@ -680,12 +688,10 @@
   CHECK_SUBR (subr);
   minargs = XSUBR (subr)->min_args;
   maxargs = XSUBR (subr)->max_args;
-  if (maxargs == MANY)
-    return Fcons (make_number (minargs), Qmany);
-  else if (maxargs == UNEVALLED)
-    return Fcons (make_number (minargs), Qunevalled);
-  else
-    return Fcons (make_number (minargs), make_number (maxargs));
+  return Fcons (make_number (minargs),
+               maxargs == MANY ?        Qmany
+               : maxargs == UNEVALLED ? Qunevalled
+               :                        make_number (maxargs));
 }
 
 DEFUN ("subr-name", Fsubr_name, Ssubr_name, 1, 1, 0,
@@ -711,7 +717,7 @@
     return Qnil;
 
   /* Use an `interactive-form' property if present, analogous to the
-     function-documentation property. */
+     function-documentation property.  */
   fun = cmd;
   while (SYMBOLP (fun))
     {
@@ -735,6 +741,8 @@
       if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_INTERACTIVE)
        return list2 (Qinteractive, AREF (fun, COMPILED_INTERACTIVE));
     }
+  else if (AUTOLOADP (fun))
+    return Finteractive_form (Fautoload_do_load (fun, cmd, Qnil));
   else if (CONSP (fun))
     {
       Lisp_Object funcar = XCAR (fun);
@@ -742,14 +750,6 @@
        return Fassq (Qinteractive, Fcdr (Fcdr (XCDR (fun))));
       else if (EQ (funcar, Qlambda))
        return Fassq (Qinteractive, Fcdr (XCDR (fun)));
-      else if (EQ (funcar, Qautoload))
-       {
-         struct gcpro gcpro1;
-         GCPRO1 (cmd);
-         Fautoload_do_load (fun, cmd, Qnil);
-         UNGCPRO;
-         return Finteractive_form (cmd);
-       }
     }
   return Qnil;
 }
@@ -2695,10 +2695,10 @@
   return arith_driver (Amult, nargs, args);
 }
 
-DEFUN ("/", Fquo, Squo, 2, MANY, 0,
+DEFUN ("/", Fquo, Squo, 1, MANY, 0,
        doc: /* Return first argument divided by all the remaining arguments.
 The arguments must be numbers or markers.
-usage: (/ DIVIDEND DIVISOR &rest DIVISORS)  */)
+usage: (/ DIVIDEND &rest DIVISORS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   ptrdiff_t argnum;
@@ -3063,6 +3063,7 @@
   DEFSYM (Qfont_object, "font-object");
 
   DEFSYM (Qinteractive_form, "interactive-form");
+  DEFSYM (Qdefalias_fset_function, "defalias-fset-function");
 
   defsubr (&Sindirect_variable);
   defsubr (&Sinteractive_form);

=== modified file 'src/eval.c'
--- a/src/eval.c        2012-10-11 20:08:38 +0000
+++ b/src/eval.c        2012-11-09 22:20:47 +0000
@@ -1876,26 +1876,19 @@
   CHECK_STRING (file);
 
   /* If function is defined and not as an autoload, don't override.  */
-  if ((CONSP (XSYMBOL (function)->function)
-       && EQ (XCAR (XSYMBOL (function)->function), Qautoload)))
-    /* Remember that the function was already an autoload.  */
-    LOADHIST_ATTACH (Fcons (Qt, function));
-  else if (!EQ (XSYMBOL (function)->function, Qunbound))
+  if (!EQ (XSYMBOL (function)->function, Qunbound)
+      && !AUTOLOADP (XSYMBOL (function)->function))
     return Qnil;
 
-  if (NILP (Vpurify_flag))
-    /* Only add entries after dumping, because the ones before are
-       not useful and else we get loads of them from the loaddefs.el.  */
-    LOADHIST_ATTACH (Fcons (Qautoload, function));
-  else if (EQ (docstring, make_number (0)))
+  if (!NILP (Vpurify_flag) && EQ (docstring, make_number (0)))
     /* `read1' in lread.c has found the docstring starting with "\
        and assumed the docstring will be provided by Snarf-documentation, so it
        passed us 0 instead.  But that leads to accidental sharing in purecopy's
        hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_number (XUNTAG (function, Lisp_Symbol));
-  return Ffset (function,
-               Fpurecopy (list5 (Qautoload, file, docstring,
-                                 interactive, type)));
+    docstring = make_number (XHASH (function));
+  return Fdefalias (function,
+                   list5 (Qautoload, file, docstring, interactive, type),
+                   Qnil);
 }
 
 Lisp_Object

=== modified file 'src/lisp.h'
--- a/src/lisp.h        2012-11-09 00:08:12 +0000
+++ b/src/lisp.h        2012-11-09 22:20:47 +0000
@@ -1694,6 +1694,8 @@
 #define MARKERP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Marker)
 #define SAVE_VALUEP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value)
 
+#define AUTOLOADP(x) (CONSP (x) && EQ (Qautoload, XCAR (x)))
+
 #define INTFWDP(x) (XFWDTYPE (x) == Lisp_Fwd_Int)
 #define BOOLFWDP(x) (XFWDTYPE (x) == Lisp_Fwd_Bool)
 #define OBJFWDP(x) (XFWDTYPE (x) == Lisp_Fwd_Obj)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]