diff --git a/manual/luatex-callbacks.tex b/manual/luatex-callbacks.tex
index ddeeb05b1b49916057391734bee115ef39881a93..62a37c5bce1b1b3e46ee08cecb6314afc36bf09c 100644
--- a/manual/luatex-callbacks.tex
+++ b/manual/luatex-callbacks.tex
@@ -852,6 +852,17 @@ end
 This callback replaces the code that prints \LUATEX's when a file is closed like
 the \type {)} for regular files.
 
+\subsection{\type {call_edit}}
+
+\startfunctioncall
+function(filename,linenumber)
+end
+\stopfunctioncall
+
+This callback replaces the call to an external editor when \quote{E} is pressed 
+in reply to an error message. Processing will end immediately after the callback
+returns control to the main program.
+
 \section{PDF-related callbacks}
 
 \subsection{\type {finish_pdffile}}
diff --git a/manual/luatex-math.tex b/manual/luatex-math.tex
index 8e0c771196d959625cf565562157a0df21a7eb0f..b6634f840f995b71d6ee56a4b4dca90effd944ce 100644
--- a/manual/luatex-math.tex
+++ b/manual/luatex-math.tex
@@ -38,6 +38,99 @@ be used as numeric values, so you can write code like this:
 \fi \fi
 \stoptyping
 
+Sometimes you won't get what you expect so a bit of explanation might help to
+understand what happens. When math is parsed and expanded it gets turned into a
+linked list. In a second pass the formula will be build. This has to do with the
+fact that in order to determine the automatically chosen sizes (in for instance
+fractions) following content can influence preceding sizes. A side effect of this
+is for instance that one cannot change the definition of a font family (and
+thereby reusing numbers) because the number that got used is stored and used in
+the second pass (so changing \type {\fam 12} mid|-|formula spoils over to
+preceding use of that family).
+
+The style switching primitives like \type {\textstyle} are turned into nodes so
+the styles set there are frozen. The \type {\mathchoice} primitive results in
+four lists being constructed of which one is used in the second pass. The fact
+that some automatic styles are not yet known also means that the \type
+{\mathstyle} primitive expands to the current style which can of course be
+different from the one really used. It's a snapshot of the first pass state. As a
+consequence in the following example you get a style number (first pass) typeset
+that can actually differ from the used style (second pass). In the case of a math
+choice used ungrouped, the chosen style is used after the choice too, unless you
+group.
+
+\startbuffer[1]
+    [a:\mathstyle]\quad
+    \bgroup
+    \mathchoice
+        {\bf \scriptstyle       (x:d :\mathstyle)}
+        {\bf \scriptscriptstyle (x:t :\mathstyle)}
+        {\bf \scriptscriptstyle (x:s :\mathstyle)}
+        {\bf \scriptscriptstyle (x:ss:\mathstyle)}
+    \egroup
+    \quad[b:\mathstyle]\quad
+    \mathchoice
+        {\bf \scriptstyle       (y:d :\mathstyle)}
+        {\bf \scriptscriptstyle (y:t :\mathstyle)}
+        {\bf \scriptscriptstyle (y:s :\mathstyle)}
+        {\bf \scriptscriptstyle (y:ss:\mathstyle)}
+    \quad[c:\mathstyle]\quad
+    \bgroup
+    \mathchoice
+        {\bf \scriptstyle       (z:d :\mathstyle)}
+        {\bf \scriptscriptstyle (z:t :\mathstyle)}
+        {\bf \scriptscriptstyle (z:s :\mathstyle)}
+        {\bf \scriptscriptstyle (z:ss:\mathstyle)}
+    \egroup
+    \quad[d:\mathstyle]
+\stopbuffer
+
+\startbuffer[2]
+    [a:\mathstyle]\quad
+    \begingroup
+    \mathchoice
+        {\bf \scriptstyle       (x:d :\mathstyle)}
+        {\bf \scriptscriptstyle (x:t :\mathstyle)}
+        {\bf \scriptscriptstyle (x:s :\mathstyle)}
+        {\bf \scriptscriptstyle (x:ss:\mathstyle)}
+    \endgroup
+    \quad[b:\mathstyle]\quad
+    \mathchoice
+        {\bf \scriptstyle       (y:d :\mathstyle)}
+        {\bf \scriptscriptstyle (y:t :\mathstyle)}
+        {\bf \scriptscriptstyle (y:s :\mathstyle)}
+        {\bf \scriptscriptstyle (y:ss:\mathstyle)}
+    \quad[c:\mathstyle]\quad
+    \begingroup
+    \mathchoice
+        {\bf \scriptstyle       (z:d :\mathstyle)}
+        {\bf \scriptscriptstyle (z:t :\mathstyle)}
+        {\bf \scriptscriptstyle (z:s :\mathstyle)}
+        {\bf \scriptscriptstyle (z:ss:\mathstyle)}
+    \endgroup
+    \quad[d:\mathstyle]
+\stopbuffer
+
+\typebuffer[1]
+
+% \typebuffer[2]
+
+This gives:
+
+\blank $\displaystyle \getbuffer[1]$ \blank
+\blank $\textstyle    \getbuffer[1]$ \blank
+
+Using \type {\begingroup} \unknown\ \type {\endgroup} instead gives:
+
+\blank $\displaystyle \getbuffer[2]$ \blank
+\blank $\textstyle    \getbuffer[2]$ \blank
+
+This might look wrong but it's just a side effect of \type {\mathstyle} expanding
+to the current (first pass) style and the number being injected in the list that
+gets converted in the second pass. It all makes sense and it illustrates the
+importance of grouping. In fact, the math choice style being effective afterwards
+has advantages. It would be hard to get it otherwise.
+
 \subsection{\type {\Ustack}}
 
 There are a few math commands in \TEX\ where the style that will be used is not
@@ -469,7 +562,12 @@ math font Cambria, but were useful enough to be added.
 There are two extra math parameters \type {\Umathnolimitsupfactor} and \type
 {\Umathnolimitsubfactor} that were added to provide some control over how limits
 are spaced (for example the position of super and subscripts after integral
-operators). They relate to an extra parameter \type {\mathnolimitsmode}.
+operators). They relate to an extra parameter \type {\mathnolimitsmode}. The half
+corrections are what happens when scripts are placed on above and below. The
+problem with italic corrections is that officially that correction italic is used
+for above|/|below placement while advanced kerns are used for placement at the
+right end. The question is: how often is this implemented, and if so, does the
+kerns assume correction too. Anyway, with this parameter one can control it.
 
 \starttabulate[|l|ck1|ck1|ck1|ck1|ck1|ck1|]
     \NC
@@ -490,29 +588,30 @@ operators). They relate to an extra parameter \type {\mathnolimitsmode}.
         \NC \tttf 8000
     \NC \NR
     \NC \bf superscript
-        \NC +ic/2
-        \NC font
         \NC 0
+        \NC font
         \NC 0
         \NC 0
+        \NC +ic/2
         \NC 0
     \NC \NR
     \NC \bf subscript
-        \NC -ic/2
+        \NC -ic
         \NC font
         \NC 0
         \NC -ic/2
-        \NC -ic
+        \NC -ic/2
         \NC 8000ic/1000
     \NC \NR
 \stoptabulate
 
 When the mode is set to one, the math parameters are used. This way a macro
 package writer can decide what looks best. Given the current state of fonts in
-\CONTEXT\ we currently use 0 for the superscript and 750 for the subscripts.
-Positive values are used for both parameters but the subscript shifts to the
-left. A \type {\mathnolimitsmode} larger that 15 is considered to be a factor
-for the subscript correction. This feature can be handy when experimenting.
+\CONTEXT\ we currently use mode 1 with factor 0 for the superscript and 750 for
+the subscripts. Positive values are used for both parameters but the subscript
+shifts to the left. A \type {\mathnolimitsmode} larger that 15 is considered to
+be a factor for the subscript correction. This feature can be handy when
+experimenting.
 
 \section{Math spacing setting}
 
diff --git a/manual/luatex-nodes.tex b/manual/luatex-nodes.tex
index fd0b47c7290d279c80b0c73a2b5866946dffd4a0..7495e6a61828fea2417538dab72f423b3fd5bc6c 100644
--- a/manual/luatex-nodes.tex
+++ b/manual/luatex-nodes.tex
@@ -739,8 +739,13 @@ Possible mode values are:
 \NC 0           \NC setorigin              \NC \NR
 \NC 1           \NC page                   \NC \NR
 \NC 2           \NC direct                 \NC \NR
+\NC 3           \NC raw                    \NC \NR
 \stoptabulate
 
+The higher the number, the less checking and the more you can run into troubles.
+Especially the \type {raw} variant can produce bad \PDF\ so you can best check
+what you generate.
+
 \subsubsubsection{pdf_refobj whatsits}
 
 \starttabulate[|lT|l|p|]
diff --git a/manual/luatex.pdf b/manual/luatex.pdf
index 563339d2678dc6bcef74a0ea86cb0588997d5b09..9fa91f4fc30a0cf2962f9d2eaee9e66eb19b1986 100644
Binary files a/manual/luatex.pdf and b/manual/luatex.pdf differ
diff --git a/manual/luatex.tex b/manual/luatex.tex
index 75e63c9bb329117930b8c449dd3fbab80ede033a..74b2a60c8fa2ca43053421f23f0e95e4d5086874 100644
--- a/manual/luatex.tex
+++ b/manual/luatex.tex
@@ -12,7 +12,7 @@
 \dontcomplain
 
 \startdocument
-  [version=0.98.4,
+  [version=0.99,
    status=pre-release]
 
 \component luatex-titlepage
diff --git a/source/texk/web2c/luatexdir/font/texfont.w b/source/texk/web2c/luatexdir/font/texfont.w
index e68deac84ade915bc8524c89b030859fe7447355..9b6c0cd6bfeb63396c01956b3e3f9cf7c4abd029 100644
--- a/source/texk/web2c/luatexdir/font/texfont.w
+++ b/source/texk/web2c/luatexdir/font/texfont.w
@@ -267,18 +267,25 @@ charinfo *copy_charinfo(charinfo * ci)
     x = ci->top_left_math_kerns;
     co->top_left_math_kerns = x;
     if (x > 0) {
-        co->top_left_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        co->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
         for (k = 0; k < co->top_left_math_kerns; k++) {
             co->top_left_math_kern_array[(2 * k)] = ci->top_left_math_kern_array[(2 * k)];
             co->top_left_math_kern_array[(2 * k) + 1] = ci->top_left_math_kern_array[(2 * k) + 1];
         }
     }
+    x = ci->bottom_left_math_kerns;
+    co->bottom_left_math_kerns = x;
+    if (x > 0) {
+        co->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        for (k = 0; k < co->bottom_left_math_kerns; k++) {
+            co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
+            co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
+        }
+    }
     x = ci->top_right_math_kerns;
     co->top_right_math_kerns = x;
     if (x > 0) {
-        co->top_right_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        co->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
         for (k = 0; k < co->top_right_math_kerns; k++) {
             co->top_right_math_kern_array[(2 * k)] = ci->top_right_math_kern_array[(2 * k)];
             co->top_right_math_kern_array[(2 * k) + 1] = ci->top_right_math_kern_array[(2 * k) + 1];
@@ -287,23 +294,12 @@ charinfo *copy_charinfo(charinfo * ci)
     x = ci->bottom_right_math_kerns;
     co->bottom_right_math_kerns = x;
     if (x > 0) {
-        co->bottom_right_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        co->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
         for (k = 0; k < co->bottom_right_math_kerns; k++) {
             co->bottom_right_math_kern_array[(2 * k)] = ci->bottom_right_math_kern_array[(2 * k)];
             co->bottom_right_math_kern_array[(2 * k) + 1] = ci->bottom_right_math_kern_array[(2 * k) + 1];
         }
     }
-    x = ci->bottom_left_math_kerns;
-    co->bottom_left_math_kerns = x;
-    if (x > 0) {
-        co->bottom_left_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-        for (k = 0; k < co->bottom_left_math_kerns; k++) {
-            co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
-            co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
-        }
-    }
     return co;
 }
 
@@ -652,10 +648,10 @@ int get_charinfo_math_kerns(charinfo * ci, int id)
         k = ci->top_left_math_kerns;
     } else if (id == bottom_left_kern) {
         k = ci->bottom_left_math_kerns;
-    } else if (id == bottom_right_kern) {
-        k = ci->bottom_right_math_kerns;
     } else if (id == top_right_kern) {
         k = ci->top_right_math_kerns;
+    } else if (id == bottom_right_kern) {
+        k = ci->bottom_right_math_kerns;
     } else {
         confusion("get_charinfo_math_kerns");
     }
@@ -674,25 +670,22 @@ void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
         ci->top_left_math_kerns++;
     } else if (id == bottom_left_kern) {
         k = ci->bottom_left_math_kerns;
-        do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2),
-                   sizeof(scaled));
+        do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
         ci->bottom_left_math_kern_array[(2 * (k))] = ht;
         ci->bottom_left_math_kern_array[(2 * (k)) + 1] = krn;
         ci->bottom_left_math_kerns++;
-    } else if (id == bottom_right_kern) {
-        k = ci->bottom_right_math_kerns;
-        do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2),
-                   sizeof(scaled));
-        ci->bottom_right_math_kern_array[(2 * (k))] = ht;
-        ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
-        ci->bottom_right_math_kerns++;
     } else if (id == top_right_kern) {
         k = ci->top_right_math_kerns;
-        do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2),
-                   sizeof(scaled));
+        do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
         ci->top_right_math_kern_array[(2 * (k))] = ht;
         ci->top_right_math_kern_array[(2 * (k)) + 1] = krn;
         ci->top_right_math_kerns++;
+    } else if (id == bottom_right_kern) {
+        k = ci->bottom_right_math_kerns;
+        do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+        ci->bottom_right_math_kern_array[(2 * (k))] = ht;
+        ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
+        ci->bottom_right_math_kerns++;
     } else {
         confusion("add_charinfo_math_kern");
     }
@@ -715,17 +708,17 @@ static void dump_math_kerns(charinfo * ci)
         dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
         dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
     }
-    l = ci->bottom_right_math_kerns;
+    l = ci->top_right_math_kerns;
     dump_int(l);
     for (k = 0; k < l; k++) {
-        dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
-        dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
+        dump_int(ci->top_right_math_kern_array[(2 * k)]);
+        dump_int(ci->top_right_math_kern_array[(2 * k) + 1]);
     }
-    l = ci->top_right_math_kerns;
+    l = ci->bottom_right_math_kerns;
     dump_int(l);
     for (k = 0; k < l; k++) {
-        dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
-        dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
+        dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
+        dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
     }
 }
 
@@ -737,8 +730,7 @@ static void undump_math_kerns(charinfo * ci)
     undump_int(x);
     ci->top_left_math_kerns = x;
     if (x > 0)
-        ci->top_left_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        ci->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
     for (k = 0; k < ci->top_left_math_kerns; k++) {
         undump_int(x);
         ci->top_left_math_kern_array[(2 * k)] = (scaled) x;
@@ -748,8 +740,7 @@ static void undump_math_kerns(charinfo * ci)
     undump_int(x);
     ci->bottom_left_math_kerns = x;
     if (x > 0)
-        ci->bottom_left_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        ci->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
     for (k = 0; k < ci->bottom_left_math_kerns; k++) {
         undump_int(x);
         ci->bottom_left_math_kern_array[(2 * k)] = (scaled) x;
@@ -757,26 +748,24 @@ static void undump_math_kerns(charinfo * ci)
         ci->bottom_left_math_kern_array[(2 * k) + 1] = (scaled) x;
     }
     undump_int(x);
-    ci->bottom_right_math_kerns = x;
+    ci->top_right_math_kerns = x;
     if (x > 0)
-        ci->bottom_right_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->bottom_right_math_kerns; k++) {
+        ci->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->top_right_math_kerns; k++) {
         undump_int(x);
-        ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
+        ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
         undump_int(x);
-        ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+        ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
     }
     undump_int(x);
-    ci->top_right_math_kerns = x;
+    ci->bottom_right_math_kerns = x;
     if (x > 0)
-        ci->top_right_math_kern_array =
-            xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->top_right_math_kerns; k++) {
+        ci->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->bottom_right_math_kerns; k++) {
         undump_int(x);
-        ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
+        ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
         undump_int(x);
-        ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+        ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
     }
 }
 
diff --git a/source/texk/web2c/luatexdir/lua/lcallbacklib.c b/source/texk/web2c/luatexdir/lua/lcallbacklib.c
index 6bdaca016fd3215f44cadf7c9dc75b1b477fa804..812ad437b1ae50d79571da075c80d55f1cc17290 100644
--- a/source/texk/web2c/luatexdir/lua/lcallbacklib.c
+++ b/source/texk/web2c/luatexdir/lua/lcallbacklib.c
@@ -72,6 +72,7 @@ static const char *const callbacknames[] = {
     "process_rule",
     "insert_local_par",
     "contribute_filter",
+    "call_edit",
     NULL
 };
 
diff --git a/source/texk/web2c/luatexdir/lua/lpdflib.c b/source/texk/web2c/luatexdir/lua/lpdflib.c
index 3b9846c0ed258bea2f86bc109ed931f81aaac6e9..82508a2a9e247335ab74978d417003fea5214efd 100644
--- a/source/texk/web2c/luatexdir/lua/lpdflib.c
+++ b/source/texk/web2c/luatexdir/lua/lpdflib.c
@@ -43,6 +43,8 @@ static int luapdfprint(lua_State * L)
                 literal_mode = direct_always;
             else if (lua_key_eq(modestr_s,page))
                 literal_mode = direct_page;
+            else if (lua_key_eq(modestr_s,raw))
+                literal_mode = direct_raw;
             else {
                 luaL_error(L, "invalid first argument for print literal mode");
             }
@@ -64,6 +66,9 @@ static int luapdfprint(lua_State * L)
         case (direct_always):
             pdf_end_string_nl(static_pdf);
             break;
+        case (direct_raw):
+            pdf_end_string_nl(static_pdf);
+            break;
         default:
             assert(0);
     }
@@ -1069,11 +1074,13 @@ static int newpdfcolorstack(lua_State * L)
     if (lua_type(L,2) == LUA_TSTRING) {
         l =	lua_tostring(L, 2);
         if (lua_key_eq(l,origin)) {
-            literal_mode = 0;
+            literal_mode = set_origin;
         } else if (lua_key_eq(l,page))  {
-            literal_mode = 1; /* direct_page */
+            literal_mode = direct_page;
         } else if (lua_key_eq(l,direct)) {
-            literal_mode = 2; /* direct_always */
+            literal_mode = direct_always;
+        } else if (lua_key_eq(l,raw)) {
+            literal_mode = direct_raw;
         } else {
             luaL_error(L, "invalid literal mode in pdf.newcolorstack()");
         }
diff --git a/source/texk/web2c/luatexdir/lua/luanode.w b/source/texk/web2c/luatexdir/lua/luanode.w
index f901eddbfa97a7f599511b5c7e5b1353cec905d1..af15748bacd6392a217ea520da44347505c32870 100644
--- a/source/texk/web2c/luatexdir/lua/luanode.w
+++ b/source/texk/web2c/luatexdir/lua/luanode.w
@@ -420,6 +420,9 @@ void show_pdf_literal(pointer p)
         case direct_always:
             tprint(" direct");
             break;
+        case direct_raw:
+            tprint(" raw");
+            break;
         default:
             confusion("literal2");
             break;
diff --git a/source/texk/web2c/luatexdir/luatex.c b/source/texk/web2c/luatexdir/luatex.c
index 7e06c9388857cf10c466010c373f1ecec161b9e4..eb3f359392c8b17cde7f8df79bba2903d590f9f4 100644
--- a/source/texk/web2c/luatexdir/luatex.c
+++ b/source/texk/web2c/luatexdir/luatex.c
@@ -28,10 +28,10 @@
 
 #define TeX
 
-int luatex_version = 98;        /* \.{\\luatexversion}  */
-int luatex_revision = '4';      /* \.{\\luatexrevision}  */
-int luatex_date_info = 2016090500;     /* the compile date is now hardwired */
-const char *luatex_version_string = "0.98.4";
+int luatex_version = 99;        /* \.{\\luatexversion}  */
+int luatex_revision = '1';      /* \.{\\luatexrevision}  */
+int luatex_date_info = 2016092300;     /* the compile date is now hardwired */
+const char *luatex_version_string = "0.99.1";
 const char *engine_name = my_name;     /* the name of this engine */
 
 #include <kpathsea/c-ctype.h>
@@ -61,10 +61,6 @@ const char *engine_name = my_name;     /* the name of this engine */
 #include <signal.h>             /* Catch interrupts.  */
 
 
-/* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
-   Unfortunately there's no way to get the banner into this code, so
-   just repeat the text.  */
-#define edit_var "TEXEDIT"
 
 /* Shell escape.
 
diff --git a/source/texk/web2c/luatexdir/luatexcallbackids.h b/source/texk/web2c/luatexdir/luatexcallbackids.h
index 4a02f05d058e785b932f610482364a3f947dfa83..cfd865b896a84d9a9e73c1ea339c3b9476850731 100644
--- a/source/texk/web2c/luatexdir/luatexcallbackids.h
+++ b/source/texk/web2c/luatexdir/luatexcallbackids.h
@@ -66,6 +66,7 @@ typedef enum {
     process_rule_callback,
     insert_local_par_callback,
     contribute_filter_callback,
+    call_edit_callback,
     total_callbacks
 } callback_callback_types;
 
diff --git a/source/texk/web2c/luatexdir/pdf/pdfgen.h b/source/texk/web2c/luatexdir/pdf/pdfgen.h
index 551f686e6fe245a87086a6cc9de9da5e4af59759..f2086663c70b82d05d0f921002e4167f437e1917 100644
--- a/source/texk/web2c/luatexdir/pdf/pdfgen.h
+++ b/source/texk/web2c/luatexdir/pdf/pdfgen.h
@@ -27,8 +27,8 @@
 #  define PROCSET_IMAGE_C (1 << 3)
 #  define PROCSET_IMAGE_I (1 << 4)
 
-#  define inf_pdf_mem_size    10000 /* min size of the |mem| array */
-#  define sup_pdf_mem_size 10000000 /* max size of the |mem| array */
+#  define inf_pdf_mem_size     10000 /* min size of the |mem| array */
+#  define sup_pdf_mem_size 100000000 /* max size of the |mem| array */
 
 extern PDF static_pdf;
 
@@ -43,10 +43,10 @@ be the first written bytes.
 
 */
 
-#  define inf_pdfout_buf_size   16384  /* initial value of |pdf->buf| size */
-#  define sup_pdfout_buf_size   16384  /* arbitrary upper hard limit of |pdf->buf| size */
-#  define inf_objstm_buf_size       1  /* initial value of |os->buf[OBJSTM_BUF]| size */
-#  define sup_objstm_buf_size 5000000  /* arbitrary upper hard limit of |os->buf[OBJSTM_BUF]| size */
+#  define inf_pdfout_buf_size     16384 /* initial value of |pdf->buf| size */
+#  define sup_pdfout_buf_size   8*16384 /* arbitrary upper hard limit of |pdf->buf| size */
+#  define inf_objstm_buf_size         1 /* initial value of |os->buf[OBJSTM_BUF]| size */
+#  define sup_objstm_buf_size   5000000 /* arbitrary upper hard limit of |os->buf[OBJSTM_BUF]| size */
 
 #  define PDF_OS_MAX_OBJS         100  /* maximum number of objects in object stream */
 
diff --git a/source/texk/web2c/luatexdir/pdf/pdfliteral.w b/source/texk/web2c/luatexdir/pdf/pdfliteral.w
index 3c6b6f6efbfb9880ec629df0ee12bb7c897bbb58..64a36dc67bfaffa5e31aa311baa0660a058ff482 100644
--- a/source/texk/web2c/luatexdir/pdf/pdfliteral.w
+++ b/source/texk/web2c/luatexdir/pdf/pdfliteral.w
@@ -66,6 +66,9 @@ void pdf_out_literal(PDF pdf, halfword p)
                 pdf_end_string_nl(pdf);
                 ps->need_tm = true;
                 break;
+            case direct_raw:
+                pdf_end_string_nl(pdf);
+                break;
             default:
                 normal_error("pdf backend","bad literal mode");
                 break;
@@ -114,6 +117,9 @@ void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn)
             } else if (str_in_cstr(s, "page:", strlen("PDF:"))) {
                 j = j + (pool_pointer) strlen("page:");
                 literal_mode = direct_page;
+            } else if (str_in_cstr(s, "raw:", strlen("PDF:"))) {
+                j = j + (pool_pointer) strlen("raw:");
+                literal_mode = direct_raw;
             } else {
                 literal_mode = set_origin;
             }
@@ -131,6 +137,9 @@ void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn)
             pdf_end_string_nl(pdf);
             p->need_tm = true;
             break;
+        case direct_raw:
+            pdf_end_string_nl(pdf);
+            break;
         default:
             normal_error("pdf backend","bad literal mode");
             break;
diff --git a/source/texk/web2c/luatexdir/pdf/pdfrule.w b/source/texk/web2c/luatexdir/pdf/pdfrule.w
index 2f75b4c761e951485a6b4381d1079783c6830a96..df4979088c8242533e41eb5d98a863bae5dee3e4 100644
--- a/source/texk/web2c/luatexdir/pdf/pdfrule.w
+++ b/source/texk/web2c/luatexdir/pdf/pdfrule.w
@@ -30,14 +30,22 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
     pdfpos dim;
     pdfstructure *p = pdf->pstruct;
     scaledpos pos = pdf->posstruct->pos;
+    halfword s = subtype(q);
     /*  (void) q; */
-    if (subtype(q) == box_rule) {
+    if (s >= math_over_rule && s <= math_radical_rule) {
+        if (callback_id == 0) {
+            s = normal_rule;
+        } else {
+            s = user_rule;
+        }
+    }
+    if (s == box_rule) {
         pdf_place_form(pdf,q);
-    } else if (subtype(q) == image_rule) {
+    } else if (s == image_rule) {
         pdf_place_image(pdf,q);
-    } else if (subtype(q) == empty_rule) {
+    } else if (s == empty_rule) {
         /* place nothing, only take space */
-    } else if (subtype(q) == user_rule) {
+    } else if (s == user_rule) {
         if (callback_id != 0) {
             pdf_goto_pagemode(pdf);
             pdf_puts(pdf, "q\n");
diff --git a/source/texk/web2c/luatexdir/tex/commands.w b/source/texk/web2c/luatexdir/tex/commands.w
index e4a269d93d010e4f53442f2acbc7671bd6d1fba5..b89dadffd1f4936b3d5f6292eecc0c9200edec9d 100644
--- a/source/texk/web2c/luatexdir/tex/commands.w
+++ b/source/texk/web2c/luatexdir/tex/commands.w
@@ -754,6 +754,8 @@ void initialize_etex_commands(void)
     primitive_luatex("mathdisplayskipmode", assign_int_cmd, int_base + math_display_skip_mode_code, int_base);
     primitive_luatex("mathscriptsmode", assign_int_cmd, int_base + math_scripts_mode_code, int_base);
     primitive_luatex("mathnolimitsmode", assign_int_cmd, int_base + math_nolimits_mode_code, int_base);
+    primitive_luatex("mathrulesmode", assign_int_cmd, int_base + math_rules_mode_code, int_base);
+    primitive_luatex("mathrulesfam", assign_int_cmd, int_base + math_rules_fam_code, int_base);
     primitive_luatex("synctex", assign_int_cmd, int_base + synctex_code, int_base);
 
     primitive_etex("currentgrouplevel", last_item_cmd, current_group_level_code, 0);
diff --git a/source/texk/web2c/luatexdir/tex/dumpdata.w b/source/texk/web2c/luatexdir/tex/dumpdata.w
index 85ff55f4e09915aa3f6888d4180c2f6f3426168a..c7bb4c2e87d4af8306436a06044d334d6c95055d 100644
--- a/source/texk/web2c/luatexdir/tex/dumpdata.w
+++ b/source/texk/web2c/luatexdir/tex/dumpdata.w
@@ -23,7 +23,7 @@
 
 /* we start with 907: the sum of the values of the bytes of "don knuth" */
 
-#define FORMAT_ID (907+18)
+#define FORMAT_ID (907+20)
 #if ((FORMAT_ID>=0) && (FORMAT_ID<=256))
 #error Wrong value for FORMAT_ID.
 #endif
diff --git a/source/texk/web2c/luatexdir/tex/equivalents.h b/source/texk/web2c/luatexdir/tex/equivalents.h
index b2bda5f605bb6ed600b0080aa85c0418814aacce..27a4f96401b51faf3e86c409274cd28ac425b72a 100644
--- a/source/texk/web2c/luatexdir/tex/equivalents.h
+++ b/source/texk/web2c/luatexdir/tex/equivalents.h
@@ -279,20 +279,22 @@ the |number_regs| \.{\\dimen} registers.
 #  define math_display_skip_mode_code 88
 #  define math_scripts_mode_code 89
 #  define math_nolimits_mode_code 90
-#  define synctex_code 91                                               /* is synctex file generation enabled ?  */
-#  define shape_mode_code 92
-#  define first_valid_language_code 93
-#  define hyphenation_bounds_code 94
+#  define math_rules_mode_code 91
+#  define math_rules_fam_code 92
+#  define synctex_code 93                                               /* is synctex file generation enabled ?  */
+#  define shape_mode_code 94
+#  define first_valid_language_code 95
+#  define hyphenation_bounds_code 96
 
-#  define math_option_code 95
+#  define math_option_code 97
 
-#  define mathoption_int_base (int_base+96)                             /* one reserve */
-#  define mathoption_int_last (int_base+104)
+#  define mathoption_int_base (int_base+98)                             /* one reserve */
+#  define mathoption_int_last (int_base+106)
 
-#  define backend_int_base (int_base+105)
-#  define backend_int_last (int_base+129)
+#  define backend_int_base (int_base+107)
+#  define backend_int_last (int_base+131)
 
-#  define tex_int_pars (130)                                            /* total number of integer parameters */
+#  define tex_int_pars (132)                                            /* total number of integer parameters */
 
 #  define page_direction_code (tex_int_pars)
 #  define body_direction_code (tex_int_pars+1)
@@ -639,6 +641,8 @@ extern halfword last_cs_name;
 #define disable_space_par                  int_par(disable_space_code)
 #define scripts_mode_par                   int_par(math_scripts_mode_code)
 #define nolimits_mode_par                  int_par(math_nolimits_mode_code)
+#define math_rules_mode_par                int_par(math_rules_mode_code)
+#define math_rules_fam_par                 int_par(math_rules_fam_code)
 
 #define thin_mu_skip_par                   glue_par(thin_mu_skip_code)
 #define med_mu_skip_par                    glue_par(med_mu_skip_code)
diff --git a/source/texk/web2c/luatexdir/tex/errors.w b/source/texk/web2c/luatexdir/tex/errors.w
index 1af16ec58ef41ea8092cf103672927a8b4b1f6c8..cec9a144f1c3fec9bc12b945b07d46eb80e7f812 100644
--- a/source/texk/web2c/luatexdir/tex/errors.w
+++ b/source/texk/web2c/luatexdir/tex/errors.w
@@ -24,6 +24,7 @@ luafflib.c
 
 @ @c
 #include "ptexlib.h"
+#define edit_var "TEXEDIT"
 
 @ When something anomalous is detected, \TeX\ typically does something like this:
 $$\vbox{\halign{#\hfil\cr
@@ -232,6 +233,155 @@ void jump_out(void)
     close_files_and_terminate();
     do_final_end();
 }
+@ Here is the function that calls the editor, if one is defined. This
+is loosely based on a similar function in kpathsea, but the calling
+convention is quite different.
+
+@c
+static const_string edit_value = EDITOR;
+
+#if defined(WIN32)
+static int
+Isspace (char c)
+{
+  return (c == ' ' || c == '\t');
+}
+#endif /* WIN32 */
+
+__attribute__ ((noreturn))
+static void luatex_calledit (int baseptr, int linenumber)
+{
+  char *temp, *command, *fullcmd;
+  char c;
+  int sdone, ddone, i;
+  char *filename = makecstring(input_stack[base_ptr].name_field);
+  int fnlength = strlen(filename);
+
+#ifdef WIN32
+  char *fp, *ffp, *env, editorname[256], buffer[256];
+  int cnt = 0;
+  int dontchange = 0;
+#endif
+
+  sdone = ddone = 0;
+
+  /* Close any open input files, since we're going to kill the job.  */
+  close_files_and_terminate();
+
+  /* Replace the default with the value of the appropriate environment
+     variable or config file value, if it's set.  */
+  temp = kpse_var_value (edit_var);
+  if (temp != NULL)
+    edit_value = temp;
+
+  /* Construct the command string.  The `11' is the maximum length an
+     integer might be.  */
+  command = xmalloc (strlen (edit_value) + fnlength + 11);
+
+  /* So we can construct it as we go.  */
+  temp = command;
+
+#ifdef WIN32
+  fp = editorname;
+  if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
+        && IS_DIR_SEP (*(edit_value + 2)))
+      || (*edit_value == '"' && isalpha(*(edit_value + 1))
+        && *(edit_value + 2) == ':'
+        && IS_DIR_SEP (*(edit_value + 3)))
+     )
+    dontchange = 1;
+#endif
+
+  while ((c = *edit_value++) != 0)
+    {
+      if (c == '%')
+        {
+          switch (c = *edit_value++)
+            {
+            case 'd':
+              if (ddone)
+                FATAL1 ("call_edit: `%%d' appears twice in editor command: `%s'", edit_value);
+              sprintf (temp, "%ld", (long int)linenumber);
+              while (*temp != '\0')
+                temp++;
+              ddone = 1;
+              break;
+
+            case 's':
+              if (sdone)
+                FATAL1 ("call_edit: `%%s' appears twice in editor command: `%s'", edit_value);
+              for (i =0; i < fnlength; i++)
+                *temp++ = filename[i];
+              sdone = 1;
+              break;
+
+            case '\0':
+              *temp++ = '%';
+              /* Back up to the null to force termination.  */
+              edit_value--;
+              break;
+
+            default:
+              *temp++ = '%';
+              *temp++ = c;
+              break;
+            }
+        }
+      else {
+#ifdef WIN32
+        if (dontchange)
+          *temp++ = c;
+        else { if(Isspace(c) && cnt == 0) {
+            cnt++;
+            temp = command;
+            *temp++ = c;
+            *fp = '\0';
+          } else if(!Isspace(c) && cnt == 0) {
+            *fp++ = c;
+          } else {
+            *temp++ = c;
+          }
+        }
+#else
+        *temp++ = c;
+#endif
+      }
+    }
+
+  *temp = 0;
+
+#ifdef WIN32
+  if (dontchange == 0) {
+    if(editorname[0] == '.' ||
+       editorname[0] == '/' ||
+       editorname[0] == '\\') {
+      fprintf(stderr, "%s is not allowed to execute.\n", editorname);
+      do_final_end();
+    }
+    env = (char *)getenv("PATH");
+    if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
+      if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
+        fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
+        do_final_end();
+      }
+    }
+    fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
+    strcpy(fullcmd, "\"");
+    strcat(fullcmd, buffer);
+    strcat(fullcmd, "\"");
+    strcat(fullcmd, command);
+  } else
+#endif
+  fullcmd = command;
+
+  /* Execute the command.  */
+  if (system (fullcmd) != 0)
+    fprintf (stderr, "! Trouble executing `%s'.\n", command);
+
+  /* Quit, since we found an error.  */
+  do_final_end ();
+}
+
 
 @ @c
 void error(void)
@@ -325,12 +475,23 @@ void error(void)
 #endif
             case 'E':
                 if (base_ptr > 0) {
-                    tprint_nl("You want to edit file ");
-                    print(input_stack[base_ptr].name_field);
-                    tprint(" at line ");
-                    print_int(line);
-                    interaction = scroll_mode;
-                    jump_out();
+                    int callback_id = callback_defined(call_edit_callback);
+                    if (callback_id>0) {
+                        (void)run_callback(callback_id, "Sd->", makecstring(input_stack[base_ptr].name_field), line);
+                        jump_out(); /* should not be reached */
+                    } else {
+                        tprint_nl("You want to edit file ");
+                        print(input_stack[base_ptr].name_field);
+                        tprint(" at line ");
+                        print_int(line);
+                        interaction = scroll_mode;
+                        if (kpse_init) {
+                            luatex_calledit(base_ptr, line);
+                        } else {
+                            tprint_nl("There is no valid callback defined.");
+                            jump_out(); /* should not be reached */
+                        }
+                    }
                 }
                 break;
             case 'H':
diff --git a/source/texk/web2c/luatexdir/tex/extensions.w b/source/texk/web2c/luatexdir/tex/extensions.w
index 838c6edcead900cc3651684ce1bde7f02e336d5e..f3c66d32ed294aa80bb61e064681f2d8d4ca8163 100644
--- a/source/texk/web2c/luatexdir/tex/extensions.w
+++ b/source/texk/web2c/luatexdir/tex/extensions.w
@@ -142,6 +142,8 @@ static void do_extension_pdf(int immediate)
             set_pdf_literal_mode(tail, direct_always);
         else if (scan_keyword("page"))
             set_pdf_literal_mode(tail, direct_page);
+        else if (scan_keyword("raw"))
+            set_pdf_literal_mode(tail, direct_raw);
         else
             set_pdf_literal_mode(tail, set_origin);
         scan_toks(false, true);
diff --git a/source/texk/web2c/luatexdir/tex/mlist.w b/source/texk/web2c/luatexdir/tex/mlist.w
index 753ce840cbccf897cb018a6dd44ac4510c56ec95..909128e93c6171229202310d6f3ddaa672b8d219 100644
--- a/source/texk/web2c/luatexdir/tex/mlist.w
+++ b/source/texk/web2c/luatexdir/tex/mlist.w
@@ -271,7 +271,7 @@ static scaled minimum_operator_size(int var)
 the backward compatibility code, and it means that we can't raise an error here.
 
 @c
-static scaled radical_rule(int var)
+static scaled radical_rule_par(int var)
 {
     scaled a = get_math_param(math_param_radical_rule, var);
     return a;
@@ -978,10 +978,16 @@ static pointer math_clone(pointer q)
   that eventually contains it.
 
 @c
-static pointer do_fraction_rule(scaled t, pointer att)
+static pointer do_fraction_rule(scaled t, pointer att, halfword some_rule, halfword cur_size, halfword cur_fam)
 {
     pointer p;                  /* the new node */
-    p = new_rule(normal_rule);
+    if (math_rules_mode_par) {
+        p = new_rule(some_rule);
+        rule_math_size(p) = cur_size;
+        rule_math_font(p) = fam_fnt(cur_fam, cur_size);
+    } else {
+        p = new_rule(normal_rule);
+    }
     rule_dir(p) = math_direction_par;
     height(p) = t;
     depth(p) = 0;
@@ -994,13 +1000,13 @@ static pointer do_fraction_rule(scaled t, pointer att)
   fraction rule of thickness |t| under additional space of height |ht|.
 
 @c
-static pointer overbar(pointer b, scaled k, scaled t, scaled ht, pointer att)
+static pointer overbar(pointer b, scaled k, scaled t, scaled ht, pointer att, halfword index, halfword cur_size, halfword cur_fam)
 {
     pointer p, q;               /* nodes being constructed */
     p = new_kern(k);
     reset_attributes(p, att);
     couple_nodes(p,b);
-    q = do_fraction_rule(t, att);
+    q = do_fraction_rule(t, att, index, cur_size, cur_fam);
     couple_nodes(q,p);
     p = new_kern(ht);
     reset_attributes(p, att);
@@ -1796,17 +1802,17 @@ illustrate the general setup of such procedures, let's begin with a
 couple of simple ones.
 
 @c
-static void make_over(pointer q, int cur_style)
+static void make_over(pointer q, int cur_style, int cur_size, int cur_fam)
 {
     pointer p;
     p = overbar(clean_box(nucleus(q), cramped_style(cur_style), cur_style),
                 overbar_vgap(cur_style), overbar_rule(cur_style),
-                overbar_kern(cur_style), node_attr(nucleus(q)));
+                overbar_kern(cur_style), node_attr(nucleus(q)), math_over_rule, cur_size, cur_fam);
     math_list(nucleus(q)) = p;
     type(nucleus(q)) = sub_box_node;
 }
 
-static void make_under(pointer q, int cur_style)
+static void make_under(pointer q, int cur_style, int cur_size, int cur_fam)
 {
     pointer p, x, y, r;         /* temporary registers for box construction */
     scaled delta;               /* overall height plus depth */
@@ -1814,7 +1820,7 @@ static void make_under(pointer q, int cur_style)
     p = new_kern(underbar_vgap(cur_style));
     reset_attributes(p, node_attr(q));
     couple_nodes(x,p);
-    r = do_fraction_rule(underbar_rule(cur_style), node_attr(q));
+    r = do_fraction_rule(underbar_rule(cur_style), node_attr(q), math_under_rule, cur_size, cur_fam);
     couple_nodes(p,r);
     y = vpackage(x, 0, additional, max_dimen, math_direction_par);
     reset_attributes(y, node_attr(q));
@@ -1878,7 +1884,7 @@ static void make_radical(pointer q, int cur_style)
     scaled delta, clr, theta, h; /* dimensions involved in the calculation */
     x = clean_box(nucleus(q), cramped_style(cur_style), cur_style);
     clr = radical_vgap(cur_style);
-    theta = radical_rule(cur_style);
+    theta = radical_rule_par(cur_style);
     if (theta == undefined_math_parameter) {
         /* a real radical */
         theta = fraction_rule(cur_style);
@@ -1912,7 +1918,7 @@ static void make_radical(pointer q, int cur_style)
     }
     shift_amount(y) = (height(y) - theta) - (height(x) + clr);
     h = depth(y) + height(y);
-    p = overbar(x, clr, theta, radical_kern(cur_style), node_attr(y));
+    p = overbar(x, clr, theta, radical_kern(cur_style), node_attr(y), math_radical_rule, cur_size, small_fam(left_delimiter(q)));
     couple_nodes(y,p);
     if (degree(q) != null) {
         scaled wr, br, ar;
@@ -2559,7 +2565,7 @@ static void make_fraction(pointer q, int cur_style)
             p = new_kern((shift_up - depth(x)) - (height(z) - shift_down));
             couple_nodes(p,z);
         } else {
-            y = do_fraction_rule(thickness(q), node_attr(q));
+            y = do_fraction_rule(thickness(q), node_attr(q), math_fraction_rule, cur_size, math_rules_fam_par);
             p = new_kern((math_axis_size(cur_size) - delta) - (height(z) - shift_down));
             reset_attributes(p, node_attr(q));
             couple_nodes(y,p);
@@ -2656,8 +2662,9 @@ static scaled make_op(pointer q, int cur_style)
                     math_character(nucleus(q)) = c;
                 }
                 delta = char_italic(cur_f, cur_c);
+printf("delta %i\n",delta);
                 x = clean_box(nucleus(q), cur_style, cur_style);
-                if (delta != null) {
+                if (delta != 0) {
                     if (do_new_math(cur_f)) {
                         /* we never added italic correction */
                     } else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
@@ -2712,8 +2719,8 @@ static scaled make_op(pointer q, int cur_style)
                 */
                 switch (mode) {
                     case 0 :
-                        /* as with limits */
-                        make_scripts(q, p, 0, cur_style, half(delta), -half(delta));
+                        /* full bottom correction */
+                        make_scripts(q, p, 0, cur_style, 0, -delta);
                         break;
                     case 1 :
                         /* MathConstants driven */
@@ -2723,22 +2730,21 @@ static scaled make_op(pointer q, int cur_style)
                     case 2 :
                         /* no correction */
                         make_scripts(q, p, 0, cur_style, 0, 0);
-                        break;
+                        break ;
                     case 3 :
                         /* half bottom correction */
                         make_scripts(q, p, 0, cur_style, 0, -half(delta));
                         break;
                     case 4 :
-                        /* full bottom correction */
-                        make_scripts(q, p, 0, cur_style, 0, -delta);
+                        /* half bottom and top correction */
+                        make_scripts(q, p, 0, cur_style, half(delta), -half(delta));
                         break;
                     default :
-                        /* half bottom and top correction */
                         if (mode > 15) {
                             /* for quickly testing values */
                             make_scripts(q, p, 0, cur_style, 0, -round_xn_over_d(delta, mode, 1000));
                         } else {
-                            make_scripts(q, p, 0, cur_style, half(delta), -half(delta));
+                            make_scripts(q, p, 0, cur_style, 0, 0);
                         }
                         break;
                 }
@@ -3913,10 +3919,10 @@ void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
                 }
                 break;
             case over_noad_type:
-                make_over(q, cur_style);
+                make_over(q, cur_style, cur_size, math_rules_fam_par);
                 break;
             case under_noad_type:
-                make_under(q, cur_style);
+                make_under(q, cur_style, cur_size, math_rules_fam_par);
                 break;
             case vcenter_noad_type:
                 make_vcenter(q);
diff --git a/source/texk/web2c/luatexdir/tex/texfileio.w b/source/texk/web2c/luatexdir/tex/texfileio.w
index c222eef975b8614628bff85e2b159760299a3d07..2281de12c4c858652b47a963712898c5e9ba46ec 100644
--- a/source/texk/web2c/luatexdir/tex/texfileio.w
+++ b/source/texk/web2c/luatexdir/tex/texfileio.w
@@ -170,12 +170,12 @@ char *luatex_find_file(const char *s, int callback_index)
         case find_data_file_callback:
             ftemp = find_in_output_directory(s);
             if (!ftemp)
-                ftemp = kpse_find_file(s, kpse_tex_format, 0);
+                ftemp = kpse_find_file(s, kpse_tex_format, 1);
             break;
         case find_font_file_callback:
-            ftemp = kpse_find_file(s, kpse_ofm_format, 0);
+            ftemp = kpse_find_file(s, kpse_ofm_format, 1);
             if (ftemp == NULL)
-                ftemp = kpse_find_file(s, kpse_tfm_format, 0);
+                ftemp = kpse_find_file(s, kpse_tfm_format, 1);
             break;
         case find_vf_file_callback:
             ftemp = kpse_find_file(s, kpse_ovf_format, 0);
diff --git a/source/texk/web2c/luatexdir/tex/texnodes.h b/source/texk/web2c/luatexdir/tex/texnodes.h
index 6650d17f41091ed70259fdaedbaeddb146e70f69..943a347554de0137370d59cc44c605f8c4392eaf 100644
--- a/source/texk/web2c/luatexdir/tex/texnodes.h
+++ b/source/texk/web2c/luatexdir/tex/texnodes.h
@@ -261,6 +261,10 @@ typedef enum {
     image_rule,
     empty_rule,
     user_rule,
+    math_over_rule,
+    math_under_rule,
+    math_fraction_rule,
+    math_radical_rule,
 } rule_subtypes;
 
 #  define rule_node_size       8
@@ -270,6 +274,9 @@ typedef enum {
 #  define synctex_tag_rule(a)  vinfo((a)+7)
 #  define synctex_line_rule(a) vlink((a)+7)
 
+#  define rule_math_size       rule_index
+#  define rule_math_font       rule_transform
+
 #  define mark_node_size   3
 #  define mark_ptr(a)      vlink((a)+2)
 #  define mark_class(a)    vinfo((a)+2)
@@ -716,6 +723,7 @@ typedef enum {
     set_origin = 0,
     direct_page,
     direct_always,
+    direct_raw,
     scan_special,
 } ctm_transform_modes;
 
diff --git a/source/texk/web2c/luatexdir/tex/texnodes.w b/source/texk/web2c/luatexdir/tex/texnodes.w
index c242577404f9d761543c86822a7b2e48028d9492..3a368c82336a6b5ef15692fadaea8b47506cc5b4 100644
--- a/source/texk/web2c/luatexdir/tex/texnodes.w
+++ b/source/texk/web2c/luatexdir/tex/texnodes.w
@@ -268,7 +268,7 @@ const char *node_subtypes_kern[] = {
     "fontkern", "userkern", "accentkern", "italiccorrection", NULL
 };
 const char *node_subtypes_rule[] = {
-    "normal", "box", "image", "empty", "user", NULL
+    "normal", "box", "image", "empty", "user", "over", "under", "fraction", "radical", NULL
 };
 const char *node_subtypes_glyph[] = {
     "character", "glyph", "ligature", "ghost", "left", "right", NULL
diff --git a/source/texk/web2c/luatexdir/tex/textoken.w b/source/texk/web2c/luatexdir/tex/textoken.w
index 8f44f686641ba0e9368fa3f9d70390324e4a174c..7b781fc082b0d39512780756e6f8a98cce92fbee 100644
--- a/source/texk/web2c/luatexdir/tex/textoken.w
+++ b/source/texk/web2c/luatexdir/tex/textoken.w
@@ -2437,6 +2437,8 @@ static int do_feedback_pdf(halfword c)
             cur_val = direct_always;
         else if (scan_keyword("page"))
             cur_val = direct_page;
+        else if (scan_keyword("raw"))
+            cur_val = direct_raw;
         else
             cur_val = set_origin;
         save_scanner_status = scanner_status;
diff --git a/source/texk/web2c/mplibdir/mp.w b/source/texk/web2c/mplibdir/mp.w
index 964c5372069c7914c9bc7cba206575a3713df57b..4977fbcefba4a9c91f939110fad8fea0d2fccbe8 100644
--- a/source/texk/web2c/mplibdir/mp.w
+++ b/source/texk/web2c/mplibdir/mp.w
@@ -1,4 +1,4 @@
-% $Id: mp.w 2080 2016-03-06 21:26:30Z luigi $
+% $Id: mp.w 2093 2016-09-20 10:09:14Z luigi $
 %
 % This file is part of MetaPost;
 % the MetaPost program is in the public domain.
@@ -140,6 +140,19 @@ typedef struct MP_instance {
 #endif
 
 @ @c
+/*#define DEBUGENVELOPE */
+#ifdef DEBUGENVELOPE 
+#define dbg_n(A) printf("['%s']=%s, ", #A, number_tostring(A))
+#define dbg_in(A) printf("['%s']=%d, ", #A, (int)(A))
+#define dbg_dn(A) printf("['%s']=%.100f, ", #A, (double)(A))
+#define dbg_key(A) printf("['%s']= ", #A)
+#define dbg_sp printf(" ")
+#define dbg_str(A) printf("%s",#A)
+#define dbg_open_t printf("{")
+#define dbg_close_t printf("}")
+#define dbg_comma printf(",")
+#define dbg_nl printf("\n")
+#endif
 #define KPATHSEA_DEBUG_H 1
 #include <w2c/config.h>
 #include <stdio.h>
@@ -171,6 +184,15 @@ typedef struct MP_instance {
 #include "mpmathdecimal.h"      /* internal header */
 #include "mpmathbinary.h"       /* internal header */
 #include "mpstrings.h"          /* internal header */
+/* BEGIN PATCH */
+mp_number dx_ap;    /* approximation of dx */
+mp_number dy_ap;    /* approximation of dy */
+mp_number dxin_ap;  /* approximation of dxin */
+mp_number dyin_ap;  /* approximation of dyin */
+mp_number ueps_ap;  /* epsilon for above approximations */
+/* END PATCH */
+
+
 extern font_number mp_read_font_info (MP mp, char *fname);      /* tfmin.w */
 @h @<Declarations@>;
 @<Basic printing procedures@>;
@@ -2568,18 +2590,18 @@ void mp_new_randoms (MP mp) {
   mp->j_random = 54;
 }
 
-@ To consume a random fraction, the program below will say `|next_random|'.
+@ To consume a random fraction, the program below will say `|next_random|'. 
 Now each number system has its own implementation,
 true to the original as much as possibile.
 
 @c
 /* Unused.
-static void mp_next_random (MP mp, mp_number *ret) {
-  if ( mp->j_random==0 )
-    mp_new_randoms(mp);
+static void mp\_next\_random (MP mp, mp\_number *ret) {
+  if ( mp->j\_random==0 )
+    mp\_new\_randoms(mp);
   else
-    decr(mp->j_random);
-  number_clone (*ret, mp->randoms[mp->j_random]);
+    decr(mp->j\_random);
+  number\_clone (*ret, mp->randoms[mp->j\_random]);
 }
 */
 
@@ -2596,31 +2618,31 @@ As said before, now each number system has its own implementation.
 
 @c
 /*Unused.
-static void mp_unif_rand (MP mp, mp_number *ret, mp_number x_orig) {
-  mp_number y;     // trial value
-  mp_number x, abs_x;
-  mp_number u;
-  new_fraction (y);
-  new_number (x);
-  new_number (abs_x);
-  new_number (u);
-  number_clone (x, x_orig);
-  number_clone (abs_x, x);
-  number_abs (abs_x);
-  mp_next_random(mp, &u);
-  take_fraction (y, abs_x, u);
-  free_number (u);
-  if (number_equal(y, abs_x)) {
-    set_number_to_zero(*ret);
-  } else if (number_positive(x)) {
-    number_clone (*ret, y);
+static void mp\_unif\_rand (MP mp, mp\_number *ret, mp\_number x\_orig) {
+  mp\_number y;     // trial value 
+  mp\_number x, abs\_x;
+  mp\_number u;
+  new\_fraction (y);
+  new\_number (x);
+  new\_number (abs\_x);
+  new\_number (u);
+  number\_clone (x, x\_orig);
+  number\_clone (abs\_x, x);
+  number\_abs (abs\_x);
+  mp\_next\_random(mp, \&u);
+  take\_fraction (y, abs\_x, u);
+  free\_number (u);
+  if (number\_equal(y, abs\_x)) {
+    set\_number\_to\_zero(*ret);
+  } else if (number\_positive(x)) {
+    number\_clone (*ret, y);
   } else {
-    number_clone (*ret, y);
-    number_negate (*ret);
+    number\_clone (*ret, y);
+    number\_negate (*ret);
   }
-  free_number (abs_x);
-  free_number (x);
-  free_number (y);
+  free\_number (abs\_x);
+  free\_number (x);
+  free\_number (y);
 }
 */
 
@@ -2634,43 +2656,43 @@ true to the original as much as possibile.
 
 @c
 /*  Unused.
-static void mp_norm_rand (MP mp, mp_number *ret) {
-  mp_number ab_vs_cd;
-  mp_number abs_x;
-  mp_number u;
-  mp_number r;
-  mp_number la, xa;
-  new_number (ab_vs_cd);
-  new_number (la);
-  new_number (xa);
-  new_number (abs_x);
-  new_number (u);
-  new_number (r);
+static void mp\_norm\_rand (MP mp, mp\_number *ret) {
+  mp\_number ab\_vs\_cd;
+  mp\_number abs\_x;
+  mp\_number u;
+  mp\_number r;
+  mp\_number la, xa;
+  new\_number (ab\_vs\_cd);
+  new\_number (la);
+  new\_number (xa);
+  new\_number (abs\_x);
+  new\_number (u);
+  new\_number (r);
   do {
     do {
-      mp_number v;
-      new_number (v);
-      mp_next_random(mp, &v);
-      number_substract (v, fraction_half_t);
-      take_fraction (xa, sqrt_8_e_k, v);
-      free_number (v);
-      mp_next_random(mp, &u);
-      number_clone (abs_x, xa);
-      number_abs (abs_x);
-    } while (number_greaterequal (abs_x, u));
-    make_fraction (r, xa, u);
-    number_clone (xa, r);
-    m_log (la, u);
-    set_number_from_substraction(la, twelve_ln_2_k, la);
-    ab_vs_cd (ab_vs_cd, one_k, la, xa, xa);
-  } while (number_negative(ab_vs_cd));
-  number_clone (*ret, xa);
-  free_number (ab_vs_cd);
-  free_number (r);
-  free_number (abs_x);
-  free_number (la);
-  free_number (xa);
-  free_number (u);
+      mp\_number v;
+      new\_number (v);
+      mp\_next\_random(mp, \&v);
+      number\_substract (v, fraction\_half\_t);
+      take\_fraction (xa, sqrt\_8\_e\_k, v);
+      free\_number (v);
+      mp\_next\_random(mp, \&u);
+      number\_clone (abs\_x, xa);
+      number\_abs (abs\_x);
+    } while (number\_greaterequal (abs\_x, u));
+    make\_fraction (r, xa, u);
+    number\_clone (xa, r);
+    m\_log (la, u);
+    set\_number\_from\_substraction(la, twelve\_ln\_2\_k, la);
+    ab\_vs\_cd (ab\_vs\_cd, one\_k, la, xa, xa);
+  } while (number\_negative(ab\_vs\_cd));
+  number\_clone (*ret, xa);
+  free\_number (ab\_vs\_cd);
+  free\_number (r);
+  free\_number (abs\_x);
+  free\_number (la);
+  free\_number (xa);
+  free\_number (u);
 }
 */
 
@@ -4705,7 +4727,7 @@ static mp_sym mp_frozen_id_lookup (MP mp, char *j, size_t l,
   return mp_do_id_lookup (mp, mp->frozen_symbols, j, l, insert_new);
 }
 
-/* see mp_print_sym  (mp_sym sym) */
+/* see mp\_print\_sym  (mp\_sym sym) */
 @ Get a numeric value from \MP\ is not easy. We have to consider
 the macro and the loops, as also the internal type (this is a
 first attempt, and more work is needed). If we are inside
@@ -13144,6 +13166,92 @@ Since an envelope spec only determines relative changes in pen offsets,
 @<Glob...@>=
 integer spec_offset;    /* number of pen edges between |h| and the initial offset */
 
+@ The next function calculates $1/3 B'(t) = (-p + (3c_1 + (-3c_2 + q)))*t^2 + (2p + (-4c_1 + 2*c_2))t + (-p + c_1)$,
+for cubic curve |B(t)| given by |p|,|c1|,|c2|,|q|
+and it's used for |t| near 0 and |t| near 1. We use double mode, otherwise we have to 
+take care of overflow.
+
+@<Declarations@>=
+static void mp_dx_dy_approx(MP mp, mp_number *dx_ap, mp_number *dy_ap,mp_knot p, mp_knot q,mp_number t);
+
+@ @c
+static void mp_dx_dy_approx(MP mp, mp_number *dx_ap, mp_number *dy_ap,mp_knot kp, mp_knot kq,mp_number t) { /* find dx dy at |t| */
+
+  /* 1/3 B'(t) = (-p + (3c1 + (-3c2 + q)))t^2 + (2p + (-4c1 + 2c2))t + (-p + c1) */   
+  /* 1/3  B'(u) = (p + (-3*c1 + (3c2 - q)))*u^2 + (2c1 + (-4c2 + 2q))u + (c2 - q) */
+
+  mp_number absval;
+  mp_number max_coef;       /* used while scaling */
+  mp_number small_nr, big_nr;
+  mp_number abs_dx, abs_dy;
+
+  double p,c1,c2,q,dt,s1;
+  new_number (absval);
+  new_number(max_coef);
+  new_number(small_nr);
+  new_number(big_nr);
+  new_number(abs_dx);
+  new_number(abs_dy);
+  
+  set_number_from_double(small_nr,0.001);
+  set_number_from_double(big_nr,1000);
+
+  dt = number_to_double(t);
+
+  p  = number_to_double(kp->x_coord);
+  c1 = number_to_double(kp->right_x);
+  c2 = number_to_double(kq->left_x);
+  q  = number_to_double(kq->x_coord);
+
+  s1 = (-p + (3*c1 + (-3*c2 + q)))*(dt*dt) + (2*p + (-4*c1 + 2*c2))*dt + (-p + c1);
+  set_number_from_double(*dx_ap,s1);
+
+
+  p  = number_to_double(kp->y_coord);
+  c1 = number_to_double(kp->right_y);
+  c2 = number_to_double(kq->left_y);
+  q  = number_to_double(kq->y_coord);
+
+  s1 = (-p + (3*c1 + (-3*c2 + q)))*(dt*dt) + (2*p + (-4*c1 + 2*c2))*dt + (-p + c1);
+  set_number_from_double(*dy_ap,s1);
+  
+
+  if (!number_zero(*dx_ap) || !number_zero(*dy_ap)) {
+    number_clone(absval, *dx_ap);
+    number_abs(absval);
+    number_clone(max_coef, *dy_ap);
+    number_abs (max_coef);
+    if (number_greater(absval, max_coef)) {
+      number_clone(max_coef, absval);
+    }
+    while (number_less(max_coef, fraction_half_t)) {
+      number_double (max_coef);
+      number_double (*dx_ap);
+      number_double (*dy_ap);
+    } 
+    number_clone(abs_dx,*dx_ap);
+    number_clone(abs_dy,*dy_ap);
+    number_abs(abs_dx);
+    number_abs(abs_dy);
+    /* This is an experimental approximation */
+    if (number_greaterequal(abs_dy,big_nr) && number_lessequal(abs_dx,small_nr)) {
+      set_number_to_zero(*dx_ap);
+    }
+    if (number_greaterequal(abs_dx,big_nr) && number_lessequal(abs_dy,small_nr)) {
+      set_number_to_zero(*dy_ap);
+    }
+  }
+
+  free_number(absval);
+  free_number(max_coef);
+  free_number(small_nr);
+  free_number(big_nr);
+  free_number(abs_dx);
+  free_number(abs_dy);
+
+}
+
+
 @ @c
 static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) {
   int n;   /* the number of vertices in the pen polygon */
@@ -13183,6 +13291,13 @@ static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) {
   new_number(u1);
   new_number(v0);
   new_number(v1);
+  new_number(dx_m);
+  new_number(dxin_m);
+  new_number(dx_ap);
+  new_number(dy_ap);
+  new_number(dxin_ap);
+  new_number(dyin_ap);
+  new_number(ueps_ap);
   new_fraction (ss);
   new_fraction (s);
   new_fraction (t);
@@ -13191,17 +13306,39 @@ static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) {
   p = c;
   c0 = c;
   k_needed = 0;
-  do {
+#ifdef DEBUGENVELOPE
+dbg_nl;dbg_str(--[==[BEGIN]==]);dbg_nl; 
+#endif
+ do {
     q = mp_next_knot (p);
+#ifdef DEBUGENVELOPE
+dbg_nl;dbg_open_t;dbg_str(--[==[begin loop]==]);dbg_nl; 
+dbg_n(p->x_coord);dbg_n(p->y_coord);
+dbg_n(p->right_x);dbg_n(p->right_y);
+dbg_n(q->left_x);dbg_n(q->left_y);
+dbg_n(q->x_coord);dbg_n(q->y_coord);
+#endif 
     @<Split the cubic between |p| and |q|, if necessary, into cubics
       associated with single offsets, after which |q| should
       point to the end of the final such cubic@>;
   NOT_FOUND:
     @<Advance |p| to node |q|, removing any ``dead'' cubics that
       might have been introduced by the splitting process@>;
+#ifdef DEBUGENVELOPE
+dbg_str(--[==[end loop]==]);dbg_nl; dbg_close_t;dbg_comma;dbg_nl;
+#endif 
   } while (q != c);
+#ifdef DEBUGENVELOPE
+ dbg_key(Fix the offset change);dbg_open_t;dbg_nl;
+  dbg_in(mp_knot_info(p));dbg_close_t;dbg_comma;dbg_nl;
+#endif
   @<Fix the offset change in |mp_knot_info(c)| and set |c| to the return value of
     |offset_prep|@>;
+#ifdef DEBUGENVELOPE  
+dbg_in(mp_knot_info(p));
+dbg_close_t;dbg_comma;dbg_nl;
+dbg_nl;dbg_str(--[==[END]==]);dbg_nl;
+#endif
   free_number (ss);
   free_number (s);
   free_number (dxin);
@@ -13232,6 +13369,13 @@ static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) {
   free_number (u1);
   free_number (v0);
   free_number (v1);
+  free_number(dx_m);
+  free_number(dxin_m);
+  free_number(dx_ap);
+  free_number(dy_ap);
+  free_number(dxin_ap);
+  free_number(dyin_ap);
+  free_number(ueps_ap);
   free_number (t);
   return c;
 }
@@ -13447,6 +13591,9 @@ mp_number dx0, dy0;       /* initial direction for the first cubic in the curve
 mp_number x0a, x1a, x2a, y0a, y1a, y2a;   /* intermediate values */
 mp_number t;     /* where the derivative passes through zero */
 mp_number s;     /* a temporary value */
+mp_number dx_m;     /* signal a pertubation of dx */
+mp_number dxin_m;   /* signal a pertubation of dxin */
+
 
 @ @<Prepare for derivative computations...@>=
 set_number_from_substraction(x0, p->right_x, p->x_coord);
@@ -13455,6 +13602,11 @@ set_number_from_substraction(x1, q->left_x, p->right_x);
 set_number_from_substraction(y0, p->right_y, p->y_coord);
 set_number_from_substraction(y2, q->y_coord, q->left_y);
 set_number_from_substraction(y1, q->left_y, p->right_y);
+#ifdef DEBUGENVELOPE
+dbg_key(Prepare for derivative computations);dbg_open_t;dbg_nl;
+dbg_n(x0);dbg_n(y0);dbg_n(x1);dbg_n(y1);dbg_n(x2);dbg_n(y2);
+dbg_close_t;dbg_comma;dbg_nl;
+#endif
 {
   mp_number absval;
   new_number (absval);
@@ -13698,6 +13850,7 @@ the true initial direction for the given cubic, even if it is almost
 degenerate.
 
 @<Find the initial direction |(dx,dy)|@>=
+number_clone(dx_m, zero_t);
 number_clone(dx, x0);
 number_clone(dy, y0);
 if (number_zero(dx) && number_zero(dy)) {
@@ -13712,8 +13865,72 @@ if (p == c) {
   number_clone(dx0, dx);
   number_clone(dy0, dy);
 }
+/* BEGIN PATCH */
+set_number_from_substraction(ueps_ap,unity_t,epsilon_t); /* |1-eps| */
+#ifdef DEBUGENVELOPE
+dbg_nl;dbg_key(mp_dx_dy_approx_t_1);dbg_open_t;dbg_nl;
+dbg_n(ueps_ap);
+dbg_n(p->x_coord);dbg_n(p->y_coord);
+dbg_n(p->right_x);dbg_n(p->right_y);
+dbg_n(q->left_x);dbg_n(q->left_y);
+dbg_n(q->x_coord);dbg_n(q->y_coord);
+#endif
+mp_dx_dy_approx(mp,&dxin_ap,&dyin_ap,p,q,ueps_ap);
+#ifdef DEBUGENVELOPE
+dbg_n(dxin_ap);dbg_n(dyin_ap);
+dbg_close_t;dbg_comma;dbg_nl;
+#endif
+/**/
+number_clone(ueps_ap,epsilon_t); 
+#ifdef DEBUGENVELOPE
+dbg_nl;dbg_key(mp_dx_dy_approx_t_0);dbg_open_t;dbg_nl;
+dbg_n(ueps_ap);
+dbg_n(p->x_coord);dbg_n(p->y_coord);
+dbg_n(p->right_x);dbg_n(p->right_y);
+dbg_n(q->left_x);dbg_n(q->left_y);
+dbg_n(q->x_coord);dbg_n(q->y_coord);
+#endif
+mp_dx_dy_approx(mp,&dx_ap,&dy_ap,p,q,ueps_ap); /*|eps|*/
+#ifdef DEBUGENVELOPE
+dbg_n(dx_ap);dbg_n(dy_ap);
+dbg_close_t;dbg_comma;dbg_nl;
+dbg_key(derivatives);dbg_open_t;dbg_nl;
+dbg_n(dx);dbg_n(dy);dbg_n(dx_ap);dbg_n(dy_ap);dbg_close_t;dbg_comma;dbg_nl;
+#endif
+/* BEGIN PATCH */
+if (number_zero(dx) && !(number_zero(dy)) && number_zero(x0) && number_zero(x2) && !number_zero(dxin) ){
+    number_clone(dx_m, epsilon_t);
+    if (number_positive(x1)){      
+     set_number_from_addition (dx, dx, epsilon_t); 
+    } else if (number_negative(x1)) {
+     set_number_from_substraction (dx, dx, epsilon_t);  
+    }
+} 
+/* this patch can conflict with the previous one */
+/* hm what about dx=dy=0 ? */
+if (number_zero(dx_ap) && !number_zero(dx)){
+  set_number_to_zero(dx);
+  if (p == c) {
+    set_number_to_zero(dx0);
+    }
+  mp_warn(mp,"x component of derivative at t=0 approximated to zero.");
+ } 
+if (number_zero(dy_ap) && !number_zero(dy)){
+  set_number_to_zero(dy);
+  if (p == c) {
+    set_number_to_zero(dy0);
+    }
+  mp_warn(mp,"y component of derivative at t=0 approximated to zero.");
+ } 
+#ifdef DEBUGENVELOPE
+dbg_key(derivatives patched);dbg_open_t;dbg_nl;
+dbg_n(dx);dbg_n(dy);dbg_n(dx_ap);dbg_n(dy_ap);dbg_close_t;dbg_comma;dbg_nl;
+#endif
+/* END PATCH */
+
 
 @ @<Find the final direction |(dxin,dyin)|@>=
+number_clone(dxin_m, zero_t);
 number_clone(dxin, x2);
 number_clone(dyin, y2);
 if (number_zero(dxin) && number_zero(dyin)) {
@@ -13724,6 +13941,45 @@ if (number_zero(dxin) && number_zero(dyin)) {
     number_clone(dyin, y0);
   }
 }
+if (number_zero(dxin_ap) && !number_zero(dxin)){
+  set_number_to_zero(dxin);
+  mp_warn(mp,"x component of derivative at t=1 approximated at zero");
+ } 
+if (number_zero(dyin_ap) && !number_zero(dyin)){
+  set_number_to_zero(dyin);
+  mp_warn(mp,"y component of derivative at t=1 approximated at zero");
+ } 
+#ifdef DEBUGENVELOPE
+dbg_key(dxin dyin);dbg_open_t;dbg_nl;
+dbg_n(dxin);dbg_n(dyin);
+dbg_close_t;dbg_comma; 
+#endif
+/* BEGIN PATCH \par
+$ 1/3 B'(t,X_0,X_1,X_2) = (1-t)^2X_0+2(1-t)tX_1+3t^2X_2 $ \par
+$ 1/3 B'(t,X_0,X_1,X_2) = (X_0 + (-2X_1 + X_2))t^2 + (-2X_0 + 2X_1)t + X_0 $ \par
+$ 1/3 B'(s,0,X_1,0)   =  (-2s^2 + 2s)X_1 \approx 2sX_1 $ for $s\rightarrow 0$ \par
+$ 1/3 B'(1-s,0,X_1,0) = (-2s^2 + 2s)X_1 \approx 2sX_1  $ for $s\rightarrow 0$ $\par
+*/
+/* Of course the same should be done for dy and dyin */
+if ( ((number_zero(dx)||number_positive(dx_m)) && number_positive(dy)) &&
+     (number_zero(dxin) && number_positive(dyin)) ){
+     number_clone(dx_m, epsilon_t);
+     number_clone(dxin_m, epsilon_t);
+     if (number_positive(x1)){      
+       set_number_from_addition (dxin, dxin, epsilon_t); 
+       set_number_from_addition (dx, dx, epsilon_t); 
+     } else if (number_negative(x1)) {
+       set_number_from_substraction (dxin, dxin, epsilon_t);  
+       set_number_from_substraction (dx, dx, epsilon_t);  
+     } else if (number_positive(x0)) { 
+       set_number_from_addition (dxin, dxin, epsilon_t); 
+       set_number_from_addition (dx, dx, epsilon_t); 
+     } else if (number_negative(x0)) {
+       set_number_from_substraction (dxin, dxin, epsilon_t);  
+       set_number_from_substraction (dx, dx, epsilon_t);  
+     }
+}
+/* END PATCH ****/
 
 @ The next step is to bracket the initial direction between consecutive
 edges of the pen polygon.  We must be careful to turn clockwise only if
@@ -13737,11 +13993,35 @@ right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
   mp_number ab_vs_cd;
   new_number (ab_vs_cd);
   ab_vs_cd (ab_vs_cd, dy, dxin, dx, dyin);
-  turn_amt = mp_get_turn_amt (mp, w0, dx, dy, number_nonnegative(ab_vs_cd));
+#ifdef DEBUGENVELOPE
+dbg_nl;
+dbg_key(mp_get_turn_amt_dx_dy);dbg_open_t;dbg_str(--[==[call mp_get_turn_amt]==]);dbg_nl; 
+dbg_n(w0->x_coord);dbg_n(w0->y_coord);dbg_n(dx);dbg_n(dy);dbg_in(number_nonnegative(ab_vs_cd));
+#endif
+ turn_amt = mp_get_turn_amt (mp, w0, dx, dy, number_nonnegative(ab_vs_cd));
+#ifdef DEBUGENVELOPE
+dbg_dn(turn_amt);
+dbg_close_t;dbg_comma;
+dbg_nl;
+#endif
   free_number (ab_vs_cd);
+#ifdef DEBUGENVELOPE
+dbg_key(w0 before walk);dbg_open_t;dbg_nl;
+dbg_n(w0->x_coord);dbg_n(w0->y_coord);
+dbg_close_t;dbg_comma;
+#endif
   w = mp_pen_walk (mp, w0, turn_amt);
   w0 = w;
+#ifdef DEBUGENVELOPE
+dbg_key(w0 after walk);dbg_open_t;dbg_nl;
+dbg_n(w0->x_coord);dbg_n(w0->y_coord);
+dbg_close_t;dbg_comma;
+dbg_open_t;dbg_in(mp_knot_info(p));
+#endif
   mp_knot_info (p) = mp_knot_info (p) + turn_amt;
+#ifdef DEBUGENVELOPE
+  dbg_in(mp_knot_info(p));dbg_close_t;dbg_comma;
+#endif
 }
 
 @ Decide how many pen offsets to go away from |w| in order to find the offset
@@ -13762,18 +14042,42 @@ integer mp_get_turn_amt (MP mp, mp_knot w, mp_number dx, mp_number dy, boolean c
   mp_knot ww;   /* a neighbor of knot~|w| */
   integer s;    /* turn amount so far */
   mp_number t;    /* |ab_vs_cd| result */
+  mp_number t_ap;    /* |ab_vs_cd| approx. result */
   mp_number arg1, arg2;
   s = 0;
   new_number (arg1);
   new_number (arg2);
   new_number (t);
+  new_number (t_ap);
   if (ccw) {
     ww = mp_next_knot (w);
     do {
       set_number_from_substraction (arg1, ww->x_coord, w->x_coord);
       set_number_from_substraction (arg2, ww->y_coord, w->y_coord);
       ab_vs_cd (t, dy, arg1, dx, arg2);
-      if (number_negative(t))
+#ifdef DEBUGENVELOPE
+     dbg_sp;
+     dbg_open_t;dbg_str(--[==[inside mp_get_turn_amt do loop ]==]);dbg_nl; 
+      dbg_n(w->x_coord);dbg_n(w->y_coord);dbg_n(ww->x_coord);dbg_n(ww->y_coord);
+      dbg_n(t);dbg_n(dy);dbg_n(arg1);dbg_n(dx);dbg_n(arg2);
+      dbg_n(t_ap);dbg_n(dy_ap);dbg_n(dx_ap);
+     dbg_close_t;dbg_comma;
+     dbg_nl;
+#endif
+      /* BEGIN PATCH */
+           if (number_zero(dx) && number_zero(arg1) && number_positive(dy) && number_positive(arg2)) 
+        break;
+      if (number_zero(dx) && number_zero(arg1) && number_negative(dy) && number_negative(arg2)) 
+        break;
+      if (number_zero(dy) && number_zero(arg2) && number_negative(dx) && number_negative(arg1)) 
+        break;
+      if (number_zero(dx) && number_zero(arg1) && number_negative(dy) && number_positive(arg2)) 
+        set_number_to_unity(t);
+      if (number_zero(dy) && number_zero(arg2) && number_positive(dx) && number_negative(arg1)) 
+        set_number_to_unity(t);
+     
+      /* END PATCH */
+      if (number_negative(t)) 
         break;
       incr (s);
       w = ww;
@@ -13794,6 +14098,7 @@ integer mp_get_turn_amt (MP mp, mp_knot w, mp_number dx, mp_number dy, boolean c
     }
   }
   free_number (t);
+  free_number (t_ap);
   free_number (arg1);
   free_number (arg2);
   return s;
@@ -13950,8 +14255,18 @@ the path should always change the sign of |turn_amt|.
 @<Decide on the net change in pen offsets and set |turn_amt|@>=
 {
   mp_number ab_vs_cd;
+  mp_number t_ap;
+  new_number (t_ap);
   new_number (ab_vs_cd);
+#ifdef DEBUGENVELOPE
+dbg_sp;
+dbg_key(Decide on the net change in pen offsets and set turn_amt);dbg_open_t;dbg_nl;
+#endif
   ab_vs_cd (ab_vs_cd, dx, dyin, dxin, dy);
+#ifdef DEBUGENVELOPE
+dbg_n(ab_vs_cd);dbg_n(dx);dbg_n(dyin);dbg_n(dxin);dbg_n(dy);
+dbg_close_t;dbg_comma;dbg_nl;
+#endif
   if (number_negative (ab_vs_cd))
     d_sign = -1;
   else if (number_zero (ab_vs_cd))
@@ -13959,6 +14274,7 @@ the path should always change the sign of |turn_amt|.
   else
     d_sign = 1;
   free_number (ab_vs_cd);
+  free_number (t_ap);
 }
 if (d_sign == 0) {
   @<Check rotation direction based on node position@>
@@ -13978,7 +14294,16 @@ if (d_sign == 0) {
 }
 @<Make |ss| negative if and only if the total change in direction is
   more than $180^\circ$@>;
+#ifdef DEBUGENVELOPE
+dbg_nl;
+dbg_key(mp_get_turn_amt_dxin_dyin);dbg_open_t;dbg_str(--[==[call mp_get_turn_amt]==]);dbg_nl; ;
+dbg_n(w->x_coord);dbg_n(w->y_coord);dbg_n(dxin);dbg_n(dyin);dbg_in((d_sign > 0));
+#endif
 turn_amt = mp_get_turn_amt (mp, w, dxin, dyin, (d_sign > 0));
+#ifdef DEBUGENVELOPE
+dbg_dn(turn_amt);
+dbg_close_t;dbg_nl;dbg_nl;
+#endif
 if (number_negative(ss))
   turn_amt = turn_amt - d_sign * n
 
@@ -14024,13 +14349,18 @@ then swapped with |(x2,y2)|.  We make use of the identities
   new_fraction (r2);
   take_fraction (r1, x0, y2);
   take_fraction (r2, x2, y0);
+#ifdef DEBUGENVELOPE
+dbg_sp;
+dbg_open_t;dbg_dn(d_sign);dbg_close_t;dbg_comma;dbg_nl;
+#endif
   number_half (r1);
   number_half (r2);
   set_number_from_substraction(t0, r1, r2);
   set_number_from_addition (arg1, y0, y2);
   take_fraction (r1, x1, arg1);
   set_number_from_addition (arg1, x0, x2);
-  take_fraction (r1, y1, arg1);
+  /*%take_fraction (r1, y1, arg1);*//* The old one, is it correct ?*/
+  take_fraction (r2, y1, arg1);
   number_half (r1);
   number_half (r2);
   set_number_from_substraction(t1, r1, r2);
@@ -14065,6 +14395,7 @@ if (number_positive(t0)) {
 }
 {
   mp_number tmp1, tmp2, r1, r2, arg1;
+  mp_number abs_ss, eps_ss;
   new_fraction (r1);
   new_fraction (r2);
   new_number(arg1);
@@ -14077,6 +14408,28 @@ if (number_positive(t0)) {
   set_number_from_addition(arg1, y0, y2);
   take_fraction (r2, arg1, tmp2);
   set_number_from_addition (ss, r1, r2);
+  /* BEGIN PATCH */
+#ifdef DEBUGENVELOPE
+dbg_key(patch ss before);dbg_open_t;dbg_nl;
+dbg_n(ss);
+dbg_close_t;dbg_comma;dbg_nl;
+#endif
+  new_number(abs_ss);
+  new_number(eps_ss);
+  set_number_from_double(eps_ss,1e-6);
+  number_clone(abs_ss,ss);
+  number_abs(abs_ss);
+  if (number_greaterequal(eps_ss,abs_ss)) {
+    set_number_to_zero(ss);/* a warning here ? */
+  }
+#ifdef DEBUGENVELOPE
+dbg_key(patch ss after);dbg_open_t;dbg_nl;
+dbg_n(ss);
+dbg_close_t;dbg_comma;dbg_nl;
+#endif
+  free_number(abs_ss);
+  free_number(eps_ss);
+  /* END PATCH */
   free_number (arg1);
   free_number (r1);
   free_number (r2);
@@ -15915,8 +16268,8 @@ static mp_value_node mp_p_plus_fq (MP mp, mp_value_node p, mp_number f,
         } else {
           if (number_greaterequal (absv, coef_bound_k) && mp->watch_coefs) {
             mp_type (qq) = independent_needing_fix;
-	    /* If we set this , then we can drop (mp_type(pp) == independent_needing_fix && mp->fix_needed) later */
-	    /* set_number_from_scaled (value_number (qq), indep_value(qq)); */
+	    /* If we set this , then we can drop |(mp_type(pp) == independent_needing_fix && mp->fix_needed)| later */
+	    /* |set_number_from_scaled (value_number (qq), indep_value(qq));| */
             mp->fix_needed = true;
           }
           set_mp_link (r, (mp_node) s);
@@ -16060,8 +16413,8 @@ static mp_value_node mp_p_plus_q (MP mp, mp_value_node p, mp_value_node q,
         } else {
           if (number_greaterequal(test, coef_bound_k) && mp->watch_coefs) {
             mp_type (qq) = independent_needing_fix;
-	    /* If we set this , then we can drop (mp_type(pp) == independent_needing_fix && mp->fix_needed) later */
-	    /* set_number_from_scaled (value_number (qq), indep_value(qq)); */
+	    /* If we set this , then we can drop |(mp_type(pp) == independent_needing_fix && mp->fix_needed)| later */
+	    /* |set_number_from_scaled (value_number (qq), indep_value(qq));| */
             mp->fix_needed = true;
           }
           set_mp_link (r, (mp_node) s);
@@ -24675,7 +25028,7 @@ static void mp_do_nullary (MP mp, quarterword c) {
     {
       mp_number r;
       new_number (r);
-      /*mp_norm_rand (mp, &r);*/
+      /*|mp_norm_rand (mp, &r)|;*/
       m_norm_rand (r);
       mp->cur_exp.type = mp_known;
       set_cur_exp_value_number (r);
@@ -24872,7 +25225,7 @@ static void mp_do_unary (MP mp, quarterword c) {
         {
           mp_number vvx;
           new_number (vvx);
-          /*mp_unif_rand (mp, &vvx, cur_exp_value_number ());*/
+          /*|mp_unif_rand (mp, &vvx, cur_exp_value_number ());|*/
           m_unif_rand (vvx, cur_exp_value_number ());
           set_cur_exp_value_number (vvx);
           free_number (vvx);
diff --git a/source/texk/web2c/mplibdir/mpmathbinary.w b/source/texk/web2c/mplibdir/mpmathbinary.w
index f0d134a58e1f77c72de32f48dd907ee7a35c0a42..287243c6d26f9dafdfbdad31de8c7919eb6099dd 100644
--- a/source/texk/web2c/mplibdir/mpmathbinary.w
+++ b/source/texk/web2c/mplibdir/mpmathbinary.w
@@ -1100,6 +1100,24 @@ void mp_ab_vs_cd (MP mp, mp_number *ret, mp_number a_orig, mp_number b_orig, mp_
   mpfr_set(b, (mpfr_ptr )b_orig.data.num, ROUNDING);
   mpfr_set(c, (mpfr_ptr )c_orig.data.num, ROUNDING);
   mpfr_set(d, (mpfr_ptr )d_orig.data.num, ROUNDING);
+  
+  mpfr_mul(q,a,b,ROUNDING);
+  mpfr_mul(r,c,d,ROUNDING);
+  cmp = mpfr_cmp(q,r);
+  if (cmp==0) {
+    mpfr_set(ret->data.num, zero, ROUNDING);
+    goto RETURN;
+  }
+  if (cmp>0) {
+    mpfr_set(ret->data.num, one, ROUNDING);
+    goto RETURN;
+  }
+  if (cmp<0) {
+    mpfr_set(ret->data.num, minusone, ROUNDING);
+    goto RETURN;
+  }
+
+  /*TODO: remove this part of the code until RETURN */
   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
   while (1) {
     mpfr_div(q,a,d, ROUNDING);
diff --git a/source/texk/web2c/mplibdir/mpmathdecimal.w b/source/texk/web2c/mplibdir/mpmathdecimal.w
index d0550c51a80c9c5d2bb109a2a1d4bd9b6061445c..6394372c5c7332c9d46ffde08762091996f15725 100644
--- a/source/texk/web2c/mplibdir/mpmathdecimal.w
+++ b/source/texk/web2c/mplibdir/mpmathdecimal.w
@@ -1213,11 +1213,21 @@ The result is $+1$, 0, or~$-1$ in the three respective cases.
 void mp_ab_vs_cd (MP mp, mp_number *ret, mp_number a_orig, mp_number b_orig, mp_number c_orig, mp_number d_orig) {
   decNumber q, r, test; /* temporary registers */
   decNumber a, b, c, d;
+  decNumber ab, cd;
   (void)mp;
   decNumberCopy(&a, (decNumber *)a_orig.data.num);
   decNumberCopy(&b, (decNumber *)b_orig.data.num);
   decNumberCopy(&c, (decNumber *)c_orig.data.num);
   decNumberCopy(&d, (decNumber *)d_orig.data.num);
+
+  decNumberMultiply (&ab, (decNumber *)a_orig.data.num, (decNumber *)b_orig.data.num, &set);
+  decNumberMultiply (&cd, (decNumber *)c_orig.data.num, (decNumber *)d_orig.data.num, &set);
+  decNumberCompare(ret->data.num, &ab, &cd, &set);
+  mp_check_decNumber(mp, ret->data.num, &set);
+  if (1>0) 
+    return;
+
+
   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
   while (1) {
     decNumberDivide(&q,&a,&d, &set);
@@ -1699,13 +1709,13 @@ static void sinecosine(decNumber *theangle, decNumber *c, decNumber *s)
 @c
 void mp_decimal_sin_cos (MP mp, mp_number z_orig, mp_number *n_cos, mp_number *n_sin) {
   decNumber rad;
+  double tmp;
   decNumber one_eighty;
-  decNumberFromInt32(&one_eighty, 180 * 16);
+  tmp = mp_number_to_double(z_orig)/16.0;
+  
 #if DEBUG
   fprintf(stdout, "\nsin_cos(%f)", mp_number_to_double(z_orig));
 #endif
-  decNumberMultiply(&rad, z_orig.data.num, &PI_decNumber, &set);
-  decNumberDivide(&rad, &rad, &one_eighty, &set);
 #if 0
   if (decNumberIsNegative(&rad)) {
     while (decNumberLess(&rad,&PI_decNumber))
@@ -1715,9 +1725,23 @@ void mp_decimal_sin_cos (MP mp, mp_number z_orig, mp_number *n_cos, mp_number *n
       decNumberSubtract(&rad, &rad, &PI_decNumber, &set);
   }
 #endif
-  sinecosine(&rad, n_sin->data.num, n_cos->data.num); 
-  decNumberMultiply(n_cos->data.num,n_cos->data.num,&fraction_multiplier_decNumber, &set);
-  decNumberMultiply(n_sin->data.num,n_sin->data.num,&fraction_multiplier_decNumber, &set);
+    if ((tmp == 90.0)||(tmp == -270)){
+    decNumberZero(n_cos->data.num);
+    decNumberCopy(n_sin->data.num,&fraction_multiplier_decNumber);
+  } else if ((tmp == -90.0)||(tmp == 270.0)) {
+    decNumberZero(n_cos->data.num);
+    decNumberCopyNegate(n_sin->data.num,&fraction_multiplier_decNumber);
+  } else if ((tmp == 180.0) || (tmp == -180.0)) {
+    decNumberCopyNegate(n_cos->data.num,&fraction_multiplier_decNumber);
+    decNumberZero(n_sin->data.num);
+  } else {
+   decNumberFromInt32(&one_eighty, 180 * 16);
+   decNumberMultiply(&rad, z_orig.data.num, &PI_decNumber, &set);
+   decNumberDivide(&rad, &rad, &one_eighty, &set);
+   sinecosine(&rad, n_sin->data.num, n_cos->data.num); 
+   decNumberMultiply(n_cos->data.num,n_cos->data.num,&fraction_multiplier_decNumber, &set);
+   decNumberMultiply(n_sin->data.num,n_sin->data.num,&fraction_multiplier_decNumber, &set);
+  }
 #if DEBUG
   fprintf(stdout, "\nsin_cos(%f,%f,%f)", decNumberToDouble(&rad),
 mp_number_to_double(*n_cos), mp_number_to_double(*n_sin));
diff --git a/source/texk/web2c/mplibdir/mpmathdouble.w b/source/texk/web2c/mplibdir/mpmathdouble.w
index d5663b2df97d56a8f943d83cc457288cf0c4abf5..75bd1e712c27a0b713f6e95cc0442235c3d552d9 100644
--- a/source/texk/web2c/mplibdir/mpmathdouble.w
+++ b/source/texk/web2c/mplibdir/mpmathdouble.w
@@ -814,6 +814,11 @@ void mp_ab_vs_cd (MP mp, mp_number *ret, mp_number a_orig, mp_number b_orig, mp_
   integer q, r; /* temporary registers */
   integer a, b, c, d;
   (void)mp;
+  
+  mp_double_ab_vs_cd(mp,ret, a_orig, b_orig, c_orig, d_orig);
+  if (1>0) 
+    return ;
+  /* TODO: remove this code until the end */
   a = a_orig.data.dval;
   b = b_orig.data.dval;
   c = c_orig.data.dval;
@@ -1208,9 +1213,21 @@ any loss of accuracy. Then |x| and~|y| are divided by~|r|.
 @c
 void mp_double_sin_cos (MP mp, mp_number z_orig, mp_number *n_cos, mp_number *n_sin) {
   double rad;
-  rad = (z_orig.data.dval / angle_multiplier) * PI/180.0;
-  n_cos->data.dval = cos(rad) * fraction_multiplier;
-  n_sin->data.dval = sin(rad) * fraction_multiplier;
+  rad = (z_orig.data.dval / angle_multiplier); /* still degrees */
+  if ((rad == 90.0)||(rad == -270)){
+    n_cos->data.dval = 0.0;
+    n_sin->data.dval = fraction_multiplier;
+  } else if ((rad == -90.0)||(rad == 270.0)) {
+    n_cos->data.dval = 0.0;
+    n_sin->data.dval = -fraction_multiplier;
+  } else if ((rad == 180.0) || (rad == -180.0)) {
+    n_cos->data.dval = -fraction_multiplier;
+    n_sin->data.dval = 0.0;
+  } else {
+    rad = rad * PI/180.0;
+    n_cos->data.dval = cos(rad) * fraction_multiplier;
+    n_sin->data.dval = sin(rad) * fraction_multiplier;
+  }
 #if DEBUG
   fprintf(stdout, "\nsin_cos(%f,%f,%f)", mp_number_to_double(z_orig),
 mp_number_to_double(*n_cos), mp_number_to_double(*n_sin));