emacs-diffs
[Top][All Lists]
Advanced

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

scratch/etags-regen ebcba77d4c 4/6: Merge branch 'master' into scratch/e


From: Dmitry Gutov
Subject: scratch/etags-regen ebcba77d4c 4/6: Merge branch 'master' into scratch/etags-regen
Date: Mon, 11 Jul 2022 14:01:52 -0400 (EDT)

branch: scratch/etags-regen
commit ebcba77d4c47ceff24115f80c2109916a6b425b1
Merge: ad50128a36 2e6ed253ce
Author: Dmitry Gutov <dgutov@yandex.ru>
Commit: Dmitry Gutov <dgutov@yandex.ru>

    Merge branch 'master' into scratch/etags-regen
---
 .gitignore                                         |    2 +
 INSTALL                                            |   11 +-
 Makefile.in                                        |   13 +-
 README                                             |    2 +-
 admin/CPP-DEFINES                                  |    1 +
 admin/authors.el                                   |    3 +-
 admin/automerge                                    |    3 +-
 admin/charsets/mapfiles/CP720.map                  |    2 +-
 admin/charsets/mapfiles/CP858.map                  |    2 +-
 admin/emake                                        |    1 +
 admin/gitmerge.el                                  |   83 +-
 admin/make-tarball.txt                             |    6 +
 admin/merge-gnulib                                 |   13 +-
 admin/notes/bugtracker                             |    2 +-
 admin/notes/emba                                   |   22 +-
 admin/notes/git-workflow                           |    8 +-
 admin/notes/multi-tty                              |    2 +-
 admin/notes/unicode                                |   21 +-
 admin/nt/dist-build/README-scripts                 |   37 +-
 admin/release-branch.txt                           |   76 +
 admin/unidata/Makefile.in                          |   12 +-
 admin/unidata/README                               |    4 +
 admin/unidata/blocks.awk                           |   23 +-
 admin/unidata/emoji-test.txt                       | 4991 ++++++++++++++++++++
 admin/unidata/emoji-zwj.awk                        |   55 +-
 build-aux/config.guess                             | 1229 ++---
 build-aux/config.sub                               |   87 +-
 build-aux/gitlog-to-changelog                      |    5 +-
 configure.ac                                       |   48 +-
 doc/emacs/anti.texi                                |  198 +-
 doc/emacs/building.texi                            |    5 +-
 doc/emacs/cmdargs.texi                             |    7 +-
 doc/emacs/custom.texi                              |   28 +-
 doc/emacs/dired.texi                               |   14 +-
 doc/emacs/display.texi                             |    8 +
 doc/emacs/emacs.texi                               |    2 +-
 doc/emacs/files.texi                               |    4 +-
 doc/emacs/fixit.texi                               |    2 +-
 doc/emacs/frames.texi                              |   38 +-
 doc/emacs/glossary.texi                            |   15 +-
 doc/emacs/help.texi                                |   55 +-
 doc/emacs/killing.texi                             |   10 +-
 doc/emacs/kmacro.texi                              |    2 +-
 doc/emacs/m-x.texi                                 |    9 +-
 doc/emacs/macos.texi                               |    2 +-
 doc/emacs/maintaining.texi                         |   25 +-
 doc/emacs/mark.texi                                |    7 +-
 doc/emacs/mini.texi                                |    5 +-
 doc/emacs/misc.texi                                |   46 +-
 doc/emacs/msdos.texi                               |   10 +-
 doc/emacs/mule.texi                                |   31 +
 doc/emacs/programs.texi                            |   26 +
 doc/emacs/search.texi                              |   17 +-
 doc/emacs/text.texi                                |    7 +
 doc/emacs/trouble.texi                             |   11 +-
 doc/emacs/windows.texi                             |    2 +-
 doc/lispintro/emacs-lisp-intro.texi                |   40 +-
 doc/lispref/anti.texi                              |  241 +-
 doc/lispref/buffers.texi                           |   44 +-
 doc/lispref/commands.texi                          |   95 +-
 doc/lispref/compile.texi                           |   14 +-
 doc/lispref/control.texi                           |   11 +-
 doc/lispref/customize.texi                         |    3 +
 doc/lispref/display.texi                           |  224 +-
 doc/lispref/edebug.texi                            |   14 +-
 doc/lispref/elisp.texi                             |    7 +-
 doc/lispref/files.texi                             |   51 +-
 doc/lispref/frames.texi                            |   85 +-
 doc/lispref/functions.texi                         |   45 +-
 doc/lispref/hooks.texi                             |   13 +-
 doc/lispref/internals.texi                         |    8 +
 doc/lispref/keymaps.texi                           |  182 +-
 doc/lispref/lists.texi                             |   17 +-
 doc/lispref/modes.texi                             |   34 +-
 doc/lispref/objects.texi                           |   46 +-
 doc/lispref/os.texi                                |   28 +-
 doc/lispref/package.texi                           |    5 +
 doc/lispref/processes.texi                         |   22 +-
 doc/lispref/searching.texi                         |  131 +-
 doc/lispref/spellfile                              |   18 +
 doc/lispref/strings.texi                           |   20 +-
 doc/lispref/symbols.texi                           |  205 +-
 doc/lispref/syntax.texi                            |    1 +
 doc/lispref/text.texi                              |   27 +-
 doc/lispref/tips.texi                              |   29 +-
 doc/lispref/variables.texi                         |   12 +-
 doc/lispref/windows.texi                           |  893 ++--
 doc/man/emacs.1.in                                 |    5 +-
 doc/man/emacsclient.1                              |    5 +-
 doc/misc/calc.texi                                 |    2 +-
 doc/misc/cc-mode.texi                              |   57 +
 doc/misc/cl.texi                                   |   18 +-
 doc/misc/efaq.texi                                 |    5 +-
 doc/misc/eieio.texi                                |    9 +-
 doc/misc/erc.texi                                  |    4 +-
 doc/misc/ert.texi                                  |  217 +-
 doc/misc/eww.texi                                  |   26 +
 doc/misc/flymake.texi                              |    2 +-
 doc/misc/gnus.texi                                 |   36 +-
 doc/misc/mairix-el.texi                            |   12 +
 doc/misc/modus-themes.org                          |  305 +-
 doc/misc/org.org                                   |  904 ++--
 doc/misc/rcirc.texi                                |   18 +-
 doc/misc/reftex.texi                               |   26 +-
 doc/misc/speedbar.texi                             |    6 +-
 doc/misc/texinfo.tex                               |  267 +-
 doc/misc/tramp.texi                                |   73 +-
 etc/DEBUG                                          |   31 +-
 etc/ERC-NEWS                                       |  196 +-
 etc/HELLO                                          |    2 +-
 etc/NEWS                                           | 4596 ++----------------
 etc/{NEWS => NEWS.28}                              |  921 ++--
 etc/ORG-NEWS                                       |  700 ++-
 etc/PROBLEMS                                       |  446 +-
 etc/TODO                                           |  257 +-
 etc/charsets/README                                |    4 +-
 etc/e/README                                       |   18 +-
 etc/e/eterm-color                                  |  Bin 1179 -> 1296 bytes
 etc/e/eterm-color.ti                               |   19 +-
 etc/e/eterm-direct                                 |  Bin 0 -> 1375 bytes
 etc/images/README                                  |    1 +
 etc/images/connect-to-url.pbm                      |  Bin 0 -> 81 bytes
 etc/images/connect-to-url.xpm                      |  281 ++
 etc/images/down.svg                                |    2 +-
 etc/images/left.svg                                |    2 +-
 etc/images/right.svg                               |    2 +-
 etc/images/up.svg                                  |    2 +-
 etc/org/csl/README                                 |   10 +
 etc/org/csl/chicago-author-date.csl                |  658 +++
 etc/org/csl/locales-en-US.xml                      |  357 ++
 etc/publicsuffix.txt                               |   98 +-
 etc/refcards/README                                |   47 +-
 etc/refcards/orgcard.tex                           |    4 +-
 etc/refcards/ru-refcard.tex                        |    2 +-
 etc/themes/adwaita-theme.el                        |    3 +
 etc/themes/deeper-blue-theme.el                    |    2 +
 etc/themes/dichromacy-theme.el                     |   37 +-
 etc/themes/leuven-theme.el                         |   27 +-
 etc/themes/light-blue-theme.el                     |    3 +
 etc/themes/manoj-dark-theme.el                     |    3 +
 etc/themes/misterioso-theme.el                     |   33 +-
 etc/themes/modus-operandi-theme.el                 |    2 +-
 etc/themes/modus-themes.el                         |  502 +-
 etc/themes/modus-vivendi-theme.el                  |    2 +-
 etc/themes/tango-dark-theme.el                     |   35 +-
 etc/themes/tango-theme.el                          |   35 +-
 etc/themes/whiteboard-theme.el                     |    2 +
 etc/themes/wombat-theme.el                         |   24 +-
 etc/tutorials/TUTORIAL.he                          |    4 +-
 lib-src/emacsclient.c                              |   26 +-
 lib-src/ntlib.c                                    |    6 +-
 lib-src/seccomp-filter.c                           |    2 +
 lib/_Noreturn.h                                    |   10 +-
 lib/af_alg.h                                       |   18 +-
 lib/alloca.in.h                                    |   20 +-
 lib/allocator.c                                    |   17 +
 lib/allocator.h                                    |   14 +-
 lib/arg-nonnull.h                                  |    8 +-
 lib/attribute.h                                    |   26 +-
 lib/binary-io.c                                    |   14 +-
 lib/binary-io.h                                    |   16 +-
 lib/byteswap.in.h                                  |   14 +-
 lib/c++defs.h                                      |    8 +-
 lib/c-ctype.c                                      |   18 +
 lib/c-ctype.h                                      |   24 +-
 lib/c-strcase.h                                    |   16 +-
 lib/c-strcasecmp.c                                 |   16 +-
 lib/c-strncasecmp.c                                |   16 +-
 lib/canonicalize-lgpl.c                            |   18 +-
 lib/careadlinkat.c                                 |   42 +-
 lib/careadlinkat.h                                 |   14 +-
 lib/cdefs.h                                        |   63 +-
 lib/cloexec.c                                      |   18 +-
 lib/cloexec.h                                      |   18 +-
 lib/close-stream.h                                 |   18 +
 lib/copy-file-range.c                              |   14 +-
 lib/count-leading-zeros.c                          |   18 +
 lib/count-leading-zeros.h                          |   14 +-
 lib/count-one-bits.c                               |   18 +
 lib/count-one-bits.h                               |   14 +-
 lib/count-trailing-zeros.c                         |   18 +
 lib/count-trailing-zeros.h                         |   14 +-
 lib/dirent.in.h                                    |  137 +-
 lib/dirfd.c                                        |   14 +-
 lib/dtoastr.c                                      |   17 +
 lib/dup2.c                                         |   14 +-
 lib/dynarray.h                                     |  273 +-
 lib/eloop-threshold.h                              |    8 +-
 lib/errno.in.h                                     |   16 +-
 lib/euidaccess.c                                   |   14 +-
 lib/execinfo.c                                     |   18 +
 lib/execinfo.in.h                                  |    8 +-
 lib/explicit_bzero.c                               |    8 +-
 lib/fcntl.c                                        |   14 +-
 lib/fcntl.in.h                                     |   14 +-
 lib/file-has-acl.c                                 |   14 +-
 lib/filename.h                                     |    8 +-
 lib/filevercmp.c                                   |   16 +-
 lib/filevercmp.h                                   |   16 +-
 lib/flexmember.h                                   |    8 +-
 lib/free.c                                         |   30 +-
 lib/fsusage.c                                      |   14 +-
 lib/fsusage.h                                      |   14 +-
 lib/fsync.c                                        |   16 +-
 lib/futimens.c                                     |   14 +-
 lib/getdtablesize.c                                |   14 +-
 lib/getgroups.c                                    |   22 +-
 lib/getopt-cdefs.in.h                              |   21 +-
 lib/getopt-core.h                                  |    8 +-
 lib/getopt-ext.h                                   |    8 +-
 lib/getopt-pfx-core.h                              |   21 +-
 lib/getopt-pfx-ext.h                               |   21 +-
 lib/getopt.c                                       |   12 +-
 lib/getopt.in.h                                    |   24 +-
 lib/getopt1.c                                      |    8 +-
 lib/getopt_int.h                                   |    8 +-
 lib/getrandom.c                                    |   20 +-
 lib/gettext.h                                      |   16 +-
 lib/gettime.c                                      |   14 +-
 lib/gettimeofday.c                                 |   16 +-
 lib/gnulib.mk.in                                   | 1303 ++---
 lib/group-member.c                                 |   22 +-
 lib/idx.h                                          |   28 +-
 lib/ieee754.in.h                                   |    8 +-
 lib/ignore-value.h                                 |   14 +-
 lib/intprops.h                                     |   27 +-
 lib/inttypes.in.h                                  |   14 +-
 lib/libc-config.h                                  |   34 +-
 lib/limits.in.h                                    |   32 +-
 lib/lstat.c                                        |   14 +-
 lib/malloc.c                                       |   51 +
 lib/malloc/dynarray-skeleton.c                     |   41 +-
 lib/malloc/dynarray.h                              |    8 +-
 lib/malloc/dynarray_at_failure.c                   |   15 +-
 lib/malloc/dynarray_emplace_enlarge.c              |   12 +-
 lib/malloc/dynarray_finalize.c                     |   12 +-
 lib/malloc/dynarray_resize.c                       |   12 +-
 lib/malloc/dynarray_resize_clear.c                 |   12 +-
 lib/malloc/scratch_buffer.h                        |    8 +-
 lib/malloc/scratch_buffer_dupfree.c                |    8 +-
 lib/malloc/scratch_buffer_grow.c                   |    8 +-
 lib/malloc/scratch_buffer_grow_preserve.c          |    8 +-
 lib/malloc/scratch_buffer_set_array_size.c         |    8 +-
 lib/malloca.c                                      |  106 -
 lib/malloca.h                                      |  123 -
 lib/md5-stream.c                                   |  141 +
 lib/md5.c                                          |  116 +-
 lib/md5.h                                          |   17 +-
 lib/memmem.c                                       |   16 +-
 lib/mempcpy.c                                      |   21 +-
 lib/memrchr.c                                      |   14 +-
 lib/mini-gmp-gnulib.c                              |   28 +-
 lib/mini-gmp.c                                     |   22 +-
 lib/mini-gmp.h                                     |    9 +-
 lib/minmax.h                                       |   16 +-
 lib/mkostemp.c                                     |   14 +-
 lib/mktime-internal.h                              |    8 +-
 lib/mktime.c                                       |    8 +-
 lib/nproc.c                                        |  403 ++
 lib/nproc.h                                        |   46 +
 lib/nstrftime.c                                    |   19 +-
 lib/open.c                                         |   14 +-
 lib/pathmax.h                                      |   16 +-
 lib/pipe2.c                                        |   18 +-
 lib/pselect.c                                      |   16 +-
 lib/pthread_sigmask.c                              |   14 +-
 lib/rawmemchr.c                                    |   95 +-
 lib/rawmemchr.valgrind                             |   14 +-
 lib/readlink.c                                     |   18 +-
 lib/realloc.c                                      |   63 +
 lib/regcomp.c                                      |   16 +-
 lib/regex.c                                        |    9 +-
 lib/regex.h                                        |   58 +-
 lib/regex_internal.c                               |   18 +-
 lib/regex_internal.h                               |   17 +-
 lib/regexec.c                                      |  109 +-
 lib/root-uid.h                                     |   18 +-
 lib/save-cwd.h                                     |    4 +-
 lib/scratch_buffer.h                               |  115 +-
 lib/set-permissions.c                              |    2 +-
 lib/sha1.c                                         |  115 +-
 lib/sha1.h                                         |   19 +-
 lib/sha256.c                                       |  130 +-
 lib/sha256.h                                       |   15 +-
 lib/sha512.c                                       |  130 +-
 lib/sha512.h                                       |   15 +-
 lib/sigdescr_np.c                                  |   16 +-
 lib/signal.in.h                                    |   14 +-
 lib/stat-time.c                                    |   18 +
 lib/stat-time.h                                    |   20 +-
 lib/stdalign.in.h                                  |   29 +-
 lib/stddef.in.h                                    |   27 +-
 lib/stdint.in.h                                    |   20 +-
 lib/stdio-impl.h                                   |   14 +-
 lib/stdio.in.h                                     |  211 +-
 lib/stdlib.in.h                                    |  335 +-
 lib/stpcpy.c                                       |   14 +-
 lib/str-two-way.h                                  |   16 +-
 lib/strftime.h                                     |   14 +-
 lib/string.in.h                                    |   98 +-
 lib/strnlen.c                                      |   16 +-
 lib/strtoimax.c                                    |   14 +-
 lib/strtol.c                                       |   55 +-
 lib/strtoll.c                                      |   14 +-
 lib/symlink.c                                      |   18 +-
 lib/sys_random.in.h                                |   16 +-
 lib/sys_select.in.h                                |   19 +-
 lib/sys_stat.in.h                                  |   16 +-
 lib/sys_time.in.h                                  |   16 +-
 lib/sys_types.in.h                                 |   16 +-
 lib/tempname.c                                     |   12 +-
 lib/tempname.h                                     |   14 +-
 lib/time-internal.h                                |   16 +-
 lib/time.in.h                                      |   58 +-
 lib/time_r.c                                       |   16 +-
 lib/time_rz.c                                      |   16 +-
 lib/timegm.c                                       |    8 +-
 lib/timespec.c                                     |   18 +
 lib/timespec.h                                     |   14 +-
 lib/u64.c                                          |   18 +
 lib/u64.h                                          |   14 +-
 lib/unistd.c                                       |   18 +
 lib/unistd.in.h                                    |   29 +-
 lib/unlocked-io.h                                  |   26 +-
 lib/utimens.c                                      |   20 +-
 lib/utimens.h                                      |   14 +-
 lib/verify.h                                       |   18 +-
 lib/warn-on-use.h                                  |    8 +-
 lib/xalloc-oversized.h                             |   53 +-
 lisp/ChangeLog.15                                  |    2 +-
 lisp/Makefile.in                                   |   23 +-
 lisp/abbrev.el                                     |    7 +-
 lisp/align.el                                      |   46 +-
 lisp/allout-widgets.el                             |    2 +-
 lisp/allout.el                                     |   12 +-
 lisp/ansi-color.el                                 |  692 ++-
 lisp/apropos.el                                    |    6 +-
 lisp/array.el                                      |    5 +-
 lisp/autoinsert.el                                 |    1 +
 lisp/avoid.el                                      |   10 +-
 lisp/bindings.el                                   |    7 +-
 lisp/bookmark.el                                   |   17 +-
 lisp/button.el                                     |   11 +-
 lisp/calc/calc-help.el                             |    3 -
 lisp/calc/calc-math.el                             |    5 +-
 lisp/calc/calc-prog.el                             |   11 +-
 lisp/calc/calc-store.el                            |    2 +-
 lisp/calc/calc-units.el                            |   39 +-
 lisp/calc/calc.el                                  |    9 +-
 lisp/calendar/time-date.el                         |    6 +-
 lisp/cedet/data-debug.el                           |    4 +-
 lisp/cedet/mode-local.el                           |   13 +-
 lisp/cedet/semantic/analyze/complete.el            |    3 +-
 lisp/cedet/semantic/complete.el                    |    9 +-
 lisp/cedet/semantic/db-find.el                     |    2 +-
 lisp/cedet/semantic/decorate/mode.el               |    8 +-
 lisp/cedet/semantic/dep.el                         |    1 +
 lisp/cedet/semantic/grm-wy-boot.el                 |    8 +-
 lisp/cedet/semantic/idle.el                        |   14 +-
 lisp/cedet/semantic/lex-spp.el                     |    9 +-
 lisp/cedet/semantic/lex.el                         |   17 +-
 lisp/cedet/semantic/tag-ls.el                      |   19 +-
 lisp/cedet/semantic/wisent.el                      |    2 +-
 lisp/cedet/semantic/wisent/python.el               |    6 +-
 lisp/cedet/srecode/dictionary.el                   |    2 +-
 lisp/cmuscheme.el                                  |    3 +-
 lisp/comint.el                                     |   66 +-
 lisp/completion.el                                 |    3 +-
 lisp/composite.el                                  |   31 +-
 lisp/cus-edit.el                                   |    4 +-
 lisp/cus-face.el                                   |    3 +
 lisp/cus-start.el                                  |    2 +-
 lisp/cus-theme.el                                  |   34 +-
 lisp/custom.el                                     |   33 +-
 lisp/descr-text.el                                 |   11 +-
 lisp/dired-aux.el                                  |   35 +-
 lisp/dired-x.el                                    |    8 +-
 lisp/dired.el                                      |   37 +-
 lisp/edmacro.el                                    |  105 +-
 lisp/elec-pair.el                                  |   78 +-
 lisp/electric.el                                   |   10 +-
 lisp/emacs-lisp/autoload.el                        |   10 +-
 lisp/emacs-lisp/avl-tree.el                        |    3 +-
 lisp/emacs-lisp/backquote.el                       |    5 +-
 lisp/emacs-lisp/byte-opt.el                        |  137 +-
 lisp/emacs-lisp/byte-run.el                        |    9 +-
 lisp/emacs-lisp/bytecomp.el                        |   45 +-
 lisp/emacs-lisp/cconv.el                           |    7 +-
 lisp/emacs-lisp/checkdoc.el                        |  134 +-
 lisp/emacs-lisp/cl-extra.el                        |    4 +-
 lisp/emacs-lisp/cl-generic.el                      |   34 +-
 lisp/emacs-lisp/cl-macs.el                         |   20 +-
 lisp/emacs-lisp/comp.el                            |   62 +-
 lisp/emacs-lisp/debug.el                           |    6 +-
 lisp/emacs-lisp/derived.el                         |   37 +-
 lisp/emacs-lisp/easy-mmode.el                      |   21 +-
 lisp/emacs-lisp/edebug.el                          |    6 +-
 lisp/emacs-lisp/eieio-compat.el                    |    4 +-
 lisp/emacs-lisp/eieio-core.el                      |   12 +-
 lisp/emacs-lisp/eieio.el                           |   11 +-
 lisp/emacs-lisp/eldoc.el                           |   10 +-
 lisp/emacs-lisp/elp.el                             |   13 +-
 lisp/emacs-lisp/ert-x.el                           |  128 +-
 lisp/emacs-lisp/ert.el                             |  194 +-
 lisp/emacs-lisp/ewoc.el                            |    4 +-
 lisp/emacs-lisp/lisp-mnt.el                        |    6 +-
 lisp/emacs-lisp/lisp-mode.el                       |   98 +-
 lisp/emacs-lisp/map.el                             |   10 +-
 lisp/emacs-lisp/memory-report.el                   |    5 +-
 lisp/emacs-lisp/package.el                         |  182 +-
 lisp/emacs-lisp/pp.el                              |  242 +-
 lisp/emacs-lisp/seq.el                             |    8 +-
 lisp/emacs-lisp/shortdoc.el                        |   80 +-
 lisp/emacs-lisp/shorthands.el                      |   80 +
 lisp/emacs-lisp/smie.el                            |    2 +-
 lisp/emacs-lisp/subr-x.el                          |   78 +-
 lisp/emacs-lisp/tabulated-list.el                  |   42 +-
 lisp/emacs-lisp/timer.el                           |   19 +-
 lisp/emulation/cua-base.el                         |   33 +-
 lisp/emulation/viper-cmd.el                        |   56 +-
 lisp/emulation/viper-ex.el                         |    1 -
 lisp/emulation/viper-init.el                       |   15 +-
 lisp/emulation/viper-keym.el                       |    2 +-
 lisp/emulation/viper-mous.el                       |    5 +-
 lisp/emulation/viper-util.el                       |   47 +-
 lisp/emulation/viper.el                            |    3 +-
 lisp/env.el                                        |   17 +
 lisp/epa-hook.el                                   |   18 +-
 lisp/epa-ks.el                                     |    3 +-
 lisp/epa.el                                        |    6 +-
 lisp/epg.el                                        |    3 +-
 lisp/erc/erc-backend.el                            |   57 +-
 lisp/erc/erc-button.el                             |    5 +-
 lisp/{obsolete => erc}/erc-compat.el               |   36 +-
 lisp/erc/erc-dcc.el                                |   12 +-
 lisp/erc/erc-goodies.el                            |    2 +-
 lisp/erc/erc-imenu.el                              |    3 +-
 lisp/erc/erc-networks.el                           |    2 +-
 lisp/erc/erc-replace.el                            |    3 +-
 lisp/erc/erc.el                                    |  125 +-
 lisp/eshell/esh-mode.el                            |   26 +-
 lisp/ezimage.el                                    |    1 +
 lisp/facemenu.el                                   |   11 +-
 lisp/faces.el                                      |   91 +-
 lisp/ffap.el                                       |    7 +-
 lisp/filenotify.el                                 |   31 +-
 lisp/files.el                                      |   89 +-
 lisp/find-file.el                                  |    2 +-
 lisp/finder.el                                     |   22 +-
 lisp/follow.el                                     |   20 +-
 lisp/font-lock.el                                  |    2 +-
 lisp/format.el                                     |    6 +-
 lisp/frame.el                                      |   31 +-
 lisp/frameset.el                                   |    3 +-
 lisp/gnus/gmm-utils.el                             |    1 +
 lisp/gnus/gnus-agent.el                            |  117 +-
 lisp/gnus/gnus-art.el                              |  242 +-
 lisp/gnus/gnus-bookmark.el                         |   53 +-
 lisp/gnus/gnus-cite.el                             |    4 +-
 lisp/gnus/gnus-dired.el                            |   10 +-
 lisp/gnus/gnus-draft.el                            |   15 +-
 lisp/gnus/gnus-eform.el                            |   11 +-
 lisp/gnus/gnus-fun.el                              |    7 +-
 lisp/gnus/gnus-group.el                            |  414 +-
 lisp/gnus/gnus-html.el                             |   26 +-
 lisp/gnus/gnus-icalendar.el                        |   59 +-
 lisp/gnus/gnus-kill.el                             |   21 +-
 lisp/gnus/gnus-ml.el                               |   17 +-
 lisp/gnus/gnus-msg.el                              |   66 +-
 lisp/gnus/gnus-range.el                            |   11 +-
 lisp/gnus/gnus-registry.el                         |    8 +-
 lisp/gnus/gnus-salt.el                             |   48 +-
 lisp/gnus/gnus-score.el                            |   31 +-
 lisp/gnus/gnus-search.el                           |    3 +-
 lisp/gnus/gnus-srvr.el                             |  139 +-
 lisp/gnus/gnus-start.el                            |    5 +-
 lisp/gnus/gnus-sum.el                              |  994 ++--
 lisp/gnus/gnus-topic.el                            |  105 +-
 lisp/gnus/gnus-undo.el                             |   15 +-
 lisp/gnus/gnus-util.el                             |   13 +-
 lisp/gnus/gnus-uu.el                               |    2 +-
 lisp/gnus/gnus.el                                  |   40 +-
 lisp/gnus/message.el                               |  200 +-
 lisp/gnus/mm-uu.el                                 |    8 +
 lisp/gnus/mm-view.el                               |   41 +-
 lisp/gnus/mml-sec.el                               |    6 +-
 lisp/gnus/mml.el                                   |   24 +-
 lisp/gnus/nnimap.el                                |   50 +-
 lisp/gnus/nnmaildir.el                             |   10 +-
 lisp/gnus/nnrss.el                                 |    2 +-
 lisp/gnus/nntp.el                                  |    4 +-
 lisp/gnus/nnvirtual.el                             |   11 +-
 lisp/gnus/spam.el                                  |   28 +-
 lisp/help-at-pt.el                                 |   10 +-
 lisp/help-fns.el                                   |   11 +-
 lisp/help-mode.el                                  |   76 +-
 lisp/help.el                                       |  358 +-
 lisp/hilit-chg.el                                  |    2 +-
 lisp/ibuf-ext.el                                   |    2 +-
 lisp/ibuffer.el                                    |    4 +-
 lisp/icomplete.el                                  |    5 -
 lisp/ido.el                                        |   10 +-
 lisp/image-dired.el                                | 1598 ++++---
 lisp/image-file.el                                 |    2 +-
 lisp/image-mode.el                                 |   82 +-
 lisp/image.el                                      |   28 +-
 lisp/image/exif.el                                 |   22 +-
 lisp/info-look.el                                  |  113 +-
 lisp/info.el                                       |    9 +-
 lisp/international/ccl.el                          |    8 +-
 lisp/international/characters.el                   |   19 +-
 lisp/international/emoji.el                        |  647 +++
 lisp/international/fontset.el                      |   19 +-
 lisp/international/mule-cmds.el                    |  131 +
 lisp/international/mule-conf.el                    |    2 +
 lisp/international/mule-diag.el                    |    4 +-
 lisp/international/mule-util.el                    |   13 +-
 lisp/international/mule.el                         |   28 +-
 lisp/international/quail.el                        |    6 +-
 lisp/international/titdic-cnv.el                   |    8 +-
 lisp/isearch.el                                    |   17 +-
 lisp/jka-cmpr-hook.el                              |    5 +-
 lisp/kmacro.el                                     |   40 +-
 lisp/language/cyril-util.el                        |    2 +-
 lisp/language/japanese.el                          |   23 -
 lisp/language/lao.el                               |   10 +-
 lisp/language/misc-lang.el                         |   20 +-
 lisp/ldefs-boot.el                                 | 1333 +++---
 lisp/leim/quail/ipa.el                             |    8 +-
 lisp/leim/quail/latin-post.el                      |   18 +-
 lisp/leim/quail/latin-pre.el                       |   18 +-
 lisp/linum.el                                      |    3 +
 lisp/loadup.el                                     |    4 +
 lisp/ls-lisp.el                                    |    1 +
 lisp/mail/emacsbug.el                              |    2 +-
 lisp/mail/feedmail.el                              |    2 +-
 lisp/mail/rmailkwd.el                              |    9 +-
 lisp/mail/rmailmm.el                               |    2 +-
 lisp/mail/rmailout.el                              |    5 +-
 lisp/mail/sendmail.el                              |    3 +-
 lisp/mail/uce.el                                   |   32 +-
 lisp/man.el                                        |   26 +-
 lisp/menu-bar.el                                   |   67 +-
 lisp/mh-e/mh-acros.el                              |   36 +-
 lisp/mh-e/mh-alias.el                              |   26 +-
 lisp/mh-e/mh-comp.el                               |   59 +-
 lisp/mh-e/mh-compat.el                             |  357 +-
 lisp/mh-e/mh-e.el                                  |  527 +--
 lisp/mh-e/mh-folder.el                             |  448 +-
 lisp/mh-e/mh-funcs.el                              |    2 +-
 lisp/mh-e/mh-gnus.el                               |  149 +-
 lisp/mh-e/mh-identity.el                           |   27 +-
 lisp/mh-e/mh-junk.el                               |    9 +-
 lisp/mh-e/mh-letter.el                             |  184 +-
 lisp/mh-e/mh-limit.el                              |    8 +-
 lisp/mh-e/mh-mime.el                               |  188 +-
 lisp/mh-e/mh-scan.el                               |   71 +-
 lisp/mh-e/mh-search.el                             |  103 +-
 lisp/mh-e/mh-seq.el                                |   38 +-
 lisp/mh-e/mh-show.el                               |  295 +-
 lisp/mh-e/mh-speed.el                              |   81 +-
 lisp/mh-e/mh-thread.el                             |   40 +-
 lisp/mh-e/mh-tool-bar.el                           |  214 +-
 lisp/mh-e/mh-utils.el                              |   90 +-
 lisp/mh-e/mh-xface.el                              |  108 +-
 lisp/minibuffer.el                                 |   67 +-
 lisp/mouse.el                                      |  173 +-
 lisp/mpc.el                                        |   33 +-
 lisp/mwheel.el                                     |    2 +-
 lisp/net/ange-ftp.el                               |    7 +-
 lisp/net/browse-url.el                             |    2 +-
 lisp/net/dbus.el                                   |   25 +-
 lisp/net/dictionary.el                             |   18 +-
 lisp/net/eudc.el                                   |    5 +-
 lisp/net/eww.el                                    |  444 +-
 lisp/net/hmac-def.el                               |    1 +
 lisp/net/mailcap.el                                |   52 +-
 lisp/net/nsm.el                                    |    3 +-
 lisp/net/ntlm.el                                   |    4 +-
 lisp/net/rcirc.el                                  |   80 +-
 lisp/net/shr.el                                    |   84 +-
 lisp/net/soap-client.el                            |    4 +-
 lisp/net/soap-inspect.el                           |    6 +-
 lisp/net/tramp-adb.el                              |   75 +-
 lisp/net/tramp-archive.el                          |    2 +-
 lisp/net/tramp-cache.el                            |   31 +-
 lisp/net/tramp-crypt.el                            |    5 +-
 lisp/net/tramp-fuse.el                             |   76 +-
 lisp/net/tramp-gvfs.el                             |   46 +-
 lisp/net/tramp-rclone.el                           |    1 +
 lisp/net/tramp-sh.el                               |   87 +-
 lisp/net/tramp-smb.el                              |    2 +-
 lisp/net/tramp-sshfs.el                            |   64 +-
 lisp/net/tramp-sudoedit.el                         |    5 +-
 lisp/net/tramp.el                                  |  138 +-
 lisp/obsolete/cc-compat.el                         |    4 +-
 lisp/obsolete/cl-compat.el                         |    1 +
 lisp/obsolete/cl.el                                |    9 +-
 lisp/obsolete/crisp.el                             |   22 +-
 lisp/obsolete/cust-print.el                        |   10 +-
 lisp/obsolete/eudcb-ph.el                          |    4 +-
 lisp/obsolete/fast-lock.el                         |   35 +-
 lisp/obsolete/iswitchb.el                          |   16 +-
 lisp/obsolete/landmark.el                          |   14 +-
 lisp/obsolete/otodo-mode.el                        |    3 +-
 lisp/obsolete/pgg-parse.el                         |    3 +-
 lisp/obsolete/pgg.el                               |    3 +-
 lisp/obsolete/rcompile.el                          |    6 +-
 lisp/obsolete/tls.el                               |    4 +-
 lisp/obsolete/tpu-edt.el                           |   23 +-
 lisp/obsolete/tpu-mapper.el                        |   54 +-
 lisp/obsolete/vip.el                               |   14 +-
 lisp/org/ob-C.el                                   |  116 +-
 lisp/org/ob-J.el                                   |  189 -
 lisp/org/ob-R.el                                   |  122 +-
 lisp/org/ob-abc.el                                 |   90 -
 lisp/org/ob-asymptote.el                           |  137 -
 lisp/org/ob-awk.el                                 |   13 +-
 lisp/org/ob-calc.el                                |    3 +-
 lisp/org/ob-clojure.el                             |    1 +
 lisp/org/ob-comint.el                              |  174 +-
 lisp/org/ob-coq.el                                 |   80 -
 lisp/org/ob-core.el                                |  162 +-
 lisp/org/ob-dot.el                                 |    3 +-
 lisp/org/ob-ebnf.el                                |   81 -
 lisp/org/ob-eshell.el                              |    3 +-
 lisp/org/ob-eval.el                                |   87 +-
 lisp/org/ob-exp.el                                 |   30 +-
 lisp/org/ob-forth.el                               |    4 +-
 lisp/org/ob-fortran.el                             |   10 +-
 lisp/org/ob-gnuplot.el                             |   26 +-
 lisp/org/ob-groovy.el                              |    3 +-
 lisp/org/ob-haskell.el                             |   11 +-
 lisp/org/ob-hledger.el                             |   69 -
 lisp/org/ob-io.el                                  |  105 -
 lisp/org/ob-java.el                                |  482 +-
 lisp/org/ob-js.el                                  |    4 +-
 lisp/org/ob-julia.el                               |  331 ++
 lisp/org/ob-latex.el                               |   63 +-
 lisp/org/ob-ledger.el                              |   68 -
 lisp/org/ob-lilypond.el                            |   26 +-
 lisp/org/ob-lisp.el                                |    2 +-
 lisp/org/ob-lua.el                                 |    6 +-
 lisp/org/ob-makefile.el                            |    3 +-
 lisp/org/ob-mscgen.el                              |   81 -
 lisp/org/ob-ocaml.el                               |    6 +-
 lisp/org/ob-octave.el                              |   18 +-
 lisp/org/ob-perl.el                                |    1 +
 lisp/org/ob-picolisp.el                            |  185 -
 lisp/org/ob-plantuml.el                            |   15 +-
 lisp/org/ob-processing.el                          |    2 +-
 lisp/org/ob-python.el                              |   69 +-
 lisp/org/ob-ruby.el                                |    2 +-
 lisp/org/ob-sass.el                                |    2 +-
 lisp/org/ob-scheme.el                              |    2 +-
 lisp/org/ob-screen.el                              |    5 +-
 lisp/org/ob-sed.el                                 |   12 +-
 lisp/org/ob-shen.el                                |   79 -
 lisp/org/ob-sql.el                                 |   78 +-
 lisp/org/ob-sqlite.el                              |   30 +-
 lisp/org/ob-stan.el                                |   86 -
 lisp/org/ob-table.el                               |    3 +-
 lisp/org/ob-tangle.el                              |  202 +-
 lisp/org/ob-vala.el                                |  116 -
 lisp/org/oc-basic.el                               |  779 +++
 lisp/org/oc-biblatex.el                            |  318 ++
 lisp/org/oc-csl.el                                 |  630 +++
 lisp/org/oc-natbib.el                              |  193 +
 lisp/org/oc.el                                     | 1649 +++++++
 lisp/org/ol-bbdb.el                                |    4 +-
 lisp/org/ol-bibtex.el                              |   38 +-
 lisp/org/ol-doi.el                                 |   72 +
 lisp/org/ol-eshell.el                              |    8 +-
 lisp/org/ol-gnus.el                                |    4 +-
 lisp/org/ol-info.el                                |    6 +-
 lisp/org/ol-man.el                                 |   86 +
 lisp/org/ol-rmail.el                               |    2 +-
 lisp/org/ol-w3m.el                                 |  105 +-
 lisp/org/ol.el                                     |  172 +-
 lisp/org/org-agenda.el                             | 1228 ++---
 lisp/org/org-archive.el                            |    2 +-
 lisp/org/org-attach-git.el                         |   33 +-
 lisp/org/org-attach.el                             |   93 +-
 lisp/org/org-capture.el                            |  338 +-
 lisp/org/org-clock.el                              |  154 +-
 lisp/org/org-colview.el                            |   38 +-
 lisp/org/org-compat.el                             |  343 +-
 lisp/org/org-crypt.el                              |    8 +-
 lisp/org/org-ctags.el                              |    6 +-
 lisp/org/org-datetree.el                           |    6 +-
 lisp/org/org-duration.el                           |    6 +-
 lisp/org/org-element.el                            |  268 +-
 lisp/org/org-entities.el                           |    4 +-
 lisp/org/org-faces.el                              |   74 +-
 lisp/org/org-feed.el                               |    2 +-
 lisp/org/org-footnote.el                           |   15 +-
 lisp/org/org-goto.el                               |   10 +-
 lisp/org/org-habit.el                              |    2 +-
 lisp/org/org-id.el                                 |  177 +-
 lisp/org/org-indent.el                             |   51 +-
 lisp/org/org-inlinetask.el                         |   26 +-
 lisp/org/org-keys.el                               |  111 +-
 lisp/org/org-lint.el                               |  104 +-
 lisp/org/org-list.el                               |  335 +-
 lisp/org/org-macro.el                              |  131 +-
 lisp/org/org-macs.el                               |   87 +-
 lisp/org/org-mobile.el                             |    2 +-
 lisp/org/org-mouse.el                              |  170 +-
 lisp/org/org-num.el                                |   10 +-
 lisp/org/org-pcomplete.el                          |    7 +-
 lisp/org/org-plot.el                               |  624 ++-
 lisp/org/org-protocol.el                           |   73 +-
 lisp/org/org-refile.el                             |   54 +-
 lisp/org/org-src.el                                |  108 +-
 lisp/org/org-table.el                              |  317 +-
 lisp/org/org-timer.el                              |    2 +-
 lisp/org/org-version.el                            |    4 +-
 lisp/org/org.el                                    | 1382 +++---
 lisp/org/ox-ascii.el                               |   65 +-
 lisp/org/ox-beamer.el                              |   65 +-
 lisp/org/ox-html.el                                |  375 +-
 lisp/org/ox-icalendar.el                           |   10 +-
 lisp/org/ox-koma-letter.el                         |  989 ++++
 lisp/org/ox-latex.el                               |  257 +-
 lisp/org/ox-man.el                                 |   32 +-
 lisp/org/ox-md.el                                  |   53 +-
 lisp/org/ox-odt.el                                 |   80 +-
 lisp/org/ox-org.el                                 |   19 +-
 lisp/org/ox-publish.el                             |   60 +-
 lisp/org/ox-texinfo.el                             |  111 +-
 lisp/org/ox.el                                     |  474 +-
 lisp/outline.el                                    |  108 +-
 lisp/paren.el                                      |   23 +
 lisp/play/doctor.el                                |    4 +-
 lisp/play/mpuz.el                                  |    2 +-
 lisp/play/zone.el                                  |    2 +-
 lisp/printing.el                                   |    2 +-
 lisp/proced.el                                     |   70 +-
 lisp/progmodes/antlr-mode.el                       |    5 +-
 lisp/progmodes/bug-reference.el                    |   23 +-
 lisp/progmodes/cc-cmds.el                          |   40 +-
 lisp/progmodes/cc-engine.el                        |   46 +-
 lisp/progmodes/cc-fonts.el                         |  220 +-
 lisp/progmodes/cc-langs.el                         |    2 +-
 lisp/progmodes/cc-mode.el                          |  116 +-
 lisp/progmodes/cc-vars.el                          |   37 +-
 lisp/progmodes/compile.el                          |    4 +-
 lisp/progmodes/cperl-mode.el                       |    8 +-
 lisp/progmodes/cpp.el                              |    7 +-
 lisp/progmodes/ebnf-dtd.el                         |    2 +-
 lisp/progmodes/ebrowse.el                          |    6 +-
 lisp/progmodes/elisp-mode.el                       |  111 +-
 lisp/progmodes/erts-mode.el                        |  220 +
 lisp/progmodes/etags.el                            |   58 +-
 lisp/progmodes/f90.el                              |    1 +
 lisp/progmodes/flymake-proc.el                     |    7 +-
 lisp/progmodes/flymake.el                          |   10 +-
 lisp/progmodes/gdb-mi.el                           |   15 +-
 lisp/progmodes/grep.el                             |    8 +-
 lisp/progmodes/gud.el                              |    4 +-
 lisp/progmodes/hideif.el                           |    2 +-
 lisp/progmodes/idlw-shell.el                       |    5 +-
 lisp/progmodes/idlwave.el                          |    8 +-
 lisp/progmodes/js.el                               | 1147 +----
 lisp/progmodes/octave.el                           |    8 +-
 lisp/progmodes/opascal.el                          |    6 +-
 lisp/progmodes/pascal.el                           |    4 +-
 lisp/progmodes/prog-mode.el                        |   30 +-
 lisp/progmodes/project.el                          |   76 +-
 lisp/progmodes/prolog.el                           |   14 +-
 lisp/progmodes/python.el                           |   47 +-
 lisp/progmodes/scheme.el                           |    1 -
 lisp/progmodes/sh-script.el                        |   16 +-
 lisp/progmodes/sql.el                              |   77 +-
 lisp/progmodes/verilog-mode.el                     |   52 +-
 lisp/progmodes/vhdl-mode.el                        |   19 +-
 lisp/progmodes/which-func.el                       |    3 +-
 lisp/progmodes/xref.el                             |  410 +-
 lisp/progmodes/xscheme.el                          |    6 +-
 lisp/ps-mule.el                                    |    4 +-
 lisp/ps-print.el                                   |  150 +-
 lisp/recentf.el                                    |   58 +-
 lisp/repeat.el                                     |   14 +-
 lisp/replace.el                                    |   10 +-
 lisp/select.el                                     |   14 +-
 lisp/server.el                                     |   36 +-
 lisp/ses.el                                        |    6 +-
 lisp/shell.el                                      |   17 +-
 lisp/simple.el                                     |  170 +-
 lisp/skeleton.el                                   |    3 +-
 lisp/sort.el                                       |    4 +-
 lisp/subr.el                                       |  376 +-
 lisp/tab-bar.el                                    |  369 +-
 lisp/tab-line.el                                   |  126 +-
 lisp/term.el                                       |  431 +-
 lisp/term/ns-win.el                                |    8 +-
 lisp/term/w32-win.el                               |    9 +-
 lisp/textmodes/artist.el                           |    5 +-
 lisp/textmodes/bibtex.el                           |    7 +-
 lisp/textmodes/css-mode.el                         |    4 +-
 lisp/textmodes/etc-authors-mode.el                 |    8 +-
 lisp/textmodes/fill.el                             |   10 +-
 lisp/textmodes/ispell.el                           |   21 +-
 lisp/textmodes/reftex-cite.el                      |    4 +-
 lisp/textmodes/reftex-global.el                    |    2 +-
 lisp/textmodes/reftex-parse.el                     |   12 +-
 lisp/textmodes/reftex-ref.el                       |    6 +-
 lisp/textmodes/reftex-toc.el                       |    4 +-
 lisp/textmodes/sgml-mode.el                        |   38 +-
 lisp/textmodes/tex-mode.el                         |    2 +-
 lisp/textmodes/texinfo.el                          |   61 +-
 lisp/textmodes/texnfo-upd.el                       |    4 +-
 lisp/textmodes/text-mode.el                        |   25 +-
 lisp/textmodes/tildify.el                          |    4 +-
 lisp/thingatpt.el                                  |   39 +-
 lisp/thumbs.el                                     |   22 +-
 lisp/time-stamp.el                                 |   46 +-
 lisp/tool-bar.el                                   |    2 +
 lisp/transient.el                                  |  594 ++-
 lisp/tree-widget.el                                |    4 +-
 lisp/url/url-tramp.el                              |   10 +-
 lisp/userlock.el                                   |   30 +-
 lisp/vc/add-log.el                                 |    3 +-
 lisp/vc/cvs-status.el                              |   27 +-
 lisp/vc/diff-mode.el                               |  152 +-
 lisp/vc/diff.el                                    |    8 +-
 lisp/vc/ediff-merg.el                              |    3 +-
 lisp/vc/ediff-mult.el                              |    2 +-
 lisp/vc/ediff-ptch.el                              |   14 +-
 lisp/vc/ediff-util.el                              |   12 +-
 lisp/vc/ediff.el                                   |    9 +-
 lisp/vc/log-edit.el                                |   30 +-
 lisp/vc/log-view.el                                |   51 +-
 lisp/vc/pcvs-defs.el                               |  154 -
 lisp/vc/pcvs.el                                    |  150 +-
 lisp/vc/smerge-mode.el                             |   43 +-
 lisp/vc/vc-annotate.el                             |    3 +-
 lisp/vc/vc-bzr.el                                  |    3 +-
 lisp/vc/vc-dir.el                                  |    7 +-
 lisp/vc/vc-dispatcher.el                           |    2 +-
 lisp/vc/vc-git.el                                  |   13 +-
 lisp/vc/vc-hg.el                                   |    7 +-
 lisp/vc/vc-hooks.el                                |    3 +-
 lisp/vc/vc.el                                      |   63 +-
 lisp/whitespace.el                                 |   56 +-
 lisp/wid-edit.el                                   |    9 +-
 lisp/widget.el                                     |    4 +-
 lisp/window.el                                     |  215 +-
 lisp/xdg.el                                        |   95 +-
 lisp/xwidget.el                                    |  358 +-
 lisp/yank-media.el                                 |  194 +
 m4/close-stream.m4                                 |   11 -
 m4/dirent_h.m4                                     |   45 +-
 m4/environ.m4                                      |    5 +-
 m4/explicit_bzero.m4                               |    2 +-
 m4/extern-inline.m4                                |    7 +-
 m4/fcntl_h.m4                                      |   39 +-
 m4/free.m4                                         |    7 +-
 m4/gettimeofday.m4                                 |    6 +-
 m4/glibc21.m4                                      |   34 -
 m4/gnulib-common.m4                                |  269 +-
 m4/gnulib-comp.m4                                  |  164 +-
 m4/inttypes.m4                                     |   31 +-
 m4/largefile.m4                                    |   28 +-
 m4/limits-h.m4                                     |    3 +-
 m4/malloc.m4                                       |  174 +
 m4/malloca.m4                                      |   14 -
 m4/manywarnings.m4                                 |   12 +-
 m4/memmem.m4                                       |    5 +-
 m4/mempcpy.m4                                      |    4 +-
 m4/memrchr.m4                                      |    4 +-
 m4/mktime.m4                                       |    4 +-
 m4/nproc.m4                                        |   54 +
 m4/pselect.m4                                      |    4 +-
 m4/pthread_sigmask.m4                              |   10 +-
 m4/rawmemchr.m4                                    |    4 +-
 m4/realloc.m4                                      |   63 +
 m4/regex.m4                                        |   44 +-
 m4/sigdescr_np.m4                                  |    4 +-
 m4/signal_h.m4                                     |   33 +-
 m4/stdalign.m4                                     |    4 +-
 m4/stddef_h.m4                                     |   23 +-
 m4/stdint.m4                                       |    6 +-
 m4/stdio_h.m4                                      |  168 +-
 m4/stdlib_h.m4                                     |  122 +-
 m4/stpcpy.m4                                       |    4 +-
 m4/string_h.m4                                     |  126 +-
 m4/strnlen.m4                                      |    4 +-
 m4/strtoll.m4                                      |   36 +-
 m4/sys_random_h.m4                                 |   25 +-
 m4/sys_select_h.m4                                 |   29 +-
 m4/sys_socket_h.m4                                 |   53 +-
 m4/sys_stat_h.m4                                   |   65 +-
 m4/sys_time_h.m4                                   |   34 +-
 m4/sys_types_h.m4                                  |   16 +-
 m4/time_h.m4                                       |   62 +-
 m4/time_r.m4                                       |    2 +-
 m4/time_rz.m4                                      |    2 +-
 m4/timegm.m4                                       |    4 +-
 m4/timer_time.m4                                   |   11 +-
 m4/unistd_h.m4                                     |  194 +-
 m4/unlocked-io.m4                                  |    7 +-
 m4/year2038.m4                                     |  124 +
 make-dist                                          |    6 +-
 msdos/autogen/config.in                            |    2 +-
 msdos/sed2v2.inp                                   |    2 +-
 nextstep/templates/Info.plist.in                   |    2 +-
 nt/ChangeLog.1                                     |    2 +-
 nt/INSTALL                                         |   17 +-
 nt/INSTALL.W64                                     |    1 +
 nt/Makefile.in                                     |    1 +
 nt/README.W32                                      |    2 +-
 nt/addpm.c                                         |    4 +
 nt/cmdproxy.c                                      |    3 +
 nt/ddeclient.c                                     |    3 +
 nt/gnulib-cfg.mk                                   |    5 +
 nt/preprep.c                                       |    3 +
 nt/runemacs.c                                      |    3 +
 oldXMenu/AddPane.c                                 |    2 +-
 oldXMenu/AddSel.c                                  |    2 +-
 src/Makefile.in                                    |   56 +-
 src/alloc.c                                        |   42 +-
 src/atimer.c                                       |   29 +-
 src/bidi.c                                         |   29 +-
 src/buffer.c                                       |   18 +-
 src/casefiddle.c                                   |   57 +-
 src/character.h                                    |    2 +
 src/comp.c                                         |    5 +-
 src/composite.c                                    |   27 +-
 src/composite.h                                    |    4 +
 src/conf_post.h                                    |    1 -
 src/dispextern.h                                   |   12 +-
 src/dispnew.c                                      |   19 +-
 src/emacs-module.h.in                              |   13 +
 src/emacs.c                                        |   50 +-
 src/eval.c                                         |   72 +-
 src/fns.c                                          |   11 +-
 src/font.c                                         |  113 +-
 src/font.h                                         |    2 +-
 src/frame.c                                        |    9 +-
 src/gtkutil.c                                      |   51 +-
 src/image.c                                        |  462 +-
 src/intervals.c                                    |   20 +-
 src/keyboard.c                                     |  186 +-
 src/keyboard.h                                     |    2 +-
 src/keymap.c                                       |  217 +-
 src/lisp.h                                         |   56 +-
 src/lread.c                                        |  184 +-
 src/macfont.m                                      |   44 +-
 src/minibuf.c                                      |  107 +-
 src/module-env-28.h                                |    4 -
 src/module-env-29.h                                |    3 +
 src/msdos.c                                        |    2 +-
 src/nsfns.m                                        |   71 +-
 src/nsfont.m                                       | 1215 +++--
 src/nsmenu.m                                       |  111 +-
 src/nsterm.h                                       |   17 +-
 src/nsterm.m                                       |  593 +--
 src/pdumper.c                                      |   38 +-
 src/pdumper.h                                      |    5 +
 src/print.c                                        |   30 +-
 src/process.c                                      |   54 +-
 src/regex-emacs.c                                  |    4 +-
 src/search.c                                       |   88 +-
 src/sysstdio.h                                     |    2 +-
 src/systhread.h                                    |   13 +-
 src/term.c                                         |    5 +-
 src/termhooks.h                                    |    2 +
 src/timefns.c                                      |    5 +
 src/unexcw.c                                       |    6 +-
 src/verbose.mk.in                                  |    4 +
 src/vm-limit.c                                     |    2 +-
 src/w16select.c                                    |    2 +-
 src/w32.c                                          |   60 +-
 src/w32.h                                          |    9 +-
 src/w32fns.c                                       |  148 +-
 src/w32font.c                                      |    4 +-
 src/w32heap.c                                      |   42 +-
 src/w32proc.c                                      |   10 -
 src/w32term.c                                      |   16 -
 src/window.c                                       |   68 +-
 src/xdisp.c                                        |  415 +-
 src/xfaces.c                                       |   11 +
 src/xfns.c                                         |   16 +-
 src/xmenu.c                                        |    8 +
 src/xterm.c                                        |  206 +-
 src/xterm.h                                        |    1 +
 src/xwidget.c                                      | 1321 +++++-
 src/xwidget.h                                      |   27 +-
 test/Makefile.in                                   |   11 +-
 test/README                                        |    9 +
 test/data/image/black.gif                          |  Bin 0 -> 143 bytes
 test/data/image/black.webp                         |  Bin 0 -> 37780 bytes
 test/infra/Dockerfile.emba                         |   39 +-
 test/infra/gitlab-ci.yml                           |  122 +-
 test/lisp/abbrev-tests.el                          |   60 +-
 test/lisp/ansi-color-tests.el                      |  155 +-
 test/lisp/auth-source-pass-tests.el                |    6 +-
 test/lisp/auth-source-tests.el                     |  180 +-
 test/lisp/autoinsert-tests.el                      |   19 +-
 test/lisp/autorevert-tests.el                      |  830 ++--
 test/lisp/bookmark-tests.el                        |   18 +-
 test/lisp/buff-menu-tests.el                       |   21 +-
 test/lisp/calc/calc-tests.el                       |   10 +-
 test/lisp/calculator-tests.el                      |    2 +-
 test/lisp/calendar/cal-french-tests.el             |    1 +
 test/lisp/calendar/icalendar-tests.el              |  108 +-
 test/lisp/calendar/solar-tests.el                  |    4 +
 test/lisp/calendar/todo-mode-tests.el              |   41 +-
 test/lisp/cedet/semantic-utest-c.el                |    2 +-
 test/lisp/cedet/semantic-utest-ia.el               |    2 +-
 test/lisp/cedet/semantic-utest.el                  |    7 +-
 test/lisp/cedet/semantic/bovine/gcc-tests.el       |    7 +-
 test/lisp/cedet/semantic/fw-tests.el               |    2 +-
 test/lisp/comint-tests.el                          |    9 +-
 test/lisp/cus-edit-tests.el                        |    2 +-
 test/lisp/custom-tests.el                          |   37 +-
 test/lisp/dabbrev-tests.el                         |   15 +-
 test/lisp/descr-text-tests.el                      |    2 +-
 test/lisp/dired-aux-tests.el                       |   62 +-
 test/lisp/dired-tests.el                           |  354 +-
 test/lisp/dired-x-tests.el                         |   32 +-
 test/lisp/edmacro-tests.el                         |   47 +
 test/lisp/electric-tests.el                        |   74 +-
 test/lisp/emacs-lisp/bytecomp-tests.el             |  242 +-
 test/lisp/emacs-lisp/cconv-tests.el                |    6 +-
 test/lisp/emacs-lisp/check-declare-tests.el        |   96 +-
 test/lisp/emacs-lisp/checkdoc-tests.el             |   74 +-
 test/lisp/emacs-lisp/cl-macs-tests.el              |   13 +-
 test/lisp/emacs-lisp/edebug-tests.el               |   42 +-
 .../eieio-tests/eieio-test-methodinvoke.el         |   20 +-
 .../emacs-lisp/eieio-tests/eieio-test-persist.el   |    6 +-
 test/lisp/emacs-lisp/eieio-tests/eieio-tests.el    |   22 +-
 test/lisp/emacs-lisp/ert-tests.el                  |   73 +-
 test/lisp/emacs-lisp/ert-x-tests.el                |   64 +-
 .../faceup-test-this-file-directory.el             |    2 +-
 test/lisp/emacs-lisp/find-func-tests.el            |    2 +-
 test/lisp/emacs-lisp/generator-tests.el            |    2 +-
 test/lisp/emacs-lisp/gv-tests.el                   |   19 +-
 test/lisp/emacs-lisp/let-alist-tests.el            |    2 +-
 test/lisp/emacs-lisp/lisp-mnt-tests.el             |    8 +
 test/lisp/emacs-lisp/memory-report-tests.el        |    2 +
 test/lisp/emacs-lisp/nadvice-tests.el              |    2 +-
 test/lisp/emacs-lisp/package-resources/key.pub     |   31 +-
 test/lisp/emacs-lisp/package-resources/key.sec     |   46 +-
 .../macro-builtin-package-1.0/macro-builtin-aux.el |   12 +
 .../macro-builtin-package-1.0/macro-builtin.el     |   21 +
 .../macro-builtin-package-2.0/macro-builtin-aux.el |   16 +
 .../macro-builtin-package-2.0/macro-builtin.el     |   30 +
 .../macro-problem-package-1.0/macro-aux.el         |    2 +-
 .../macro-problem-package-1.0/macro-problem.el     |    4 +-
 .../macro-problem-package-2.0/macro-aux.el         |    4 +-
 .../macro-problem-package-2.0/macro-problem.el     |    8 +-
 .../newer-versions/simple-single-1.4.el            |    6 +-
 .../package-resources/signed/archive-contents.sig  |  Bin 181 -> 95 bytes
 .../package-resources/signed/signed-bad-1.0.el     |    6 +-
 .../package-resources/signed/signed-good-1.0.el    |    6 +-
 .../signed/signed-good-1.0.el.sig                  |  Bin 181 -> 95 bytes
 .../package-resources/simple-depend-1.0.el         |    2 +-
 .../package-resources/simple-single-1.3.el         |    6 +-
 .../package-resources/simple-two-depend-1.1.el     |    2 +-
 test/lisp/emacs-lisp/package-tests.el              |  178 +-
 .../lisp/emacs-lisp/pp-resources/code-formats.erts |  124 +
 test/lisp/emacs-lisp/pp-tests.el                   |    4 +
 test/lisp/emacs-lisp/regexp-opt-tests.el           |    2 +-
 test/lisp/emacs-lisp/rx-tests.el                   |    4 +
 test/lisp/emacs-lisp/shortdoc-tests.el             |    4 +
 test/lisp/emacs-lisp/subr-x-tests.el               |   38 +
 ...ulated-list-test.el => tabulated-list-tests.el} |   40 +-
 .../emacs-lisp/testcover-resources/testcases.el    |   10 +-
 test/lisp/emacs-lisp/testcover-tests.el            |  108 +-
 test/lisp/emacs-lisp/unsafep-tests.el              |    2 +-
 test/lisp/emulation/viper-tests.el                 |   80 +-
 test/lisp/epg-tests.el                             |   77 +-
 test/lisp/erc/erc-tests.el                         |   73 +
 test/lisp/erc/erc-track-tests.el                   |    2 +
 test/lisp/eshell/em-hist-tests.el                  |   17 +-
 test/lisp/eshell/em-ls-tests.el                    |   38 +-
 test/lisp/eshell/eshell-tests.el                   |   34 +-
 test/lisp/faces-resources/faces-test-dark-theme.el |    2 +-
 .../lisp/faces-resources/faces-test-light-theme.el |    2 +-
 test/lisp/faces-tests.el                           |    2 +-
 test/lisp/ffap-tests.el                            |   29 +-
 test/lisp/filenotify-tests.el                      |   33 +-
 test/lisp/files-tests.el                           |  310 +-
 test/lisp/gnus/gnus-group-tests.el                 |   52 +
 test/lisp/gnus/gnus-icalendar-tests.el             |    2 +-
 test/lisp/gnus/gnus-search-tests.el                |    2 +-
 test/lisp/gnus/gnus-util-tests.el                  |    2 +-
 test/lisp/gnus/message-tests.el                    |    2 +-
 test/lisp/help-fns-tests.el                        |    4 +-
 test/lisp/help-tests.el                            |  117 +-
 test/lisp/hi-lock-tests.el                         |   15 +-
 test/lisp/htmlfontify-tests.el                     |    2 +-
 test/lisp/ibuffer-tests.el                         |    2 +-
 .../{newcomment-tests.el => image-dired-tests.el}  |   32 +-
 test/lisp/image-tests.el                           |   64 +-
 test/lisp/image/exif-tests.el                      |   21 +-
 test/lisp/info-xref-tests.el                       |   82 +-
 test/lisp/international/ccl-tests.el               |    2 +
 test/lisp/international/mule-tests.el              |    2 +-
 test/lisp/international/ucs-normalize-tests.el     |    6 +-
 test/lisp/jit-lock-tests.el                        |    2 +
 test/lisp/kmacro-tests.el                          |    2 +-
 test/lisp/ls-lisp-tests.el                         |   33 +-
 test/lisp/mail/rmail-tests.el                      |    2 +-
 test/lisp/mail/rmailmm-tests.el                    |    2 +-
 test/lisp/mail/uudecode-tests.el                   |   30 +-
 test/lisp/mh-e/mh-utils-tests.el                   |  119 +-
 test/lisp/mh-e/test-all-mh-variants.sh             |  104 +
 test/lisp/net/browse-url-tests.el                  |    6 +-
 test/lisp/net/dbus-tests.el                        |   13 +-
 test/lisp/net/shr-tests.el                         |    2 +-
 test/lisp/net/socks-tests.el                       |    4 +-
 test/lisp/net/tramp-archive-tests.el               |    5 +-
 test/lisp/net/tramp-tests.el                       |  250 +-
 test/lisp/newcomment-tests.el                      |    4 +-
 test/lisp/org/org-tests.el                         |    2 +
 test/lisp/paren-tests.el                           |   31 +
 test/lisp/play/cookie1-tests.el                    |    2 +-
 test/lisp/progmodes/bug-reference-tests.el         |  128 +
 .../elisp-mode-resources/elisp-indents.erts        |   88 +
 test/lisp/progmodes/elisp-mode-resources/flet.erts |  353 ++
 .../elisp-mode-resources/simple-shorthand-test.el  |   40 +
 test/lisp/progmodes/elisp-mode-tests.el            |  189 +-
 test/lisp/progmodes/etags-tests.el                 |   33 +-
 test/lisp/progmodes/flymake-tests.el               |   34 +-
 test/lisp/progmodes/gdb-mi-tests.el                |    4 +
 test/lisp/progmodes/opascal-tests.el               |    2 +
 test/lisp/progmodes/pascal-tests.el                |    4 +
 test/lisp/progmodes/project-tests.el               |   20 +-
 test/lisp/progmodes/python-tests.el                |   23 +-
 test/lisp/progmodes/sql-tests.el                   |  102 +-
 test/lisp/ps-print-tests.el                        |    2 +
 test/lisp/repeat-tests.el                          |  111 +
 test/lisp/saveplace-tests.el                       |   69 +-
 test/lisp/ses-tests.el                             |    2 +
 test/lisp/shell-tests.el                           |    2 +-
 test/lisp/simple-tests.el                          |    2 +-
 test/lisp/so-long-tests/so-long-tests-helpers.el   |    4 +-
 test/lisp/so-long-tests/spelling-tests.el          |   30 +-
 test/lisp/subr-tests.el                            |  241 +-
 test/lisp/tar-mode-tests.el                        |    2 +-
 test/lisp/term-tests.el                            |   79 +-
 test/lisp/term/tty-colors-tests.el                 |    2 +-
 test/lisp/textmodes/dns-mode-tests.el              |    2 +
 test/lisp/textmodes/fill-tests.el                  |   22 +
 test/lisp/textmodes/reftex-tests.el                |  101 +-
 test/lisp/textmodes/texinfo-resources/fill.erts    |   70 +
 .../textmodes/texinfo-tests.el}                    |   17 +-
 test/lisp/thingatpt-tests.el                       |    4 +-
 test/lisp/thumbs-tests.el                          |   10 +-
 test/lisp/time-stamp-tests.el                      |   25 +-
 test/lisp/time-tests.el                            |    2 +
 test/lisp/timezone-tests.el                        |    2 +
 ...{url-handlers-test.el => url-handlers-tests.el} |    5 +-
 test/lisp/url/url-parse-tests.el                   |    2 +-
 test/lisp/vc/add-log-tests.el                      |    4 +-
 test/lisp/vc/diff-mode-tests.el                    |   57 +-
 test/lisp/vc/ediff-ptch-tests.el                   |   60 +-
 test/lisp/vc/smerge-mode-tests.el                  |    2 +
 test/lisp/vc/vc-bzr-tests.el                       |  174 +-
 test/lisp/vc/vc-tests.el                           |  876 ++--
 test/lisp/wdired-tests.el                          |  267 +-
 test/lisp/whitespace-tests.el                      |    2 +-
 test/lisp/xml-tests.el                             |    4 +-
 test/manual/biditest.el                            |    2 +
 test/manual/cedet/ede-tests.el                     |    2 +-
 test/manual/cedet/semantic-tests.el                |    2 +
 test/manual/cedet/tests/test.el                    |   32 +-
 .../etags/el-src/emacs/lisp/progmodes/etags.el     |    2 +-
 test/manual/image-size-tests.el                    |    2 +
 test/manual/image-transforms-tests.el              |    2 +
 test/manual/redisplay-testsuite.el                 |    2 +
 test/misc/test-custom-libs.el                      |    4 +-
 test/src/alloc-tests.el                            |    2 +
 test/src/buffer-tests.el                           |  117 +-
 test/src/casefiddle-tests.el                       |   16 +
 test/src/character-tests.el                        |    2 +
 test/src/charset-tests.el                          |    4 +-
 test/src/coding-tests.el                           |    2 +-
 test/src/comp-resources/comp-test-funcs.el         |   13 +-
 test/src/comp-tests.el                             |   56 +-
 test/src/data-tests.el                             |   24 +-
 test/src/decompress-tests.el                       |    2 +-
 test/src/editfns-tests.el                          |   48 +-
 test/src/emacs-module-resources/mod-test.c         |    5 +-
 test/src/emacs-module-tests.el                     |   21 +-
 test/src/emacs-tests.el                            |   30 +-
 test/src/eval-tests.el                             |   57 +-
 test/src/fileio-tests.el                           |   12 +-
 test/src/filelock-tests.el                         |   31 +-
 test/src/floatfns-tests.el                         |   66 +
 test/src/fns-tests.el                              |   69 +
 test/src/image-tests.el                            |  245 +
 test/src/indent-tests.el                           |    2 +
 test/src/inotify-tests.el                          |   36 +-
 test/src/keymap-tests.el                           |   68 +-
 test/src/lcms-tests.el                             |    4 +-
 test/src/lread-tests.el                            |   10 +-
 test/src/marker-tests.el                           |    2 +-
 test/src/minibuf-tests.el                          |    4 +-
 test/src/process-tests.el                          |   57 +-
 test/src/regex-emacs-tests.el                      |   28 +-
 test/src/textprop-tests.el                         |    2 +-
 test/src/thread-tests.el                           |    8 +-
 test/src/timefns-tests.el                          |    2 +
 test/src/undo-tests.el                             |   20 +-
 test/src/xdisp-tests.el                            |   55 +
 test/src/xfaces-tests.el                           |    4 +
 test/src/xml-tests.el                              |    2 +-
 1211 files changed, 56501 insertions(+), 31031 deletions(-)

diff --git a/.gitignore b/.gitignore
index e49e970d09..ea1662c9b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ lib/ieee754.h
 lib/inttypes.h
 lib/libgnu.a
 lib/limits.h
+lib/malloc/*.gl.h
 lib/signal.h
 lib/std*.h
 !lib/std*.in.h
@@ -214,6 +215,7 @@ lisp/international/charprop.el
 lisp/international/charscript.el
 lisp/international/cp51932.el
 lisp/international/emoji-zwj.el
+lisp/international/emoji-labels.el
 lisp/international/eucjp-ms.el
 lisp/international/uni-*.el
 lisp/language/pinyin.el
diff --git a/INSTALL b/INSTALL
index b6f681a153..21298422af 100644
--- a/INSTALL
+++ b/INSTALL
@@ -187,6 +187,7 @@ X11 is being used.
   X libtiff for TIFF: http://www.simplesystems.org/libtiff/
   X libgif for GIF:   http://giflib.sourceforge.net/
     librsvg2 for SVG: https://wiki.gnome.org/Projects/LibRsvg
+    libwebp for WebP: https://developers.google.com/speed/webp/
 
 If you supply the appropriate --without-LIB option, 'configure' will
 omit the corresponding library from Emacs, even if that makes for a
@@ -220,7 +221,7 @@ GNU/Linux distribution that you use, and the options that 
you want to
 configure Emacs with.  On Debian-based systems, you can install all the
 packages needed to build the installed version of Emacs with a command
 like 'apt-get build-dep emacs' (on older systems, replace 'emacs' with
-eg 'emacs25').  On Red Hat-based systems, the corresponding command is
+e.g. 'emacs25').  On Red Hat-based systems, the corresponding command is
 'dnf builddep emacs' (on older systems, use 'yum-builddep' instead).
 
 On FreeBSD, the command is 'pkg install -y `pkg rquery %dn emacs-devel`'.
@@ -313,6 +314,7 @@ or more of these options:
   --without-gif          for GIF image support
   --without-png          for PNG image support
   --without-rsvg         for SVG image support
+  --without-webp         for WebP image support
 
 Although ImageMagick support is disabled by default due to security
 and stability concerns, you can enable it with --with-imagemagick.
@@ -322,8 +324,11 @@ Use --without-toolkit-scroll-bars to disable Motif or 
Xaw3d scroll bars.
 Use --without-xim to inhibit the default use of X Input Methods.
 In this case, the X resource useXIM can be used to turn on use of XIM.
 
-Use --disable-largefile to omit support for files larger than 2GB on
-systems which support that.
+Use --disable-largefile to omit support for files larger than 2GB, and
+--disable-year2038 to omit support for timestamps past the year 2038,
+on systems which allow omitting such support.  This may help when
+linking Emacs to a library with an ABI that requires a particular
+width for off_t or for time_t.
 
 Use --without-sound to disable sound support.
 
diff --git a/Makefile.in b/Makefile.in
index 235b707673..ccb5d93f2f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -285,10 +285,16 @@ use_gamedir=$(gameuser)$(gamegroup)
 # not use an absolute path.  So we must take care to always run
 # INSTALL-type commands from the directory containing the Makefile.
 # This explains (I think) the cd thisdir seen in several install rules.
+SYSTEM_TYPE = @SYSTEM_TYPE@
 INSTALL = @INSTALL@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_INFO = @INSTALL_INFO@
+ifeq ($(SYSTEM_TYPE),cygwin)
+  INSTALL_ELN = $(INSTALL)
+else
+  INSTALL_ELN = $(INSTALL_DATA)
+endif
 # By default, we uphold the dignity of our programs.
 INSTALL_STRIP =
 MKDIR_P = @MKDIR_P@
@@ -307,6 +313,7 @@ TRANSFORM = @program_transform_name@
 EMACS_NAME = `echo emacs | sed '$(TRANSFORM)'`
 EMACS = ${EMACS_NAME}${EXEEXT}
 EMACSFULL = `echo emacs-${version} | sed '$(TRANSFORM)'`${EXEEXT}
+EMACS_PDMP = `./src/emacs${EXEEXT} --fingerprint`.pdmp
 
 # Subdirectories to make recursively.
 SUBDIR = $(NTDIR) lib lib-src src lisp
@@ -515,7 +522,7 @@ install-arch-dep: src install-arch-indep install-etcdoc 
install-$(NTDIR)
 ifeq (${ns_self_contained},no)
        ${INSTALL_PROGRAM} $(INSTALL_STRIP) src/emacs${EXEEXT} 
"$(DESTDIR)${bindir}/$(EMACSFULL)"
 ifeq (${DUMPING},pdumper)
-       ${INSTALL_DATA} src/emacs.pdmp 
"$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs.pdmp
+       ${INSTALL_DATA} src/emacs.pdmp 
"$(DESTDIR)${libexecdir}/emacs/${version}/${configuration}"/emacs-${EMACS_PDMP}
 endif
        -chmod 755 "$(DESTDIR)${bindir}/$(EMACSFULL)"
 ifndef NO_BIN_LINK
@@ -791,7 +798,7 @@ install-eln: lisp
 ifeq ($(HAVE_NATIVE_COMP),yes)
        umask 022 ; \
        find native-lisp -type d -exec $(MKDIR_P) "$(ELN_DESTDIR){}" \; ; \
-       find native-lisp -type f -exec ${INSTALL_DATA} "{}" "$(ELN_DESTDIR){}" 
\;
+       find native-lisp -type f -exec ${INSTALL_ELN} "{}" "$(ELN_DESTDIR){}" \;
 endif
 
 ### Build Emacs and install it, stripping binaries while installing them.
@@ -1158,7 +1165,7 @@ ChangeLog:
          ./$(emacslog) -o $(CHANGELOG) -n $(CHANGELOG_HISTORY_INDEX_MAX)
 
 # Check that we are in a good state for changing history.
-PREFERRED_BRANCH = emacs-27
+PREFERRED_BRANCH = emacs-28
 preferred-branch-is-current:
        git branch | grep -q '^\* $(PREFERRED_BRANCH)$$'
 unchanged-history-files:
diff --git a/README b/README
index a1d5e2dcef..6329a7775e 100644
--- a/README
+++ b/README
@@ -2,7 +2,7 @@ Copyright (C) 2001-2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
 
-This directory tree holds version 28.0.50 of GNU Emacs, the extensible,
+This directory tree holds version 29.0.50 of GNU Emacs, the extensible,
 customizable, self-documenting real-time display editor.
 
 The file INSTALL in this directory says how to build and install GNU
diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES
index 68c12438f5..634d6f3f3b 100644
--- a/admin/CPP-DEFINES
+++ b/admin/CPP-DEFINES
@@ -287,6 +287,7 @@ HAVE_UTIMENSAT
 HAVE_UTMP_H
 HAVE_VFORK
 HAVE_VFORK_H
+HAVE_WEBP
 HAVE_WCHAR_H
 HAVE_WCHAR_T
 HAVE_WINDOW_SYSTEM
diff --git a/admin/authors.el b/admin/authors.el
index 3dec23c191..fd46dabaa3 100644
--- a/admin/authors.el
+++ b/admin/authors.el
@@ -1610,7 +1610,8 @@ and a buffer *Authors Errors* containing references to 
unknown files."
       ;; the versioned ChangeLog.N rather than the unversioned ChangeLog.
       (zerop (call-process "make" nil nil nil
                            "-C" root "change-history-nocommit"))
-      (error "Problem updating ChangeLog, try \"C-u M-x authors RET\""))
+      (error (substitute-command-keys
+              "Problem updating ChangeLog, try \"\\[universal-argument] 
\\[authors]\"")))
   (let ((logs (process-lines find-program root "-name" "ChangeLog*"))
        (table (make-hash-table :test 'equal))
        (buffer-name "*Authors*")
diff --git a/admin/automerge b/admin/automerge
index 61570587d6..d54f6cb4ac 100755
--- a/admin/automerge
+++ b/admin/automerge
@@ -108,7 +108,8 @@ OPTIND=1
 
 
 [ "$nocd" ] || {
-    cd $PD                      # this should be the admin directory
+    # $PD should be the admin directory
+    cd $PD || die "Could not change directory to $PD"
     cd ../
 }
 
diff --git a/admin/charsets/mapfiles/CP720.map 
b/admin/charsets/mapfiles/CP720.map
index e27deac7ee..0e95b5d66e 100644
--- a/admin/charsets/mapfiles/CP720.map
+++ b/admin/charsets/mapfiles/CP720.map
@@ -1,4 +1,4 @@
-# Created manually from <http://en.wikipedia.org/wiki/Code_page_720>.
+# Created manually from <https://en.wikipedia.org/wiki/Code_page_720>.
 # The text in that page is available under the terms of the GNU Free
 # Documentation License.
 0x00-0x7F 0x0000
diff --git a/admin/charsets/mapfiles/CP858.map 
b/admin/charsets/mapfiles/CP858.map
index 753dc50946..d5a59b2c52 100644
--- a/admin/charsets/mapfiles/CP858.map
+++ b/admin/charsets/mapfiles/CP858.map
@@ -1,4 +1,4 @@
-# Created manually from <http://en.wikipedia.org/wiki/Code_page_858>.
+# Created manually from <https://en.wikipedia.org/wiki/Code_page_858>.
 # The text in that page is available under the terms of the GNU Free
 # Documentation License.
 0x00-0x7F 0x0000
diff --git a/admin/emake b/admin/emake
index bdaabc026b..8c37c16055 100755
--- a/admin/emake
+++ b/admin/emake
@@ -28,6 +28,7 @@ s#^Installing git hooks...# Installing git hooks...#
 s#^Running # Running #
 s#^Configured for # Configured for #
 s#^./temacs.*#  \\& #
+s#^make.*Error#  \\& #
 ' | \
 egrep --line-buffered -v "^make|\
 ^Loading|\
diff --git a/admin/gitmerge.el b/admin/gitmerge.el
index 851212c7bb..adb13fc4e2 100644
--- a/admin/gitmerge.el
+++ b/admin/gitmerge.el
@@ -122,7 +122,8 @@ If nil, the function `gitmerge-default-branch' guesses.")
   (with-temp-buffer
     (if (not branch)
         (insert-file-contents "configure.ac")
-      (call-process "git" nil t nil "show" (format "%s:configure.ac" branch))
+      (let ((coding-system-for-read vc-git-log-output-coding-system))
+       (call-process "git" nil t nil "show" (format "%s:configure.ac" branch)))
       (goto-char (point-min)))
     (re-search-forward "^AC_INIT([^,]+, \\([0-9]+\\)\\.")
     (string-to-number (match-string 1))))
@@ -148,7 +149,8 @@ If nil, the function `gitmerge-default-branch' guesses.")
        (pop-to-buffer (get-buffer-create gitmerge-output-buffer))
        (fundamental-mode)
        (erase-buffer)
-       (call-process "git" nil t nil "log" "-1" commit)
+       (let ((coding-system-for-read vc-git-log-output-coding-system))
+         (call-process "git" nil t nil "log" "-1" commit))
        (goto-char (point-min))
        (gitmerge-highlight-skip-regexp)))))
 
@@ -160,7 +162,8 @@ If nil, the function `gitmerge-default-branch' guesses.")
       (when commit
        (pop-to-buffer (get-buffer-create gitmerge-output-buffer))
        (erase-buffer)
-       (call-process "git" nil t nil "diff-tree" "-p" commit)
+       (let ((coding-system-for-read vc-git-log-output-coding-system))
+         (call-process "git" nil t nil "diff-tree" "-p" commit))
        (goto-char (point-min))
        (diff-mode)))))
 
@@ -173,7 +176,9 @@ If nil, the function `gitmerge-default-branch' guesses.")
        (pop-to-buffer (get-buffer-create gitmerge-output-buffer))
        (erase-buffer)
        (fundamental-mode)
-       (call-process "git" nil t nil "diff" "--name-only" (concat commit "^!"))
+       (let ((coding-system-for-read vc-git-log-output-coding-system))
+         (call-process "git" nil t nil "diff" "--name-only"
+                       (concat commit "^!")))
        (goto-char (point-min))))))
 
 (defun gitmerge-toggle-skip ()
@@ -216,9 +221,10 @@ if and why this commit should be skipped."
     ;; Go through the log and remember all commits that match
     ;; `gitmerge-skip-regexp' or are marked by --cherry-mark.
     (with-temp-buffer
-      (call-process "git" nil t nil "log" "--cherry-mark" "--left-only"
-                   "--no-decorate"
-                   (concat from "..." (car (vc-git-branches))))
+      (let ((coding-system-for-read vc-git-log-output-coding-system))
+       (call-process "git" nil t nil "log" "--cherry-mark" "--left-only"
+                     "--no-decorate"
+                     (concat from "..." (car (vc-git-branches)))))
       (goto-char (point-max))
       (while (re-search-backward "^commit \\(.+\\) \\([0-9a-f]+\\).*" nil t)
        (let ((cherrymark (match-string 1))
@@ -241,9 +247,10 @@ if and why this commit should be skipped."
   "Create the buffer for choosing commits."
   (with-current-buffer (get-buffer-create gitmerge-buffer)
     (erase-buffer)
-    (call-process "git" nil t nil "log" "--left-only"
-                 "--pretty=format:%h %<(20,trunc) %an: %<(100,trunc) %s"
-                 (concat from "..." (car (vc-git-branches))))
+    (let ((coding-system-for-read vc-git-log-output-coding-system))
+      (call-process "git" nil t nil "log" "--left-only"
+                   "--pretty=format:%h %<(20,trunc) %an: %<(100,trunc) %s"
+                   (concat from "..." (car (vc-git-branches)))))
     (goto-char (point-min))
     (while (looking-at "^\\([a-f0-9]+\\)")
       (let ((skipreason (gitmerge-skip-commit-p (match-string 1) commits)))
@@ -326,7 +333,8 @@ Returns non-nil if conflicts remain."
             ;; (pop-to-buffer (current-buffer)) (debug 'before-resolve)
             ))
           ;; Try to resolve the conflicts.
-          (let (temp)
+          (let ((coding-system-for-read vc-git-log-output-coding-system)
+               temp)
             (cond
              ;; FIXME when merging release branch to master, we still
              ;; need to detect and handle the case where NEWS was modified
@@ -392,9 +400,10 @@ is nil, only the single commit BEG is merged."
                        (if end "s were " " was ")
                        "skipped:\n\n")
              ""))
-    (apply #'call-process "git" nil t nil "log" "--oneline"
-          (if end (list (concat beg "~.." end))
-            `("-1" ,beg)))
+    (let ((coding-system-for-read vc-git-log-output-coding-system))
+      (apply #'call-process "git" nil t nil "log" "--oneline"
+            (if end (list (concat beg "~.." end))
+              `("-1" ,beg))))
     (insert "\n")
     ;; Truncate to 72 chars so that the resulting ChangeLog line fits in 80.
     (goto-char (point-min))
@@ -408,8 +417,9 @@ MISSING must be a list of SHA1 strings."
   (with-current-buffer (get-buffer-create gitmerge-output-buffer)
     (erase-buffer)
     (let* ((skip (cdar missing))
+          (coding-system-for-read vc-git-log-output-coding-system)
           (beg (car (pop missing)))
-          end commitmessage)
+          end commitmessage commitmessage1 commitmessage-file status)
       ;; Determine last revision with same boolean skip status.
       (while (and missing
                  (eq (null (cdar missing))
@@ -423,12 +433,32 @@ MISSING must be a list of SHA1 strings."
               (if end (concat ".." (substring end 0 6)) ""))
       (unless end
        (setq end beg))
-      (unless (zerop
-              (apply #'call-process "git" nil t nil "merge" "--no-ff"
-                     (append (when skip '("-s" "ours"))
-                             `("-m" ,commitmessage ,end))))
+      (when (eq system-type 'windows-nt)
+        ;; Command lines on MS-Windows cannot include newlines.
+       ;; Since "git merge" doesn't accept a -F FILE option, we
+       ;; commit the merge with a shortened single-line log message,
+       ;; and then invoke "git commit --amend" with the full log
+       ;; message from a temporary file.
+       (setq commitmessage1
+             ;; Make sure the commit message is at most a single line.
+             (car (split-string commitmessage "[\f\n\r\v]+")))
+       (setq commitmessage-file (make-nearby-temp-file "gitmerge-msg"))
+       (let ((coding-system-for-write vc-git-commits-coding-system))
+         (write-region commitmessage nil commitmessage-file nil 'silent)))
+      (unless (setq status
+                   (zerop
+                    (apply #'call-process "git" nil t nil "merge" "--no-ff"
+                           (append (when skip '("-s" "ours"))
+                                   (if commitmessage-file
+                                       `("-m" ,commitmessage1 ,end)
+                                     `("-m" ,commitmessage ,end))))))
        (gitmerge-write-missing missing from)
-       (gitmerge-resolve-unmerged)))
+       (gitmerge-resolve-unmerged))
+      (when (and commitmessage-file (file-exists-p commitmessage-file))
+       (if status
+           (call-process "git" nil t nil
+                         "commit" "--amend" "-F" commitmessage-file))
+       (delete-file commitmessage-file)))
     missing))
 
 (defun gitmerge-resolve-unmerged ()
@@ -436,7 +466,8 @@ MISSING must be a list of SHA1 strings."
 Throw an user-error if we cannot resolve automatically."
   (with-current-buffer (get-buffer-create gitmerge-output-buffer)
     (erase-buffer)
-    (let (files conflicted)
+    (let ((coding-system-for-read vc-git-log-output-coding-system)
+         files conflicted)
       ;; List unmerged files
       (if (not (zerop
                (call-process "git" nil t nil
@@ -479,17 +510,19 @@ Throw an user-error if we cannot resolve automatically."
 (defun gitmerge-repo-clean ()
   "Return non-nil if repository is clean."
   (with-temp-buffer
+    (let ((coding-system-for-read vc-git-log-output-coding-system))
       (call-process "git" nil t nil
                    "diff" "--staged" "--name-only")
       (call-process "git" nil t nil
                    "diff" "--name-only")
-      (zerop (buffer-size))))
+      (zerop (buffer-size)))))
 
 (defun gitmerge-commit ()
   "Commit, and return non-nil if it succeeds."
   (with-current-buffer (get-buffer-create gitmerge-output-buffer)
-    (erase-buffer)
-    (eq 0 (call-process "git" nil t nil "commit" "--no-edit"))))
+    (let ((coding-system-for-read vc-git-log-output-coding-system))
+      (erase-buffer)
+      (eq 0 (call-process "git" nil t nil "commit" "--no-edit")))))
 
 (defun gitmerge-maybe-resume ()
   "Check if we have to resume a merge.
@@ -603,7 +636,7 @@ Branch FROM will be prepended to the list."
                "(s) Toggle skip, (l) Show log, (d) Show diff, "
                "(f) Show files, (m) Start merge\n"
                (propertize "Flags:    " 'font-lock-face 'bold)
-               "(C) Detected backport (cherry-mark), (R) Log matches "
+               "(C) Detected backport (cherry-mark), (R) Matches skip "
                "regexp, (M) Manually picked\n\n")
        (gitmerge-mode)
        (pop-to-buffer (current-buffer))
diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt
index ae007d76b0..22276080c5 100644
--- a/admin/make-tarball.txt
+++ b/admin/make-tarball.txt
@@ -42,6 +42,12 @@ General steps (for each step, check for possible errors):
     because some of the commands below run Make, so they need
     Makefiles to be present.
 
+    For Emacs 28, and as long as --with-native-compilation is not the
+    default, the tree needs to be configured with native-compilation
+    enabled, to ensure all the pertinent *.elc files will end up in
+    the tarball.  Otherwise, the *.eln files might not build correctly
+    on the user's system.
+
 2.  Regenerate the etc/AUTHORS file:
       M-: (require 'authors) RET
       M-x authors RET
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index c12e83dd2f..c9fe3b2f95 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -30,7 +30,8 @@ GNULIB_MODULES='
   canonicalize-lgpl
   careadlinkat close-stream copy-file-range
   count-leading-zeros count-one-bits count-trailing-zeros
-  crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer 
crypto/sha512-buffer
+  crypto/md5 crypto/md5-buffer
+  crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
   d-type diffseq double-slash-root dtoastr dtotimespec dup2
   environ execinfo explicit_bzero faccessat
   fchmodat fcntl fcntl-h fdopendir file-has-acl
@@ -38,7 +39,8 @@ GNULIB_MODULES='
   free-posix fstatat fsusage fsync futimens
   getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
   ieee754-h ignore-value intprops largefile libgmp lstat
-  manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime nstrftime
+  manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime
+  nproc nstrftime
   pathmax pipe2 pselect pthread_sigmask
   qcopy-acl readlink readlinkat regex
   sig2str sigdescr_np socklen stat-time std-gnu11 stdalign stddef stdio
@@ -49,8 +51,8 @@ GNULIB_MODULES='
 '
 
 AVOIDED_MODULES='
-  btowc close dup fchdir fstat langinfo lock
-  malloc-posix mbrtowc mbsinit memchr mkdir msvc-inval msvc-nothrow nl_langinfo
+  btowc close crypto/af_alg dup fchdir fstat langinfo lock
+  mbrtowc mbsinit memchr mkdir msvc-inval msvc-nothrow nl_langinfo
   openat-die opendir pthread-h raise
   save-cwd select setenv sigprocmask stat stdarg stdbool
   threadlib tzset unsetenv utime utime-h
@@ -118,5 +120,8 @@ cp -- "$gnulib_srcdir"/build-aux/config.guess \
       "$gnulib_srcdir"/build-aux/install-sh \
       "$gnulib_srcdir"/build-aux/move-if-change \
    "$src"build-aux &&
+cp -- "$gnulib_srcdir"/lib/af_alg.h \
+      "$gnulib_srcdir"/lib/save-cwd.h \
+   "$src"lib &&
 { test -z "$src" || cd "$src"; } &&
 ./autogen.sh
diff --git a/admin/notes/bugtracker b/admin/notes/bugtracker
index 9eb65e1f86..deb06f552c 100644
--- a/admin/notes/bugtracker
+++ b/admin/notes/bugtracker
@@ -84,7 +84,7 @@ generate a new report.  The only time to send mail to the bug 
list
 address is to create a new report.
 
 Gnus users can add the following to message-dont-reply-to-names;
-similarly with Rmail and rmail-dont-reply-to-names:
+similarly with Rmail and mail-dont-reply-to-names:
 
 "\\(emacs-pretest-bug\\|bug-gnu-emacs\\|bug-\\(e\\|gnu\\)macs\\)@gnu\\.org\\|\
 \\(submit\\|control\\|owner\\)@debbugs\\.gnu\\.org"
diff --git a/admin/notes/emba b/admin/notes/emba
index 36b126e773..4e500bc92c 100644
--- a/admin/notes/emba
+++ b/admin/notes/emba
@@ -31,20 +31,26 @@ The Emacs jobset is defined in the Emacs source tree, file
 '.gitlab-ci.yml'.  It could be adapted for every Emacs branch, see
 <https://emba.gnu.org/help/ci/yaml/README.md>.
 
+A jobset on Gitlab is called pipeline.  Emacs pipelines run through
+the stages 'build-images', 'platform-images' and 'native-comp-images'
+(create an Emacs instance by 'make bootstrap' with different
+configuration parameters) as well as 'normal', 'slow', 'platforms' and
+'native-comp' (run respective test jobs based on the produced images).
+
 Every job runs in a Debian docker container.  It uses the local clone
 of the Emacs git repository to perform a bootstrap and test of Emacs.
 This could happen for several jobs with changed configuration, compile
 and test parameters.
 
-There are different types of jobs: 'prep-image-base' is responsible to
-prepare the environment for the following jobs.  'build-image-*' jobs
-are responsible to compile Emacs in different configuration.  The
-corresponding 'test-*' jobs run the ert tests.
+The 'build-image-*' jobs of the different '*-images' stages run only
+if there are severe changes in the Emacs sources, like in Makefiles
+etc.  Otherwise they are skipped, and the corresponding 'test-*' jobs
+run just 'make -C test ...' in the respective Docker image from a
+previous build run.
 
-A special job is 'test-all-inotify', which runs 'make check-expensive'.
-While most of the jobs run as soon as a respective file has been
-committed into the Emacs git repository, this test job runs scheduled,
-every 8 hours.
+Jobs in the 'build-images' and 'normal' stages are triggered by
+changes of respective files in the Emacs git repository.  All other
+jobs run scheduled in a pipeline every 8 hours.
 
 The log files for every test job are kept on the server for a week.
 They can be downloaded from the server, visiting the URL
diff --git a/admin/notes/git-workflow b/admin/notes/git-workflow
index d109cdaa35..265a106bad 100644
--- a/admin/notes/git-workflow
+++ b/admin/notes/git-workflow
@@ -16,14 +16,14 @@ Initial setup
 
 Then we want to clone the repository.  We normally want to have both
 the current master and (if there is one) the active release branch
-(eg emacs-27).
+(eg emacs-28).
 
 mkdir ~/emacs
 cd ~/emacs
 git clone <membername>@git.sv.gnu.org:/srv/git/emacs.git master
 cd master
 git config push.default current
-git worktree add ../emacs-27 emacs-27
+git worktree add ../emacs-28 emacs-28
 
 You now have both branches conveniently accessible, and you can do
 "git pull" in them once in a while to keep updated.
@@ -67,7 +67,7 @@ which will look like
 
 commit 958b768a6534ae6e77a8547a56fc31b46b63710b
 
-cd ~/emacs/emacs-27
+cd ~/emacs/emacs-28
 git cherry-pick -xe 958b768a6534ae6e77a8547a56fc31b46b63710b
 
 and add "Backport:" to the commit string.  Then
@@ -109,7 +109,7 @@ up-to-date by doing a pull.  Then start Emacs with
   emacs -l admin/gitmerge.el -f gitmerge
 
 You'll be asked for the branch to merge, which will default to
-(eg) 'origin/emacs-27', which you should accept.  Merging a local tracking
+(eg) 'origin/emacs-28', which you should accept.  Merging a local tracking
 branch is discouraged, since it might not be up-to-date, or worse,
 contain commits from you which are not yet pushed upstream.
 
diff --git a/admin/notes/multi-tty b/admin/notes/multi-tty
index 1a337b9d79..fa4df820ae 100644
--- a/admin/notes/multi-tty
+++ b/admin/notes/multi-tty
@@ -474,7 +474,7 @@ THINGS TO DO
    definition.
 
    Exceptions found so far: x-select-text and
-   x-cut-buffer-or-selection-value.
+   x-selection-value (old name: x-cut-buffer-or-selection-value).
 
 ** Have a look at fatal_error_hook.
 
diff --git a/admin/notes/unicode b/admin/notes/unicode
index 21233ac281..be51d09d37 100644
--- a/admin/notes/unicode
+++ b/admin/notes/unicode
@@ -21,11 +21,14 @@ Emacs uses the following files from the Unicode Character 
Database
   . emoji-sequences.txt
   . BidiCharacterTest.txt
 
-First, the first 10 files need to be copied into admin/unidata/, and
-the file https://www.unicode.org/copyright.html should be copied over
-copyright.html in admin/unidata (some of them might need trailing
-whitespace removed before they can be committed to the Emacs
-repository).
+Emacs also uses the file emoji-test.txt which should be imported from
+the Unicode's Public/emoji/ directory.
+
+First, the first 10 files and emoji-test.txt need to be copied into
+admin/unidata/, and the file https://www.unicode.org/copyright.html
+should be copied over copyright.html in admin/unidata (some of them
+might need trailing whitespace removed before they can be committed to
+the Emacs repository).
 
 Then Emacs should be rebuilt for them to take effect.  Rebuilding
 Emacs updates several derived files elsewhere in the Emacs source
@@ -116,8 +119,12 @@ FONT-NAME-REGEXP is checked using `string-match'."
 
 Visit "emoji-zwj-sequences.txt" and "emoji-sequences.txt" with the
 rebuilt Emacs, and check that the sample sequences are composed
-properly.  Note that your emoji font might not have glyphs for the
-newest codepoints yet.
+properly.  Also check the Unicode style chart file available at
+https://unicode.org/emoji/charts/emoji-style.txt for any issues
+involving VS-15 and VS-16, if so you may need to update the value
+generated for auto-composition-emoji-eligible-codepoints by
+admin/unidata/emoji-zwj.awk.  Note that your emoji font might not have
+glyphs for the newest codepoints yet.
 
 Finally, etc/NEWS should be updated to announce the support for the
 new Unicode version.
diff --git a/admin/nt/dist-build/README-scripts 
b/admin/nt/dist-build/README-scripts
index f27bcd3bd6..6b1adbe03e 100644
--- a/admin/nt/dist-build/README-scripts
+++ b/admin/nt/dist-build/README-scripts
@@ -3,6 +3,15 @@ Distribution Build Scripts for Windows
 
 The scripts are used to build the binary distribution zip files for windows.
 
+Environment
+-----------
+
+A full installation of msys2 is required along for the build. The
+various dependencies of Emacs need to be installed also. These change
+over time, but are listed in build-deps-zips.py.
+
+
+
 File System Organization
 ------------------------
 
@@ -15,15 +24,19 @@ The file system needs to be organized like so:
 
 ~/emacs-build/git
 
-Contains a checkout of the Emacs git repository, organized according
-to branches, with git worktree
+Contains checkouts and worktrees of the Emacs git repository,
+organized according to branches.
 
-~/emacs-build/git/emacs-$branch
+~/emacs-build/git/master
 
-A branch of the git repository containing the current release
+A checkout out of the master branch of the Emacs git repository.
+
+~/emacs-build/git/emacs-$major-version
+
+A worktree of the git repository containing the current release
 branch. This has to be created by hand.
 
-~/emacs-build/git/emacs-$version
+~/emacs-build/git/emacs-$release-version
 
 A branch of the git repository containing the last release. The
 build-zips.sh file will create this for you.
@@ -63,8 +76,8 @@ uploaded.
 Build Process
 -------------
 
-For each major version
-----------------------
+
+### For each major version
 
 The dependencies files need to be created. This can be around the time
 of the pre-tests, then used for all releases of that version, to
@@ -88,8 +101,7 @@ files will be created in ~/emacs-upload from where they can 
be signed
 and uploaded with `gnupload`.
 
 
-For snapshots from Master
--------------------------
+### For snapshots from Master
 
 Snapshots are generally created from master when there is a release
 branch on which a release has already been created. At this point,
@@ -110,8 +122,7 @@ used.
 Now, run `build-zips.sh -s` to build a snapshot release.
 
 
-For snapshots from a Release Branch
------------------------------------
+### For snapshots from a Release Branch
 
 Snapshots can be built from a release branch; this is really only
 useful before a pre-test has happened.
@@ -123,8 +134,8 @@ version number must be added to the command line with 
`build-zips.sh
 the version (e.g emacs-27-2019-12-26.zip) rather than than the Emacs
 version (e.g emacs-27.0.50.zip).
 
-For snapshots from another branch
----------------------------------
+
+### For snapshots from another branch
 
 Snapshots can be build from any other branch.  There is rarely a need
 to do this, except where some significant, wide-ranging feature is
diff --git a/admin/release-branch.txt b/admin/release-branch.txt
new file mode 100644
index 0000000000..0c393a9ecc
--- /dev/null
+++ b/admin/release-branch.txt
@@ -0,0 +1,76 @@
+Instructions for cutting the Emacs release branch
+
+1.  In the clone of the Emacs Git repository, switch to the 'master'
+    branch, "git pull", and build it (using 'make bootstrap') to make
+    sure it's not broken.  Run 'make check-expensive' and ensure all
+    tests pass.  (Alternatively, verify that the automated build
+    servers are showing success for the latest revision.)
+
+2.  Create the release branch and switch to it.  Assuming that it is
+    for releasing Emacs versions XY.1, XY.2, etc., the command is:
+
+     git checkout -b emacs-XY
+
+3.  Switch the release branch to the suitable version.  The convention
+    is that release branches start with version XY.0.60, whereas the
+    master branch from which the release branch was cut was at the
+    version XY.0.50.  To change the version, do the following inside
+    Emacs:
+
+     M-x load-file RET admin/admin.el RET
+     M-x set-version RET XY.0.60 RET
+
+    Change the value of 'customize-changed-options-previous-release'
+    in cus-edit.el to reference the last release from the emacs-XY-1
+    branch (last release for the previous major version).
+
+    The above modifies several files in the tree; commit the changes
+    with the appropriate log message, something like "Bump Emacs
+    version to XY.0.60", and with header saying "Cut the emacs-XY
+    release branch".  Then push the changes:
+
+     git push --set-upstream origin emacs-XY
+
+    The "push" command should show the new branch just created.
+
+4.  Switch back to the master branch.
+
+     git checkout master
+     git pull
+
+    Set the version on the master branch to the next major release:
+
+     M-x set-version RET XY+1.0.50 RET
+
+    This creates a new file etc/NEWS.XY.  "git add" it.
+
+    Change the value of 'customize-changed-options-previous-release'
+    in cus-edit.el to reference emacs-XY.1, the next version to be
+    released from the newly-committed release branch.
+
+    Update the emacs-module sources for the new version XY+1.  This
+    entails:
+
+     . adding a new file src/module-env-XY+1.h, with contents just the
+       comment taken from the beginning of src/module-env-XY.h
+     . removing the comment from the beginning of src/module-env-XY.h
+     . adding two lines to configure.ac:
+
+       AC_SUBST_FILE([module_env_snippet_XY+1])
+       module_env_snippet_XY+1="$srcdir/src/module-env-XY+1.h"
+
+     . adding a new 'struct emacs_env_XY+1' to src/emacs-module.h.in,
+       with the contents identical to'struct emacs_env_XY', with one
+       line added:
+
+         @module_env_snippet_XY+1@
+
+     (FIXME: "M-x set-version" should do this emacs-module stuff
+     automatically when the version is NN.0.60, or when there's no
+     src/module-env-NN.h file.)
+
+    "git add" the new src/module-env-XY+1.h file.
+
+    Then rebuild Emacs.  Then commit the new/changed files and push.
+
+5.  Announce the new release branch on emacs-devel.
diff --git a/admin/unidata/Makefile.in b/admin/unidata/Makefile.in
index a2a2e425ff..701fb92b81 100644
--- a/admin/unidata/Makefile.in
+++ b/admin/unidata/Makefile.in
@@ -41,7 +41,7 @@ unifiles = $(addprefix ${unidir}/,$(sort $(shell sed -n 's/^[ 
\t][ \t]*${lparen}
 .PHONY: all
 
 all: ${top_srcdir}/src/macuvs.h ${unifiles} ${unidir}/charscript.el \
-  ${unidir}/charprop.el ${unidir}/emoji-zwj.el
+  ${unidir}/charprop.el ${unidir}/emoji-zwj.el ${unidir}/emoji-labels.el
 
 ## Specify .elc as an order-only prereq so as to not needlessly rebuild
 ## target just because the .elc is missing.
@@ -72,9 +72,12 @@ ${unifiles}: ${srcdir}/unidata-gen.el \
   ${srcdir}/BidiBrackets.txt | \
   ${srcdir}/unidata-gen.elc unidata.txt
        $(AM_V_at)[ ! -f $@ ] || chmod +w $@
-       $(AM_V_GEN)${emacs} -L ${srcdir} -l unidata-gen \
+       $(AM_V_at)${emacs} -L ${srcdir} -l unidata-gen \
          -f unidata-gen-file $@ ${srcdir}
 
+${unidir}/emoji-labels.el: ${unidir}/../international/emoji.el \
+         ${srcdir}/emoji-test.txt
+       $(AM_V_at)${emacs} -l emoji.el -f emoji--generate-file $@
 
 .PHONY: charscript.el
 charscript.el: ${unidir}/charscript.el
@@ -91,8 +94,8 @@ emoji-zwj.el: ${unidir}/emoji-zwj.el
 
 zwj = ${srcdir}/emoji-zwj.awk
 
-${unidir}/emoji-zwj.el: ${srcdir}/emoji-zwj-sequences.txt ${zwj}
-       $(AM_V_GEN)$(AWK) -f ${zwj} < $< > $@
+${unidir}/emoji-zwj.el: ${srcdir}/emoji-zwj-sequences.txt 
$(srcdir)/emoji-sequences.txt ${zwj}
+       $(AM_V_GEN)$(AWK) -f ${zwj} $^ > $@
 
 .PHONY: clean bootstrap-clean distclean maintainer-clean gen-clean
 
@@ -113,6 +116,7 @@ gen-clean:
        rm -f ${unidir}/charscript.el*
        rm -f ${unidir}/emoji-zwj.el*
        rm -f ${unifiles} ${unidir}/charprop.el
+       rm -f ${unidir}/emoji-labels.el*
 ## ref: https://lists.gnu.org/r/emacs-devel/2013-11/msg01029.html
 
 maintainer-clean: gen-clean distclean
diff --git a/admin/unidata/README b/admin/unidata/README
index 656ee15c54..4b8444b0fe 100644
--- a/admin/unidata/README
+++ b/admin/unidata/README
@@ -44,3 +44,7 @@ 
https://www.unicode.org/Public/emoji/14.0/emoji-zwj-sequences.txt
 emoji-sequences.txt
 https://www.unicode.org/Public/emoji/14.0/emoji-sequences.txt
 2020-08-26
+
+emoji-test.txt
+https://unicode.org/Public/emoji/14.0/emoji-test.txt
+2021-10-28
diff --git a/admin/unidata/blocks.awk b/admin/unidata/blocks.awk
index eab778cb1e..314ac3e939 100755
--- a/admin/unidata/blocks.awk
+++ b/admin/unidata/blocks.awk
@@ -221,24 +221,11 @@ FILENAME ~ "emoji-data.txt" && /^[0-9A-F].*; 
Emoji_Presentation / {
 }
 
 END {
-    ## These codepoints have Emoji_Presentation = No, but they are
-    ## used in emoji-sequences.txt and emoji-zwj-sequences.txt (with a
-    ## Variation Selector), so force them into the emoji script so
-    ## they will get composed correctly.  FIXME: delete this when we
-    ## can change the font used for a codepoint based on whether it's
-    ## followed by a VS (usually VS-16)
     idx = 0
-    override_start[idx] = "1F3CB"
-    override_end[idx] = "1F3CC"
-    idx++
-    override_start[idx] = "1F3F3"
-    override_end[idx] = "1F3F4"
-    idx++
-    override_start[idx] = "1F441"
-    override_end[idx] = "1F441"
-    idx++
-    override_start[idx] = "1F575"
-    override_end[idx] = "1F575"
+    # ## These are here so that font_range can choose Emoji presentation
+    # ## for the preceding codepoint when it encounters a VS
+    override_start[idx] = "FE00"
+    override_end[idx] = "FE0F"
 
     for (k in override_start)
     {
@@ -250,7 +237,7 @@ END {
     }
 
     print ";;; charscript.el --- character script table  -*- lexical-binding:t 
-*-"
-    print ";;; Automatically generated from admin/unidata/Blocks.txt"
+    print ";;; Automatically generated from 
admin/unidata/{Blocks,emoji-data}.txt"
     print "(let (script-list)"
     print "  (dolist (elt '("
 
diff --git a/admin/unidata/emoji-test.txt b/admin/unidata/emoji-test.txt
new file mode 100644
index 0000000000..42e6210cd2
--- /dev/null
+++ b/admin/unidata/emoji-test.txt
@@ -0,0 +1,4991 @@
+# emoji-test.txt
+# Date: 2021-08-26, 17:22:23 GMT
+# © 2021 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in 
the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Emoji Keyboard/Display Test Data for UTS #51
+# Version: 14.0
+#
+# For documentation and usage, see http://www.unicode.org/reports/tr51
+#
+# This file provides data for testing which emoji forms should be in keyboards 
and which should also be displayed/processed.
+# Format: code points; status # emoji name
+#     Code points — list of one or more hex code points, separated by spaces
+#     Status
+#       component           — an Emoji_Component,
+#                             excluding Regional_Indicators, ASCII, and 
non-Emoji.
+#       fully-qualified     — a fully-qualified emoji (see ED-18 in UTS #51),
+#                             excluding Emoji_Component
+#       minimally-qualified — a minimally-qualified emoji (see ED-18a in UTS 
#51)
+#       unqualified         — a unqualified emoji (See ED-19 in UTS #51)
+# Notes:
+#   • This includes the emoji components that need emoji presentation (skin 
tone and hair)
+#     when isolated, but omits the components that need not have an emoji
+#     presentation when isolated.
+#   • The RGI set is covered by the listed fully-qualified emoji.
+#   • The listed minimally-qualified and unqualified cover all cases where an
+#     element of the RGI set is missing one or more emoji presentation 
selectors.
+#   • The file is in CLDR order, not codepoint order. This is recommended (but 
not required!) for keyboard palettes.
+#   • The groups and subgroups are illustrative. See the Emoji Order chart for 
more information.
+
+
+# group: Smileys & Emotion
+
+# subgroup: face-smiling
+1F600                                                  ; fully-qualified     # 
😀 E1.0 grinning face
+1F603                                                  ; fully-qualified     # 
😃 E0.6 grinning face with big eyes
+1F604                                                  ; fully-qualified     # 
😄 E0.6 grinning face with smiling eyes
+1F601                                                  ; fully-qualified     # 
😁 E0.6 beaming face with smiling eyes
+1F606                                                  ; fully-qualified     # 
😆 E0.6 grinning squinting face
+1F605                                                  ; fully-qualified     # 
😅 E0.6 grinning face with sweat
+1F923                                                  ; fully-qualified     # 
🤣 E3.0 rolling on the floor laughing
+1F602                                                  ; fully-qualified     # 
😂 E0.6 face with tears of joy
+1F642                                                  ; fully-qualified     # 
🙂 E1.0 slightly smiling face
+1F643                                                  ; fully-qualified     # 
🙃 E1.0 upside-down face
+1FAE0                                                  ; fully-qualified     # 
🫠 E14.0 melting face
+1F609                                                  ; fully-qualified     # 
😉 E0.6 winking face
+1F60A                                                  ; fully-qualified     # 
😊 E0.6 smiling face with smiling eyes
+1F607                                                  ; fully-qualified     # 
😇 E1.0 smiling face with halo
+
+# subgroup: face-affection
+1F970                                                  ; fully-qualified     # 
🥰 E11.0 smiling face with hearts
+1F60D                                                  ; fully-qualified     # 
😍 E0.6 smiling face with heart-eyes
+1F929                                                  ; fully-qualified     # 
🤩 E5.0 star-struck
+1F618                                                  ; fully-qualified     # 
😘 E0.6 face blowing a kiss
+1F617                                                  ; fully-qualified     # 
😗 E1.0 kissing face
+263A FE0F                                              ; fully-qualified     # 
☺️ E0.6 smiling face
+263A                                                   ; unqualified         # 
☺ E0.6 smiling face
+1F61A                                                  ; fully-qualified     # 
😚 E0.6 kissing face with closed eyes
+1F619                                                  ; fully-qualified     # 
😙 E1.0 kissing face with smiling eyes
+1F972                                                  ; fully-qualified     # 
🥲 E13.0 smiling face with tear
+
+# subgroup: face-tongue
+1F60B                                                  ; fully-qualified     # 
😋 E0.6 face savoring food
+1F61B                                                  ; fully-qualified     # 
😛 E1.0 face with tongue
+1F61C                                                  ; fully-qualified     # 
😜 E0.6 winking face with tongue
+1F92A                                                  ; fully-qualified     # 
🤪 E5.0 zany face
+1F61D                                                  ; fully-qualified     # 
😝 E0.6 squinting face with tongue
+1F911                                                  ; fully-qualified     # 
🤑 E1.0 money-mouth face
+
+# subgroup: face-hand
+1F917                                                  ; fully-qualified     # 
🤗 E1.0 smiling face with open hands
+1F92D                                                  ; fully-qualified     # 
🤭 E5.0 face with hand over mouth
+1FAE2                                                  ; fully-qualified     # 
🫢 E14.0 face with open eyes and hand over mouth
+1FAE3                                                  ; fully-qualified     # 
🫣 E14.0 face with peeking eye
+1F92B                                                  ; fully-qualified     # 
🤫 E5.0 shushing face
+1F914                                                  ; fully-qualified     # 
🤔 E1.0 thinking face
+1FAE1                                                  ; fully-qualified     # 
🫡 E14.0 saluting face
+
+# subgroup: face-neutral-skeptical
+1F910                                                  ; fully-qualified     # 
🤐 E1.0 zipper-mouth face
+1F928                                                  ; fully-qualified     # 
🤨 E5.0 face with raised eyebrow
+1F610                                                  ; fully-qualified     # 
😐 E0.7 neutral face
+1F611                                                  ; fully-qualified     # 
😑 E1.0 expressionless face
+1F636                                                  ; fully-qualified     # 
😶 E1.0 face without mouth
+1FAE5                                                  ; fully-qualified     # 
🫥 E14.0 dotted line face
+1F636 200D 1F32B FE0F                                  ; fully-qualified     # 
😶‍🌫️ E13.1 face in clouds
+1F636 200D 1F32B                                       ; minimally-qualified # 
😶‍🌫 E13.1 face in clouds
+1F60F                                                  ; fully-qualified     # 
😏 E0.6 smirking face
+1F612                                                  ; fully-qualified     # 
😒 E0.6 unamused face
+1F644                                                  ; fully-qualified     # 
🙄 E1.0 face with rolling eyes
+1F62C                                                  ; fully-qualified     # 
😬 E1.0 grimacing face
+1F62E 200D 1F4A8                                       ; fully-qualified     # 
😮‍💨 E13.1 face exhaling
+1F925                                                  ; fully-qualified     # 
🤥 E3.0 lying face
+
+# subgroup: face-sleepy
+1F60C                                                  ; fully-qualified     # 
😌 E0.6 relieved face
+1F614                                                  ; fully-qualified     # 
😔 E0.6 pensive face
+1F62A                                                  ; fully-qualified     # 
😪 E0.6 sleepy face
+1F924                                                  ; fully-qualified     # 
🤤 E3.0 drooling face
+1F634                                                  ; fully-qualified     # 
😴 E1.0 sleeping face
+
+# subgroup: face-unwell
+1F637                                                  ; fully-qualified     # 
😷 E0.6 face with medical mask
+1F912                                                  ; fully-qualified     # 
🤒 E1.0 face with thermometer
+1F915                                                  ; fully-qualified     # 
🤕 E1.0 face with head-bandage
+1F922                                                  ; fully-qualified     # 
🤢 E3.0 nauseated face
+1F92E                                                  ; fully-qualified     # 
🤮 E5.0 face vomiting
+1F927                                                  ; fully-qualified     # 
🤧 E3.0 sneezing face
+1F975                                                  ; fully-qualified     # 
🥵 E11.0 hot face
+1F976                                                  ; fully-qualified     # 
🥶 E11.0 cold face
+1F974                                                  ; fully-qualified     # 
🥴 E11.0 woozy face
+1F635                                                  ; fully-qualified     # 
😵 E0.6 face with crossed-out eyes
+1F635 200D 1F4AB                                       ; fully-qualified     # 
😵‍💫 E13.1 face with spiral eyes
+1F92F                                                  ; fully-qualified     # 
🤯 E5.0 exploding head
+
+# subgroup: face-hat
+1F920                                                  ; fully-qualified     # 
🤠 E3.0 cowboy hat face
+1F973                                                  ; fully-qualified     # 
🥳 E11.0 partying face
+1F978                                                  ; fully-qualified     # 
🥸 E13.0 disguised face
+
+# subgroup: face-glasses
+1F60E                                                  ; fully-qualified     # 
😎 E1.0 smiling face with sunglasses
+1F913                                                  ; fully-qualified     # 
🤓 E1.0 nerd face
+1F9D0                                                  ; fully-qualified     # 
🧐 E5.0 face with monocle
+
+# subgroup: face-concerned
+1F615                                                  ; fully-qualified     # 
😕 E1.0 confused face
+1FAE4                                                  ; fully-qualified     # 
🫤 E14.0 face with diagonal mouth
+1F61F                                                  ; fully-qualified     # 
😟 E1.0 worried face
+1F641                                                  ; fully-qualified     # 
🙁 E1.0 slightly frowning face
+2639 FE0F                                              ; fully-qualified     # 
☹️ E0.7 frowning face
+2639                                                   ; unqualified         # 
☹ E0.7 frowning face
+1F62E                                                  ; fully-qualified     # 
😮 E1.0 face with open mouth
+1F62F                                                  ; fully-qualified     # 
😯 E1.0 hushed face
+1F632                                                  ; fully-qualified     # 
😲 E0.6 astonished face
+1F633                                                  ; fully-qualified     # 
😳 E0.6 flushed face
+1F97A                                                  ; fully-qualified     # 
🥺 E11.0 pleading face
+1F979                                                  ; fully-qualified     # 
🥹 E14.0 face holding back tears
+1F626                                                  ; fully-qualified     # 
😦 E1.0 frowning face with open mouth
+1F627                                                  ; fully-qualified     # 
😧 E1.0 anguished face
+1F628                                                  ; fully-qualified     # 
😨 E0.6 fearful face
+1F630                                                  ; fully-qualified     # 
😰 E0.6 anxious face with sweat
+1F625                                                  ; fully-qualified     # 
😥 E0.6 sad but relieved face
+1F622                                                  ; fully-qualified     # 
😢 E0.6 crying face
+1F62D                                                  ; fully-qualified     # 
😭 E0.6 loudly crying face
+1F631                                                  ; fully-qualified     # 
😱 E0.6 face screaming in fear
+1F616                                                  ; fully-qualified     # 
😖 E0.6 confounded face
+1F623                                                  ; fully-qualified     # 
😣 E0.6 persevering face
+1F61E                                                  ; fully-qualified     # 
😞 E0.6 disappointed face
+1F613                                                  ; fully-qualified     # 
😓 E0.6 downcast face with sweat
+1F629                                                  ; fully-qualified     # 
😩 E0.6 weary face
+1F62B                                                  ; fully-qualified     # 
😫 E0.6 tired face
+1F971                                                  ; fully-qualified     # 
🥱 E12.0 yawning face
+
+# subgroup: face-negative
+1F624                                                  ; fully-qualified     # 
😤 E0.6 face with steam from nose
+1F621                                                  ; fully-qualified     # 
😡 E0.6 pouting face
+1F620                                                  ; fully-qualified     # 
😠 E0.6 angry face
+1F92C                                                  ; fully-qualified     # 
🤬 E5.0 face with symbols on mouth
+1F608                                                  ; fully-qualified     # 
😈 E1.0 smiling face with horns
+1F47F                                                  ; fully-qualified     # 
👿 E0.6 angry face with horns
+1F480                                                  ; fully-qualified     # 
💀 E0.6 skull
+2620 FE0F                                              ; fully-qualified     # 
☠️ E1.0 skull and crossbones
+2620                                                   ; unqualified         # 
☠ E1.0 skull and crossbones
+
+# subgroup: face-costume
+1F4A9                                                  ; fully-qualified     # 
💩 E0.6 pile of poo
+1F921                                                  ; fully-qualified     # 
🤡 E3.0 clown face
+1F479                                                  ; fully-qualified     # 
👹 E0.6 ogre
+1F47A                                                  ; fully-qualified     # 
👺 E0.6 goblin
+1F47B                                                  ; fully-qualified     # 
👻 E0.6 ghost
+1F47D                                                  ; fully-qualified     # 
👽 E0.6 alien
+1F47E                                                  ; fully-qualified     # 
👾 E0.6 alien monster
+1F916                                                  ; fully-qualified     # 
🤖 E1.0 robot
+
+# subgroup: cat-face
+1F63A                                                  ; fully-qualified     # 
😺 E0.6 grinning cat
+1F638                                                  ; fully-qualified     # 
😸 E0.6 grinning cat with smiling eyes
+1F639                                                  ; fully-qualified     # 
😹 E0.6 cat with tears of joy
+1F63B                                                  ; fully-qualified     # 
😻 E0.6 smiling cat with heart-eyes
+1F63C                                                  ; fully-qualified     # 
😼 E0.6 cat with wry smile
+1F63D                                                  ; fully-qualified     # 
😽 E0.6 kissing cat
+1F640                                                  ; fully-qualified     # 
🙀 E0.6 weary cat
+1F63F                                                  ; fully-qualified     # 
😿 E0.6 crying cat
+1F63E                                                  ; fully-qualified     # 
😾 E0.6 pouting cat
+
+# subgroup: monkey-face
+1F648                                                  ; fully-qualified     # 
🙈 E0.6 see-no-evil monkey
+1F649                                                  ; fully-qualified     # 
🙉 E0.6 hear-no-evil monkey
+1F64A                                                  ; fully-qualified     # 
🙊 E0.6 speak-no-evil monkey
+
+# subgroup: emotion
+1F48B                                                  ; fully-qualified     # 
💋 E0.6 kiss mark
+1F48C                                                  ; fully-qualified     # 
💌 E0.6 love letter
+1F498                                                  ; fully-qualified     # 
💘 E0.6 heart with arrow
+1F49D                                                  ; fully-qualified     # 
💝 E0.6 heart with ribbon
+1F496                                                  ; fully-qualified     # 
💖 E0.6 sparkling heart
+1F497                                                  ; fully-qualified     # 
💗 E0.6 growing heart
+1F493                                                  ; fully-qualified     # 
💓 E0.6 beating heart
+1F49E                                                  ; fully-qualified     # 
💞 E0.6 revolving hearts
+1F495                                                  ; fully-qualified     # 
💕 E0.6 two hearts
+1F49F                                                  ; fully-qualified     # 
💟 E0.6 heart decoration
+2763 FE0F                                              ; fully-qualified     # 
❣️ E1.0 heart exclamation
+2763                                                   ; unqualified         # 
❣ E1.0 heart exclamation
+1F494                                                  ; fully-qualified     # 
💔 E0.6 broken heart
+2764 FE0F 200D 1F525                                   ; fully-qualified     # 
❤️‍🔥 E13.1 heart on fire
+2764 200D 1F525                                        ; unqualified         # 
❤‍🔥 E13.1 heart on fire
+2764 FE0F 200D 1FA79                                   ; fully-qualified     # 
❤️‍🩹 E13.1 mending heart
+2764 200D 1FA79                                        ; unqualified         # 
❤‍🩹 E13.1 mending heart
+2764 FE0F                                              ; fully-qualified     # 
❤️ E0.6 red heart
+2764                                                   ; unqualified         # 
❤ E0.6 red heart
+1F9E1                                                  ; fully-qualified     # 
🧡 E5.0 orange heart
+1F49B                                                  ; fully-qualified     # 
💛 E0.6 yellow heart
+1F49A                                                  ; fully-qualified     # 
💚 E0.6 green heart
+1F499                                                  ; fully-qualified     # 
💙 E0.6 blue heart
+1F49C                                                  ; fully-qualified     # 
💜 E0.6 purple heart
+1F90E                                                  ; fully-qualified     # 
🤎 E12.0 brown heart
+1F5A4                                                  ; fully-qualified     # 
🖤 E3.0 black heart
+1F90D                                                  ; fully-qualified     # 
🤍 E12.0 white heart
+1F4AF                                                  ; fully-qualified     # 
💯 E0.6 hundred points
+1F4A2                                                  ; fully-qualified     # 
💢 E0.6 anger symbol
+1F4A5                                                  ; fully-qualified     # 
💥 E0.6 collision
+1F4AB                                                  ; fully-qualified     # 
💫 E0.6 dizzy
+1F4A6                                                  ; fully-qualified     # 
💦 E0.6 sweat droplets
+1F4A8                                                  ; fully-qualified     # 
💨 E0.6 dashing away
+1F573 FE0F                                             ; fully-qualified     # 
🕳️ E0.7 hole
+1F573                                                  ; unqualified         # 
🕳 E0.7 hole
+1F4A3                                                  ; fully-qualified     # 
💣 E0.6 bomb
+1F4AC                                                  ; fully-qualified     # 
💬 E0.6 speech balloon
+1F441 FE0F 200D 1F5E8 FE0F                             ; fully-qualified     # 
👁️‍🗨️ E2.0 eye in speech bubble
+1F441 200D 1F5E8 FE0F                                  ; unqualified         # 
👁‍🗨️ E2.0 eye in speech bubble
+1F441 FE0F 200D 1F5E8                                  ; unqualified         # 
👁️‍🗨 E2.0 eye in speech bubble
+1F441 200D 1F5E8                                       ; unqualified         # 
👁‍🗨 E2.0 eye in speech bubble
+1F5E8 FE0F                                             ; fully-qualified     # 
🗨️ E2.0 left speech bubble
+1F5E8                                                  ; unqualified         # 
🗨 E2.0 left speech bubble
+1F5EF FE0F                                             ; fully-qualified     # 
🗯️ E0.7 right anger bubble
+1F5EF                                                  ; unqualified         # 
🗯 E0.7 right anger bubble
+1F4AD                                                  ; fully-qualified     # 
💭 E1.0 thought balloon
+1F4A4                                                  ; fully-qualified     # 
💤 E0.6 zzz
+
+# Smileys & Emotion subtotal:          177
+# Smileys & Emotion subtotal:          177     w/o modifiers
+
+# group: People & Body
+
+# subgroup: hand-fingers-open
+1F44B                                                  ; fully-qualified     # 
👋 E0.6 waving hand
+1F44B 1F3FB                                            ; fully-qualified     # 
👋🏻 E1.0 waving hand: light skin tone
+1F44B 1F3FC                                            ; fully-qualified     # 
👋🏼 E1.0 waving hand: medium-light skin tone
+1F44B 1F3FD                                            ; fully-qualified     # 
👋🏽 E1.0 waving hand: medium skin tone
+1F44B 1F3FE                                            ; fully-qualified     # 
👋🏾 E1.0 waving hand: medium-dark skin tone
+1F44B 1F3FF                                            ; fully-qualified     # 
👋🏿 E1.0 waving hand: dark skin tone
+1F91A                                                  ; fully-qualified     # 
🤚 E3.0 raised back of hand
+1F91A 1F3FB                                            ; fully-qualified     # 
🤚🏻 E3.0 raised back of hand: light skin tone
+1F91A 1F3FC                                            ; fully-qualified     # 
🤚🏼 E3.0 raised back of hand: medium-light skin tone
+1F91A 1F3FD                                            ; fully-qualified     # 
🤚🏽 E3.0 raised back of hand: medium skin tone
+1F91A 1F3FE                                            ; fully-qualified     # 
🤚🏾 E3.0 raised back of hand: medium-dark skin tone
+1F91A 1F3FF                                            ; fully-qualified     # 
🤚🏿 E3.0 raised back of hand: dark skin tone
+1F590 FE0F                                             ; fully-qualified     # 
🖐️ E0.7 hand with fingers splayed
+1F590                                                  ; unqualified         # 
🖐 E0.7 hand with fingers splayed
+1F590 1F3FB                                            ; fully-qualified     # 
🖐🏻 E1.0 hand with fingers splayed: light skin tone
+1F590 1F3FC                                            ; fully-qualified     # 
🖐🏼 E1.0 hand with fingers splayed: medium-light skin tone
+1F590 1F3FD                                            ; fully-qualified     # 
🖐🏽 E1.0 hand with fingers splayed: medium skin tone
+1F590 1F3FE                                            ; fully-qualified     # 
🖐🏾 E1.0 hand with fingers splayed: medium-dark skin tone
+1F590 1F3FF                                            ; fully-qualified     # 
🖐🏿 E1.0 hand with fingers splayed: dark skin tone
+270B                                                   ; fully-qualified     # 
✋ E0.6 raised hand
+270B 1F3FB                                             ; fully-qualified     # 
✋🏻 E1.0 raised hand: light skin tone
+270B 1F3FC                                             ; fully-qualified     # 
✋🏼 E1.0 raised hand: medium-light skin tone
+270B 1F3FD                                             ; fully-qualified     # 
✋🏽 E1.0 raised hand: medium skin tone
+270B 1F3FE                                             ; fully-qualified     # 
✋🏾 E1.0 raised hand: medium-dark skin tone
+270B 1F3FF                                             ; fully-qualified     # 
✋🏿 E1.0 raised hand: dark skin tone
+1F596                                                  ; fully-qualified     # 
🖖 E1.0 vulcan salute
+1F596 1F3FB                                            ; fully-qualified     # 
🖖🏻 E1.0 vulcan salute: light skin tone
+1F596 1F3FC                                            ; fully-qualified     # 
🖖🏼 E1.0 vulcan salute: medium-light skin tone
+1F596 1F3FD                                            ; fully-qualified     # 
🖖🏽 E1.0 vulcan salute: medium skin tone
+1F596 1F3FE                                            ; fully-qualified     # 
🖖🏾 E1.0 vulcan salute: medium-dark skin tone
+1F596 1F3FF                                            ; fully-qualified     # 
🖖🏿 E1.0 vulcan salute: dark skin tone
+1FAF1                                                  ; fully-qualified     # 
🫱 E14.0 rightwards hand
+1FAF1 1F3FB                                            ; fully-qualified     # 
🫱🏻 E14.0 rightwards hand: light skin tone
+1FAF1 1F3FC                                            ; fully-qualified     # 
🫱🏼 E14.0 rightwards hand: medium-light skin tone
+1FAF1 1F3FD                                            ; fully-qualified     # 
🫱🏽 E14.0 rightwards hand: medium skin tone
+1FAF1 1F3FE                                            ; fully-qualified     # 
🫱🏾 E14.0 rightwards hand: medium-dark skin tone
+1FAF1 1F3FF                                            ; fully-qualified     # 
🫱🏿 E14.0 rightwards hand: dark skin tone
+1FAF2                                                  ; fully-qualified     # 
🫲 E14.0 leftwards hand
+1FAF2 1F3FB                                            ; fully-qualified     # 
🫲🏻 E14.0 leftwards hand: light skin tone
+1FAF2 1F3FC                                            ; fully-qualified     # 
🫲🏼 E14.0 leftwards hand: medium-light skin tone
+1FAF2 1F3FD                                            ; fully-qualified     # 
🫲🏽 E14.0 leftwards hand: medium skin tone
+1FAF2 1F3FE                                            ; fully-qualified     # 
🫲🏾 E14.0 leftwards hand: medium-dark skin tone
+1FAF2 1F3FF                                            ; fully-qualified     # 
🫲🏿 E14.0 leftwards hand: dark skin tone
+1FAF3                                                  ; fully-qualified     # 
🫳 E14.0 palm down hand
+1FAF3 1F3FB                                            ; fully-qualified     # 
🫳🏻 E14.0 palm down hand: light skin tone
+1FAF3 1F3FC                                            ; fully-qualified     # 
🫳🏼 E14.0 palm down hand: medium-light skin tone
+1FAF3 1F3FD                                            ; fully-qualified     # 
🫳🏽 E14.0 palm down hand: medium skin tone
+1FAF3 1F3FE                                            ; fully-qualified     # 
🫳🏾 E14.0 palm down hand: medium-dark skin tone
+1FAF3 1F3FF                                            ; fully-qualified     # 
🫳🏿 E14.0 palm down hand: dark skin tone
+1FAF4                                                  ; fully-qualified     # 
🫴 E14.0 palm up hand
+1FAF4 1F3FB                                            ; fully-qualified     # 
🫴🏻 E14.0 palm up hand: light skin tone
+1FAF4 1F3FC                                            ; fully-qualified     # 
🫴🏼 E14.0 palm up hand: medium-light skin tone
+1FAF4 1F3FD                                            ; fully-qualified     # 
🫴🏽 E14.0 palm up hand: medium skin tone
+1FAF4 1F3FE                                            ; fully-qualified     # 
🫴🏾 E14.0 palm up hand: medium-dark skin tone
+1FAF4 1F3FF                                            ; fully-qualified     # 
🫴🏿 E14.0 palm up hand: dark skin tone
+
+# subgroup: hand-fingers-partial
+1F44C                                                  ; fully-qualified     # 
👌 E0.6 OK hand
+1F44C 1F3FB                                            ; fully-qualified     # 
👌🏻 E1.0 OK hand: light skin tone
+1F44C 1F3FC                                            ; fully-qualified     # 
👌🏼 E1.0 OK hand: medium-light skin tone
+1F44C 1F3FD                                            ; fully-qualified     # 
👌🏽 E1.0 OK hand: medium skin tone
+1F44C 1F3FE                                            ; fully-qualified     # 
👌🏾 E1.0 OK hand: medium-dark skin tone
+1F44C 1F3FF                                            ; fully-qualified     # 
👌🏿 E1.0 OK hand: dark skin tone
+1F90C                                                  ; fully-qualified     # 
🤌 E13.0 pinched fingers
+1F90C 1F3FB                                            ; fully-qualified     # 
🤌🏻 E13.0 pinched fingers: light skin tone
+1F90C 1F3FC                                            ; fully-qualified     # 
🤌🏼 E13.0 pinched fingers: medium-light skin tone
+1F90C 1F3FD                                            ; fully-qualified     # 
🤌🏽 E13.0 pinched fingers: medium skin tone
+1F90C 1F3FE                                            ; fully-qualified     # 
🤌🏾 E13.0 pinched fingers: medium-dark skin tone
+1F90C 1F3FF                                            ; fully-qualified     # 
🤌🏿 E13.0 pinched fingers: dark skin tone
+1F90F                                                  ; fully-qualified     # 
🤏 E12.0 pinching hand
+1F90F 1F3FB                                            ; fully-qualified     # 
🤏🏻 E12.0 pinching hand: light skin tone
+1F90F 1F3FC                                            ; fully-qualified     # 
🤏🏼 E12.0 pinching hand: medium-light skin tone
+1F90F 1F3FD                                            ; fully-qualified     # 
🤏🏽 E12.0 pinching hand: medium skin tone
+1F90F 1F3FE                                            ; fully-qualified     # 
🤏🏾 E12.0 pinching hand: medium-dark skin tone
+1F90F 1F3FF                                            ; fully-qualified     # 
🤏🏿 E12.0 pinching hand: dark skin tone
+270C FE0F                                              ; fully-qualified     # 
✌️ E0.6 victory hand
+270C                                                   ; unqualified         # 
✌ E0.6 victory hand
+270C 1F3FB                                             ; fully-qualified     # 
✌🏻 E1.0 victory hand: light skin tone
+270C 1F3FC                                             ; fully-qualified     # 
✌🏼 E1.0 victory hand: medium-light skin tone
+270C 1F3FD                                             ; fully-qualified     # 
✌🏽 E1.0 victory hand: medium skin tone
+270C 1F3FE                                             ; fully-qualified     # 
✌🏾 E1.0 victory hand: medium-dark skin tone
+270C 1F3FF                                             ; fully-qualified     # 
✌🏿 E1.0 victory hand: dark skin tone
+1F91E                                                  ; fully-qualified     # 
🤞 E3.0 crossed fingers
+1F91E 1F3FB                                            ; fully-qualified     # 
🤞🏻 E3.0 crossed fingers: light skin tone
+1F91E 1F3FC                                            ; fully-qualified     # 
🤞🏼 E3.0 crossed fingers: medium-light skin tone
+1F91E 1F3FD                                            ; fully-qualified     # 
🤞🏽 E3.0 crossed fingers: medium skin tone
+1F91E 1F3FE                                            ; fully-qualified     # 
🤞🏾 E3.0 crossed fingers: medium-dark skin tone
+1F91E 1F3FF                                            ; fully-qualified     # 
🤞🏿 E3.0 crossed fingers: dark skin tone
+1FAF0                                                  ; fully-qualified     # 
🫰 E14.0 hand with index finger and thumb crossed
+1FAF0 1F3FB                                            ; fully-qualified     # 
🫰🏻 E14.0 hand with index finger and thumb crossed: light skin tone
+1FAF0 1F3FC                                            ; fully-qualified     # 
🫰🏼 E14.0 hand with index finger and thumb crossed: medium-light skin tone
+1FAF0 1F3FD                                            ; fully-qualified     # 
🫰🏽 E14.0 hand with index finger and thumb crossed: medium skin tone
+1FAF0 1F3FE                                            ; fully-qualified     # 
🫰🏾 E14.0 hand with index finger and thumb crossed: medium-dark skin tone
+1FAF0 1F3FF                                            ; fully-qualified     # 
🫰🏿 E14.0 hand with index finger and thumb crossed: dark skin tone
+1F91F                                                  ; fully-qualified     # 
🤟 E5.0 love-you gesture
+1F91F 1F3FB                                            ; fully-qualified     # 
🤟🏻 E5.0 love-you gesture: light skin tone
+1F91F 1F3FC                                            ; fully-qualified     # 
🤟🏼 E5.0 love-you gesture: medium-light skin tone
+1F91F 1F3FD                                            ; fully-qualified     # 
🤟🏽 E5.0 love-you gesture: medium skin tone
+1F91F 1F3FE                                            ; fully-qualified     # 
🤟🏾 E5.0 love-you gesture: medium-dark skin tone
+1F91F 1F3FF                                            ; fully-qualified     # 
🤟🏿 E5.0 love-you gesture: dark skin tone
+1F918                                                  ; fully-qualified     # 
🤘 E1.0 sign of the horns
+1F918 1F3FB                                            ; fully-qualified     # 
🤘🏻 E1.0 sign of the horns: light skin tone
+1F918 1F3FC                                            ; fully-qualified     # 
🤘🏼 E1.0 sign of the horns: medium-light skin tone
+1F918 1F3FD                                            ; fully-qualified     # 
🤘🏽 E1.0 sign of the horns: medium skin tone
+1F918 1F3FE                                            ; fully-qualified     # 
🤘🏾 E1.0 sign of the horns: medium-dark skin tone
+1F918 1F3FF                                            ; fully-qualified     # 
🤘🏿 E1.0 sign of the horns: dark skin tone
+1F919                                                  ; fully-qualified     # 
🤙 E3.0 call me hand
+1F919 1F3FB                                            ; fully-qualified     # 
🤙🏻 E3.0 call me hand: light skin tone
+1F919 1F3FC                                            ; fully-qualified     # 
🤙🏼 E3.0 call me hand: medium-light skin tone
+1F919 1F3FD                                            ; fully-qualified     # 
🤙🏽 E3.0 call me hand: medium skin tone
+1F919 1F3FE                                            ; fully-qualified     # 
🤙🏾 E3.0 call me hand: medium-dark skin tone
+1F919 1F3FF                                            ; fully-qualified     # 
🤙🏿 E3.0 call me hand: dark skin tone
+
+# subgroup: hand-single-finger
+1F448                                                  ; fully-qualified     # 
👈 E0.6 backhand index pointing left
+1F448 1F3FB                                            ; fully-qualified     # 
👈🏻 E1.0 backhand index pointing left: light skin tone
+1F448 1F3FC                                            ; fully-qualified     # 
👈🏼 E1.0 backhand index pointing left: medium-light skin tone
+1F448 1F3FD                                            ; fully-qualified     # 
👈🏽 E1.0 backhand index pointing left: medium skin tone
+1F448 1F3FE                                            ; fully-qualified     # 
👈🏾 E1.0 backhand index pointing left: medium-dark skin tone
+1F448 1F3FF                                            ; fully-qualified     # 
👈🏿 E1.0 backhand index pointing left: dark skin tone
+1F449                                                  ; fully-qualified     # 
👉 E0.6 backhand index pointing right
+1F449 1F3FB                                            ; fully-qualified     # 
👉🏻 E1.0 backhand index pointing right: light skin tone
+1F449 1F3FC                                            ; fully-qualified     # 
👉🏼 E1.0 backhand index pointing right: medium-light skin tone
+1F449 1F3FD                                            ; fully-qualified     # 
👉🏽 E1.0 backhand index pointing right: medium skin tone
+1F449 1F3FE                                            ; fully-qualified     # 
👉🏾 E1.0 backhand index pointing right: medium-dark skin tone
+1F449 1F3FF                                            ; fully-qualified     # 
👉🏿 E1.0 backhand index pointing right: dark skin tone
+1F446                                                  ; fully-qualified     # 
👆 E0.6 backhand index pointing up
+1F446 1F3FB                                            ; fully-qualified     # 
👆🏻 E1.0 backhand index pointing up: light skin tone
+1F446 1F3FC                                            ; fully-qualified     # 
👆🏼 E1.0 backhand index pointing up: medium-light skin tone
+1F446 1F3FD                                            ; fully-qualified     # 
👆🏽 E1.0 backhand index pointing up: medium skin tone
+1F446 1F3FE                                            ; fully-qualified     # 
👆🏾 E1.0 backhand index pointing up: medium-dark skin tone
+1F446 1F3FF                                            ; fully-qualified     # 
👆🏿 E1.0 backhand index pointing up: dark skin tone
+1F595                                                  ; fully-qualified     # 
🖕 E1.0 middle finger
+1F595 1F3FB                                            ; fully-qualified     # 
🖕🏻 E1.0 middle finger: light skin tone
+1F595 1F3FC                                            ; fully-qualified     # 
🖕🏼 E1.0 middle finger: medium-light skin tone
+1F595 1F3FD                                            ; fully-qualified     # 
🖕🏽 E1.0 middle finger: medium skin tone
+1F595 1F3FE                                            ; fully-qualified     # 
🖕🏾 E1.0 middle finger: medium-dark skin tone
+1F595 1F3FF                                            ; fully-qualified     # 
🖕🏿 E1.0 middle finger: dark skin tone
+1F447                                                  ; fully-qualified     # 
👇 E0.6 backhand index pointing down
+1F447 1F3FB                                            ; fully-qualified     # 
👇🏻 E1.0 backhand index pointing down: light skin tone
+1F447 1F3FC                                            ; fully-qualified     # 
👇🏼 E1.0 backhand index pointing down: medium-light skin tone
+1F447 1F3FD                                            ; fully-qualified     # 
👇🏽 E1.0 backhand index pointing down: medium skin tone
+1F447 1F3FE                                            ; fully-qualified     # 
👇🏾 E1.0 backhand index pointing down: medium-dark skin tone
+1F447 1F3FF                                            ; fully-qualified     # 
👇🏿 E1.0 backhand index pointing down: dark skin tone
+261D FE0F                                              ; fully-qualified     # 
☝️ E0.6 index pointing up
+261D                                                   ; unqualified         # 
☝ E0.6 index pointing up
+261D 1F3FB                                             ; fully-qualified     # 
☝🏻 E1.0 index pointing up: light skin tone
+261D 1F3FC                                             ; fully-qualified     # 
☝🏼 E1.0 index pointing up: medium-light skin tone
+261D 1F3FD                                             ; fully-qualified     # 
☝🏽 E1.0 index pointing up: medium skin tone
+261D 1F3FE                                             ; fully-qualified     # 
☝🏾 E1.0 index pointing up: medium-dark skin tone
+261D 1F3FF                                             ; fully-qualified     # 
☝🏿 E1.0 index pointing up: dark skin tone
+1FAF5                                                  ; fully-qualified     # 
🫵 E14.0 index pointing at the viewer
+1FAF5 1F3FB                                            ; fully-qualified     # 
🫵🏻 E14.0 index pointing at the viewer: light skin tone
+1FAF5 1F3FC                                            ; fully-qualified     # 
🫵🏼 E14.0 index pointing at the viewer: medium-light skin tone
+1FAF5 1F3FD                                            ; fully-qualified     # 
🫵🏽 E14.0 index pointing at the viewer: medium skin tone
+1FAF5 1F3FE                                            ; fully-qualified     # 
🫵🏾 E14.0 index pointing at the viewer: medium-dark skin tone
+1FAF5 1F3FF                                            ; fully-qualified     # 
🫵🏿 E14.0 index pointing at the viewer: dark skin tone
+
+# subgroup: hand-fingers-closed
+1F44D                                                  ; fully-qualified     # 
👍 E0.6 thumbs up
+1F44D 1F3FB                                            ; fully-qualified     # 
👍🏻 E1.0 thumbs up: light skin tone
+1F44D 1F3FC                                            ; fully-qualified     # 
👍🏼 E1.0 thumbs up: medium-light skin tone
+1F44D 1F3FD                                            ; fully-qualified     # 
👍🏽 E1.0 thumbs up: medium skin tone
+1F44D 1F3FE                                            ; fully-qualified     # 
👍🏾 E1.0 thumbs up: medium-dark skin tone
+1F44D 1F3FF                                            ; fully-qualified     # 
👍🏿 E1.0 thumbs up: dark skin tone
+1F44E                                                  ; fully-qualified     # 
👎 E0.6 thumbs down
+1F44E 1F3FB                                            ; fully-qualified     # 
👎🏻 E1.0 thumbs down: light skin tone
+1F44E 1F3FC                                            ; fully-qualified     # 
👎🏼 E1.0 thumbs down: medium-light skin tone
+1F44E 1F3FD                                            ; fully-qualified     # 
👎🏽 E1.0 thumbs down: medium skin tone
+1F44E 1F3FE                                            ; fully-qualified     # 
👎🏾 E1.0 thumbs down: medium-dark skin tone
+1F44E 1F3FF                                            ; fully-qualified     # 
👎🏿 E1.0 thumbs down: dark skin tone
+270A                                                   ; fully-qualified     # 
✊ E0.6 raised fist
+270A 1F3FB                                             ; fully-qualified     # 
✊🏻 E1.0 raised fist: light skin tone
+270A 1F3FC                                             ; fully-qualified     # 
✊🏼 E1.0 raised fist: medium-light skin tone
+270A 1F3FD                                             ; fully-qualified     # 
✊🏽 E1.0 raised fist: medium skin tone
+270A 1F3FE                                             ; fully-qualified     # 
✊🏾 E1.0 raised fist: medium-dark skin tone
+270A 1F3FF                                             ; fully-qualified     # 
✊🏿 E1.0 raised fist: dark skin tone
+1F44A                                                  ; fully-qualified     # 
👊 E0.6 oncoming fist
+1F44A 1F3FB                                            ; fully-qualified     # 
👊🏻 E1.0 oncoming fist: light skin tone
+1F44A 1F3FC                                            ; fully-qualified     # 
👊🏼 E1.0 oncoming fist: medium-light skin tone
+1F44A 1F3FD                                            ; fully-qualified     # 
👊🏽 E1.0 oncoming fist: medium skin tone
+1F44A 1F3FE                                            ; fully-qualified     # 
👊🏾 E1.0 oncoming fist: medium-dark skin tone
+1F44A 1F3FF                                            ; fully-qualified     # 
👊🏿 E1.0 oncoming fist: dark skin tone
+1F91B                                                  ; fully-qualified     # 
🤛 E3.0 left-facing fist
+1F91B 1F3FB                                            ; fully-qualified     # 
🤛🏻 E3.0 left-facing fist: light skin tone
+1F91B 1F3FC                                            ; fully-qualified     # 
🤛🏼 E3.0 left-facing fist: medium-light skin tone
+1F91B 1F3FD                                            ; fully-qualified     # 
🤛🏽 E3.0 left-facing fist: medium skin tone
+1F91B 1F3FE                                            ; fully-qualified     # 
🤛🏾 E3.0 left-facing fist: medium-dark skin tone
+1F91B 1F3FF                                            ; fully-qualified     # 
🤛🏿 E3.0 left-facing fist: dark skin tone
+1F91C                                                  ; fully-qualified     # 
🤜 E3.0 right-facing fist
+1F91C 1F3FB                                            ; fully-qualified     # 
🤜🏻 E3.0 right-facing fist: light skin tone
+1F91C 1F3FC                                            ; fully-qualified     # 
🤜🏼 E3.0 right-facing fist: medium-light skin tone
+1F91C 1F3FD                                            ; fully-qualified     # 
🤜🏽 E3.0 right-facing fist: medium skin tone
+1F91C 1F3FE                                            ; fully-qualified     # 
🤜🏾 E3.0 right-facing fist: medium-dark skin tone
+1F91C 1F3FF                                            ; fully-qualified     # 
🤜🏿 E3.0 right-facing fist: dark skin tone
+
+# subgroup: hands
+1F44F                                                  ; fully-qualified     # 
👏 E0.6 clapping hands
+1F44F 1F3FB                                            ; fully-qualified     # 
👏🏻 E1.0 clapping hands: light skin tone
+1F44F 1F3FC                                            ; fully-qualified     # 
👏🏼 E1.0 clapping hands: medium-light skin tone
+1F44F 1F3FD                                            ; fully-qualified     # 
👏🏽 E1.0 clapping hands: medium skin tone
+1F44F 1F3FE                                            ; fully-qualified     # 
👏🏾 E1.0 clapping hands: medium-dark skin tone
+1F44F 1F3FF                                            ; fully-qualified     # 
👏🏿 E1.0 clapping hands: dark skin tone
+1F64C                                                  ; fully-qualified     # 
🙌 E0.6 raising hands
+1F64C 1F3FB                                            ; fully-qualified     # 
🙌🏻 E1.0 raising hands: light skin tone
+1F64C 1F3FC                                            ; fully-qualified     # 
🙌🏼 E1.0 raising hands: medium-light skin tone
+1F64C 1F3FD                                            ; fully-qualified     # 
🙌🏽 E1.0 raising hands: medium skin tone
+1F64C 1F3FE                                            ; fully-qualified     # 
🙌🏾 E1.0 raising hands: medium-dark skin tone
+1F64C 1F3FF                                            ; fully-qualified     # 
🙌🏿 E1.0 raising hands: dark skin tone
+1FAF6                                                  ; fully-qualified     # 
🫶 E14.0 heart hands
+1FAF6 1F3FB                                            ; fully-qualified     # 
🫶🏻 E14.0 heart hands: light skin tone
+1FAF6 1F3FC                                            ; fully-qualified     # 
🫶🏼 E14.0 heart hands: medium-light skin tone
+1FAF6 1F3FD                                            ; fully-qualified     # 
🫶🏽 E14.0 heart hands: medium skin tone
+1FAF6 1F3FE                                            ; fully-qualified     # 
🫶🏾 E14.0 heart hands: medium-dark skin tone
+1FAF6 1F3FF                                            ; fully-qualified     # 
🫶🏿 E14.0 heart hands: dark skin tone
+1F450                                                  ; fully-qualified     # 
👐 E0.6 open hands
+1F450 1F3FB                                            ; fully-qualified     # 
👐🏻 E1.0 open hands: light skin tone
+1F450 1F3FC                                            ; fully-qualified     # 
👐🏼 E1.0 open hands: medium-light skin tone
+1F450 1F3FD                                            ; fully-qualified     # 
👐🏽 E1.0 open hands: medium skin tone
+1F450 1F3FE                                            ; fully-qualified     # 
👐🏾 E1.0 open hands: medium-dark skin tone
+1F450 1F3FF                                            ; fully-qualified     # 
👐🏿 E1.0 open hands: dark skin tone
+1F932                                                  ; fully-qualified     # 
🤲 E5.0 palms up together
+1F932 1F3FB                                            ; fully-qualified     # 
🤲🏻 E5.0 palms up together: light skin tone
+1F932 1F3FC                                            ; fully-qualified     # 
🤲🏼 E5.0 palms up together: medium-light skin tone
+1F932 1F3FD                                            ; fully-qualified     # 
🤲🏽 E5.0 palms up together: medium skin tone
+1F932 1F3FE                                            ; fully-qualified     # 
🤲🏾 E5.0 palms up together: medium-dark skin tone
+1F932 1F3FF                                            ; fully-qualified     # 
🤲🏿 E5.0 palms up together: dark skin tone
+1F91D                                                  ; fully-qualified     # 
🤝 E3.0 handshake
+1F91D 1F3FB                                            ; fully-qualified     # 
🤝🏻 E3.0 handshake: light skin tone
+1F91D 1F3FC                                            ; fully-qualified     # 
🤝🏼 E3.0 handshake: medium-light skin tone
+1F91D 1F3FD                                            ; fully-qualified     # 
🤝🏽 E3.0 handshake: medium skin tone
+1F91D 1F3FE                                            ; fully-qualified     # 
🤝🏾 E3.0 handshake: medium-dark skin tone
+1F91D 1F3FF                                            ; fully-qualified     # 
🤝🏿 E3.0 handshake: dark skin tone
+1FAF1 1F3FB 200D 1FAF2 1F3FC                           ; fully-qualified     # 
🫱🏻‍🫲🏼 E14.0 handshake: light skin tone, medium-light skin tone
+1FAF1 1F3FB 200D 1FAF2 1F3FD                           ; fully-qualified     # 
🫱🏻‍🫲🏽 E14.0 handshake: light skin tone, medium skin tone
+1FAF1 1F3FB 200D 1FAF2 1F3FE                           ; fully-qualified     # 
🫱🏻‍🫲🏾 E14.0 handshake: light skin tone, medium-dark skin tone
+1FAF1 1F3FB 200D 1FAF2 1F3FF                           ; fully-qualified     # 
🫱🏻‍🫲🏿 E14.0 handshake: light skin tone, dark skin tone
+1FAF1 1F3FC 200D 1FAF2 1F3FB                           ; fully-qualified     # 
🫱🏼‍🫲🏻 E14.0 handshake: medium-light skin tone, light skin tone
+1FAF1 1F3FC 200D 1FAF2 1F3FD                           ; fully-qualified     # 
🫱🏼‍🫲🏽 E14.0 handshake: medium-light skin tone, medium skin tone
+1FAF1 1F3FC 200D 1FAF2 1F3FE                           ; fully-qualified     # 
🫱🏼‍🫲🏾 E14.0 handshake: medium-light skin tone, medium-dark skin tone
+1FAF1 1F3FC 200D 1FAF2 1F3FF                           ; fully-qualified     # 
🫱🏼‍🫲🏿 E14.0 handshake: medium-light skin tone, dark skin tone
+1FAF1 1F3FD 200D 1FAF2 1F3FB                           ; fully-qualified     # 
🫱🏽‍🫲🏻 E14.0 handshake: medium skin tone, light skin tone
+1FAF1 1F3FD 200D 1FAF2 1F3FC                           ; fully-qualified     # 
🫱🏽‍🫲🏼 E14.0 handshake: medium skin tone, medium-light skin tone
+1FAF1 1F3FD 200D 1FAF2 1F3FE                           ; fully-qualified     # 
🫱🏽‍🫲🏾 E14.0 handshake: medium skin tone, medium-dark skin tone
+1FAF1 1F3FD 200D 1FAF2 1F3FF                           ; fully-qualified     # 
🫱🏽‍🫲🏿 E14.0 handshake: medium skin tone, dark skin tone
+1FAF1 1F3FE 200D 1FAF2 1F3FB                           ; fully-qualified     # 
🫱🏾‍🫲🏻 E14.0 handshake: medium-dark skin tone, light skin tone
+1FAF1 1F3FE 200D 1FAF2 1F3FC                           ; fully-qualified     # 
🫱🏾‍🫲🏼 E14.0 handshake: medium-dark skin tone, medium-light skin tone
+1FAF1 1F3FE 200D 1FAF2 1F3FD                           ; fully-qualified     # 
🫱🏾‍🫲🏽 E14.0 handshake: medium-dark skin tone, medium skin tone
+1FAF1 1F3FE 200D 1FAF2 1F3FF                           ; fully-qualified     # 
🫱🏾‍🫲🏿 E14.0 handshake: medium-dark skin tone, dark skin tone
+1FAF1 1F3FF 200D 1FAF2 1F3FB                           ; fully-qualified     # 
🫱🏿‍🫲🏻 E14.0 handshake: dark skin tone, light skin tone
+1FAF1 1F3FF 200D 1FAF2 1F3FC                           ; fully-qualified     # 
🫱🏿‍🫲🏼 E14.0 handshake: dark skin tone, medium-light skin tone
+1FAF1 1F3FF 200D 1FAF2 1F3FD                           ; fully-qualified     # 
🫱🏿‍🫲🏽 E14.0 handshake: dark skin tone, medium skin tone
+1FAF1 1F3FF 200D 1FAF2 1F3FE                           ; fully-qualified     # 
🫱🏿‍🫲🏾 E14.0 handshake: dark skin tone, medium-dark skin tone
+1F64F                                                  ; fully-qualified     # 
🙏 E0.6 folded hands
+1F64F 1F3FB                                            ; fully-qualified     # 
🙏🏻 E1.0 folded hands: light skin tone
+1F64F 1F3FC                                            ; fully-qualified     # 
🙏🏼 E1.0 folded hands: medium-light skin tone
+1F64F 1F3FD                                            ; fully-qualified     # 
🙏🏽 E1.0 folded hands: medium skin tone
+1F64F 1F3FE                                            ; fully-qualified     # 
🙏🏾 E1.0 folded hands: medium-dark skin tone
+1F64F 1F3FF                                            ; fully-qualified     # 
🙏🏿 E1.0 folded hands: dark skin tone
+
+# subgroup: hand-prop
+270D FE0F                                              ; fully-qualified     # 
✍️ E0.7 writing hand
+270D                                                   ; unqualified         # 
✍ E0.7 writing hand
+270D 1F3FB                                             ; fully-qualified     # 
✍🏻 E1.0 writing hand: light skin tone
+270D 1F3FC                                             ; fully-qualified     # 
✍🏼 E1.0 writing hand: medium-light skin tone
+270D 1F3FD                                             ; fully-qualified     # 
✍🏽 E1.0 writing hand: medium skin tone
+270D 1F3FE                                             ; fully-qualified     # 
✍🏾 E1.0 writing hand: medium-dark skin tone
+270D 1F3FF                                             ; fully-qualified     # 
✍🏿 E1.0 writing hand: dark skin tone
+1F485                                                  ; fully-qualified     # 
💅 E0.6 nail polish
+1F485 1F3FB                                            ; fully-qualified     # 
💅🏻 E1.0 nail polish: light skin tone
+1F485 1F3FC                                            ; fully-qualified     # 
💅🏼 E1.0 nail polish: medium-light skin tone
+1F485 1F3FD                                            ; fully-qualified     # 
💅🏽 E1.0 nail polish: medium skin tone
+1F485 1F3FE                                            ; fully-qualified     # 
💅🏾 E1.0 nail polish: medium-dark skin tone
+1F485 1F3FF                                            ; fully-qualified     # 
💅🏿 E1.0 nail polish: dark skin tone
+1F933                                                  ; fully-qualified     # 
🤳 E3.0 selfie
+1F933 1F3FB                                            ; fully-qualified     # 
🤳🏻 E3.0 selfie: light skin tone
+1F933 1F3FC                                            ; fully-qualified     # 
🤳🏼 E3.0 selfie: medium-light skin tone
+1F933 1F3FD                                            ; fully-qualified     # 
🤳🏽 E3.0 selfie: medium skin tone
+1F933 1F3FE                                            ; fully-qualified     # 
🤳🏾 E3.0 selfie: medium-dark skin tone
+1F933 1F3FF                                            ; fully-qualified     # 
🤳🏿 E3.0 selfie: dark skin tone
+
+# subgroup: body-parts
+1F4AA                                                  ; fully-qualified     # 
💪 E0.6 flexed biceps
+1F4AA 1F3FB                                            ; fully-qualified     # 
💪🏻 E1.0 flexed biceps: light skin tone
+1F4AA 1F3FC                                            ; fully-qualified     # 
💪🏼 E1.0 flexed biceps: medium-light skin tone
+1F4AA 1F3FD                                            ; fully-qualified     # 
💪🏽 E1.0 flexed biceps: medium skin tone
+1F4AA 1F3FE                                            ; fully-qualified     # 
💪🏾 E1.0 flexed biceps: medium-dark skin tone
+1F4AA 1F3FF                                            ; fully-qualified     # 
💪🏿 E1.0 flexed biceps: dark skin tone
+1F9BE                                                  ; fully-qualified     # 
🦾 E12.0 mechanical arm
+1F9BF                                                  ; fully-qualified     # 
🦿 E12.0 mechanical leg
+1F9B5                                                  ; fully-qualified     # 
🦵 E11.0 leg
+1F9B5 1F3FB                                            ; fully-qualified     # 
🦵🏻 E11.0 leg: light skin tone
+1F9B5 1F3FC                                            ; fully-qualified     # 
🦵🏼 E11.0 leg: medium-light skin tone
+1F9B5 1F3FD                                            ; fully-qualified     # 
🦵🏽 E11.0 leg: medium skin tone
+1F9B5 1F3FE                                            ; fully-qualified     # 
🦵🏾 E11.0 leg: medium-dark skin tone
+1F9B5 1F3FF                                            ; fully-qualified     # 
🦵🏿 E11.0 leg: dark skin tone
+1F9B6                                                  ; fully-qualified     # 
🦶 E11.0 foot
+1F9B6 1F3FB                                            ; fully-qualified     # 
🦶🏻 E11.0 foot: light skin tone
+1F9B6 1F3FC                                            ; fully-qualified     # 
🦶🏼 E11.0 foot: medium-light skin tone
+1F9B6 1F3FD                                            ; fully-qualified     # 
🦶🏽 E11.0 foot: medium skin tone
+1F9B6 1F3FE                                            ; fully-qualified     # 
🦶🏾 E11.0 foot: medium-dark skin tone
+1F9B6 1F3FF                                            ; fully-qualified     # 
🦶🏿 E11.0 foot: dark skin tone
+1F442                                                  ; fully-qualified     # 
👂 E0.6 ear
+1F442 1F3FB                                            ; fully-qualified     # 
👂🏻 E1.0 ear: light skin tone
+1F442 1F3FC                                            ; fully-qualified     # 
👂🏼 E1.0 ear: medium-light skin tone
+1F442 1F3FD                                            ; fully-qualified     # 
👂🏽 E1.0 ear: medium skin tone
+1F442 1F3FE                                            ; fully-qualified     # 
👂🏾 E1.0 ear: medium-dark skin tone
+1F442 1F3FF                                            ; fully-qualified     # 
👂🏿 E1.0 ear: dark skin tone
+1F9BB                                                  ; fully-qualified     # 
🦻 E12.0 ear with hearing aid
+1F9BB 1F3FB                                            ; fully-qualified     # 
🦻🏻 E12.0 ear with hearing aid: light skin tone
+1F9BB 1F3FC                                            ; fully-qualified     # 
🦻🏼 E12.0 ear with hearing aid: medium-light skin tone
+1F9BB 1F3FD                                            ; fully-qualified     # 
🦻🏽 E12.0 ear with hearing aid: medium skin tone
+1F9BB 1F3FE                                            ; fully-qualified     # 
🦻🏾 E12.0 ear with hearing aid: medium-dark skin tone
+1F9BB 1F3FF                                            ; fully-qualified     # 
🦻🏿 E12.0 ear with hearing aid: dark skin tone
+1F443                                                  ; fully-qualified     # 
👃 E0.6 nose
+1F443 1F3FB                                            ; fully-qualified     # 
👃🏻 E1.0 nose: light skin tone
+1F443 1F3FC                                            ; fully-qualified     # 
👃🏼 E1.0 nose: medium-light skin tone
+1F443 1F3FD                                            ; fully-qualified     # 
👃🏽 E1.0 nose: medium skin tone
+1F443 1F3FE                                            ; fully-qualified     # 
👃🏾 E1.0 nose: medium-dark skin tone
+1F443 1F3FF                                            ; fully-qualified     # 
👃🏿 E1.0 nose: dark skin tone
+1F9E0                                                  ; fully-qualified     # 
🧠 E5.0 brain
+1FAC0                                                  ; fully-qualified     # 
🫀 E13.0 anatomical heart
+1FAC1                                                  ; fully-qualified     # 
🫁 E13.0 lungs
+1F9B7                                                  ; fully-qualified     # 
🦷 E11.0 tooth
+1F9B4                                                  ; fully-qualified     # 
🦴 E11.0 bone
+1F440                                                  ; fully-qualified     # 
👀 E0.6 eyes
+1F441 FE0F                                             ; fully-qualified     # 
👁️ E0.7 eye
+1F441                                                  ; unqualified         # 
👁 E0.7 eye
+1F445                                                  ; fully-qualified     # 
👅 E0.6 tongue
+1F444                                                  ; fully-qualified     # 
👄 E0.6 mouth
+1FAE6                                                  ; fully-qualified     # 
🫦 E14.0 biting lip
+
+# subgroup: person
+1F476                                                  ; fully-qualified     # 
👶 E0.6 baby
+1F476 1F3FB                                            ; fully-qualified     # 
👶🏻 E1.0 baby: light skin tone
+1F476 1F3FC                                            ; fully-qualified     # 
👶🏼 E1.0 baby: medium-light skin tone
+1F476 1F3FD                                            ; fully-qualified     # 
👶🏽 E1.0 baby: medium skin tone
+1F476 1F3FE                                            ; fully-qualified     # 
👶🏾 E1.0 baby: medium-dark skin tone
+1F476 1F3FF                                            ; fully-qualified     # 
👶🏿 E1.0 baby: dark skin tone
+1F9D2                                                  ; fully-qualified     # 
🧒 E5.0 child
+1F9D2 1F3FB                                            ; fully-qualified     # 
🧒🏻 E5.0 child: light skin tone
+1F9D2 1F3FC                                            ; fully-qualified     # 
🧒🏼 E5.0 child: medium-light skin tone
+1F9D2 1F3FD                                            ; fully-qualified     # 
🧒🏽 E5.0 child: medium skin tone
+1F9D2 1F3FE                                            ; fully-qualified     # 
🧒🏾 E5.0 child: medium-dark skin tone
+1F9D2 1F3FF                                            ; fully-qualified     # 
🧒🏿 E5.0 child: dark skin tone
+1F466                                                  ; fully-qualified     # 
👦 E0.6 boy
+1F466 1F3FB                                            ; fully-qualified     # 
👦🏻 E1.0 boy: light skin tone
+1F466 1F3FC                                            ; fully-qualified     # 
👦🏼 E1.0 boy: medium-light skin tone
+1F466 1F3FD                                            ; fully-qualified     # 
👦🏽 E1.0 boy: medium skin tone
+1F466 1F3FE                                            ; fully-qualified     # 
👦🏾 E1.0 boy: medium-dark skin tone
+1F466 1F3FF                                            ; fully-qualified     # 
👦🏿 E1.0 boy: dark skin tone
+1F467                                                  ; fully-qualified     # 
👧 E0.6 girl
+1F467 1F3FB                                            ; fully-qualified     # 
👧🏻 E1.0 girl: light skin tone
+1F467 1F3FC                                            ; fully-qualified     # 
👧🏼 E1.0 girl: medium-light skin tone
+1F467 1F3FD                                            ; fully-qualified     # 
👧🏽 E1.0 girl: medium skin tone
+1F467 1F3FE                                            ; fully-qualified     # 
👧🏾 E1.0 girl: medium-dark skin tone
+1F467 1F3FF                                            ; fully-qualified     # 
👧🏿 E1.0 girl: dark skin tone
+1F9D1                                                  ; fully-qualified     # 
🧑 E5.0 person
+1F9D1 1F3FB                                            ; fully-qualified     # 
🧑🏻 E5.0 person: light skin tone
+1F9D1 1F3FC                                            ; fully-qualified     # 
🧑🏼 E5.0 person: medium-light skin tone
+1F9D1 1F3FD                                            ; fully-qualified     # 
🧑🏽 E5.0 person: medium skin tone
+1F9D1 1F3FE                                            ; fully-qualified     # 
🧑🏾 E5.0 person: medium-dark skin tone
+1F9D1 1F3FF                                            ; fully-qualified     # 
🧑🏿 E5.0 person: dark skin tone
+1F471                                                  ; fully-qualified     # 
👱 E0.6 person: blond hair
+1F471 1F3FB                                            ; fully-qualified     # 
👱🏻 E1.0 person: light skin tone, blond hair
+1F471 1F3FC                                            ; fully-qualified     # 
👱🏼 E1.0 person: medium-light skin tone, blond hair
+1F471 1F3FD                                            ; fully-qualified     # 
👱🏽 E1.0 person: medium skin tone, blond hair
+1F471 1F3FE                                            ; fully-qualified     # 
👱🏾 E1.0 person: medium-dark skin tone, blond hair
+1F471 1F3FF                                            ; fully-qualified     # 
👱🏿 E1.0 person: dark skin tone, blond hair
+1F468                                                  ; fully-qualified     # 
👨 E0.6 man
+1F468 1F3FB                                            ; fully-qualified     # 
👨🏻 E1.0 man: light skin tone
+1F468 1F3FC                                            ; fully-qualified     # 
👨🏼 E1.0 man: medium-light skin tone
+1F468 1F3FD                                            ; fully-qualified     # 
👨🏽 E1.0 man: medium skin tone
+1F468 1F3FE                                            ; fully-qualified     # 
👨🏾 E1.0 man: medium-dark skin tone
+1F468 1F3FF                                            ; fully-qualified     # 
👨🏿 E1.0 man: dark skin tone
+1F9D4                                                  ; fully-qualified     # 
🧔 E5.0 person: beard
+1F9D4 1F3FB                                            ; fully-qualified     # 
🧔🏻 E5.0 person: light skin tone, beard
+1F9D4 1F3FC                                            ; fully-qualified     # 
🧔🏼 E5.0 person: medium-light skin tone, beard
+1F9D4 1F3FD                                            ; fully-qualified     # 
🧔🏽 E5.0 person: medium skin tone, beard
+1F9D4 1F3FE                                            ; fully-qualified     # 
🧔🏾 E5.0 person: medium-dark skin tone, beard
+1F9D4 1F3FF                                            ; fully-qualified     # 
🧔🏿 E5.0 person: dark skin tone, beard
+1F9D4 200D 2642 FE0F                                   ; fully-qualified     # 
🧔‍♂️ E13.1 man: beard
+1F9D4 200D 2642                                        ; minimally-qualified # 
🧔‍♂ E13.1 man: beard
+1F9D4 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧔🏻‍♂️ E13.1 man: light skin tone, beard
+1F9D4 1F3FB 200D 2642                                  ; minimally-qualified # 
🧔🏻‍♂ E13.1 man: light skin tone, beard
+1F9D4 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧔🏼‍♂️ E13.1 man: medium-light skin tone, beard
+1F9D4 1F3FC 200D 2642                                  ; minimally-qualified # 
🧔🏼‍♂ E13.1 man: medium-light skin tone, beard
+1F9D4 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧔🏽‍♂️ E13.1 man: medium skin tone, beard
+1F9D4 1F3FD 200D 2642                                  ; minimally-qualified # 
🧔🏽‍♂ E13.1 man: medium skin tone, beard
+1F9D4 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧔🏾‍♂️ E13.1 man: medium-dark skin tone, beard
+1F9D4 1F3FE 200D 2642                                  ; minimally-qualified # 
🧔🏾‍♂ E13.1 man: medium-dark skin tone, beard
+1F9D4 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧔🏿‍♂️ E13.1 man: dark skin tone, beard
+1F9D4 1F3FF 200D 2642                                  ; minimally-qualified # 
🧔🏿‍♂ E13.1 man: dark skin tone, beard
+1F9D4 200D 2640 FE0F                                   ; fully-qualified     # 
🧔‍♀️ E13.1 woman: beard
+1F9D4 200D 2640                                        ; minimally-qualified # 
🧔‍♀ E13.1 woman: beard
+1F9D4 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧔🏻‍♀️ E13.1 woman: light skin tone, beard
+1F9D4 1F3FB 200D 2640                                  ; minimally-qualified # 
🧔🏻‍♀ E13.1 woman: light skin tone, beard
+1F9D4 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧔🏼‍♀️ E13.1 woman: medium-light skin tone, beard
+1F9D4 1F3FC 200D 2640                                  ; minimally-qualified # 
🧔🏼‍♀ E13.1 woman: medium-light skin tone, beard
+1F9D4 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧔🏽‍♀️ E13.1 woman: medium skin tone, beard
+1F9D4 1F3FD 200D 2640                                  ; minimally-qualified # 
🧔🏽‍♀ E13.1 woman: medium skin tone, beard
+1F9D4 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧔🏾‍♀️ E13.1 woman: medium-dark skin tone, beard
+1F9D4 1F3FE 200D 2640                                  ; minimally-qualified # 
🧔🏾‍♀ E13.1 woman: medium-dark skin tone, beard
+1F9D4 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧔🏿‍♀️ E13.1 woman: dark skin tone, beard
+1F9D4 1F3FF 200D 2640                                  ; minimally-qualified # 
🧔🏿‍♀ E13.1 woman: dark skin tone, beard
+1F468 200D 1F9B0                                       ; fully-qualified     # 
👨‍🦰 E11.0 man: red hair
+1F468 1F3FB 200D 1F9B0                                 ; fully-qualified     # 
👨🏻‍🦰 E11.0 man: light skin tone, red hair
+1F468 1F3FC 200D 1F9B0                                 ; fully-qualified     # 
👨🏼‍🦰 E11.0 man: medium-light skin tone, red hair
+1F468 1F3FD 200D 1F9B0                                 ; fully-qualified     # 
👨🏽‍🦰 E11.0 man: medium skin tone, red hair
+1F468 1F3FE 200D 1F9B0                                 ; fully-qualified     # 
👨🏾‍🦰 E11.0 man: medium-dark skin tone, red hair
+1F468 1F3FF 200D 1F9B0                                 ; fully-qualified     # 
👨🏿‍🦰 E11.0 man: dark skin tone, red hair
+1F468 200D 1F9B1                                       ; fully-qualified     # 
👨‍🦱 E11.0 man: curly hair
+1F468 1F3FB 200D 1F9B1                                 ; fully-qualified     # 
👨🏻‍🦱 E11.0 man: light skin tone, curly hair
+1F468 1F3FC 200D 1F9B1                                 ; fully-qualified     # 
👨🏼‍🦱 E11.0 man: medium-light skin tone, curly hair
+1F468 1F3FD 200D 1F9B1                                 ; fully-qualified     # 
👨🏽‍🦱 E11.0 man: medium skin tone, curly hair
+1F468 1F3FE 200D 1F9B1                                 ; fully-qualified     # 
👨🏾‍🦱 E11.0 man: medium-dark skin tone, curly hair
+1F468 1F3FF 200D 1F9B1                                 ; fully-qualified     # 
👨🏿‍🦱 E11.0 man: dark skin tone, curly hair
+1F468 200D 1F9B3                                       ; fully-qualified     # 
👨‍🦳 E11.0 man: white hair
+1F468 1F3FB 200D 1F9B3                                 ; fully-qualified     # 
👨🏻‍🦳 E11.0 man: light skin tone, white hair
+1F468 1F3FC 200D 1F9B3                                 ; fully-qualified     # 
👨🏼‍🦳 E11.0 man: medium-light skin tone, white hair
+1F468 1F3FD 200D 1F9B3                                 ; fully-qualified     # 
👨🏽‍🦳 E11.0 man: medium skin tone, white hair
+1F468 1F3FE 200D 1F9B3                                 ; fully-qualified     # 
👨🏾‍🦳 E11.0 man: medium-dark skin tone, white hair
+1F468 1F3FF 200D 1F9B3                                 ; fully-qualified     # 
👨🏿‍🦳 E11.0 man: dark skin tone, white hair
+1F468 200D 1F9B2                                       ; fully-qualified     # 
👨‍🦲 E11.0 man: bald
+1F468 1F3FB 200D 1F9B2                                 ; fully-qualified     # 
👨🏻‍🦲 E11.0 man: light skin tone, bald
+1F468 1F3FC 200D 1F9B2                                 ; fully-qualified     # 
👨🏼‍🦲 E11.0 man: medium-light skin tone, bald
+1F468 1F3FD 200D 1F9B2                                 ; fully-qualified     # 
👨🏽‍🦲 E11.0 man: medium skin tone, bald
+1F468 1F3FE 200D 1F9B2                                 ; fully-qualified     # 
👨🏾‍🦲 E11.0 man: medium-dark skin tone, bald
+1F468 1F3FF 200D 1F9B2                                 ; fully-qualified     # 
👨🏿‍🦲 E11.0 man: dark skin tone, bald
+1F469                                                  ; fully-qualified     # 
👩 E0.6 woman
+1F469 1F3FB                                            ; fully-qualified     # 
👩🏻 E1.0 woman: light skin tone
+1F469 1F3FC                                            ; fully-qualified     # 
👩🏼 E1.0 woman: medium-light skin tone
+1F469 1F3FD                                            ; fully-qualified     # 
👩🏽 E1.0 woman: medium skin tone
+1F469 1F3FE                                            ; fully-qualified     # 
👩🏾 E1.0 woman: medium-dark skin tone
+1F469 1F3FF                                            ; fully-qualified     # 
👩🏿 E1.0 woman: dark skin tone
+1F469 200D 1F9B0                                       ; fully-qualified     # 
👩‍🦰 E11.0 woman: red hair
+1F469 1F3FB 200D 1F9B0                                 ; fully-qualified     # 
👩🏻‍🦰 E11.0 woman: light skin tone, red hair
+1F469 1F3FC 200D 1F9B0                                 ; fully-qualified     # 
👩🏼‍🦰 E11.0 woman: medium-light skin tone, red hair
+1F469 1F3FD 200D 1F9B0                                 ; fully-qualified     # 
👩🏽‍🦰 E11.0 woman: medium skin tone, red hair
+1F469 1F3FE 200D 1F9B0                                 ; fully-qualified     # 
👩🏾‍🦰 E11.0 woman: medium-dark skin tone, red hair
+1F469 1F3FF 200D 1F9B0                                 ; fully-qualified     # 
👩🏿‍🦰 E11.0 woman: dark skin tone, red hair
+1F9D1 200D 1F9B0                                       ; fully-qualified     # 
🧑‍🦰 E12.1 person: red hair
+1F9D1 1F3FB 200D 1F9B0                                 ; fully-qualified     # 
🧑🏻‍🦰 E12.1 person: light skin tone, red hair
+1F9D1 1F3FC 200D 1F9B0                                 ; fully-qualified     # 
🧑🏼‍🦰 E12.1 person: medium-light skin tone, red hair
+1F9D1 1F3FD 200D 1F9B0                                 ; fully-qualified     # 
🧑🏽‍🦰 E12.1 person: medium skin tone, red hair
+1F9D1 1F3FE 200D 1F9B0                                 ; fully-qualified     # 
🧑🏾‍🦰 E12.1 person: medium-dark skin tone, red hair
+1F9D1 1F3FF 200D 1F9B0                                 ; fully-qualified     # 
🧑🏿‍🦰 E12.1 person: dark skin tone, red hair
+1F469 200D 1F9B1                                       ; fully-qualified     # 
👩‍🦱 E11.0 woman: curly hair
+1F469 1F3FB 200D 1F9B1                                 ; fully-qualified     # 
👩🏻‍🦱 E11.0 woman: light skin tone, curly hair
+1F469 1F3FC 200D 1F9B1                                 ; fully-qualified     # 
👩🏼‍🦱 E11.0 woman: medium-light skin tone, curly hair
+1F469 1F3FD 200D 1F9B1                                 ; fully-qualified     # 
👩🏽‍🦱 E11.0 woman: medium skin tone, curly hair
+1F469 1F3FE 200D 1F9B1                                 ; fully-qualified     # 
👩🏾‍🦱 E11.0 woman: medium-dark skin tone, curly hair
+1F469 1F3FF 200D 1F9B1                                 ; fully-qualified     # 
👩🏿‍🦱 E11.0 woman: dark skin tone, curly hair
+1F9D1 200D 1F9B1                                       ; fully-qualified     # 
🧑‍🦱 E12.1 person: curly hair
+1F9D1 1F3FB 200D 1F9B1                                 ; fully-qualified     # 
🧑🏻‍🦱 E12.1 person: light skin tone, curly hair
+1F9D1 1F3FC 200D 1F9B1                                 ; fully-qualified     # 
🧑🏼‍🦱 E12.1 person: medium-light skin tone, curly hair
+1F9D1 1F3FD 200D 1F9B1                                 ; fully-qualified     # 
🧑🏽‍🦱 E12.1 person: medium skin tone, curly hair
+1F9D1 1F3FE 200D 1F9B1                                 ; fully-qualified     # 
🧑🏾‍🦱 E12.1 person: medium-dark skin tone, curly hair
+1F9D1 1F3FF 200D 1F9B1                                 ; fully-qualified     # 
🧑🏿‍🦱 E12.1 person: dark skin tone, curly hair
+1F469 200D 1F9B3                                       ; fully-qualified     # 
👩‍🦳 E11.0 woman: white hair
+1F469 1F3FB 200D 1F9B3                                 ; fully-qualified     # 
👩🏻‍🦳 E11.0 woman: light skin tone, white hair
+1F469 1F3FC 200D 1F9B3                                 ; fully-qualified     # 
👩🏼‍🦳 E11.0 woman: medium-light skin tone, white hair
+1F469 1F3FD 200D 1F9B3                                 ; fully-qualified     # 
👩🏽‍🦳 E11.0 woman: medium skin tone, white hair
+1F469 1F3FE 200D 1F9B3                                 ; fully-qualified     # 
👩🏾‍🦳 E11.0 woman: medium-dark skin tone, white hair
+1F469 1F3FF 200D 1F9B3                                 ; fully-qualified     # 
👩🏿‍🦳 E11.0 woman: dark skin tone, white hair
+1F9D1 200D 1F9B3                                       ; fully-qualified     # 
🧑‍🦳 E12.1 person: white hair
+1F9D1 1F3FB 200D 1F9B3                                 ; fully-qualified     # 
🧑🏻‍🦳 E12.1 person: light skin tone, white hair
+1F9D1 1F3FC 200D 1F9B3                                 ; fully-qualified     # 
🧑🏼‍🦳 E12.1 person: medium-light skin tone, white hair
+1F9D1 1F3FD 200D 1F9B3                                 ; fully-qualified     # 
🧑🏽‍🦳 E12.1 person: medium skin tone, white hair
+1F9D1 1F3FE 200D 1F9B3                                 ; fully-qualified     # 
🧑🏾‍🦳 E12.1 person: medium-dark skin tone, white hair
+1F9D1 1F3FF 200D 1F9B3                                 ; fully-qualified     # 
🧑🏿‍🦳 E12.1 person: dark skin tone, white hair
+1F469 200D 1F9B2                                       ; fully-qualified     # 
👩‍🦲 E11.0 woman: bald
+1F469 1F3FB 200D 1F9B2                                 ; fully-qualified     # 
👩🏻‍🦲 E11.0 woman: light skin tone, bald
+1F469 1F3FC 200D 1F9B2                                 ; fully-qualified     # 
👩🏼‍🦲 E11.0 woman: medium-light skin tone, bald
+1F469 1F3FD 200D 1F9B2                                 ; fully-qualified     # 
👩🏽‍🦲 E11.0 woman: medium skin tone, bald
+1F469 1F3FE 200D 1F9B2                                 ; fully-qualified     # 
👩🏾‍🦲 E11.0 woman: medium-dark skin tone, bald
+1F469 1F3FF 200D 1F9B2                                 ; fully-qualified     # 
👩🏿‍🦲 E11.0 woman: dark skin tone, bald
+1F9D1 200D 1F9B2                                       ; fully-qualified     # 
🧑‍🦲 E12.1 person: bald
+1F9D1 1F3FB 200D 1F9B2                                 ; fully-qualified     # 
🧑🏻‍🦲 E12.1 person: light skin tone, bald
+1F9D1 1F3FC 200D 1F9B2                                 ; fully-qualified     # 
🧑🏼‍🦲 E12.1 person: medium-light skin tone, bald
+1F9D1 1F3FD 200D 1F9B2                                 ; fully-qualified     # 
🧑🏽‍🦲 E12.1 person: medium skin tone, bald
+1F9D1 1F3FE 200D 1F9B2                                 ; fully-qualified     # 
🧑🏾‍🦲 E12.1 person: medium-dark skin tone, bald
+1F9D1 1F3FF 200D 1F9B2                                 ; fully-qualified     # 
🧑🏿‍🦲 E12.1 person: dark skin tone, bald
+1F471 200D 2640 FE0F                                   ; fully-qualified     # 
👱‍♀️ E4.0 woman: blond hair
+1F471 200D 2640                                        ; minimally-qualified # 
👱‍♀ E4.0 woman: blond hair
+1F471 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
👱🏻‍♀️ E4.0 woman: light skin tone, blond hair
+1F471 1F3FB 200D 2640                                  ; minimally-qualified # 
👱🏻‍♀ E4.0 woman: light skin tone, blond hair
+1F471 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
👱🏼‍♀️ E4.0 woman: medium-light skin tone, blond hair
+1F471 1F3FC 200D 2640                                  ; minimally-qualified # 
👱🏼‍♀ E4.0 woman: medium-light skin tone, blond hair
+1F471 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
👱🏽‍♀️ E4.0 woman: medium skin tone, blond hair
+1F471 1F3FD 200D 2640                                  ; minimally-qualified # 
👱🏽‍♀ E4.0 woman: medium skin tone, blond hair
+1F471 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
👱🏾‍♀️ E4.0 woman: medium-dark skin tone, blond hair
+1F471 1F3FE 200D 2640                                  ; minimally-qualified # 
👱🏾‍♀ E4.0 woman: medium-dark skin tone, blond hair
+1F471 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
👱🏿‍♀️ E4.0 woman: dark skin tone, blond hair
+1F471 1F3FF 200D 2640                                  ; minimally-qualified # 
👱🏿‍♀ E4.0 woman: dark skin tone, blond hair
+1F471 200D 2642 FE0F                                   ; fully-qualified     # 
👱‍♂️ E4.0 man: blond hair
+1F471 200D 2642                                        ; minimally-qualified # 
👱‍♂ E4.0 man: blond hair
+1F471 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
👱🏻‍♂️ E4.0 man: light skin tone, blond hair
+1F471 1F3FB 200D 2642                                  ; minimally-qualified # 
👱🏻‍♂ E4.0 man: light skin tone, blond hair
+1F471 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
👱🏼‍♂️ E4.0 man: medium-light skin tone, blond hair
+1F471 1F3FC 200D 2642                                  ; minimally-qualified # 
👱🏼‍♂ E4.0 man: medium-light skin tone, blond hair
+1F471 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
👱🏽‍♂️ E4.0 man: medium skin tone, blond hair
+1F471 1F3FD 200D 2642                                  ; minimally-qualified # 
👱🏽‍♂ E4.0 man: medium skin tone, blond hair
+1F471 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
👱🏾‍♂️ E4.0 man: medium-dark skin tone, blond hair
+1F471 1F3FE 200D 2642                                  ; minimally-qualified # 
👱🏾‍♂ E4.0 man: medium-dark skin tone, blond hair
+1F471 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
👱🏿‍♂️ E4.0 man: dark skin tone, blond hair
+1F471 1F3FF 200D 2642                                  ; minimally-qualified # 
👱🏿‍♂ E4.0 man: dark skin tone, blond hair
+1F9D3                                                  ; fully-qualified     # 
🧓 E5.0 older person
+1F9D3 1F3FB                                            ; fully-qualified     # 
🧓🏻 E5.0 older person: light skin tone
+1F9D3 1F3FC                                            ; fully-qualified     # 
🧓🏼 E5.0 older person: medium-light skin tone
+1F9D3 1F3FD                                            ; fully-qualified     # 
🧓🏽 E5.0 older person: medium skin tone
+1F9D3 1F3FE                                            ; fully-qualified     # 
🧓🏾 E5.0 older person: medium-dark skin tone
+1F9D3 1F3FF                                            ; fully-qualified     # 
🧓🏿 E5.0 older person: dark skin tone
+1F474                                                  ; fully-qualified     # 
👴 E0.6 old man
+1F474 1F3FB                                            ; fully-qualified     # 
👴🏻 E1.0 old man: light skin tone
+1F474 1F3FC                                            ; fully-qualified     # 
👴🏼 E1.0 old man: medium-light skin tone
+1F474 1F3FD                                            ; fully-qualified     # 
👴🏽 E1.0 old man: medium skin tone
+1F474 1F3FE                                            ; fully-qualified     # 
👴🏾 E1.0 old man: medium-dark skin tone
+1F474 1F3FF                                            ; fully-qualified     # 
👴🏿 E1.0 old man: dark skin tone
+1F475                                                  ; fully-qualified     # 
👵 E0.6 old woman
+1F475 1F3FB                                            ; fully-qualified     # 
👵🏻 E1.0 old woman: light skin tone
+1F475 1F3FC                                            ; fully-qualified     # 
👵🏼 E1.0 old woman: medium-light skin tone
+1F475 1F3FD                                            ; fully-qualified     # 
👵🏽 E1.0 old woman: medium skin tone
+1F475 1F3FE                                            ; fully-qualified     # 
👵🏾 E1.0 old woman: medium-dark skin tone
+1F475 1F3FF                                            ; fully-qualified     # 
👵🏿 E1.0 old woman: dark skin tone
+
+# subgroup: person-gesture
+1F64D                                                  ; fully-qualified     # 
🙍 E0.6 person frowning
+1F64D 1F3FB                                            ; fully-qualified     # 
🙍🏻 E1.0 person frowning: light skin tone
+1F64D 1F3FC                                            ; fully-qualified     # 
🙍🏼 E1.0 person frowning: medium-light skin tone
+1F64D 1F3FD                                            ; fully-qualified     # 
🙍🏽 E1.0 person frowning: medium skin tone
+1F64D 1F3FE                                            ; fully-qualified     # 
🙍🏾 E1.0 person frowning: medium-dark skin tone
+1F64D 1F3FF                                            ; fully-qualified     # 
🙍🏿 E1.0 person frowning: dark skin tone
+1F64D 200D 2642 FE0F                                   ; fully-qualified     # 
🙍‍♂️ E4.0 man frowning
+1F64D 200D 2642                                        ; minimally-qualified # 
🙍‍♂ E4.0 man frowning
+1F64D 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙍🏻‍♂️ E4.0 man frowning: light skin tone
+1F64D 1F3FB 200D 2642                                  ; minimally-qualified # 
🙍🏻‍♂ E4.0 man frowning: light skin tone
+1F64D 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙍🏼‍♂️ E4.0 man frowning: medium-light skin tone
+1F64D 1F3FC 200D 2642                                  ; minimally-qualified # 
🙍🏼‍♂ E4.0 man frowning: medium-light skin tone
+1F64D 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙍🏽‍♂️ E4.0 man frowning: medium skin tone
+1F64D 1F3FD 200D 2642                                  ; minimally-qualified # 
🙍🏽‍♂ E4.0 man frowning: medium skin tone
+1F64D 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙍🏾‍♂️ E4.0 man frowning: medium-dark skin tone
+1F64D 1F3FE 200D 2642                                  ; minimally-qualified # 
🙍🏾‍♂ E4.0 man frowning: medium-dark skin tone
+1F64D 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙍🏿‍♂️ E4.0 man frowning: dark skin tone
+1F64D 1F3FF 200D 2642                                  ; minimally-qualified # 
🙍🏿‍♂ E4.0 man frowning: dark skin tone
+1F64D 200D 2640 FE0F                                   ; fully-qualified     # 
🙍‍♀️ E4.0 woman frowning
+1F64D 200D 2640                                        ; minimally-qualified # 
🙍‍♀ E4.0 woman frowning
+1F64D 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙍🏻‍♀️ E4.0 woman frowning: light skin tone
+1F64D 1F3FB 200D 2640                                  ; minimally-qualified # 
🙍🏻‍♀ E4.0 woman frowning: light skin tone
+1F64D 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙍🏼‍♀️ E4.0 woman frowning: medium-light skin tone
+1F64D 1F3FC 200D 2640                                  ; minimally-qualified # 
🙍🏼‍♀ E4.0 woman frowning: medium-light skin tone
+1F64D 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙍🏽‍♀️ E4.0 woman frowning: medium skin tone
+1F64D 1F3FD 200D 2640                                  ; minimally-qualified # 
🙍🏽‍♀ E4.0 woman frowning: medium skin tone
+1F64D 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙍🏾‍♀️ E4.0 woman frowning: medium-dark skin tone
+1F64D 1F3FE 200D 2640                                  ; minimally-qualified # 
🙍🏾‍♀ E4.0 woman frowning: medium-dark skin tone
+1F64D 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙍🏿‍♀️ E4.0 woman frowning: dark skin tone
+1F64D 1F3FF 200D 2640                                  ; minimally-qualified # 
🙍🏿‍♀ E4.0 woman frowning: dark skin tone
+1F64E                                                  ; fully-qualified     # 
🙎 E0.6 person pouting
+1F64E 1F3FB                                            ; fully-qualified     # 
🙎🏻 E1.0 person pouting: light skin tone
+1F64E 1F3FC                                            ; fully-qualified     # 
🙎🏼 E1.0 person pouting: medium-light skin tone
+1F64E 1F3FD                                            ; fully-qualified     # 
🙎🏽 E1.0 person pouting: medium skin tone
+1F64E 1F3FE                                            ; fully-qualified     # 
🙎🏾 E1.0 person pouting: medium-dark skin tone
+1F64E 1F3FF                                            ; fully-qualified     # 
🙎🏿 E1.0 person pouting: dark skin tone
+1F64E 200D 2642 FE0F                                   ; fully-qualified     # 
🙎‍♂️ E4.0 man pouting
+1F64E 200D 2642                                        ; minimally-qualified # 
🙎‍♂ E4.0 man pouting
+1F64E 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙎🏻‍♂️ E4.0 man pouting: light skin tone
+1F64E 1F3FB 200D 2642                                  ; minimally-qualified # 
🙎🏻‍♂ E4.0 man pouting: light skin tone
+1F64E 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙎🏼‍♂️ E4.0 man pouting: medium-light skin tone
+1F64E 1F3FC 200D 2642                                  ; minimally-qualified # 
🙎🏼‍♂ E4.0 man pouting: medium-light skin tone
+1F64E 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙎🏽‍♂️ E4.0 man pouting: medium skin tone
+1F64E 1F3FD 200D 2642                                  ; minimally-qualified # 
🙎🏽‍♂ E4.0 man pouting: medium skin tone
+1F64E 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙎🏾‍♂️ E4.0 man pouting: medium-dark skin tone
+1F64E 1F3FE 200D 2642                                  ; minimally-qualified # 
🙎🏾‍♂ E4.0 man pouting: medium-dark skin tone
+1F64E 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙎🏿‍♂️ E4.0 man pouting: dark skin tone
+1F64E 1F3FF 200D 2642                                  ; minimally-qualified # 
🙎🏿‍♂ E4.0 man pouting: dark skin tone
+1F64E 200D 2640 FE0F                                   ; fully-qualified     # 
🙎‍♀️ E4.0 woman pouting
+1F64E 200D 2640                                        ; minimally-qualified # 
🙎‍♀ E4.0 woman pouting
+1F64E 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙎🏻‍♀️ E4.0 woman pouting: light skin tone
+1F64E 1F3FB 200D 2640                                  ; minimally-qualified # 
🙎🏻‍♀ E4.0 woman pouting: light skin tone
+1F64E 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙎🏼‍♀️ E4.0 woman pouting: medium-light skin tone
+1F64E 1F3FC 200D 2640                                  ; minimally-qualified # 
🙎🏼‍♀ E4.0 woman pouting: medium-light skin tone
+1F64E 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙎🏽‍♀️ E4.0 woman pouting: medium skin tone
+1F64E 1F3FD 200D 2640                                  ; minimally-qualified # 
🙎🏽‍♀ E4.0 woman pouting: medium skin tone
+1F64E 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙎🏾‍♀️ E4.0 woman pouting: medium-dark skin tone
+1F64E 1F3FE 200D 2640                                  ; minimally-qualified # 
🙎🏾‍♀ E4.0 woman pouting: medium-dark skin tone
+1F64E 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙎🏿‍♀️ E4.0 woman pouting: dark skin tone
+1F64E 1F3FF 200D 2640                                  ; minimally-qualified # 
🙎🏿‍♀ E4.0 woman pouting: dark skin tone
+1F645                                                  ; fully-qualified     # 
🙅 E0.6 person gesturing NO
+1F645 1F3FB                                            ; fully-qualified     # 
🙅🏻 E1.0 person gesturing NO: light skin tone
+1F645 1F3FC                                            ; fully-qualified     # 
🙅🏼 E1.0 person gesturing NO: medium-light skin tone
+1F645 1F3FD                                            ; fully-qualified     # 
🙅🏽 E1.0 person gesturing NO: medium skin tone
+1F645 1F3FE                                            ; fully-qualified     # 
🙅🏾 E1.0 person gesturing NO: medium-dark skin tone
+1F645 1F3FF                                            ; fully-qualified     # 
🙅🏿 E1.0 person gesturing NO: dark skin tone
+1F645 200D 2642 FE0F                                   ; fully-qualified     # 
🙅‍♂️ E4.0 man gesturing NO
+1F645 200D 2642                                        ; minimally-qualified # 
🙅‍♂ E4.0 man gesturing NO
+1F645 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙅🏻‍♂️ E4.0 man gesturing NO: light skin tone
+1F645 1F3FB 200D 2642                                  ; minimally-qualified # 
🙅🏻‍♂ E4.0 man gesturing NO: light skin tone
+1F645 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙅🏼‍♂️ E4.0 man gesturing NO: medium-light skin tone
+1F645 1F3FC 200D 2642                                  ; minimally-qualified # 
🙅🏼‍♂ E4.0 man gesturing NO: medium-light skin tone
+1F645 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙅🏽‍♂️ E4.0 man gesturing NO: medium skin tone
+1F645 1F3FD 200D 2642                                  ; minimally-qualified # 
🙅🏽‍♂ E4.0 man gesturing NO: medium skin tone
+1F645 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙅🏾‍♂️ E4.0 man gesturing NO: medium-dark skin tone
+1F645 1F3FE 200D 2642                                  ; minimally-qualified # 
🙅🏾‍♂ E4.0 man gesturing NO: medium-dark skin tone
+1F645 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙅🏿‍♂️ E4.0 man gesturing NO: dark skin tone
+1F645 1F3FF 200D 2642                                  ; minimally-qualified # 
🙅🏿‍♂ E4.0 man gesturing NO: dark skin tone
+1F645 200D 2640 FE0F                                   ; fully-qualified     # 
🙅‍♀️ E4.0 woman gesturing NO
+1F645 200D 2640                                        ; minimally-qualified # 
🙅‍♀ E4.0 woman gesturing NO
+1F645 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙅🏻‍♀️ E4.0 woman gesturing NO: light skin tone
+1F645 1F3FB 200D 2640                                  ; minimally-qualified # 
🙅🏻‍♀ E4.0 woman gesturing NO: light skin tone
+1F645 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙅🏼‍♀️ E4.0 woman gesturing NO: medium-light skin tone
+1F645 1F3FC 200D 2640                                  ; minimally-qualified # 
🙅🏼‍♀ E4.0 woman gesturing NO: medium-light skin tone
+1F645 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙅🏽‍♀️ E4.0 woman gesturing NO: medium skin tone
+1F645 1F3FD 200D 2640                                  ; minimally-qualified # 
🙅🏽‍♀ E4.0 woman gesturing NO: medium skin tone
+1F645 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙅🏾‍♀️ E4.0 woman gesturing NO: medium-dark skin tone
+1F645 1F3FE 200D 2640                                  ; minimally-qualified # 
🙅🏾‍♀ E4.0 woman gesturing NO: medium-dark skin tone
+1F645 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙅🏿‍♀️ E4.0 woman gesturing NO: dark skin tone
+1F645 1F3FF 200D 2640                                  ; minimally-qualified # 
🙅🏿‍♀ E4.0 woman gesturing NO: dark skin tone
+1F646                                                  ; fully-qualified     # 
🙆 E0.6 person gesturing OK
+1F646 1F3FB                                            ; fully-qualified     # 
🙆🏻 E1.0 person gesturing OK: light skin tone
+1F646 1F3FC                                            ; fully-qualified     # 
🙆🏼 E1.0 person gesturing OK: medium-light skin tone
+1F646 1F3FD                                            ; fully-qualified     # 
🙆🏽 E1.0 person gesturing OK: medium skin tone
+1F646 1F3FE                                            ; fully-qualified     # 
🙆🏾 E1.0 person gesturing OK: medium-dark skin tone
+1F646 1F3FF                                            ; fully-qualified     # 
🙆🏿 E1.0 person gesturing OK: dark skin tone
+1F646 200D 2642 FE0F                                   ; fully-qualified     # 
🙆‍♂️ E4.0 man gesturing OK
+1F646 200D 2642                                        ; minimally-qualified # 
🙆‍♂ E4.0 man gesturing OK
+1F646 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙆🏻‍♂️ E4.0 man gesturing OK: light skin tone
+1F646 1F3FB 200D 2642                                  ; minimally-qualified # 
🙆🏻‍♂ E4.0 man gesturing OK: light skin tone
+1F646 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙆🏼‍♂️ E4.0 man gesturing OK: medium-light skin tone
+1F646 1F3FC 200D 2642                                  ; minimally-qualified # 
🙆🏼‍♂ E4.0 man gesturing OK: medium-light skin tone
+1F646 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙆🏽‍♂️ E4.0 man gesturing OK: medium skin tone
+1F646 1F3FD 200D 2642                                  ; minimally-qualified # 
🙆🏽‍♂ E4.0 man gesturing OK: medium skin tone
+1F646 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙆🏾‍♂️ E4.0 man gesturing OK: medium-dark skin tone
+1F646 1F3FE 200D 2642                                  ; minimally-qualified # 
🙆🏾‍♂ E4.0 man gesturing OK: medium-dark skin tone
+1F646 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙆🏿‍♂️ E4.0 man gesturing OK: dark skin tone
+1F646 1F3FF 200D 2642                                  ; minimally-qualified # 
🙆🏿‍♂ E4.0 man gesturing OK: dark skin tone
+1F646 200D 2640 FE0F                                   ; fully-qualified     # 
🙆‍♀️ E4.0 woman gesturing OK
+1F646 200D 2640                                        ; minimally-qualified # 
🙆‍♀ E4.0 woman gesturing OK
+1F646 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙆🏻‍♀️ E4.0 woman gesturing OK: light skin tone
+1F646 1F3FB 200D 2640                                  ; minimally-qualified # 
🙆🏻‍♀ E4.0 woman gesturing OK: light skin tone
+1F646 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙆🏼‍♀️ E4.0 woman gesturing OK: medium-light skin tone
+1F646 1F3FC 200D 2640                                  ; minimally-qualified # 
🙆🏼‍♀ E4.0 woman gesturing OK: medium-light skin tone
+1F646 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙆🏽‍♀️ E4.0 woman gesturing OK: medium skin tone
+1F646 1F3FD 200D 2640                                  ; minimally-qualified # 
🙆🏽‍♀ E4.0 woman gesturing OK: medium skin tone
+1F646 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙆🏾‍♀️ E4.0 woman gesturing OK: medium-dark skin tone
+1F646 1F3FE 200D 2640                                  ; minimally-qualified # 
🙆🏾‍♀ E4.0 woman gesturing OK: medium-dark skin tone
+1F646 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙆🏿‍♀️ E4.0 woman gesturing OK: dark skin tone
+1F646 1F3FF 200D 2640                                  ; minimally-qualified # 
🙆🏿‍♀ E4.0 woman gesturing OK: dark skin tone
+1F481                                                  ; fully-qualified     # 
💁 E0.6 person tipping hand
+1F481 1F3FB                                            ; fully-qualified     # 
💁🏻 E1.0 person tipping hand: light skin tone
+1F481 1F3FC                                            ; fully-qualified     # 
💁🏼 E1.0 person tipping hand: medium-light skin tone
+1F481 1F3FD                                            ; fully-qualified     # 
💁🏽 E1.0 person tipping hand: medium skin tone
+1F481 1F3FE                                            ; fully-qualified     # 
💁🏾 E1.0 person tipping hand: medium-dark skin tone
+1F481 1F3FF                                            ; fully-qualified     # 
💁🏿 E1.0 person tipping hand: dark skin tone
+1F481 200D 2642 FE0F                                   ; fully-qualified     # 
💁‍♂️ E4.0 man tipping hand
+1F481 200D 2642                                        ; minimally-qualified # 
💁‍♂ E4.0 man tipping hand
+1F481 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
💁🏻‍♂️ E4.0 man tipping hand: light skin tone
+1F481 1F3FB 200D 2642                                  ; minimally-qualified # 
💁🏻‍♂ E4.0 man tipping hand: light skin tone
+1F481 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
💁🏼‍♂️ E4.0 man tipping hand: medium-light skin tone
+1F481 1F3FC 200D 2642                                  ; minimally-qualified # 
💁🏼‍♂ E4.0 man tipping hand: medium-light skin tone
+1F481 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
💁🏽‍♂️ E4.0 man tipping hand: medium skin tone
+1F481 1F3FD 200D 2642                                  ; minimally-qualified # 
💁🏽‍♂ E4.0 man tipping hand: medium skin tone
+1F481 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
💁🏾‍♂️ E4.0 man tipping hand: medium-dark skin tone
+1F481 1F3FE 200D 2642                                  ; minimally-qualified # 
💁🏾‍♂ E4.0 man tipping hand: medium-dark skin tone
+1F481 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
💁🏿‍♂️ E4.0 man tipping hand: dark skin tone
+1F481 1F3FF 200D 2642                                  ; minimally-qualified # 
💁🏿‍♂ E4.0 man tipping hand: dark skin tone
+1F481 200D 2640 FE0F                                   ; fully-qualified     # 
💁‍♀️ E4.0 woman tipping hand
+1F481 200D 2640                                        ; minimally-qualified # 
💁‍♀ E4.0 woman tipping hand
+1F481 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
💁🏻‍♀️ E4.0 woman tipping hand: light skin tone
+1F481 1F3FB 200D 2640                                  ; minimally-qualified # 
💁🏻‍♀ E4.0 woman tipping hand: light skin tone
+1F481 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
💁🏼‍♀️ E4.0 woman tipping hand: medium-light skin tone
+1F481 1F3FC 200D 2640                                  ; minimally-qualified # 
💁🏼‍♀ E4.0 woman tipping hand: medium-light skin tone
+1F481 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
💁🏽‍♀️ E4.0 woman tipping hand: medium skin tone
+1F481 1F3FD 200D 2640                                  ; minimally-qualified # 
💁🏽‍♀ E4.0 woman tipping hand: medium skin tone
+1F481 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
💁🏾‍♀️ E4.0 woman tipping hand: medium-dark skin tone
+1F481 1F3FE 200D 2640                                  ; minimally-qualified # 
💁🏾‍♀ E4.0 woman tipping hand: medium-dark skin tone
+1F481 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
💁🏿‍♀️ E4.0 woman tipping hand: dark skin tone
+1F481 1F3FF 200D 2640                                  ; minimally-qualified # 
💁🏿‍♀ E4.0 woman tipping hand: dark skin tone
+1F64B                                                  ; fully-qualified     # 
🙋 E0.6 person raising hand
+1F64B 1F3FB                                            ; fully-qualified     # 
🙋🏻 E1.0 person raising hand: light skin tone
+1F64B 1F3FC                                            ; fully-qualified     # 
🙋🏼 E1.0 person raising hand: medium-light skin tone
+1F64B 1F3FD                                            ; fully-qualified     # 
🙋🏽 E1.0 person raising hand: medium skin tone
+1F64B 1F3FE                                            ; fully-qualified     # 
🙋🏾 E1.0 person raising hand: medium-dark skin tone
+1F64B 1F3FF                                            ; fully-qualified     # 
🙋🏿 E1.0 person raising hand: dark skin tone
+1F64B 200D 2642 FE0F                                   ; fully-qualified     # 
🙋‍♂️ E4.0 man raising hand
+1F64B 200D 2642                                        ; minimally-qualified # 
🙋‍♂ E4.0 man raising hand
+1F64B 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙋🏻‍♂️ E4.0 man raising hand: light skin tone
+1F64B 1F3FB 200D 2642                                  ; minimally-qualified # 
🙋🏻‍♂ E4.0 man raising hand: light skin tone
+1F64B 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙋🏼‍♂️ E4.0 man raising hand: medium-light skin tone
+1F64B 1F3FC 200D 2642                                  ; minimally-qualified # 
🙋🏼‍♂ E4.0 man raising hand: medium-light skin tone
+1F64B 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙋🏽‍♂️ E4.0 man raising hand: medium skin tone
+1F64B 1F3FD 200D 2642                                  ; minimally-qualified # 
🙋🏽‍♂ E4.0 man raising hand: medium skin tone
+1F64B 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙋🏾‍♂️ E4.0 man raising hand: medium-dark skin tone
+1F64B 1F3FE 200D 2642                                  ; minimally-qualified # 
🙋🏾‍♂ E4.0 man raising hand: medium-dark skin tone
+1F64B 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙋🏿‍♂️ E4.0 man raising hand: dark skin tone
+1F64B 1F3FF 200D 2642                                  ; minimally-qualified # 
🙋🏿‍♂ E4.0 man raising hand: dark skin tone
+1F64B 200D 2640 FE0F                                   ; fully-qualified     # 
🙋‍♀️ E4.0 woman raising hand
+1F64B 200D 2640                                        ; minimally-qualified # 
🙋‍♀ E4.0 woman raising hand
+1F64B 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙋🏻‍♀️ E4.0 woman raising hand: light skin tone
+1F64B 1F3FB 200D 2640                                  ; minimally-qualified # 
🙋🏻‍♀ E4.0 woman raising hand: light skin tone
+1F64B 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙋🏼‍♀️ E4.0 woman raising hand: medium-light skin tone
+1F64B 1F3FC 200D 2640                                  ; minimally-qualified # 
🙋🏼‍♀ E4.0 woman raising hand: medium-light skin tone
+1F64B 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙋🏽‍♀️ E4.0 woman raising hand: medium skin tone
+1F64B 1F3FD 200D 2640                                  ; minimally-qualified # 
🙋🏽‍♀ E4.0 woman raising hand: medium skin tone
+1F64B 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙋🏾‍♀️ E4.0 woman raising hand: medium-dark skin tone
+1F64B 1F3FE 200D 2640                                  ; minimally-qualified # 
🙋🏾‍♀ E4.0 woman raising hand: medium-dark skin tone
+1F64B 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙋🏿‍♀️ E4.0 woman raising hand: dark skin tone
+1F64B 1F3FF 200D 2640                                  ; minimally-qualified # 
🙋🏿‍♀ E4.0 woman raising hand: dark skin tone
+1F9CF                                                  ; fully-qualified     # 
🧏 E12.0 deaf person
+1F9CF 1F3FB                                            ; fully-qualified     # 
🧏🏻 E12.0 deaf person: light skin tone
+1F9CF 1F3FC                                            ; fully-qualified     # 
🧏🏼 E12.0 deaf person: medium-light skin tone
+1F9CF 1F3FD                                            ; fully-qualified     # 
🧏🏽 E12.0 deaf person: medium skin tone
+1F9CF 1F3FE                                            ; fully-qualified     # 
🧏🏾 E12.0 deaf person: medium-dark skin tone
+1F9CF 1F3FF                                            ; fully-qualified     # 
🧏🏿 E12.0 deaf person: dark skin tone
+1F9CF 200D 2642 FE0F                                   ; fully-qualified     # 
🧏‍♂️ E12.0 deaf man
+1F9CF 200D 2642                                        ; minimally-qualified # 
🧏‍♂ E12.0 deaf man
+1F9CF 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧏🏻‍♂️ E12.0 deaf man: light skin tone
+1F9CF 1F3FB 200D 2642                                  ; minimally-qualified # 
🧏🏻‍♂ E12.0 deaf man: light skin tone
+1F9CF 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧏🏼‍♂️ E12.0 deaf man: medium-light skin tone
+1F9CF 1F3FC 200D 2642                                  ; minimally-qualified # 
🧏🏼‍♂ E12.0 deaf man: medium-light skin tone
+1F9CF 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧏🏽‍♂️ E12.0 deaf man: medium skin tone
+1F9CF 1F3FD 200D 2642                                  ; minimally-qualified # 
🧏🏽‍♂ E12.0 deaf man: medium skin tone
+1F9CF 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧏🏾‍♂️ E12.0 deaf man: medium-dark skin tone
+1F9CF 1F3FE 200D 2642                                  ; minimally-qualified # 
🧏🏾‍♂ E12.0 deaf man: medium-dark skin tone
+1F9CF 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧏🏿‍♂️ E12.0 deaf man: dark skin tone
+1F9CF 1F3FF 200D 2642                                  ; minimally-qualified # 
🧏🏿‍♂ E12.0 deaf man: dark skin tone
+1F9CF 200D 2640 FE0F                                   ; fully-qualified     # 
🧏‍♀️ E12.0 deaf woman
+1F9CF 200D 2640                                        ; minimally-qualified # 
🧏‍♀ E12.0 deaf woman
+1F9CF 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧏🏻‍♀️ E12.0 deaf woman: light skin tone
+1F9CF 1F3FB 200D 2640                                  ; minimally-qualified # 
🧏🏻‍♀ E12.0 deaf woman: light skin tone
+1F9CF 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧏🏼‍♀️ E12.0 deaf woman: medium-light skin tone
+1F9CF 1F3FC 200D 2640                                  ; minimally-qualified # 
🧏🏼‍♀ E12.0 deaf woman: medium-light skin tone
+1F9CF 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧏🏽‍♀️ E12.0 deaf woman: medium skin tone
+1F9CF 1F3FD 200D 2640                                  ; minimally-qualified # 
🧏🏽‍♀ E12.0 deaf woman: medium skin tone
+1F9CF 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧏🏾‍♀️ E12.0 deaf woman: medium-dark skin tone
+1F9CF 1F3FE 200D 2640                                  ; minimally-qualified # 
🧏🏾‍♀ E12.0 deaf woman: medium-dark skin tone
+1F9CF 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧏🏿‍♀️ E12.0 deaf woman: dark skin tone
+1F9CF 1F3FF 200D 2640                                  ; minimally-qualified # 
🧏🏿‍♀ E12.0 deaf woman: dark skin tone
+1F647                                                  ; fully-qualified     # 
🙇 E0.6 person bowing
+1F647 1F3FB                                            ; fully-qualified     # 
🙇🏻 E1.0 person bowing: light skin tone
+1F647 1F3FC                                            ; fully-qualified     # 
🙇🏼 E1.0 person bowing: medium-light skin tone
+1F647 1F3FD                                            ; fully-qualified     # 
🙇🏽 E1.0 person bowing: medium skin tone
+1F647 1F3FE                                            ; fully-qualified     # 
🙇🏾 E1.0 person bowing: medium-dark skin tone
+1F647 1F3FF                                            ; fully-qualified     # 
🙇🏿 E1.0 person bowing: dark skin tone
+1F647 200D 2642 FE0F                                   ; fully-qualified     # 
🙇‍♂️ E4.0 man bowing
+1F647 200D 2642                                        ; minimally-qualified # 
🙇‍♂ E4.0 man bowing
+1F647 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🙇🏻‍♂️ E4.0 man bowing: light skin tone
+1F647 1F3FB 200D 2642                                  ; minimally-qualified # 
🙇🏻‍♂ E4.0 man bowing: light skin tone
+1F647 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🙇🏼‍♂️ E4.0 man bowing: medium-light skin tone
+1F647 1F3FC 200D 2642                                  ; minimally-qualified # 
🙇🏼‍♂ E4.0 man bowing: medium-light skin tone
+1F647 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🙇🏽‍♂️ E4.0 man bowing: medium skin tone
+1F647 1F3FD 200D 2642                                  ; minimally-qualified # 
🙇🏽‍♂ E4.0 man bowing: medium skin tone
+1F647 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🙇🏾‍♂️ E4.0 man bowing: medium-dark skin tone
+1F647 1F3FE 200D 2642                                  ; minimally-qualified # 
🙇🏾‍♂ E4.0 man bowing: medium-dark skin tone
+1F647 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🙇🏿‍♂️ E4.0 man bowing: dark skin tone
+1F647 1F3FF 200D 2642                                  ; minimally-qualified # 
🙇🏿‍♂ E4.0 man bowing: dark skin tone
+1F647 200D 2640 FE0F                                   ; fully-qualified     # 
🙇‍♀️ E4.0 woman bowing
+1F647 200D 2640                                        ; minimally-qualified # 
🙇‍♀ E4.0 woman bowing
+1F647 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🙇🏻‍♀️ E4.0 woman bowing: light skin tone
+1F647 1F3FB 200D 2640                                  ; minimally-qualified # 
🙇🏻‍♀ E4.0 woman bowing: light skin tone
+1F647 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🙇🏼‍♀️ E4.0 woman bowing: medium-light skin tone
+1F647 1F3FC 200D 2640                                  ; minimally-qualified # 
🙇🏼‍♀ E4.0 woman bowing: medium-light skin tone
+1F647 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🙇🏽‍♀️ E4.0 woman bowing: medium skin tone
+1F647 1F3FD 200D 2640                                  ; minimally-qualified # 
🙇🏽‍♀ E4.0 woman bowing: medium skin tone
+1F647 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🙇🏾‍♀️ E4.0 woman bowing: medium-dark skin tone
+1F647 1F3FE 200D 2640                                  ; minimally-qualified # 
🙇🏾‍♀ E4.0 woman bowing: medium-dark skin tone
+1F647 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🙇🏿‍♀️ E4.0 woman bowing: dark skin tone
+1F647 1F3FF 200D 2640                                  ; minimally-qualified # 
🙇🏿‍♀ E4.0 woman bowing: dark skin tone
+1F926                                                  ; fully-qualified     # 
🤦 E3.0 person facepalming
+1F926 1F3FB                                            ; fully-qualified     # 
🤦🏻 E3.0 person facepalming: light skin tone
+1F926 1F3FC                                            ; fully-qualified     # 
🤦🏼 E3.0 person facepalming: medium-light skin tone
+1F926 1F3FD                                            ; fully-qualified     # 
🤦🏽 E3.0 person facepalming: medium skin tone
+1F926 1F3FE                                            ; fully-qualified     # 
🤦🏾 E3.0 person facepalming: medium-dark skin tone
+1F926 1F3FF                                            ; fully-qualified     # 
🤦🏿 E3.0 person facepalming: dark skin tone
+1F926 200D 2642 FE0F                                   ; fully-qualified     # 
🤦‍♂️ E4.0 man facepalming
+1F926 200D 2642                                        ; minimally-qualified # 
🤦‍♂ E4.0 man facepalming
+1F926 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤦🏻‍♂️ E4.0 man facepalming: light skin tone
+1F926 1F3FB 200D 2642                                  ; minimally-qualified # 
🤦🏻‍♂ E4.0 man facepalming: light skin tone
+1F926 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤦🏼‍♂️ E4.0 man facepalming: medium-light skin tone
+1F926 1F3FC 200D 2642                                  ; minimally-qualified # 
🤦🏼‍♂ E4.0 man facepalming: medium-light skin tone
+1F926 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤦🏽‍♂️ E4.0 man facepalming: medium skin tone
+1F926 1F3FD 200D 2642                                  ; minimally-qualified # 
🤦🏽‍♂ E4.0 man facepalming: medium skin tone
+1F926 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤦🏾‍♂️ E4.0 man facepalming: medium-dark skin tone
+1F926 1F3FE 200D 2642                                  ; minimally-qualified # 
🤦🏾‍♂ E4.0 man facepalming: medium-dark skin tone
+1F926 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤦🏿‍♂️ E4.0 man facepalming: dark skin tone
+1F926 1F3FF 200D 2642                                  ; minimally-qualified # 
🤦🏿‍♂ E4.0 man facepalming: dark skin tone
+1F926 200D 2640 FE0F                                   ; fully-qualified     # 
🤦‍♀️ E4.0 woman facepalming
+1F926 200D 2640                                        ; minimally-qualified # 
🤦‍♀ E4.0 woman facepalming
+1F926 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤦🏻‍♀️ E4.0 woman facepalming: light skin tone
+1F926 1F3FB 200D 2640                                  ; minimally-qualified # 
🤦🏻‍♀ E4.0 woman facepalming: light skin tone
+1F926 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤦🏼‍♀️ E4.0 woman facepalming: medium-light skin tone
+1F926 1F3FC 200D 2640                                  ; minimally-qualified # 
🤦🏼‍♀ E4.0 woman facepalming: medium-light skin tone
+1F926 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤦🏽‍♀️ E4.0 woman facepalming: medium skin tone
+1F926 1F3FD 200D 2640                                  ; minimally-qualified # 
🤦🏽‍♀ E4.0 woman facepalming: medium skin tone
+1F926 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤦🏾‍♀️ E4.0 woman facepalming: medium-dark skin tone
+1F926 1F3FE 200D 2640                                  ; minimally-qualified # 
🤦🏾‍♀ E4.0 woman facepalming: medium-dark skin tone
+1F926 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤦🏿‍♀️ E4.0 woman facepalming: dark skin tone
+1F926 1F3FF 200D 2640                                  ; minimally-qualified # 
🤦🏿‍♀ E4.0 woman facepalming: dark skin tone
+1F937                                                  ; fully-qualified     # 
🤷 E3.0 person shrugging
+1F937 1F3FB                                            ; fully-qualified     # 
🤷🏻 E3.0 person shrugging: light skin tone
+1F937 1F3FC                                            ; fully-qualified     # 
🤷🏼 E3.0 person shrugging: medium-light skin tone
+1F937 1F3FD                                            ; fully-qualified     # 
🤷🏽 E3.0 person shrugging: medium skin tone
+1F937 1F3FE                                            ; fully-qualified     # 
🤷🏾 E3.0 person shrugging: medium-dark skin tone
+1F937 1F3FF                                            ; fully-qualified     # 
🤷🏿 E3.0 person shrugging: dark skin tone
+1F937 200D 2642 FE0F                                   ; fully-qualified     # 
🤷‍♂️ E4.0 man shrugging
+1F937 200D 2642                                        ; minimally-qualified # 
🤷‍♂ E4.0 man shrugging
+1F937 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤷🏻‍♂️ E4.0 man shrugging: light skin tone
+1F937 1F3FB 200D 2642                                  ; minimally-qualified # 
🤷🏻‍♂ E4.0 man shrugging: light skin tone
+1F937 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤷🏼‍♂️ E4.0 man shrugging: medium-light skin tone
+1F937 1F3FC 200D 2642                                  ; minimally-qualified # 
🤷🏼‍♂ E4.0 man shrugging: medium-light skin tone
+1F937 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤷🏽‍♂️ E4.0 man shrugging: medium skin tone
+1F937 1F3FD 200D 2642                                  ; minimally-qualified # 
🤷🏽‍♂ E4.0 man shrugging: medium skin tone
+1F937 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤷🏾‍♂️ E4.0 man shrugging: medium-dark skin tone
+1F937 1F3FE 200D 2642                                  ; minimally-qualified # 
🤷🏾‍♂ E4.0 man shrugging: medium-dark skin tone
+1F937 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤷🏿‍♂️ E4.0 man shrugging: dark skin tone
+1F937 1F3FF 200D 2642                                  ; minimally-qualified # 
🤷🏿‍♂ E4.0 man shrugging: dark skin tone
+1F937 200D 2640 FE0F                                   ; fully-qualified     # 
🤷‍♀️ E4.0 woman shrugging
+1F937 200D 2640                                        ; minimally-qualified # 
🤷‍♀ E4.0 woman shrugging
+1F937 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤷🏻‍♀️ E4.0 woman shrugging: light skin tone
+1F937 1F3FB 200D 2640                                  ; minimally-qualified # 
🤷🏻‍♀ E4.0 woman shrugging: light skin tone
+1F937 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤷🏼‍♀️ E4.0 woman shrugging: medium-light skin tone
+1F937 1F3FC 200D 2640                                  ; minimally-qualified # 
🤷🏼‍♀ E4.0 woman shrugging: medium-light skin tone
+1F937 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤷🏽‍♀️ E4.0 woman shrugging: medium skin tone
+1F937 1F3FD 200D 2640                                  ; minimally-qualified # 
🤷🏽‍♀ E4.0 woman shrugging: medium skin tone
+1F937 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤷🏾‍♀️ E4.0 woman shrugging: medium-dark skin tone
+1F937 1F3FE 200D 2640                                  ; minimally-qualified # 
🤷🏾‍♀ E4.0 woman shrugging: medium-dark skin tone
+1F937 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤷🏿‍♀️ E4.0 woman shrugging: dark skin tone
+1F937 1F3FF 200D 2640                                  ; minimally-qualified # 
🤷🏿‍♀ E4.0 woman shrugging: dark skin tone
+
+# subgroup: person-role
+1F9D1 200D 2695 FE0F                                   ; fully-qualified     # 
🧑‍⚕️ E12.1 health worker
+1F9D1 200D 2695                                        ; minimally-qualified # 
🧑‍⚕ E12.1 health worker
+1F9D1 1F3FB 200D 2695 FE0F                             ; fully-qualified     # 
🧑🏻‍⚕️ E12.1 health worker: light skin tone
+1F9D1 1F3FB 200D 2695                                  ; minimally-qualified # 
🧑🏻‍⚕ E12.1 health worker: light skin tone
+1F9D1 1F3FC 200D 2695 FE0F                             ; fully-qualified     # 
🧑🏼‍⚕️ E12.1 health worker: medium-light skin tone
+1F9D1 1F3FC 200D 2695                                  ; minimally-qualified # 
🧑🏼‍⚕ E12.1 health worker: medium-light skin tone
+1F9D1 1F3FD 200D 2695 FE0F                             ; fully-qualified     # 
🧑🏽‍⚕️ E12.1 health worker: medium skin tone
+1F9D1 1F3FD 200D 2695                                  ; minimally-qualified # 
🧑🏽‍⚕ E12.1 health worker: medium skin tone
+1F9D1 1F3FE 200D 2695 FE0F                             ; fully-qualified     # 
🧑🏾‍⚕️ E12.1 health worker: medium-dark skin tone
+1F9D1 1F3FE 200D 2695                                  ; minimally-qualified # 
🧑🏾‍⚕ E12.1 health worker: medium-dark skin tone
+1F9D1 1F3FF 200D 2695 FE0F                             ; fully-qualified     # 
🧑🏿‍⚕️ E12.1 health worker: dark skin tone
+1F9D1 1F3FF 200D 2695                                  ; minimally-qualified # 
🧑🏿‍⚕ E12.1 health worker: dark skin tone
+1F468 200D 2695 FE0F                                   ; fully-qualified     # 
👨‍⚕️ E4.0 man health worker
+1F468 200D 2695                                        ; minimally-qualified # 
👨‍⚕ E4.0 man health worker
+1F468 1F3FB 200D 2695 FE0F                             ; fully-qualified     # 
👨🏻‍⚕️ E4.0 man health worker: light skin tone
+1F468 1F3FB 200D 2695                                  ; minimally-qualified # 
👨🏻‍⚕ E4.0 man health worker: light skin tone
+1F468 1F3FC 200D 2695 FE0F                             ; fully-qualified     # 
👨🏼‍⚕️ E4.0 man health worker: medium-light skin tone
+1F468 1F3FC 200D 2695                                  ; minimally-qualified # 
👨🏼‍⚕ E4.0 man health worker: medium-light skin tone
+1F468 1F3FD 200D 2695 FE0F                             ; fully-qualified     # 
👨🏽‍⚕️ E4.0 man health worker: medium skin tone
+1F468 1F3FD 200D 2695                                  ; minimally-qualified # 
👨🏽‍⚕ E4.0 man health worker: medium skin tone
+1F468 1F3FE 200D 2695 FE0F                             ; fully-qualified     # 
👨🏾‍⚕️ E4.0 man health worker: medium-dark skin tone
+1F468 1F3FE 200D 2695                                  ; minimally-qualified # 
👨🏾‍⚕ E4.0 man health worker: medium-dark skin tone
+1F468 1F3FF 200D 2695 FE0F                             ; fully-qualified     # 
👨🏿‍⚕️ E4.0 man health worker: dark skin tone
+1F468 1F3FF 200D 2695                                  ; minimally-qualified # 
👨🏿‍⚕ E4.0 man health worker: dark skin tone
+1F469 200D 2695 FE0F                                   ; fully-qualified     # 
👩‍⚕️ E4.0 woman health worker
+1F469 200D 2695                                        ; minimally-qualified # 
👩‍⚕ E4.0 woman health worker
+1F469 1F3FB 200D 2695 FE0F                             ; fully-qualified     # 
👩🏻‍⚕️ E4.0 woman health worker: light skin tone
+1F469 1F3FB 200D 2695                                  ; minimally-qualified # 
👩🏻‍⚕ E4.0 woman health worker: light skin tone
+1F469 1F3FC 200D 2695 FE0F                             ; fully-qualified     # 
👩🏼‍⚕️ E4.0 woman health worker: medium-light skin tone
+1F469 1F3FC 200D 2695                                  ; minimally-qualified # 
👩🏼‍⚕ E4.0 woman health worker: medium-light skin tone
+1F469 1F3FD 200D 2695 FE0F                             ; fully-qualified     # 
👩🏽‍⚕️ E4.0 woman health worker: medium skin tone
+1F469 1F3FD 200D 2695                                  ; minimally-qualified # 
👩🏽‍⚕ E4.0 woman health worker: medium skin tone
+1F469 1F3FE 200D 2695 FE0F                             ; fully-qualified     # 
👩🏾‍⚕️ E4.0 woman health worker: medium-dark skin tone
+1F469 1F3FE 200D 2695                                  ; minimally-qualified # 
👩🏾‍⚕ E4.0 woman health worker: medium-dark skin tone
+1F469 1F3FF 200D 2695 FE0F                             ; fully-qualified     # 
👩🏿‍⚕️ E4.0 woman health worker: dark skin tone
+1F469 1F3FF 200D 2695                                  ; minimally-qualified # 
👩🏿‍⚕ E4.0 woman health worker: dark skin tone
+1F9D1 200D 1F393                                       ; fully-qualified     # 
🧑‍🎓 E12.1 student
+1F9D1 1F3FB 200D 1F393                                 ; fully-qualified     # 
🧑🏻‍🎓 E12.1 student: light skin tone
+1F9D1 1F3FC 200D 1F393                                 ; fully-qualified     # 
🧑🏼‍🎓 E12.1 student: medium-light skin tone
+1F9D1 1F3FD 200D 1F393                                 ; fully-qualified     # 
🧑🏽‍🎓 E12.1 student: medium skin tone
+1F9D1 1F3FE 200D 1F393                                 ; fully-qualified     # 
🧑🏾‍🎓 E12.1 student: medium-dark skin tone
+1F9D1 1F3FF 200D 1F393                                 ; fully-qualified     # 
🧑🏿‍🎓 E12.1 student: dark skin tone
+1F468 200D 1F393                                       ; fully-qualified     # 
👨‍🎓 E4.0 man student
+1F468 1F3FB 200D 1F393                                 ; fully-qualified     # 
👨🏻‍🎓 E4.0 man student: light skin tone
+1F468 1F3FC 200D 1F393                                 ; fully-qualified     # 
👨🏼‍🎓 E4.0 man student: medium-light skin tone
+1F468 1F3FD 200D 1F393                                 ; fully-qualified     # 
👨🏽‍🎓 E4.0 man student: medium skin tone
+1F468 1F3FE 200D 1F393                                 ; fully-qualified     # 
👨🏾‍🎓 E4.0 man student: medium-dark skin tone
+1F468 1F3FF 200D 1F393                                 ; fully-qualified     # 
👨🏿‍🎓 E4.0 man student: dark skin tone
+1F469 200D 1F393                                       ; fully-qualified     # 
👩‍🎓 E4.0 woman student
+1F469 1F3FB 200D 1F393                                 ; fully-qualified     # 
👩🏻‍🎓 E4.0 woman student: light skin tone
+1F469 1F3FC 200D 1F393                                 ; fully-qualified     # 
👩🏼‍🎓 E4.0 woman student: medium-light skin tone
+1F469 1F3FD 200D 1F393                                 ; fully-qualified     # 
👩🏽‍🎓 E4.0 woman student: medium skin tone
+1F469 1F3FE 200D 1F393                                 ; fully-qualified     # 
👩🏾‍🎓 E4.0 woman student: medium-dark skin tone
+1F469 1F3FF 200D 1F393                                 ; fully-qualified     # 
👩🏿‍🎓 E4.0 woman student: dark skin tone
+1F9D1 200D 1F3EB                                       ; fully-qualified     # 
🧑‍🏫 E12.1 teacher
+1F9D1 1F3FB 200D 1F3EB                                 ; fully-qualified     # 
🧑🏻‍🏫 E12.1 teacher: light skin tone
+1F9D1 1F3FC 200D 1F3EB                                 ; fully-qualified     # 
🧑🏼‍🏫 E12.1 teacher: medium-light skin tone
+1F9D1 1F3FD 200D 1F3EB                                 ; fully-qualified     # 
🧑🏽‍🏫 E12.1 teacher: medium skin tone
+1F9D1 1F3FE 200D 1F3EB                                 ; fully-qualified     # 
🧑🏾‍🏫 E12.1 teacher: medium-dark skin tone
+1F9D1 1F3FF 200D 1F3EB                                 ; fully-qualified     # 
🧑🏿‍🏫 E12.1 teacher: dark skin tone
+1F468 200D 1F3EB                                       ; fully-qualified     # 
👨‍🏫 E4.0 man teacher
+1F468 1F3FB 200D 1F3EB                                 ; fully-qualified     # 
👨🏻‍🏫 E4.0 man teacher: light skin tone
+1F468 1F3FC 200D 1F3EB                                 ; fully-qualified     # 
👨🏼‍🏫 E4.0 man teacher: medium-light skin tone
+1F468 1F3FD 200D 1F3EB                                 ; fully-qualified     # 
👨🏽‍🏫 E4.0 man teacher: medium skin tone
+1F468 1F3FE 200D 1F3EB                                 ; fully-qualified     # 
👨🏾‍🏫 E4.0 man teacher: medium-dark skin tone
+1F468 1F3FF 200D 1F3EB                                 ; fully-qualified     # 
👨🏿‍🏫 E4.0 man teacher: dark skin tone
+1F469 200D 1F3EB                                       ; fully-qualified     # 
👩‍🏫 E4.0 woman teacher
+1F469 1F3FB 200D 1F3EB                                 ; fully-qualified     # 
👩🏻‍🏫 E4.0 woman teacher: light skin tone
+1F469 1F3FC 200D 1F3EB                                 ; fully-qualified     # 
👩🏼‍🏫 E4.0 woman teacher: medium-light skin tone
+1F469 1F3FD 200D 1F3EB                                 ; fully-qualified     # 
👩🏽‍🏫 E4.0 woman teacher: medium skin tone
+1F469 1F3FE 200D 1F3EB                                 ; fully-qualified     # 
👩🏾‍🏫 E4.0 woman teacher: medium-dark skin tone
+1F469 1F3FF 200D 1F3EB                                 ; fully-qualified     # 
👩🏿‍🏫 E4.0 woman teacher: dark skin tone
+1F9D1 200D 2696 FE0F                                   ; fully-qualified     # 
🧑‍⚖️ E12.1 judge
+1F9D1 200D 2696                                        ; minimally-qualified # 
🧑‍⚖ E12.1 judge
+1F9D1 1F3FB 200D 2696 FE0F                             ; fully-qualified     # 
🧑🏻‍⚖️ E12.1 judge: light skin tone
+1F9D1 1F3FB 200D 2696                                  ; minimally-qualified # 
🧑🏻‍⚖ E12.1 judge: light skin tone
+1F9D1 1F3FC 200D 2696 FE0F                             ; fully-qualified     # 
🧑🏼‍⚖️ E12.1 judge: medium-light skin tone
+1F9D1 1F3FC 200D 2696                                  ; minimally-qualified # 
🧑🏼‍⚖ E12.1 judge: medium-light skin tone
+1F9D1 1F3FD 200D 2696 FE0F                             ; fully-qualified     # 
🧑🏽‍⚖️ E12.1 judge: medium skin tone
+1F9D1 1F3FD 200D 2696                                  ; minimally-qualified # 
🧑🏽‍⚖ E12.1 judge: medium skin tone
+1F9D1 1F3FE 200D 2696 FE0F                             ; fully-qualified     # 
🧑🏾‍⚖️ E12.1 judge: medium-dark skin tone
+1F9D1 1F3FE 200D 2696                                  ; minimally-qualified # 
🧑🏾‍⚖ E12.1 judge: medium-dark skin tone
+1F9D1 1F3FF 200D 2696 FE0F                             ; fully-qualified     # 
🧑🏿‍⚖️ E12.1 judge: dark skin tone
+1F9D1 1F3FF 200D 2696                                  ; minimally-qualified # 
🧑🏿‍⚖ E12.1 judge: dark skin tone
+1F468 200D 2696 FE0F                                   ; fully-qualified     # 
👨‍⚖️ E4.0 man judge
+1F468 200D 2696                                        ; minimally-qualified # 
👨‍⚖ E4.0 man judge
+1F468 1F3FB 200D 2696 FE0F                             ; fully-qualified     # 
👨🏻‍⚖️ E4.0 man judge: light skin tone
+1F468 1F3FB 200D 2696                                  ; minimally-qualified # 
👨🏻‍⚖ E4.0 man judge: light skin tone
+1F468 1F3FC 200D 2696 FE0F                             ; fully-qualified     # 
👨🏼‍⚖️ E4.0 man judge: medium-light skin tone
+1F468 1F3FC 200D 2696                                  ; minimally-qualified # 
👨🏼‍⚖ E4.0 man judge: medium-light skin tone
+1F468 1F3FD 200D 2696 FE0F                             ; fully-qualified     # 
👨🏽‍⚖️ E4.0 man judge: medium skin tone
+1F468 1F3FD 200D 2696                                  ; minimally-qualified # 
👨🏽‍⚖ E4.0 man judge: medium skin tone
+1F468 1F3FE 200D 2696 FE0F                             ; fully-qualified     # 
👨🏾‍⚖️ E4.0 man judge: medium-dark skin tone
+1F468 1F3FE 200D 2696                                  ; minimally-qualified # 
👨🏾‍⚖ E4.0 man judge: medium-dark skin tone
+1F468 1F3FF 200D 2696 FE0F                             ; fully-qualified     # 
👨🏿‍⚖️ E4.0 man judge: dark skin tone
+1F468 1F3FF 200D 2696                                  ; minimally-qualified # 
👨🏿‍⚖ E4.0 man judge: dark skin tone
+1F469 200D 2696 FE0F                                   ; fully-qualified     # 
👩‍⚖️ E4.0 woman judge
+1F469 200D 2696                                        ; minimally-qualified # 
👩‍⚖ E4.0 woman judge
+1F469 1F3FB 200D 2696 FE0F                             ; fully-qualified     # 
👩🏻‍⚖️ E4.0 woman judge: light skin tone
+1F469 1F3FB 200D 2696                                  ; minimally-qualified # 
👩🏻‍⚖ E4.0 woman judge: light skin tone
+1F469 1F3FC 200D 2696 FE0F                             ; fully-qualified     # 
👩🏼‍⚖️ E4.0 woman judge: medium-light skin tone
+1F469 1F3FC 200D 2696                                  ; minimally-qualified # 
👩🏼‍⚖ E4.0 woman judge: medium-light skin tone
+1F469 1F3FD 200D 2696 FE0F                             ; fully-qualified     # 
👩🏽‍⚖️ E4.0 woman judge: medium skin tone
+1F469 1F3FD 200D 2696                                  ; minimally-qualified # 
👩🏽‍⚖ E4.0 woman judge: medium skin tone
+1F469 1F3FE 200D 2696 FE0F                             ; fully-qualified     # 
👩🏾‍⚖️ E4.0 woman judge: medium-dark skin tone
+1F469 1F3FE 200D 2696                                  ; minimally-qualified # 
👩🏾‍⚖ E4.0 woman judge: medium-dark skin tone
+1F469 1F3FF 200D 2696 FE0F                             ; fully-qualified     # 
👩🏿‍⚖️ E4.0 woman judge: dark skin tone
+1F469 1F3FF 200D 2696                                  ; minimally-qualified # 
👩🏿‍⚖ E4.0 woman judge: dark skin tone
+1F9D1 200D 1F33E                                       ; fully-qualified     # 
🧑‍🌾 E12.1 farmer
+1F9D1 1F3FB 200D 1F33E                                 ; fully-qualified     # 
🧑🏻‍🌾 E12.1 farmer: light skin tone
+1F9D1 1F3FC 200D 1F33E                                 ; fully-qualified     # 
🧑🏼‍🌾 E12.1 farmer: medium-light skin tone
+1F9D1 1F3FD 200D 1F33E                                 ; fully-qualified     # 
🧑🏽‍🌾 E12.1 farmer: medium skin tone
+1F9D1 1F3FE 200D 1F33E                                 ; fully-qualified     # 
🧑🏾‍🌾 E12.1 farmer: medium-dark skin tone
+1F9D1 1F3FF 200D 1F33E                                 ; fully-qualified     # 
🧑🏿‍🌾 E12.1 farmer: dark skin tone
+1F468 200D 1F33E                                       ; fully-qualified     # 
👨‍🌾 E4.0 man farmer
+1F468 1F3FB 200D 1F33E                                 ; fully-qualified     # 
👨🏻‍🌾 E4.0 man farmer: light skin tone
+1F468 1F3FC 200D 1F33E                                 ; fully-qualified     # 
👨🏼‍🌾 E4.0 man farmer: medium-light skin tone
+1F468 1F3FD 200D 1F33E                                 ; fully-qualified     # 
👨🏽‍🌾 E4.0 man farmer: medium skin tone
+1F468 1F3FE 200D 1F33E                                 ; fully-qualified     # 
👨🏾‍🌾 E4.0 man farmer: medium-dark skin tone
+1F468 1F3FF 200D 1F33E                                 ; fully-qualified     # 
👨🏿‍🌾 E4.0 man farmer: dark skin tone
+1F469 200D 1F33E                                       ; fully-qualified     # 
👩‍🌾 E4.0 woman farmer
+1F469 1F3FB 200D 1F33E                                 ; fully-qualified     # 
👩🏻‍🌾 E4.0 woman farmer: light skin tone
+1F469 1F3FC 200D 1F33E                                 ; fully-qualified     # 
👩🏼‍🌾 E4.0 woman farmer: medium-light skin tone
+1F469 1F3FD 200D 1F33E                                 ; fully-qualified     # 
👩🏽‍🌾 E4.0 woman farmer: medium skin tone
+1F469 1F3FE 200D 1F33E                                 ; fully-qualified     # 
👩🏾‍🌾 E4.0 woman farmer: medium-dark skin tone
+1F469 1F3FF 200D 1F33E                                 ; fully-qualified     # 
👩🏿‍🌾 E4.0 woman farmer: dark skin tone
+1F9D1 200D 1F373                                       ; fully-qualified     # 
🧑‍🍳 E12.1 cook
+1F9D1 1F3FB 200D 1F373                                 ; fully-qualified     # 
🧑🏻‍🍳 E12.1 cook: light skin tone
+1F9D1 1F3FC 200D 1F373                                 ; fully-qualified     # 
🧑🏼‍🍳 E12.1 cook: medium-light skin tone
+1F9D1 1F3FD 200D 1F373                                 ; fully-qualified     # 
🧑🏽‍🍳 E12.1 cook: medium skin tone
+1F9D1 1F3FE 200D 1F373                                 ; fully-qualified     # 
🧑🏾‍🍳 E12.1 cook: medium-dark skin tone
+1F9D1 1F3FF 200D 1F373                                 ; fully-qualified     # 
🧑🏿‍🍳 E12.1 cook: dark skin tone
+1F468 200D 1F373                                       ; fully-qualified     # 
👨‍🍳 E4.0 man cook
+1F468 1F3FB 200D 1F373                                 ; fully-qualified     # 
👨🏻‍🍳 E4.0 man cook: light skin tone
+1F468 1F3FC 200D 1F373                                 ; fully-qualified     # 
👨🏼‍🍳 E4.0 man cook: medium-light skin tone
+1F468 1F3FD 200D 1F373                                 ; fully-qualified     # 
👨🏽‍🍳 E4.0 man cook: medium skin tone
+1F468 1F3FE 200D 1F373                                 ; fully-qualified     # 
👨🏾‍🍳 E4.0 man cook: medium-dark skin tone
+1F468 1F3FF 200D 1F373                                 ; fully-qualified     # 
👨🏿‍🍳 E4.0 man cook: dark skin tone
+1F469 200D 1F373                                       ; fully-qualified     # 
👩‍🍳 E4.0 woman cook
+1F469 1F3FB 200D 1F373                                 ; fully-qualified     # 
👩🏻‍🍳 E4.0 woman cook: light skin tone
+1F469 1F3FC 200D 1F373                                 ; fully-qualified     # 
👩🏼‍🍳 E4.0 woman cook: medium-light skin tone
+1F469 1F3FD 200D 1F373                                 ; fully-qualified     # 
👩🏽‍🍳 E4.0 woman cook: medium skin tone
+1F469 1F3FE 200D 1F373                                 ; fully-qualified     # 
👩🏾‍🍳 E4.0 woman cook: medium-dark skin tone
+1F469 1F3FF 200D 1F373                                 ; fully-qualified     # 
👩🏿‍🍳 E4.0 woman cook: dark skin tone
+1F9D1 200D 1F527                                       ; fully-qualified     # 
🧑‍🔧 E12.1 mechanic
+1F9D1 1F3FB 200D 1F527                                 ; fully-qualified     # 
🧑🏻‍🔧 E12.1 mechanic: light skin tone
+1F9D1 1F3FC 200D 1F527                                 ; fully-qualified     # 
🧑🏼‍🔧 E12.1 mechanic: medium-light skin tone
+1F9D1 1F3FD 200D 1F527                                 ; fully-qualified     # 
🧑🏽‍🔧 E12.1 mechanic: medium skin tone
+1F9D1 1F3FE 200D 1F527                                 ; fully-qualified     # 
🧑🏾‍🔧 E12.1 mechanic: medium-dark skin tone
+1F9D1 1F3FF 200D 1F527                                 ; fully-qualified     # 
🧑🏿‍🔧 E12.1 mechanic: dark skin tone
+1F468 200D 1F527                                       ; fully-qualified     # 
👨‍🔧 E4.0 man mechanic
+1F468 1F3FB 200D 1F527                                 ; fully-qualified     # 
👨🏻‍🔧 E4.0 man mechanic: light skin tone
+1F468 1F3FC 200D 1F527                                 ; fully-qualified     # 
👨🏼‍🔧 E4.0 man mechanic: medium-light skin tone
+1F468 1F3FD 200D 1F527                                 ; fully-qualified     # 
👨🏽‍🔧 E4.0 man mechanic: medium skin tone
+1F468 1F3FE 200D 1F527                                 ; fully-qualified     # 
👨🏾‍🔧 E4.0 man mechanic: medium-dark skin tone
+1F468 1F3FF 200D 1F527                                 ; fully-qualified     # 
👨🏿‍🔧 E4.0 man mechanic: dark skin tone
+1F469 200D 1F527                                       ; fully-qualified     # 
👩‍🔧 E4.0 woman mechanic
+1F469 1F3FB 200D 1F527                                 ; fully-qualified     # 
👩🏻‍🔧 E4.0 woman mechanic: light skin tone
+1F469 1F3FC 200D 1F527                                 ; fully-qualified     # 
👩🏼‍🔧 E4.0 woman mechanic: medium-light skin tone
+1F469 1F3FD 200D 1F527                                 ; fully-qualified     # 
👩🏽‍🔧 E4.0 woman mechanic: medium skin tone
+1F469 1F3FE 200D 1F527                                 ; fully-qualified     # 
👩🏾‍🔧 E4.0 woman mechanic: medium-dark skin tone
+1F469 1F3FF 200D 1F527                                 ; fully-qualified     # 
👩🏿‍🔧 E4.0 woman mechanic: dark skin tone
+1F9D1 200D 1F3ED                                       ; fully-qualified     # 
🧑‍🏭 E12.1 factory worker
+1F9D1 1F3FB 200D 1F3ED                                 ; fully-qualified     # 
🧑🏻‍🏭 E12.1 factory worker: light skin tone
+1F9D1 1F3FC 200D 1F3ED                                 ; fully-qualified     # 
🧑🏼‍🏭 E12.1 factory worker: medium-light skin tone
+1F9D1 1F3FD 200D 1F3ED                                 ; fully-qualified     # 
🧑🏽‍🏭 E12.1 factory worker: medium skin tone
+1F9D1 1F3FE 200D 1F3ED                                 ; fully-qualified     # 
🧑🏾‍🏭 E12.1 factory worker: medium-dark skin tone
+1F9D1 1F3FF 200D 1F3ED                                 ; fully-qualified     # 
🧑🏿‍🏭 E12.1 factory worker: dark skin tone
+1F468 200D 1F3ED                                       ; fully-qualified     # 
👨‍🏭 E4.0 man factory worker
+1F468 1F3FB 200D 1F3ED                                 ; fully-qualified     # 
👨🏻‍🏭 E4.0 man factory worker: light skin tone
+1F468 1F3FC 200D 1F3ED                                 ; fully-qualified     # 
👨🏼‍🏭 E4.0 man factory worker: medium-light skin tone
+1F468 1F3FD 200D 1F3ED                                 ; fully-qualified     # 
👨🏽‍🏭 E4.0 man factory worker: medium skin tone
+1F468 1F3FE 200D 1F3ED                                 ; fully-qualified     # 
👨🏾‍🏭 E4.0 man factory worker: medium-dark skin tone
+1F468 1F3FF 200D 1F3ED                                 ; fully-qualified     # 
👨🏿‍🏭 E4.0 man factory worker: dark skin tone
+1F469 200D 1F3ED                                       ; fully-qualified     # 
👩‍🏭 E4.0 woman factory worker
+1F469 1F3FB 200D 1F3ED                                 ; fully-qualified     # 
👩🏻‍🏭 E4.0 woman factory worker: light skin tone
+1F469 1F3FC 200D 1F3ED                                 ; fully-qualified     # 
👩🏼‍🏭 E4.0 woman factory worker: medium-light skin tone
+1F469 1F3FD 200D 1F3ED                                 ; fully-qualified     # 
👩🏽‍🏭 E4.0 woman factory worker: medium skin tone
+1F469 1F3FE 200D 1F3ED                                 ; fully-qualified     # 
👩🏾‍🏭 E4.0 woman factory worker: medium-dark skin tone
+1F469 1F3FF 200D 1F3ED                                 ; fully-qualified     # 
👩🏿‍🏭 E4.0 woman factory worker: dark skin tone
+1F9D1 200D 1F4BC                                       ; fully-qualified     # 
🧑‍💼 E12.1 office worker
+1F9D1 1F3FB 200D 1F4BC                                 ; fully-qualified     # 
🧑🏻‍💼 E12.1 office worker: light skin tone
+1F9D1 1F3FC 200D 1F4BC                                 ; fully-qualified     # 
🧑🏼‍💼 E12.1 office worker: medium-light skin tone
+1F9D1 1F3FD 200D 1F4BC                                 ; fully-qualified     # 
🧑🏽‍💼 E12.1 office worker: medium skin tone
+1F9D1 1F3FE 200D 1F4BC                                 ; fully-qualified     # 
🧑🏾‍💼 E12.1 office worker: medium-dark skin tone
+1F9D1 1F3FF 200D 1F4BC                                 ; fully-qualified     # 
🧑🏿‍💼 E12.1 office worker: dark skin tone
+1F468 200D 1F4BC                                       ; fully-qualified     # 
👨‍💼 E4.0 man office worker
+1F468 1F3FB 200D 1F4BC                                 ; fully-qualified     # 
👨🏻‍💼 E4.0 man office worker: light skin tone
+1F468 1F3FC 200D 1F4BC                                 ; fully-qualified     # 
👨🏼‍💼 E4.0 man office worker: medium-light skin tone
+1F468 1F3FD 200D 1F4BC                                 ; fully-qualified     # 
👨🏽‍💼 E4.0 man office worker: medium skin tone
+1F468 1F3FE 200D 1F4BC                                 ; fully-qualified     # 
👨🏾‍💼 E4.0 man office worker: medium-dark skin tone
+1F468 1F3FF 200D 1F4BC                                 ; fully-qualified     # 
👨🏿‍💼 E4.0 man office worker: dark skin tone
+1F469 200D 1F4BC                                       ; fully-qualified     # 
👩‍💼 E4.0 woman office worker
+1F469 1F3FB 200D 1F4BC                                 ; fully-qualified     # 
👩🏻‍💼 E4.0 woman office worker: light skin tone
+1F469 1F3FC 200D 1F4BC                                 ; fully-qualified     # 
👩🏼‍💼 E4.0 woman office worker: medium-light skin tone
+1F469 1F3FD 200D 1F4BC                                 ; fully-qualified     # 
👩🏽‍💼 E4.0 woman office worker: medium skin tone
+1F469 1F3FE 200D 1F4BC                                 ; fully-qualified     # 
👩🏾‍💼 E4.0 woman office worker: medium-dark skin tone
+1F469 1F3FF 200D 1F4BC                                 ; fully-qualified     # 
👩🏿‍💼 E4.0 woman office worker: dark skin tone
+1F9D1 200D 1F52C                                       ; fully-qualified     # 
🧑‍🔬 E12.1 scientist
+1F9D1 1F3FB 200D 1F52C                                 ; fully-qualified     # 
🧑🏻‍🔬 E12.1 scientist: light skin tone
+1F9D1 1F3FC 200D 1F52C                                 ; fully-qualified     # 
🧑🏼‍🔬 E12.1 scientist: medium-light skin tone
+1F9D1 1F3FD 200D 1F52C                                 ; fully-qualified     # 
🧑🏽‍🔬 E12.1 scientist: medium skin tone
+1F9D1 1F3FE 200D 1F52C                                 ; fully-qualified     # 
🧑🏾‍🔬 E12.1 scientist: medium-dark skin tone
+1F9D1 1F3FF 200D 1F52C                                 ; fully-qualified     # 
🧑🏿‍🔬 E12.1 scientist: dark skin tone
+1F468 200D 1F52C                                       ; fully-qualified     # 
👨‍🔬 E4.0 man scientist
+1F468 1F3FB 200D 1F52C                                 ; fully-qualified     # 
👨🏻‍🔬 E4.0 man scientist: light skin tone
+1F468 1F3FC 200D 1F52C                                 ; fully-qualified     # 
👨🏼‍🔬 E4.0 man scientist: medium-light skin tone
+1F468 1F3FD 200D 1F52C                                 ; fully-qualified     # 
👨🏽‍🔬 E4.0 man scientist: medium skin tone
+1F468 1F3FE 200D 1F52C                                 ; fully-qualified     # 
👨🏾‍🔬 E4.0 man scientist: medium-dark skin tone
+1F468 1F3FF 200D 1F52C                                 ; fully-qualified     # 
👨🏿‍🔬 E4.0 man scientist: dark skin tone
+1F469 200D 1F52C                                       ; fully-qualified     # 
👩‍🔬 E4.0 woman scientist
+1F469 1F3FB 200D 1F52C                                 ; fully-qualified     # 
👩🏻‍🔬 E4.0 woman scientist: light skin tone
+1F469 1F3FC 200D 1F52C                                 ; fully-qualified     # 
👩🏼‍🔬 E4.0 woman scientist: medium-light skin tone
+1F469 1F3FD 200D 1F52C                                 ; fully-qualified     # 
👩🏽‍🔬 E4.0 woman scientist: medium skin tone
+1F469 1F3FE 200D 1F52C                                 ; fully-qualified     # 
👩🏾‍🔬 E4.0 woman scientist: medium-dark skin tone
+1F469 1F3FF 200D 1F52C                                 ; fully-qualified     # 
👩🏿‍🔬 E4.0 woman scientist: dark skin tone
+1F9D1 200D 1F4BB                                       ; fully-qualified     # 
🧑‍💻 E12.1 technologist
+1F9D1 1F3FB 200D 1F4BB                                 ; fully-qualified     # 
🧑🏻‍💻 E12.1 technologist: light skin tone
+1F9D1 1F3FC 200D 1F4BB                                 ; fully-qualified     # 
🧑🏼‍💻 E12.1 technologist: medium-light skin tone
+1F9D1 1F3FD 200D 1F4BB                                 ; fully-qualified     # 
🧑🏽‍💻 E12.1 technologist: medium skin tone
+1F9D1 1F3FE 200D 1F4BB                                 ; fully-qualified     # 
🧑🏾‍💻 E12.1 technologist: medium-dark skin tone
+1F9D1 1F3FF 200D 1F4BB                                 ; fully-qualified     # 
🧑🏿‍💻 E12.1 technologist: dark skin tone
+1F468 200D 1F4BB                                       ; fully-qualified     # 
👨‍💻 E4.0 man technologist
+1F468 1F3FB 200D 1F4BB                                 ; fully-qualified     # 
👨🏻‍💻 E4.0 man technologist: light skin tone
+1F468 1F3FC 200D 1F4BB                                 ; fully-qualified     # 
👨🏼‍💻 E4.0 man technologist: medium-light skin tone
+1F468 1F3FD 200D 1F4BB                                 ; fully-qualified     # 
👨🏽‍💻 E4.0 man technologist: medium skin tone
+1F468 1F3FE 200D 1F4BB                                 ; fully-qualified     # 
👨🏾‍💻 E4.0 man technologist: medium-dark skin tone
+1F468 1F3FF 200D 1F4BB                                 ; fully-qualified     # 
👨🏿‍💻 E4.0 man technologist: dark skin tone
+1F469 200D 1F4BB                                       ; fully-qualified     # 
👩‍💻 E4.0 woman technologist
+1F469 1F3FB 200D 1F4BB                                 ; fully-qualified     # 
👩🏻‍💻 E4.0 woman technologist: light skin tone
+1F469 1F3FC 200D 1F4BB                                 ; fully-qualified     # 
👩🏼‍💻 E4.0 woman technologist: medium-light skin tone
+1F469 1F3FD 200D 1F4BB                                 ; fully-qualified     # 
👩🏽‍💻 E4.0 woman technologist: medium skin tone
+1F469 1F3FE 200D 1F4BB                                 ; fully-qualified     # 
👩🏾‍💻 E4.0 woman technologist: medium-dark skin tone
+1F469 1F3FF 200D 1F4BB                                 ; fully-qualified     # 
👩🏿‍💻 E4.0 woman technologist: dark skin tone
+1F9D1 200D 1F3A4                                       ; fully-qualified     # 
🧑‍🎤 E12.1 singer
+1F9D1 1F3FB 200D 1F3A4                                 ; fully-qualified     # 
🧑🏻‍🎤 E12.1 singer: light skin tone
+1F9D1 1F3FC 200D 1F3A4                                 ; fully-qualified     # 
🧑🏼‍🎤 E12.1 singer: medium-light skin tone
+1F9D1 1F3FD 200D 1F3A4                                 ; fully-qualified     # 
🧑🏽‍🎤 E12.1 singer: medium skin tone
+1F9D1 1F3FE 200D 1F3A4                                 ; fully-qualified     # 
🧑🏾‍🎤 E12.1 singer: medium-dark skin tone
+1F9D1 1F3FF 200D 1F3A4                                 ; fully-qualified     # 
🧑🏿‍🎤 E12.1 singer: dark skin tone
+1F468 200D 1F3A4                                       ; fully-qualified     # 
👨‍🎤 E4.0 man singer
+1F468 1F3FB 200D 1F3A4                                 ; fully-qualified     # 
👨🏻‍🎤 E4.0 man singer: light skin tone
+1F468 1F3FC 200D 1F3A4                                 ; fully-qualified     # 
👨🏼‍🎤 E4.0 man singer: medium-light skin tone
+1F468 1F3FD 200D 1F3A4                                 ; fully-qualified     # 
👨🏽‍🎤 E4.0 man singer: medium skin tone
+1F468 1F3FE 200D 1F3A4                                 ; fully-qualified     # 
👨🏾‍🎤 E4.0 man singer: medium-dark skin tone
+1F468 1F3FF 200D 1F3A4                                 ; fully-qualified     # 
👨🏿‍🎤 E4.0 man singer: dark skin tone
+1F469 200D 1F3A4                                       ; fully-qualified     # 
👩‍🎤 E4.0 woman singer
+1F469 1F3FB 200D 1F3A4                                 ; fully-qualified     # 
👩🏻‍🎤 E4.0 woman singer: light skin tone
+1F469 1F3FC 200D 1F3A4                                 ; fully-qualified     # 
👩🏼‍🎤 E4.0 woman singer: medium-light skin tone
+1F469 1F3FD 200D 1F3A4                                 ; fully-qualified     # 
👩🏽‍🎤 E4.0 woman singer: medium skin tone
+1F469 1F3FE 200D 1F3A4                                 ; fully-qualified     # 
👩🏾‍🎤 E4.0 woman singer: medium-dark skin tone
+1F469 1F3FF 200D 1F3A4                                 ; fully-qualified     # 
👩🏿‍🎤 E4.0 woman singer: dark skin tone
+1F9D1 200D 1F3A8                                       ; fully-qualified     # 
🧑‍🎨 E12.1 artist
+1F9D1 1F3FB 200D 1F3A8                                 ; fully-qualified     # 
🧑🏻‍🎨 E12.1 artist: light skin tone
+1F9D1 1F3FC 200D 1F3A8                                 ; fully-qualified     # 
🧑🏼‍🎨 E12.1 artist: medium-light skin tone
+1F9D1 1F3FD 200D 1F3A8                                 ; fully-qualified     # 
🧑🏽‍🎨 E12.1 artist: medium skin tone
+1F9D1 1F3FE 200D 1F3A8                                 ; fully-qualified     # 
🧑🏾‍🎨 E12.1 artist: medium-dark skin tone
+1F9D1 1F3FF 200D 1F3A8                                 ; fully-qualified     # 
🧑🏿‍🎨 E12.1 artist: dark skin tone
+1F468 200D 1F3A8                                       ; fully-qualified     # 
👨‍🎨 E4.0 man artist
+1F468 1F3FB 200D 1F3A8                                 ; fully-qualified     # 
👨🏻‍🎨 E4.0 man artist: light skin tone
+1F468 1F3FC 200D 1F3A8                                 ; fully-qualified     # 
👨🏼‍🎨 E4.0 man artist: medium-light skin tone
+1F468 1F3FD 200D 1F3A8                                 ; fully-qualified     # 
👨🏽‍🎨 E4.0 man artist: medium skin tone
+1F468 1F3FE 200D 1F3A8                                 ; fully-qualified     # 
👨🏾‍🎨 E4.0 man artist: medium-dark skin tone
+1F468 1F3FF 200D 1F3A8                                 ; fully-qualified     # 
👨🏿‍🎨 E4.0 man artist: dark skin tone
+1F469 200D 1F3A8                                       ; fully-qualified     # 
👩‍🎨 E4.0 woman artist
+1F469 1F3FB 200D 1F3A8                                 ; fully-qualified     # 
👩🏻‍🎨 E4.0 woman artist: light skin tone
+1F469 1F3FC 200D 1F3A8                                 ; fully-qualified     # 
👩🏼‍🎨 E4.0 woman artist: medium-light skin tone
+1F469 1F3FD 200D 1F3A8                                 ; fully-qualified     # 
👩🏽‍🎨 E4.0 woman artist: medium skin tone
+1F469 1F3FE 200D 1F3A8                                 ; fully-qualified     # 
👩🏾‍🎨 E4.0 woman artist: medium-dark skin tone
+1F469 1F3FF 200D 1F3A8                                 ; fully-qualified     # 
👩🏿‍🎨 E4.0 woman artist: dark skin tone
+1F9D1 200D 2708 FE0F                                   ; fully-qualified     # 
🧑‍✈️ E12.1 pilot
+1F9D1 200D 2708                                        ; minimally-qualified # 
🧑‍✈ E12.1 pilot
+1F9D1 1F3FB 200D 2708 FE0F                             ; fully-qualified     # 
🧑🏻‍✈️ E12.1 pilot: light skin tone
+1F9D1 1F3FB 200D 2708                                  ; minimally-qualified # 
🧑🏻‍✈ E12.1 pilot: light skin tone
+1F9D1 1F3FC 200D 2708 FE0F                             ; fully-qualified     # 
🧑🏼‍✈️ E12.1 pilot: medium-light skin tone
+1F9D1 1F3FC 200D 2708                                  ; minimally-qualified # 
🧑🏼‍✈ E12.1 pilot: medium-light skin tone
+1F9D1 1F3FD 200D 2708 FE0F                             ; fully-qualified     # 
🧑🏽‍✈️ E12.1 pilot: medium skin tone
+1F9D1 1F3FD 200D 2708                                  ; minimally-qualified # 
🧑🏽‍✈ E12.1 pilot: medium skin tone
+1F9D1 1F3FE 200D 2708 FE0F                             ; fully-qualified     # 
🧑🏾‍✈️ E12.1 pilot: medium-dark skin tone
+1F9D1 1F3FE 200D 2708                                  ; minimally-qualified # 
🧑🏾‍✈ E12.1 pilot: medium-dark skin tone
+1F9D1 1F3FF 200D 2708 FE0F                             ; fully-qualified     # 
🧑🏿‍✈️ E12.1 pilot: dark skin tone
+1F9D1 1F3FF 200D 2708                                  ; minimally-qualified # 
🧑🏿‍✈ E12.1 pilot: dark skin tone
+1F468 200D 2708 FE0F                                   ; fully-qualified     # 
👨‍✈️ E4.0 man pilot
+1F468 200D 2708                                        ; minimally-qualified # 
👨‍✈ E4.0 man pilot
+1F468 1F3FB 200D 2708 FE0F                             ; fully-qualified     # 
👨🏻‍✈️ E4.0 man pilot: light skin tone
+1F468 1F3FB 200D 2708                                  ; minimally-qualified # 
👨🏻‍✈ E4.0 man pilot: light skin tone
+1F468 1F3FC 200D 2708 FE0F                             ; fully-qualified     # 
👨🏼‍✈️ E4.0 man pilot: medium-light skin tone
+1F468 1F3FC 200D 2708                                  ; minimally-qualified # 
👨🏼‍✈ E4.0 man pilot: medium-light skin tone
+1F468 1F3FD 200D 2708 FE0F                             ; fully-qualified     # 
👨🏽‍✈️ E4.0 man pilot: medium skin tone
+1F468 1F3FD 200D 2708                                  ; minimally-qualified # 
👨🏽‍✈ E4.0 man pilot: medium skin tone
+1F468 1F3FE 200D 2708 FE0F                             ; fully-qualified     # 
👨🏾‍✈️ E4.0 man pilot: medium-dark skin tone
+1F468 1F3FE 200D 2708                                  ; minimally-qualified # 
👨🏾‍✈ E4.0 man pilot: medium-dark skin tone
+1F468 1F3FF 200D 2708 FE0F                             ; fully-qualified     # 
👨🏿‍✈️ E4.0 man pilot: dark skin tone
+1F468 1F3FF 200D 2708                                  ; minimally-qualified # 
👨🏿‍✈ E4.0 man pilot: dark skin tone
+1F469 200D 2708 FE0F                                   ; fully-qualified     # 
👩‍✈️ E4.0 woman pilot
+1F469 200D 2708                                        ; minimally-qualified # 
👩‍✈ E4.0 woman pilot
+1F469 1F3FB 200D 2708 FE0F                             ; fully-qualified     # 
👩🏻‍✈️ E4.0 woman pilot: light skin tone
+1F469 1F3FB 200D 2708                                  ; minimally-qualified # 
👩🏻‍✈ E4.0 woman pilot: light skin tone
+1F469 1F3FC 200D 2708 FE0F                             ; fully-qualified     # 
👩🏼‍✈️ E4.0 woman pilot: medium-light skin tone
+1F469 1F3FC 200D 2708                                  ; minimally-qualified # 
👩🏼‍✈ E4.0 woman pilot: medium-light skin tone
+1F469 1F3FD 200D 2708 FE0F                             ; fully-qualified     # 
👩🏽‍✈️ E4.0 woman pilot: medium skin tone
+1F469 1F3FD 200D 2708                                  ; minimally-qualified # 
👩🏽‍✈ E4.0 woman pilot: medium skin tone
+1F469 1F3FE 200D 2708 FE0F                             ; fully-qualified     # 
👩🏾‍✈️ E4.0 woman pilot: medium-dark skin tone
+1F469 1F3FE 200D 2708                                  ; minimally-qualified # 
👩🏾‍✈ E4.0 woman pilot: medium-dark skin tone
+1F469 1F3FF 200D 2708 FE0F                             ; fully-qualified     # 
👩🏿‍✈️ E4.0 woman pilot: dark skin tone
+1F469 1F3FF 200D 2708                                  ; minimally-qualified # 
👩🏿‍✈ E4.0 woman pilot: dark skin tone
+1F9D1 200D 1F680                                       ; fully-qualified     # 
🧑‍🚀 E12.1 astronaut
+1F9D1 1F3FB 200D 1F680                                 ; fully-qualified     # 
🧑🏻‍🚀 E12.1 astronaut: light skin tone
+1F9D1 1F3FC 200D 1F680                                 ; fully-qualified     # 
🧑🏼‍🚀 E12.1 astronaut: medium-light skin tone
+1F9D1 1F3FD 200D 1F680                                 ; fully-qualified     # 
🧑🏽‍🚀 E12.1 astronaut: medium skin tone
+1F9D1 1F3FE 200D 1F680                                 ; fully-qualified     # 
🧑🏾‍🚀 E12.1 astronaut: medium-dark skin tone
+1F9D1 1F3FF 200D 1F680                                 ; fully-qualified     # 
🧑🏿‍🚀 E12.1 astronaut: dark skin tone
+1F468 200D 1F680                                       ; fully-qualified     # 
👨‍🚀 E4.0 man astronaut
+1F468 1F3FB 200D 1F680                                 ; fully-qualified     # 
👨🏻‍🚀 E4.0 man astronaut: light skin tone
+1F468 1F3FC 200D 1F680                                 ; fully-qualified     # 
👨🏼‍🚀 E4.0 man astronaut: medium-light skin tone
+1F468 1F3FD 200D 1F680                                 ; fully-qualified     # 
👨🏽‍🚀 E4.0 man astronaut: medium skin tone
+1F468 1F3FE 200D 1F680                                 ; fully-qualified     # 
👨🏾‍🚀 E4.0 man astronaut: medium-dark skin tone
+1F468 1F3FF 200D 1F680                                 ; fully-qualified     # 
👨🏿‍🚀 E4.0 man astronaut: dark skin tone
+1F469 200D 1F680                                       ; fully-qualified     # 
👩‍🚀 E4.0 woman astronaut
+1F469 1F3FB 200D 1F680                                 ; fully-qualified     # 
👩🏻‍🚀 E4.0 woman astronaut: light skin tone
+1F469 1F3FC 200D 1F680                                 ; fully-qualified     # 
👩🏼‍🚀 E4.0 woman astronaut: medium-light skin tone
+1F469 1F3FD 200D 1F680                                 ; fully-qualified     # 
👩🏽‍🚀 E4.0 woman astronaut: medium skin tone
+1F469 1F3FE 200D 1F680                                 ; fully-qualified     # 
👩🏾‍🚀 E4.0 woman astronaut: medium-dark skin tone
+1F469 1F3FF 200D 1F680                                 ; fully-qualified     # 
👩🏿‍🚀 E4.0 woman astronaut: dark skin tone
+1F9D1 200D 1F692                                       ; fully-qualified     # 
🧑‍🚒 E12.1 firefighter
+1F9D1 1F3FB 200D 1F692                                 ; fully-qualified     # 
🧑🏻‍🚒 E12.1 firefighter: light skin tone
+1F9D1 1F3FC 200D 1F692                                 ; fully-qualified     # 
🧑🏼‍🚒 E12.1 firefighter: medium-light skin tone
+1F9D1 1F3FD 200D 1F692                                 ; fully-qualified     # 
🧑🏽‍🚒 E12.1 firefighter: medium skin tone
+1F9D1 1F3FE 200D 1F692                                 ; fully-qualified     # 
🧑🏾‍🚒 E12.1 firefighter: medium-dark skin tone
+1F9D1 1F3FF 200D 1F692                                 ; fully-qualified     # 
🧑🏿‍🚒 E12.1 firefighter: dark skin tone
+1F468 200D 1F692                                       ; fully-qualified     # 
👨‍🚒 E4.0 man firefighter
+1F468 1F3FB 200D 1F692                                 ; fully-qualified     # 
👨🏻‍🚒 E4.0 man firefighter: light skin tone
+1F468 1F3FC 200D 1F692                                 ; fully-qualified     # 
👨🏼‍🚒 E4.0 man firefighter: medium-light skin tone
+1F468 1F3FD 200D 1F692                                 ; fully-qualified     # 
👨🏽‍🚒 E4.0 man firefighter: medium skin tone
+1F468 1F3FE 200D 1F692                                 ; fully-qualified     # 
👨🏾‍🚒 E4.0 man firefighter: medium-dark skin tone
+1F468 1F3FF 200D 1F692                                 ; fully-qualified     # 
👨🏿‍🚒 E4.0 man firefighter: dark skin tone
+1F469 200D 1F692                                       ; fully-qualified     # 
👩‍🚒 E4.0 woman firefighter
+1F469 1F3FB 200D 1F692                                 ; fully-qualified     # 
👩🏻‍🚒 E4.0 woman firefighter: light skin tone
+1F469 1F3FC 200D 1F692                                 ; fully-qualified     # 
👩🏼‍🚒 E4.0 woman firefighter: medium-light skin tone
+1F469 1F3FD 200D 1F692                                 ; fully-qualified     # 
👩🏽‍🚒 E4.0 woman firefighter: medium skin tone
+1F469 1F3FE 200D 1F692                                 ; fully-qualified     # 
👩🏾‍🚒 E4.0 woman firefighter: medium-dark skin tone
+1F469 1F3FF 200D 1F692                                 ; fully-qualified     # 
👩🏿‍🚒 E4.0 woman firefighter: dark skin tone
+1F46E                                                  ; fully-qualified     # 
👮 E0.6 police officer
+1F46E 1F3FB                                            ; fully-qualified     # 
👮🏻 E1.0 police officer: light skin tone
+1F46E 1F3FC                                            ; fully-qualified     # 
👮🏼 E1.0 police officer: medium-light skin tone
+1F46E 1F3FD                                            ; fully-qualified     # 
👮🏽 E1.0 police officer: medium skin tone
+1F46E 1F3FE                                            ; fully-qualified     # 
👮🏾 E1.0 police officer: medium-dark skin tone
+1F46E 1F3FF                                            ; fully-qualified     # 
👮🏿 E1.0 police officer: dark skin tone
+1F46E 200D 2642 FE0F                                   ; fully-qualified     # 
👮‍♂️ E4.0 man police officer
+1F46E 200D 2642                                        ; minimally-qualified # 
👮‍♂ E4.0 man police officer
+1F46E 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
👮🏻‍♂️ E4.0 man police officer: light skin tone
+1F46E 1F3FB 200D 2642                                  ; minimally-qualified # 
👮🏻‍♂ E4.0 man police officer: light skin tone
+1F46E 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
👮🏼‍♂️ E4.0 man police officer: medium-light skin tone
+1F46E 1F3FC 200D 2642                                  ; minimally-qualified # 
👮🏼‍♂ E4.0 man police officer: medium-light skin tone
+1F46E 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
👮🏽‍♂️ E4.0 man police officer: medium skin tone
+1F46E 1F3FD 200D 2642                                  ; minimally-qualified # 
👮🏽‍♂ E4.0 man police officer: medium skin tone
+1F46E 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
👮🏾‍♂️ E4.0 man police officer: medium-dark skin tone
+1F46E 1F3FE 200D 2642                                  ; minimally-qualified # 
👮🏾‍♂ E4.0 man police officer: medium-dark skin tone
+1F46E 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
👮🏿‍♂️ E4.0 man police officer: dark skin tone
+1F46E 1F3FF 200D 2642                                  ; minimally-qualified # 
👮🏿‍♂ E4.0 man police officer: dark skin tone
+1F46E 200D 2640 FE0F                                   ; fully-qualified     # 
👮‍♀️ E4.0 woman police officer
+1F46E 200D 2640                                        ; minimally-qualified # 
👮‍♀ E4.0 woman police officer
+1F46E 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
👮🏻‍♀️ E4.0 woman police officer: light skin tone
+1F46E 1F3FB 200D 2640                                  ; minimally-qualified # 
👮🏻‍♀ E4.0 woman police officer: light skin tone
+1F46E 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
👮🏼‍♀️ E4.0 woman police officer: medium-light skin tone
+1F46E 1F3FC 200D 2640                                  ; minimally-qualified # 
👮🏼‍♀ E4.0 woman police officer: medium-light skin tone
+1F46E 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
👮🏽‍♀️ E4.0 woman police officer: medium skin tone
+1F46E 1F3FD 200D 2640                                  ; minimally-qualified # 
👮🏽‍♀ E4.0 woman police officer: medium skin tone
+1F46E 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
👮🏾‍♀️ E4.0 woman police officer: medium-dark skin tone
+1F46E 1F3FE 200D 2640                                  ; minimally-qualified # 
👮🏾‍♀ E4.0 woman police officer: medium-dark skin tone
+1F46E 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
👮🏿‍♀️ E4.0 woman police officer: dark skin tone
+1F46E 1F3FF 200D 2640                                  ; minimally-qualified # 
👮🏿‍♀ E4.0 woman police officer: dark skin tone
+1F575 FE0F                                             ; fully-qualified     # 
🕵️ E0.7 detective
+1F575                                                  ; unqualified         # 
🕵 E0.7 detective
+1F575 1F3FB                                            ; fully-qualified     # 
🕵🏻 E2.0 detective: light skin tone
+1F575 1F3FC                                            ; fully-qualified     # 
🕵🏼 E2.0 detective: medium-light skin tone
+1F575 1F3FD                                            ; fully-qualified     # 
🕵🏽 E2.0 detective: medium skin tone
+1F575 1F3FE                                            ; fully-qualified     # 
🕵🏾 E2.0 detective: medium-dark skin tone
+1F575 1F3FF                                            ; fully-qualified     # 
🕵🏿 E2.0 detective: dark skin tone
+1F575 FE0F 200D 2642 FE0F                              ; fully-qualified     # 
🕵️‍♂️ E4.0 man detective
+1F575 200D 2642 FE0F                                   ; unqualified         # 
🕵‍♂️ E4.0 man detective
+1F575 FE0F 200D 2642                                   ; unqualified         # 
🕵️‍♂ E4.0 man detective
+1F575 200D 2642                                        ; unqualified         # 
🕵‍♂ E4.0 man detective
+1F575 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🕵🏻‍♂️ E4.0 man detective: light skin tone
+1F575 1F3FB 200D 2642                                  ; minimally-qualified # 
🕵🏻‍♂ E4.0 man detective: light skin tone
+1F575 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🕵🏼‍♂️ E4.0 man detective: medium-light skin tone
+1F575 1F3FC 200D 2642                                  ; minimally-qualified # 
🕵🏼‍♂ E4.0 man detective: medium-light skin tone
+1F575 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🕵🏽‍♂️ E4.0 man detective: medium skin tone
+1F575 1F3FD 200D 2642                                  ; minimally-qualified # 
🕵🏽‍♂ E4.0 man detective: medium skin tone
+1F575 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🕵🏾‍♂️ E4.0 man detective: medium-dark skin tone
+1F575 1F3FE 200D 2642                                  ; minimally-qualified # 
🕵🏾‍♂ E4.0 man detective: medium-dark skin tone
+1F575 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🕵🏿‍♂️ E4.0 man detective: dark skin tone
+1F575 1F3FF 200D 2642                                  ; minimally-qualified # 
🕵🏿‍♂ E4.0 man detective: dark skin tone
+1F575 FE0F 200D 2640 FE0F                              ; fully-qualified     # 
🕵️‍♀️ E4.0 woman detective
+1F575 200D 2640 FE0F                                   ; unqualified         # 
🕵‍♀️ E4.0 woman detective
+1F575 FE0F 200D 2640                                   ; unqualified         # 
🕵️‍♀ E4.0 woman detective
+1F575 200D 2640                                        ; unqualified         # 
🕵‍♀ E4.0 woman detective
+1F575 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🕵🏻‍♀️ E4.0 woman detective: light skin tone
+1F575 1F3FB 200D 2640                                  ; minimally-qualified # 
🕵🏻‍♀ E4.0 woman detective: light skin tone
+1F575 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🕵🏼‍♀️ E4.0 woman detective: medium-light skin tone
+1F575 1F3FC 200D 2640                                  ; minimally-qualified # 
🕵🏼‍♀ E4.0 woman detective: medium-light skin tone
+1F575 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🕵🏽‍♀️ E4.0 woman detective: medium skin tone
+1F575 1F3FD 200D 2640                                  ; minimally-qualified # 
🕵🏽‍♀ E4.0 woman detective: medium skin tone
+1F575 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🕵🏾‍♀️ E4.0 woman detective: medium-dark skin tone
+1F575 1F3FE 200D 2640                                  ; minimally-qualified # 
🕵🏾‍♀ E4.0 woman detective: medium-dark skin tone
+1F575 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🕵🏿‍♀️ E4.0 woman detective: dark skin tone
+1F575 1F3FF 200D 2640                                  ; minimally-qualified # 
🕵🏿‍♀ E4.0 woman detective: dark skin tone
+1F482                                                  ; fully-qualified     # 
💂 E0.6 guard
+1F482 1F3FB                                            ; fully-qualified     # 
💂🏻 E1.0 guard: light skin tone
+1F482 1F3FC                                            ; fully-qualified     # 
💂🏼 E1.0 guard: medium-light skin tone
+1F482 1F3FD                                            ; fully-qualified     # 
💂🏽 E1.0 guard: medium skin tone
+1F482 1F3FE                                            ; fully-qualified     # 
💂🏾 E1.0 guard: medium-dark skin tone
+1F482 1F3FF                                            ; fully-qualified     # 
💂🏿 E1.0 guard: dark skin tone
+1F482 200D 2642 FE0F                                   ; fully-qualified     # 
💂‍♂️ E4.0 man guard
+1F482 200D 2642                                        ; minimally-qualified # 
💂‍♂ E4.0 man guard
+1F482 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
💂🏻‍♂️ E4.0 man guard: light skin tone
+1F482 1F3FB 200D 2642                                  ; minimally-qualified # 
💂🏻‍♂ E4.0 man guard: light skin tone
+1F482 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
💂🏼‍♂️ E4.0 man guard: medium-light skin tone
+1F482 1F3FC 200D 2642                                  ; minimally-qualified # 
💂🏼‍♂ E4.0 man guard: medium-light skin tone
+1F482 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
💂🏽‍♂️ E4.0 man guard: medium skin tone
+1F482 1F3FD 200D 2642                                  ; minimally-qualified # 
💂🏽‍♂ E4.0 man guard: medium skin tone
+1F482 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
💂🏾‍♂️ E4.0 man guard: medium-dark skin tone
+1F482 1F3FE 200D 2642                                  ; minimally-qualified # 
💂🏾‍♂ E4.0 man guard: medium-dark skin tone
+1F482 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
💂🏿‍♂️ E4.0 man guard: dark skin tone
+1F482 1F3FF 200D 2642                                  ; minimally-qualified # 
💂🏿‍♂ E4.0 man guard: dark skin tone
+1F482 200D 2640 FE0F                                   ; fully-qualified     # 
💂‍♀️ E4.0 woman guard
+1F482 200D 2640                                        ; minimally-qualified # 
💂‍♀ E4.0 woman guard
+1F482 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
💂🏻‍♀️ E4.0 woman guard: light skin tone
+1F482 1F3FB 200D 2640                                  ; minimally-qualified # 
💂🏻‍♀ E4.0 woman guard: light skin tone
+1F482 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
💂🏼‍♀️ E4.0 woman guard: medium-light skin tone
+1F482 1F3FC 200D 2640                                  ; minimally-qualified # 
💂🏼‍♀ E4.0 woman guard: medium-light skin tone
+1F482 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
💂🏽‍♀️ E4.0 woman guard: medium skin tone
+1F482 1F3FD 200D 2640                                  ; minimally-qualified # 
💂🏽‍♀ E4.0 woman guard: medium skin tone
+1F482 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
💂🏾‍♀️ E4.0 woman guard: medium-dark skin tone
+1F482 1F3FE 200D 2640                                  ; minimally-qualified # 
💂🏾‍♀ E4.0 woman guard: medium-dark skin tone
+1F482 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
💂🏿‍♀️ E4.0 woman guard: dark skin tone
+1F482 1F3FF 200D 2640                                  ; minimally-qualified # 
💂🏿‍♀ E4.0 woman guard: dark skin tone
+1F977                                                  ; fully-qualified     # 
🥷 E13.0 ninja
+1F977 1F3FB                                            ; fully-qualified     # 
🥷🏻 E13.0 ninja: light skin tone
+1F977 1F3FC                                            ; fully-qualified     # 
🥷🏼 E13.0 ninja: medium-light skin tone
+1F977 1F3FD                                            ; fully-qualified     # 
🥷🏽 E13.0 ninja: medium skin tone
+1F977 1F3FE                                            ; fully-qualified     # 
🥷🏾 E13.0 ninja: medium-dark skin tone
+1F977 1F3FF                                            ; fully-qualified     # 
🥷🏿 E13.0 ninja: dark skin tone
+1F477                                                  ; fully-qualified     # 
👷 E0.6 construction worker
+1F477 1F3FB                                            ; fully-qualified     # 
👷🏻 E1.0 construction worker: light skin tone
+1F477 1F3FC                                            ; fully-qualified     # 
👷🏼 E1.0 construction worker: medium-light skin tone
+1F477 1F3FD                                            ; fully-qualified     # 
👷🏽 E1.0 construction worker: medium skin tone
+1F477 1F3FE                                            ; fully-qualified     # 
👷🏾 E1.0 construction worker: medium-dark skin tone
+1F477 1F3FF                                            ; fully-qualified     # 
👷🏿 E1.0 construction worker: dark skin tone
+1F477 200D 2642 FE0F                                   ; fully-qualified     # 
👷‍♂️ E4.0 man construction worker
+1F477 200D 2642                                        ; minimally-qualified # 
👷‍♂ E4.0 man construction worker
+1F477 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
👷🏻‍♂️ E4.0 man construction worker: light skin tone
+1F477 1F3FB 200D 2642                                  ; minimally-qualified # 
👷🏻‍♂ E4.0 man construction worker: light skin tone
+1F477 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
👷🏼‍♂️ E4.0 man construction worker: medium-light skin tone
+1F477 1F3FC 200D 2642                                  ; minimally-qualified # 
👷🏼‍♂ E4.0 man construction worker: medium-light skin tone
+1F477 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
👷🏽‍♂️ E4.0 man construction worker: medium skin tone
+1F477 1F3FD 200D 2642                                  ; minimally-qualified # 
👷🏽‍♂ E4.0 man construction worker: medium skin tone
+1F477 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
👷🏾‍♂️ E4.0 man construction worker: medium-dark skin tone
+1F477 1F3FE 200D 2642                                  ; minimally-qualified # 
👷🏾‍♂ E4.0 man construction worker: medium-dark skin tone
+1F477 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
👷🏿‍♂️ E4.0 man construction worker: dark skin tone
+1F477 1F3FF 200D 2642                                  ; minimally-qualified # 
👷🏿‍♂ E4.0 man construction worker: dark skin tone
+1F477 200D 2640 FE0F                                   ; fully-qualified     # 
👷‍♀️ E4.0 woman construction worker
+1F477 200D 2640                                        ; minimally-qualified # 
👷‍♀ E4.0 woman construction worker
+1F477 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
👷🏻‍♀️ E4.0 woman construction worker: light skin tone
+1F477 1F3FB 200D 2640                                  ; minimally-qualified # 
👷🏻‍♀ E4.0 woman construction worker: light skin tone
+1F477 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
👷🏼‍♀️ E4.0 woman construction worker: medium-light skin tone
+1F477 1F3FC 200D 2640                                  ; minimally-qualified # 
👷🏼‍♀ E4.0 woman construction worker: medium-light skin tone
+1F477 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
👷🏽‍♀️ E4.0 woman construction worker: medium skin tone
+1F477 1F3FD 200D 2640                                  ; minimally-qualified # 
👷🏽‍♀ E4.0 woman construction worker: medium skin tone
+1F477 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
👷🏾‍♀️ E4.0 woman construction worker: medium-dark skin tone
+1F477 1F3FE 200D 2640                                  ; minimally-qualified # 
👷🏾‍♀ E4.0 woman construction worker: medium-dark skin tone
+1F477 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
👷🏿‍♀️ E4.0 woman construction worker: dark skin tone
+1F477 1F3FF 200D 2640                                  ; minimally-qualified # 
👷🏿‍♀ E4.0 woman construction worker: dark skin tone
+1FAC5                                                  ; fully-qualified     # 
🫅 E14.0 person with crown
+1FAC5 1F3FB                                            ; fully-qualified     # 
🫅🏻 E14.0 person with crown: light skin tone
+1FAC5 1F3FC                                            ; fully-qualified     # 
🫅🏼 E14.0 person with crown: medium-light skin tone
+1FAC5 1F3FD                                            ; fully-qualified     # 
🫅🏽 E14.0 person with crown: medium skin tone
+1FAC5 1F3FE                                            ; fully-qualified     # 
🫅🏾 E14.0 person with crown: medium-dark skin tone
+1FAC5 1F3FF                                            ; fully-qualified     # 
🫅🏿 E14.0 person with crown: dark skin tone
+1F934                                                  ; fully-qualified     # 
🤴 E3.0 prince
+1F934 1F3FB                                            ; fully-qualified     # 
🤴🏻 E3.0 prince: light skin tone
+1F934 1F3FC                                            ; fully-qualified     # 
🤴🏼 E3.0 prince: medium-light skin tone
+1F934 1F3FD                                            ; fully-qualified     # 
🤴🏽 E3.0 prince: medium skin tone
+1F934 1F3FE                                            ; fully-qualified     # 
🤴🏾 E3.0 prince: medium-dark skin tone
+1F934 1F3FF                                            ; fully-qualified     # 
🤴🏿 E3.0 prince: dark skin tone
+1F478                                                  ; fully-qualified     # 
👸 E0.6 princess
+1F478 1F3FB                                            ; fully-qualified     # 
👸🏻 E1.0 princess: light skin tone
+1F478 1F3FC                                            ; fully-qualified     # 
👸🏼 E1.0 princess: medium-light skin tone
+1F478 1F3FD                                            ; fully-qualified     # 
👸🏽 E1.0 princess: medium skin tone
+1F478 1F3FE                                            ; fully-qualified     # 
👸🏾 E1.0 princess: medium-dark skin tone
+1F478 1F3FF                                            ; fully-qualified     # 
👸🏿 E1.0 princess: dark skin tone
+1F473                                                  ; fully-qualified     # 
👳 E0.6 person wearing turban
+1F473 1F3FB                                            ; fully-qualified     # 
👳🏻 E1.0 person wearing turban: light skin tone
+1F473 1F3FC                                            ; fully-qualified     # 
👳🏼 E1.0 person wearing turban: medium-light skin tone
+1F473 1F3FD                                            ; fully-qualified     # 
👳🏽 E1.0 person wearing turban: medium skin tone
+1F473 1F3FE                                            ; fully-qualified     # 
👳🏾 E1.0 person wearing turban: medium-dark skin tone
+1F473 1F3FF                                            ; fully-qualified     # 
👳🏿 E1.0 person wearing turban: dark skin tone
+1F473 200D 2642 FE0F                                   ; fully-qualified     # 
👳‍♂️ E4.0 man wearing turban
+1F473 200D 2642                                        ; minimally-qualified # 
👳‍♂ E4.0 man wearing turban
+1F473 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
👳🏻‍♂️ E4.0 man wearing turban: light skin tone
+1F473 1F3FB 200D 2642                                  ; minimally-qualified # 
👳🏻‍♂ E4.0 man wearing turban: light skin tone
+1F473 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
👳🏼‍♂️ E4.0 man wearing turban: medium-light skin tone
+1F473 1F3FC 200D 2642                                  ; minimally-qualified # 
👳🏼‍♂ E4.0 man wearing turban: medium-light skin tone
+1F473 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
👳🏽‍♂️ E4.0 man wearing turban: medium skin tone
+1F473 1F3FD 200D 2642                                  ; minimally-qualified # 
👳🏽‍♂ E4.0 man wearing turban: medium skin tone
+1F473 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
👳🏾‍♂️ E4.0 man wearing turban: medium-dark skin tone
+1F473 1F3FE 200D 2642                                  ; minimally-qualified # 
👳🏾‍♂ E4.0 man wearing turban: medium-dark skin tone
+1F473 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
👳🏿‍♂️ E4.0 man wearing turban: dark skin tone
+1F473 1F3FF 200D 2642                                  ; minimally-qualified # 
👳🏿‍♂ E4.0 man wearing turban: dark skin tone
+1F473 200D 2640 FE0F                                   ; fully-qualified     # 
👳‍♀️ E4.0 woman wearing turban
+1F473 200D 2640                                        ; minimally-qualified # 
👳‍♀ E4.0 woman wearing turban
+1F473 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
👳🏻‍♀️ E4.0 woman wearing turban: light skin tone
+1F473 1F3FB 200D 2640                                  ; minimally-qualified # 
👳🏻‍♀ E4.0 woman wearing turban: light skin tone
+1F473 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
👳🏼‍♀️ E4.0 woman wearing turban: medium-light skin tone
+1F473 1F3FC 200D 2640                                  ; minimally-qualified # 
👳🏼‍♀ E4.0 woman wearing turban: medium-light skin tone
+1F473 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
👳🏽‍♀️ E4.0 woman wearing turban: medium skin tone
+1F473 1F3FD 200D 2640                                  ; minimally-qualified # 
👳🏽‍♀ E4.0 woman wearing turban: medium skin tone
+1F473 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
👳🏾‍♀️ E4.0 woman wearing turban: medium-dark skin tone
+1F473 1F3FE 200D 2640                                  ; minimally-qualified # 
👳🏾‍♀ E4.0 woman wearing turban: medium-dark skin tone
+1F473 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
👳🏿‍♀️ E4.0 woman wearing turban: dark skin tone
+1F473 1F3FF 200D 2640                                  ; minimally-qualified # 
👳🏿‍♀ E4.0 woman wearing turban: dark skin tone
+1F472                                                  ; fully-qualified     # 
👲 E0.6 person with skullcap
+1F472 1F3FB                                            ; fully-qualified     # 
👲🏻 E1.0 person with skullcap: light skin tone
+1F472 1F3FC                                            ; fully-qualified     # 
👲🏼 E1.0 person with skullcap: medium-light skin tone
+1F472 1F3FD                                            ; fully-qualified     # 
👲🏽 E1.0 person with skullcap: medium skin tone
+1F472 1F3FE                                            ; fully-qualified     # 
👲🏾 E1.0 person with skullcap: medium-dark skin tone
+1F472 1F3FF                                            ; fully-qualified     # 
👲🏿 E1.0 person with skullcap: dark skin tone
+1F9D5                                                  ; fully-qualified     # 
🧕 E5.0 woman with headscarf
+1F9D5 1F3FB                                            ; fully-qualified     # 
🧕🏻 E5.0 woman with headscarf: light skin tone
+1F9D5 1F3FC                                            ; fully-qualified     # 
🧕🏼 E5.0 woman with headscarf: medium-light skin tone
+1F9D5 1F3FD                                            ; fully-qualified     # 
🧕🏽 E5.0 woman with headscarf: medium skin tone
+1F9D5 1F3FE                                            ; fully-qualified     # 
🧕🏾 E5.0 woman with headscarf: medium-dark skin tone
+1F9D5 1F3FF                                            ; fully-qualified     # 
🧕🏿 E5.0 woman with headscarf: dark skin tone
+1F935                                                  ; fully-qualified     # 
🤵 E3.0 person in tuxedo
+1F935 1F3FB                                            ; fully-qualified     # 
🤵🏻 E3.0 person in tuxedo: light skin tone
+1F935 1F3FC                                            ; fully-qualified     # 
🤵🏼 E3.0 person in tuxedo: medium-light skin tone
+1F935 1F3FD                                            ; fully-qualified     # 
🤵🏽 E3.0 person in tuxedo: medium skin tone
+1F935 1F3FE                                            ; fully-qualified     # 
🤵🏾 E3.0 person in tuxedo: medium-dark skin tone
+1F935 1F3FF                                            ; fully-qualified     # 
🤵🏿 E3.0 person in tuxedo: dark skin tone
+1F935 200D 2642 FE0F                                   ; fully-qualified     # 
🤵‍♂️ E13.0 man in tuxedo
+1F935 200D 2642                                        ; minimally-qualified # 
🤵‍♂ E13.0 man in tuxedo
+1F935 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤵🏻‍♂️ E13.0 man in tuxedo: light skin tone
+1F935 1F3FB 200D 2642                                  ; minimally-qualified # 
🤵🏻‍♂ E13.0 man in tuxedo: light skin tone
+1F935 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤵🏼‍♂️ E13.0 man in tuxedo: medium-light skin tone
+1F935 1F3FC 200D 2642                                  ; minimally-qualified # 
🤵🏼‍♂ E13.0 man in tuxedo: medium-light skin tone
+1F935 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤵🏽‍♂️ E13.0 man in tuxedo: medium skin tone
+1F935 1F3FD 200D 2642                                  ; minimally-qualified # 
🤵🏽‍♂ E13.0 man in tuxedo: medium skin tone
+1F935 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤵🏾‍♂️ E13.0 man in tuxedo: medium-dark skin tone
+1F935 1F3FE 200D 2642                                  ; minimally-qualified # 
🤵🏾‍♂ E13.0 man in tuxedo: medium-dark skin tone
+1F935 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤵🏿‍♂️ E13.0 man in tuxedo: dark skin tone
+1F935 1F3FF 200D 2642                                  ; minimally-qualified # 
🤵🏿‍♂ E13.0 man in tuxedo: dark skin tone
+1F935 200D 2640 FE0F                                   ; fully-qualified     # 
🤵‍♀️ E13.0 woman in tuxedo
+1F935 200D 2640                                        ; minimally-qualified # 
🤵‍♀ E13.0 woman in tuxedo
+1F935 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤵🏻‍♀️ E13.0 woman in tuxedo: light skin tone
+1F935 1F3FB 200D 2640                                  ; minimally-qualified # 
🤵🏻‍♀ E13.0 woman in tuxedo: light skin tone
+1F935 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤵🏼‍♀️ E13.0 woman in tuxedo: medium-light skin tone
+1F935 1F3FC 200D 2640                                  ; minimally-qualified # 
🤵🏼‍♀ E13.0 woman in tuxedo: medium-light skin tone
+1F935 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤵🏽‍♀️ E13.0 woman in tuxedo: medium skin tone
+1F935 1F3FD 200D 2640                                  ; minimally-qualified # 
🤵🏽‍♀ E13.0 woman in tuxedo: medium skin tone
+1F935 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤵🏾‍♀️ E13.0 woman in tuxedo: medium-dark skin tone
+1F935 1F3FE 200D 2640                                  ; minimally-qualified # 
🤵🏾‍♀ E13.0 woman in tuxedo: medium-dark skin tone
+1F935 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤵🏿‍♀️ E13.0 woman in tuxedo: dark skin tone
+1F935 1F3FF 200D 2640                                  ; minimally-qualified # 
🤵🏿‍♀ E13.0 woman in tuxedo: dark skin tone
+1F470                                                  ; fully-qualified     # 
👰 E0.6 person with veil
+1F470 1F3FB                                            ; fully-qualified     # 
👰🏻 E1.0 person with veil: light skin tone
+1F470 1F3FC                                            ; fully-qualified     # 
👰🏼 E1.0 person with veil: medium-light skin tone
+1F470 1F3FD                                            ; fully-qualified     # 
👰🏽 E1.0 person with veil: medium skin tone
+1F470 1F3FE                                            ; fully-qualified     # 
👰🏾 E1.0 person with veil: medium-dark skin tone
+1F470 1F3FF                                            ; fully-qualified     # 
👰🏿 E1.0 person with veil: dark skin tone
+1F470 200D 2642 FE0F                                   ; fully-qualified     # 
👰‍♂️ E13.0 man with veil
+1F470 200D 2642                                        ; minimally-qualified # 
👰‍♂ E13.0 man with veil
+1F470 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
👰🏻‍♂️ E13.0 man with veil: light skin tone
+1F470 1F3FB 200D 2642                                  ; minimally-qualified # 
👰🏻‍♂ E13.0 man with veil: light skin tone
+1F470 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
👰🏼‍♂️ E13.0 man with veil: medium-light skin tone
+1F470 1F3FC 200D 2642                                  ; minimally-qualified # 
👰🏼‍♂ E13.0 man with veil: medium-light skin tone
+1F470 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
👰🏽‍♂️ E13.0 man with veil: medium skin tone
+1F470 1F3FD 200D 2642                                  ; minimally-qualified # 
👰🏽‍♂ E13.0 man with veil: medium skin tone
+1F470 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
👰🏾‍♂️ E13.0 man with veil: medium-dark skin tone
+1F470 1F3FE 200D 2642                                  ; minimally-qualified # 
👰🏾‍♂ E13.0 man with veil: medium-dark skin tone
+1F470 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
👰🏿‍♂️ E13.0 man with veil: dark skin tone
+1F470 1F3FF 200D 2642                                  ; minimally-qualified # 
👰🏿‍♂ E13.0 man with veil: dark skin tone
+1F470 200D 2640 FE0F                                   ; fully-qualified     # 
👰‍♀️ E13.0 woman with veil
+1F470 200D 2640                                        ; minimally-qualified # 
👰‍♀ E13.0 woman with veil
+1F470 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
👰🏻‍♀️ E13.0 woman with veil: light skin tone
+1F470 1F3FB 200D 2640                                  ; minimally-qualified # 
👰🏻‍♀ E13.0 woman with veil: light skin tone
+1F470 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
👰🏼‍♀️ E13.0 woman with veil: medium-light skin tone
+1F470 1F3FC 200D 2640                                  ; minimally-qualified # 
👰🏼‍♀ E13.0 woman with veil: medium-light skin tone
+1F470 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
👰🏽‍♀️ E13.0 woman with veil: medium skin tone
+1F470 1F3FD 200D 2640                                  ; minimally-qualified # 
👰🏽‍♀ E13.0 woman with veil: medium skin tone
+1F470 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
👰🏾‍♀️ E13.0 woman with veil: medium-dark skin tone
+1F470 1F3FE 200D 2640                                  ; minimally-qualified # 
👰🏾‍♀ E13.0 woman with veil: medium-dark skin tone
+1F470 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
👰🏿‍♀️ E13.0 woman with veil: dark skin tone
+1F470 1F3FF 200D 2640                                  ; minimally-qualified # 
👰🏿‍♀ E13.0 woman with veil: dark skin tone
+1F930                                                  ; fully-qualified     # 
🤰 E3.0 pregnant woman
+1F930 1F3FB                                            ; fully-qualified     # 
🤰🏻 E3.0 pregnant woman: light skin tone
+1F930 1F3FC                                            ; fully-qualified     # 
🤰🏼 E3.0 pregnant woman: medium-light skin tone
+1F930 1F3FD                                            ; fully-qualified     # 
🤰🏽 E3.0 pregnant woman: medium skin tone
+1F930 1F3FE                                            ; fully-qualified     # 
🤰🏾 E3.0 pregnant woman: medium-dark skin tone
+1F930 1F3FF                                            ; fully-qualified     # 
🤰🏿 E3.0 pregnant woman: dark skin tone
+1FAC3                                                  ; fully-qualified     # 
🫃 E14.0 pregnant man
+1FAC3 1F3FB                                            ; fully-qualified     # 
🫃🏻 E14.0 pregnant man: light skin tone
+1FAC3 1F3FC                                            ; fully-qualified     # 
🫃🏼 E14.0 pregnant man: medium-light skin tone
+1FAC3 1F3FD                                            ; fully-qualified     # 
🫃🏽 E14.0 pregnant man: medium skin tone
+1FAC3 1F3FE                                            ; fully-qualified     # 
🫃🏾 E14.0 pregnant man: medium-dark skin tone
+1FAC3 1F3FF                                            ; fully-qualified     # 
🫃🏿 E14.0 pregnant man: dark skin tone
+1FAC4                                                  ; fully-qualified     # 
🫄 E14.0 pregnant person
+1FAC4 1F3FB                                            ; fully-qualified     # 
🫄🏻 E14.0 pregnant person: light skin tone
+1FAC4 1F3FC                                            ; fully-qualified     # 
🫄🏼 E14.0 pregnant person: medium-light skin tone
+1FAC4 1F3FD                                            ; fully-qualified     # 
🫄🏽 E14.0 pregnant person: medium skin tone
+1FAC4 1F3FE                                            ; fully-qualified     # 
🫄🏾 E14.0 pregnant person: medium-dark skin tone
+1FAC4 1F3FF                                            ; fully-qualified     # 
🫄🏿 E14.0 pregnant person: dark skin tone
+1F931                                                  ; fully-qualified     # 
🤱 E5.0 breast-feeding
+1F931 1F3FB                                            ; fully-qualified     # 
🤱🏻 E5.0 breast-feeding: light skin tone
+1F931 1F3FC                                            ; fully-qualified     # 
🤱🏼 E5.0 breast-feeding: medium-light skin tone
+1F931 1F3FD                                            ; fully-qualified     # 
🤱🏽 E5.0 breast-feeding: medium skin tone
+1F931 1F3FE                                            ; fully-qualified     # 
🤱🏾 E5.0 breast-feeding: medium-dark skin tone
+1F931 1F3FF                                            ; fully-qualified     # 
🤱🏿 E5.0 breast-feeding: dark skin tone
+1F469 200D 1F37C                                       ; fully-qualified     # 
👩‍🍼 E13.0 woman feeding baby
+1F469 1F3FB 200D 1F37C                                 ; fully-qualified     # 
👩🏻‍🍼 E13.0 woman feeding baby: light skin tone
+1F469 1F3FC 200D 1F37C                                 ; fully-qualified     # 
👩🏼‍🍼 E13.0 woman feeding baby: medium-light skin tone
+1F469 1F3FD 200D 1F37C                                 ; fully-qualified     # 
👩🏽‍🍼 E13.0 woman feeding baby: medium skin tone
+1F469 1F3FE 200D 1F37C                                 ; fully-qualified     # 
👩🏾‍🍼 E13.0 woman feeding baby: medium-dark skin tone
+1F469 1F3FF 200D 1F37C                                 ; fully-qualified     # 
👩🏿‍🍼 E13.0 woman feeding baby: dark skin tone
+1F468 200D 1F37C                                       ; fully-qualified     # 
👨‍🍼 E13.0 man feeding baby
+1F468 1F3FB 200D 1F37C                                 ; fully-qualified     # 
👨🏻‍🍼 E13.0 man feeding baby: light skin tone
+1F468 1F3FC 200D 1F37C                                 ; fully-qualified     # 
👨🏼‍🍼 E13.0 man feeding baby: medium-light skin tone
+1F468 1F3FD 200D 1F37C                                 ; fully-qualified     # 
👨🏽‍🍼 E13.0 man feeding baby: medium skin tone
+1F468 1F3FE 200D 1F37C                                 ; fully-qualified     # 
👨🏾‍🍼 E13.0 man feeding baby: medium-dark skin tone
+1F468 1F3FF 200D 1F37C                                 ; fully-qualified     # 
👨🏿‍🍼 E13.0 man feeding baby: dark skin tone
+1F9D1 200D 1F37C                                       ; fully-qualified     # 
🧑‍🍼 E13.0 person feeding baby
+1F9D1 1F3FB 200D 1F37C                                 ; fully-qualified     # 
🧑🏻‍🍼 E13.0 person feeding baby: light skin tone
+1F9D1 1F3FC 200D 1F37C                                 ; fully-qualified     # 
🧑🏼‍🍼 E13.0 person feeding baby: medium-light skin tone
+1F9D1 1F3FD 200D 1F37C                                 ; fully-qualified     # 
🧑🏽‍🍼 E13.0 person feeding baby: medium skin tone
+1F9D1 1F3FE 200D 1F37C                                 ; fully-qualified     # 
🧑🏾‍🍼 E13.0 person feeding baby: medium-dark skin tone
+1F9D1 1F3FF 200D 1F37C                                 ; fully-qualified     # 
🧑🏿‍🍼 E13.0 person feeding baby: dark skin tone
+
+# subgroup: person-fantasy
+1F47C                                                  ; fully-qualified     # 
👼 E0.6 baby angel
+1F47C 1F3FB                                            ; fully-qualified     # 
👼🏻 E1.0 baby angel: light skin tone
+1F47C 1F3FC                                            ; fully-qualified     # 
👼🏼 E1.0 baby angel: medium-light skin tone
+1F47C 1F3FD                                            ; fully-qualified     # 
👼🏽 E1.0 baby angel: medium skin tone
+1F47C 1F3FE                                            ; fully-qualified     # 
👼🏾 E1.0 baby angel: medium-dark skin tone
+1F47C 1F3FF                                            ; fully-qualified     # 
👼🏿 E1.0 baby angel: dark skin tone
+1F385                                                  ; fully-qualified     # 
🎅 E0.6 Santa Claus
+1F385 1F3FB                                            ; fully-qualified     # 
🎅🏻 E1.0 Santa Claus: light skin tone
+1F385 1F3FC                                            ; fully-qualified     # 
🎅🏼 E1.0 Santa Claus: medium-light skin tone
+1F385 1F3FD                                            ; fully-qualified     # 
🎅🏽 E1.0 Santa Claus: medium skin tone
+1F385 1F3FE                                            ; fully-qualified     # 
🎅🏾 E1.0 Santa Claus: medium-dark skin tone
+1F385 1F3FF                                            ; fully-qualified     # 
🎅🏿 E1.0 Santa Claus: dark skin tone
+1F936                                                  ; fully-qualified     # 
🤶 E3.0 Mrs. Claus
+1F936 1F3FB                                            ; fully-qualified     # 
🤶🏻 E3.0 Mrs. Claus: light skin tone
+1F936 1F3FC                                            ; fully-qualified     # 
🤶🏼 E3.0 Mrs. Claus: medium-light skin tone
+1F936 1F3FD                                            ; fully-qualified     # 
🤶🏽 E3.0 Mrs. Claus: medium skin tone
+1F936 1F3FE                                            ; fully-qualified     # 
🤶🏾 E3.0 Mrs. Claus: medium-dark skin tone
+1F936 1F3FF                                            ; fully-qualified     # 
🤶🏿 E3.0 Mrs. Claus: dark skin tone
+1F9D1 200D 1F384                                       ; fully-qualified     # 
🧑‍🎄 E13.0 mx claus
+1F9D1 1F3FB 200D 1F384                                 ; fully-qualified     # 
🧑🏻‍🎄 E13.0 mx claus: light skin tone
+1F9D1 1F3FC 200D 1F384                                 ; fully-qualified     # 
🧑🏼‍🎄 E13.0 mx claus: medium-light skin tone
+1F9D1 1F3FD 200D 1F384                                 ; fully-qualified     # 
🧑🏽‍🎄 E13.0 mx claus: medium skin tone
+1F9D1 1F3FE 200D 1F384                                 ; fully-qualified     # 
🧑🏾‍🎄 E13.0 mx claus: medium-dark skin tone
+1F9D1 1F3FF 200D 1F384                                 ; fully-qualified     # 
🧑🏿‍🎄 E13.0 mx claus: dark skin tone
+1F9B8                                                  ; fully-qualified     # 
🦸 E11.0 superhero
+1F9B8 1F3FB                                            ; fully-qualified     # 
🦸🏻 E11.0 superhero: light skin tone
+1F9B8 1F3FC                                            ; fully-qualified     # 
🦸🏼 E11.0 superhero: medium-light skin tone
+1F9B8 1F3FD                                            ; fully-qualified     # 
🦸🏽 E11.0 superhero: medium skin tone
+1F9B8 1F3FE                                            ; fully-qualified     # 
🦸🏾 E11.0 superhero: medium-dark skin tone
+1F9B8 1F3FF                                            ; fully-qualified     # 
🦸🏿 E11.0 superhero: dark skin tone
+1F9B8 200D 2642 FE0F                                   ; fully-qualified     # 
🦸‍♂️ E11.0 man superhero
+1F9B8 200D 2642                                        ; minimally-qualified # 
🦸‍♂ E11.0 man superhero
+1F9B8 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🦸🏻‍♂️ E11.0 man superhero: light skin tone
+1F9B8 1F3FB 200D 2642                                  ; minimally-qualified # 
🦸🏻‍♂ E11.0 man superhero: light skin tone
+1F9B8 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🦸🏼‍♂️ E11.0 man superhero: medium-light skin tone
+1F9B8 1F3FC 200D 2642                                  ; minimally-qualified # 
🦸🏼‍♂ E11.0 man superhero: medium-light skin tone
+1F9B8 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🦸🏽‍♂️ E11.0 man superhero: medium skin tone
+1F9B8 1F3FD 200D 2642                                  ; minimally-qualified # 
🦸🏽‍♂ E11.0 man superhero: medium skin tone
+1F9B8 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🦸🏾‍♂️ E11.0 man superhero: medium-dark skin tone
+1F9B8 1F3FE 200D 2642                                  ; minimally-qualified # 
🦸🏾‍♂ E11.0 man superhero: medium-dark skin tone
+1F9B8 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🦸🏿‍♂️ E11.0 man superhero: dark skin tone
+1F9B8 1F3FF 200D 2642                                  ; minimally-qualified # 
🦸🏿‍♂ E11.0 man superhero: dark skin tone
+1F9B8 200D 2640 FE0F                                   ; fully-qualified     # 
🦸‍♀️ E11.0 woman superhero
+1F9B8 200D 2640                                        ; minimally-qualified # 
🦸‍♀ E11.0 woman superhero
+1F9B8 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🦸🏻‍♀️ E11.0 woman superhero: light skin tone
+1F9B8 1F3FB 200D 2640                                  ; minimally-qualified # 
🦸🏻‍♀ E11.0 woman superhero: light skin tone
+1F9B8 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🦸🏼‍♀️ E11.0 woman superhero: medium-light skin tone
+1F9B8 1F3FC 200D 2640                                  ; minimally-qualified # 
🦸🏼‍♀ E11.0 woman superhero: medium-light skin tone
+1F9B8 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🦸🏽‍♀️ E11.0 woman superhero: medium skin tone
+1F9B8 1F3FD 200D 2640                                  ; minimally-qualified # 
🦸🏽‍♀ E11.0 woman superhero: medium skin tone
+1F9B8 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🦸🏾‍♀️ E11.0 woman superhero: medium-dark skin tone
+1F9B8 1F3FE 200D 2640                                  ; minimally-qualified # 
🦸🏾‍♀ E11.0 woman superhero: medium-dark skin tone
+1F9B8 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🦸🏿‍♀️ E11.0 woman superhero: dark skin tone
+1F9B8 1F3FF 200D 2640                                  ; minimally-qualified # 
🦸🏿‍♀ E11.0 woman superhero: dark skin tone
+1F9B9                                                  ; fully-qualified     # 
🦹 E11.0 supervillain
+1F9B9 1F3FB                                            ; fully-qualified     # 
🦹🏻 E11.0 supervillain: light skin tone
+1F9B9 1F3FC                                            ; fully-qualified     # 
🦹🏼 E11.0 supervillain: medium-light skin tone
+1F9B9 1F3FD                                            ; fully-qualified     # 
🦹🏽 E11.0 supervillain: medium skin tone
+1F9B9 1F3FE                                            ; fully-qualified     # 
🦹🏾 E11.0 supervillain: medium-dark skin tone
+1F9B9 1F3FF                                            ; fully-qualified     # 
🦹🏿 E11.0 supervillain: dark skin tone
+1F9B9 200D 2642 FE0F                                   ; fully-qualified     # 
🦹‍♂️ E11.0 man supervillain
+1F9B9 200D 2642                                        ; minimally-qualified # 
🦹‍♂ E11.0 man supervillain
+1F9B9 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🦹🏻‍♂️ E11.0 man supervillain: light skin tone
+1F9B9 1F3FB 200D 2642                                  ; minimally-qualified # 
🦹🏻‍♂ E11.0 man supervillain: light skin tone
+1F9B9 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🦹🏼‍♂️ E11.0 man supervillain: medium-light skin tone
+1F9B9 1F3FC 200D 2642                                  ; minimally-qualified # 
🦹🏼‍♂ E11.0 man supervillain: medium-light skin tone
+1F9B9 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🦹🏽‍♂️ E11.0 man supervillain: medium skin tone
+1F9B9 1F3FD 200D 2642                                  ; minimally-qualified # 
🦹🏽‍♂ E11.0 man supervillain: medium skin tone
+1F9B9 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🦹🏾‍♂️ E11.0 man supervillain: medium-dark skin tone
+1F9B9 1F3FE 200D 2642                                  ; minimally-qualified # 
🦹🏾‍♂ E11.0 man supervillain: medium-dark skin tone
+1F9B9 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🦹🏿‍♂️ E11.0 man supervillain: dark skin tone
+1F9B9 1F3FF 200D 2642                                  ; minimally-qualified # 
🦹🏿‍♂ E11.0 man supervillain: dark skin tone
+1F9B9 200D 2640 FE0F                                   ; fully-qualified     # 
🦹‍♀️ E11.0 woman supervillain
+1F9B9 200D 2640                                        ; minimally-qualified # 
🦹‍♀ E11.0 woman supervillain
+1F9B9 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🦹🏻‍♀️ E11.0 woman supervillain: light skin tone
+1F9B9 1F3FB 200D 2640                                  ; minimally-qualified # 
🦹🏻‍♀ E11.0 woman supervillain: light skin tone
+1F9B9 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🦹🏼‍♀️ E11.0 woman supervillain: medium-light skin tone
+1F9B9 1F3FC 200D 2640                                  ; minimally-qualified # 
🦹🏼‍♀ E11.0 woman supervillain: medium-light skin tone
+1F9B9 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🦹🏽‍♀️ E11.0 woman supervillain: medium skin tone
+1F9B9 1F3FD 200D 2640                                  ; minimally-qualified # 
🦹🏽‍♀ E11.0 woman supervillain: medium skin tone
+1F9B9 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🦹🏾‍♀️ E11.0 woman supervillain: medium-dark skin tone
+1F9B9 1F3FE 200D 2640                                  ; minimally-qualified # 
🦹🏾‍♀ E11.0 woman supervillain: medium-dark skin tone
+1F9B9 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🦹🏿‍♀️ E11.0 woman supervillain: dark skin tone
+1F9B9 1F3FF 200D 2640                                  ; minimally-qualified # 
🦹🏿‍♀ E11.0 woman supervillain: dark skin tone
+1F9D9                                                  ; fully-qualified     # 
🧙 E5.0 mage
+1F9D9 1F3FB                                            ; fully-qualified     # 
🧙🏻 E5.0 mage: light skin tone
+1F9D9 1F3FC                                            ; fully-qualified     # 
🧙🏼 E5.0 mage: medium-light skin tone
+1F9D9 1F3FD                                            ; fully-qualified     # 
🧙🏽 E5.0 mage: medium skin tone
+1F9D9 1F3FE                                            ; fully-qualified     # 
🧙🏾 E5.0 mage: medium-dark skin tone
+1F9D9 1F3FF                                            ; fully-qualified     # 
🧙🏿 E5.0 mage: dark skin tone
+1F9D9 200D 2642 FE0F                                   ; fully-qualified     # 
🧙‍♂️ E5.0 man mage
+1F9D9 200D 2642                                        ; minimally-qualified # 
🧙‍♂ E5.0 man mage
+1F9D9 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧙🏻‍♂️ E5.0 man mage: light skin tone
+1F9D9 1F3FB 200D 2642                                  ; minimally-qualified # 
🧙🏻‍♂ E5.0 man mage: light skin tone
+1F9D9 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧙🏼‍♂️ E5.0 man mage: medium-light skin tone
+1F9D9 1F3FC 200D 2642                                  ; minimally-qualified # 
🧙🏼‍♂ E5.0 man mage: medium-light skin tone
+1F9D9 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧙🏽‍♂️ E5.0 man mage: medium skin tone
+1F9D9 1F3FD 200D 2642                                  ; minimally-qualified # 
🧙🏽‍♂ E5.0 man mage: medium skin tone
+1F9D9 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧙🏾‍♂️ E5.0 man mage: medium-dark skin tone
+1F9D9 1F3FE 200D 2642                                  ; minimally-qualified # 
🧙🏾‍♂ E5.0 man mage: medium-dark skin tone
+1F9D9 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧙🏿‍♂️ E5.0 man mage: dark skin tone
+1F9D9 1F3FF 200D 2642                                  ; minimally-qualified # 
🧙🏿‍♂ E5.0 man mage: dark skin tone
+1F9D9 200D 2640 FE0F                                   ; fully-qualified     # 
🧙‍♀️ E5.0 woman mage
+1F9D9 200D 2640                                        ; minimally-qualified # 
🧙‍♀ E5.0 woman mage
+1F9D9 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧙🏻‍♀️ E5.0 woman mage: light skin tone
+1F9D9 1F3FB 200D 2640                                  ; minimally-qualified # 
🧙🏻‍♀ E5.0 woman mage: light skin tone
+1F9D9 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧙🏼‍♀️ E5.0 woman mage: medium-light skin tone
+1F9D9 1F3FC 200D 2640                                  ; minimally-qualified # 
🧙🏼‍♀ E5.0 woman mage: medium-light skin tone
+1F9D9 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧙🏽‍♀️ E5.0 woman mage: medium skin tone
+1F9D9 1F3FD 200D 2640                                  ; minimally-qualified # 
🧙🏽‍♀ E5.0 woman mage: medium skin tone
+1F9D9 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧙🏾‍♀️ E5.0 woman mage: medium-dark skin tone
+1F9D9 1F3FE 200D 2640                                  ; minimally-qualified # 
🧙🏾‍♀ E5.0 woman mage: medium-dark skin tone
+1F9D9 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧙🏿‍♀️ E5.0 woman mage: dark skin tone
+1F9D9 1F3FF 200D 2640                                  ; minimally-qualified # 
🧙🏿‍♀ E5.0 woman mage: dark skin tone
+1F9DA                                                  ; fully-qualified     # 
🧚 E5.0 fairy
+1F9DA 1F3FB                                            ; fully-qualified     # 
🧚🏻 E5.0 fairy: light skin tone
+1F9DA 1F3FC                                            ; fully-qualified     # 
🧚🏼 E5.0 fairy: medium-light skin tone
+1F9DA 1F3FD                                            ; fully-qualified     # 
🧚🏽 E5.0 fairy: medium skin tone
+1F9DA 1F3FE                                            ; fully-qualified     # 
🧚🏾 E5.0 fairy: medium-dark skin tone
+1F9DA 1F3FF                                            ; fully-qualified     # 
🧚🏿 E5.0 fairy: dark skin tone
+1F9DA 200D 2642 FE0F                                   ; fully-qualified     # 
🧚‍♂️ E5.0 man fairy
+1F9DA 200D 2642                                        ; minimally-qualified # 
🧚‍♂ E5.0 man fairy
+1F9DA 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧚🏻‍♂️ E5.0 man fairy: light skin tone
+1F9DA 1F3FB 200D 2642                                  ; minimally-qualified # 
🧚🏻‍♂ E5.0 man fairy: light skin tone
+1F9DA 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧚🏼‍♂️ E5.0 man fairy: medium-light skin tone
+1F9DA 1F3FC 200D 2642                                  ; minimally-qualified # 
🧚🏼‍♂ E5.0 man fairy: medium-light skin tone
+1F9DA 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧚🏽‍♂️ E5.0 man fairy: medium skin tone
+1F9DA 1F3FD 200D 2642                                  ; minimally-qualified # 
🧚🏽‍♂ E5.0 man fairy: medium skin tone
+1F9DA 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧚🏾‍♂️ E5.0 man fairy: medium-dark skin tone
+1F9DA 1F3FE 200D 2642                                  ; minimally-qualified # 
🧚🏾‍♂ E5.0 man fairy: medium-dark skin tone
+1F9DA 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧚🏿‍♂️ E5.0 man fairy: dark skin tone
+1F9DA 1F3FF 200D 2642                                  ; minimally-qualified # 
🧚🏿‍♂ E5.0 man fairy: dark skin tone
+1F9DA 200D 2640 FE0F                                   ; fully-qualified     # 
🧚‍♀️ E5.0 woman fairy
+1F9DA 200D 2640                                        ; minimally-qualified # 
🧚‍♀ E5.0 woman fairy
+1F9DA 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧚🏻‍♀️ E5.0 woman fairy: light skin tone
+1F9DA 1F3FB 200D 2640                                  ; minimally-qualified # 
🧚🏻‍♀ E5.0 woman fairy: light skin tone
+1F9DA 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧚🏼‍♀️ E5.0 woman fairy: medium-light skin tone
+1F9DA 1F3FC 200D 2640                                  ; minimally-qualified # 
🧚🏼‍♀ E5.0 woman fairy: medium-light skin tone
+1F9DA 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧚🏽‍♀️ E5.0 woman fairy: medium skin tone
+1F9DA 1F3FD 200D 2640                                  ; minimally-qualified # 
🧚🏽‍♀ E5.0 woman fairy: medium skin tone
+1F9DA 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧚🏾‍♀️ E5.0 woman fairy: medium-dark skin tone
+1F9DA 1F3FE 200D 2640                                  ; minimally-qualified # 
🧚🏾‍♀ E5.0 woman fairy: medium-dark skin tone
+1F9DA 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧚🏿‍♀️ E5.0 woman fairy: dark skin tone
+1F9DA 1F3FF 200D 2640                                  ; minimally-qualified # 
🧚🏿‍♀ E5.0 woman fairy: dark skin tone
+1F9DB                                                  ; fully-qualified     # 
🧛 E5.0 vampire
+1F9DB 1F3FB                                            ; fully-qualified     # 
🧛🏻 E5.0 vampire: light skin tone
+1F9DB 1F3FC                                            ; fully-qualified     # 
🧛🏼 E5.0 vampire: medium-light skin tone
+1F9DB 1F3FD                                            ; fully-qualified     # 
🧛🏽 E5.0 vampire: medium skin tone
+1F9DB 1F3FE                                            ; fully-qualified     # 
🧛🏾 E5.0 vampire: medium-dark skin tone
+1F9DB 1F3FF                                            ; fully-qualified     # 
🧛🏿 E5.0 vampire: dark skin tone
+1F9DB 200D 2642 FE0F                                   ; fully-qualified     # 
🧛‍♂️ E5.0 man vampire
+1F9DB 200D 2642                                        ; minimally-qualified # 
🧛‍♂ E5.0 man vampire
+1F9DB 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧛🏻‍♂️ E5.0 man vampire: light skin tone
+1F9DB 1F3FB 200D 2642                                  ; minimally-qualified # 
🧛🏻‍♂ E5.0 man vampire: light skin tone
+1F9DB 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧛🏼‍♂️ E5.0 man vampire: medium-light skin tone
+1F9DB 1F3FC 200D 2642                                  ; minimally-qualified # 
🧛🏼‍♂ E5.0 man vampire: medium-light skin tone
+1F9DB 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧛🏽‍♂️ E5.0 man vampire: medium skin tone
+1F9DB 1F3FD 200D 2642                                  ; minimally-qualified # 
🧛🏽‍♂ E5.0 man vampire: medium skin tone
+1F9DB 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧛🏾‍♂️ E5.0 man vampire: medium-dark skin tone
+1F9DB 1F3FE 200D 2642                                  ; minimally-qualified # 
🧛🏾‍♂ E5.0 man vampire: medium-dark skin tone
+1F9DB 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧛🏿‍♂️ E5.0 man vampire: dark skin tone
+1F9DB 1F3FF 200D 2642                                  ; minimally-qualified # 
🧛🏿‍♂ E5.0 man vampire: dark skin tone
+1F9DB 200D 2640 FE0F                                   ; fully-qualified     # 
🧛‍♀️ E5.0 woman vampire
+1F9DB 200D 2640                                        ; minimally-qualified # 
🧛‍♀ E5.0 woman vampire
+1F9DB 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧛🏻‍♀️ E5.0 woman vampire: light skin tone
+1F9DB 1F3FB 200D 2640                                  ; minimally-qualified # 
🧛🏻‍♀ E5.0 woman vampire: light skin tone
+1F9DB 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧛🏼‍♀️ E5.0 woman vampire: medium-light skin tone
+1F9DB 1F3FC 200D 2640                                  ; minimally-qualified # 
🧛🏼‍♀ E5.0 woman vampire: medium-light skin tone
+1F9DB 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧛🏽‍♀️ E5.0 woman vampire: medium skin tone
+1F9DB 1F3FD 200D 2640                                  ; minimally-qualified # 
🧛🏽‍♀ E5.0 woman vampire: medium skin tone
+1F9DB 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧛🏾‍♀️ E5.0 woman vampire: medium-dark skin tone
+1F9DB 1F3FE 200D 2640                                  ; minimally-qualified # 
🧛🏾‍♀ E5.0 woman vampire: medium-dark skin tone
+1F9DB 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧛🏿‍♀️ E5.0 woman vampire: dark skin tone
+1F9DB 1F3FF 200D 2640                                  ; minimally-qualified # 
🧛🏿‍♀ E5.0 woman vampire: dark skin tone
+1F9DC                                                  ; fully-qualified     # 
🧜 E5.0 merperson
+1F9DC 1F3FB                                            ; fully-qualified     # 
🧜🏻 E5.0 merperson: light skin tone
+1F9DC 1F3FC                                            ; fully-qualified     # 
🧜🏼 E5.0 merperson: medium-light skin tone
+1F9DC 1F3FD                                            ; fully-qualified     # 
🧜🏽 E5.0 merperson: medium skin tone
+1F9DC 1F3FE                                            ; fully-qualified     # 
🧜🏾 E5.0 merperson: medium-dark skin tone
+1F9DC 1F3FF                                            ; fully-qualified     # 
🧜🏿 E5.0 merperson: dark skin tone
+1F9DC 200D 2642 FE0F                                   ; fully-qualified     # 
🧜‍♂️ E5.0 merman
+1F9DC 200D 2642                                        ; minimally-qualified # 
🧜‍♂ E5.0 merman
+1F9DC 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧜🏻‍♂️ E5.0 merman: light skin tone
+1F9DC 1F3FB 200D 2642                                  ; minimally-qualified # 
🧜🏻‍♂ E5.0 merman: light skin tone
+1F9DC 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧜🏼‍♂️ E5.0 merman: medium-light skin tone
+1F9DC 1F3FC 200D 2642                                  ; minimally-qualified # 
🧜🏼‍♂ E5.0 merman: medium-light skin tone
+1F9DC 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧜🏽‍♂️ E5.0 merman: medium skin tone
+1F9DC 1F3FD 200D 2642                                  ; minimally-qualified # 
🧜🏽‍♂ E5.0 merman: medium skin tone
+1F9DC 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧜🏾‍♂️ E5.0 merman: medium-dark skin tone
+1F9DC 1F3FE 200D 2642                                  ; minimally-qualified # 
🧜🏾‍♂ E5.0 merman: medium-dark skin tone
+1F9DC 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧜🏿‍♂️ E5.0 merman: dark skin tone
+1F9DC 1F3FF 200D 2642                                  ; minimally-qualified # 
🧜🏿‍♂ E5.0 merman: dark skin tone
+1F9DC 200D 2640 FE0F                                   ; fully-qualified     # 
🧜‍♀️ E5.0 mermaid
+1F9DC 200D 2640                                        ; minimally-qualified # 
🧜‍♀ E5.0 mermaid
+1F9DC 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧜🏻‍♀️ E5.0 mermaid: light skin tone
+1F9DC 1F3FB 200D 2640                                  ; minimally-qualified # 
🧜🏻‍♀ E5.0 mermaid: light skin tone
+1F9DC 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧜🏼‍♀️ E5.0 mermaid: medium-light skin tone
+1F9DC 1F3FC 200D 2640                                  ; minimally-qualified # 
🧜🏼‍♀ E5.0 mermaid: medium-light skin tone
+1F9DC 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧜🏽‍♀️ E5.0 mermaid: medium skin tone
+1F9DC 1F3FD 200D 2640                                  ; minimally-qualified # 
🧜🏽‍♀ E5.0 mermaid: medium skin tone
+1F9DC 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧜🏾‍♀️ E5.0 mermaid: medium-dark skin tone
+1F9DC 1F3FE 200D 2640                                  ; minimally-qualified # 
🧜🏾‍♀ E5.0 mermaid: medium-dark skin tone
+1F9DC 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧜🏿‍♀️ E5.0 mermaid: dark skin tone
+1F9DC 1F3FF 200D 2640                                  ; minimally-qualified # 
🧜🏿‍♀ E5.0 mermaid: dark skin tone
+1F9DD                                                  ; fully-qualified     # 
🧝 E5.0 elf
+1F9DD 1F3FB                                            ; fully-qualified     # 
🧝🏻 E5.0 elf: light skin tone
+1F9DD 1F3FC                                            ; fully-qualified     # 
🧝🏼 E5.0 elf: medium-light skin tone
+1F9DD 1F3FD                                            ; fully-qualified     # 
🧝🏽 E5.0 elf: medium skin tone
+1F9DD 1F3FE                                            ; fully-qualified     # 
🧝🏾 E5.0 elf: medium-dark skin tone
+1F9DD 1F3FF                                            ; fully-qualified     # 
🧝🏿 E5.0 elf: dark skin tone
+1F9DD 200D 2642 FE0F                                   ; fully-qualified     # 
🧝‍♂️ E5.0 man elf
+1F9DD 200D 2642                                        ; minimally-qualified # 
🧝‍♂ E5.0 man elf
+1F9DD 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧝🏻‍♂️ E5.0 man elf: light skin tone
+1F9DD 1F3FB 200D 2642                                  ; minimally-qualified # 
🧝🏻‍♂ E5.0 man elf: light skin tone
+1F9DD 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧝🏼‍♂️ E5.0 man elf: medium-light skin tone
+1F9DD 1F3FC 200D 2642                                  ; minimally-qualified # 
🧝🏼‍♂ E5.0 man elf: medium-light skin tone
+1F9DD 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧝🏽‍♂️ E5.0 man elf: medium skin tone
+1F9DD 1F3FD 200D 2642                                  ; minimally-qualified # 
🧝🏽‍♂ E5.0 man elf: medium skin tone
+1F9DD 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧝🏾‍♂️ E5.0 man elf: medium-dark skin tone
+1F9DD 1F3FE 200D 2642                                  ; minimally-qualified # 
🧝🏾‍♂ E5.0 man elf: medium-dark skin tone
+1F9DD 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧝🏿‍♂️ E5.0 man elf: dark skin tone
+1F9DD 1F3FF 200D 2642                                  ; minimally-qualified # 
🧝🏿‍♂ E5.0 man elf: dark skin tone
+1F9DD 200D 2640 FE0F                                   ; fully-qualified     # 
🧝‍♀️ E5.0 woman elf
+1F9DD 200D 2640                                        ; minimally-qualified # 
🧝‍♀ E5.0 woman elf
+1F9DD 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧝🏻‍♀️ E5.0 woman elf: light skin tone
+1F9DD 1F3FB 200D 2640                                  ; minimally-qualified # 
🧝🏻‍♀ E5.0 woman elf: light skin tone
+1F9DD 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧝🏼‍♀️ E5.0 woman elf: medium-light skin tone
+1F9DD 1F3FC 200D 2640                                  ; minimally-qualified # 
🧝🏼‍♀ E5.0 woman elf: medium-light skin tone
+1F9DD 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧝🏽‍♀️ E5.0 woman elf: medium skin tone
+1F9DD 1F3FD 200D 2640                                  ; minimally-qualified # 
🧝🏽‍♀ E5.0 woman elf: medium skin tone
+1F9DD 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧝🏾‍♀️ E5.0 woman elf: medium-dark skin tone
+1F9DD 1F3FE 200D 2640                                  ; minimally-qualified # 
🧝🏾‍♀ E5.0 woman elf: medium-dark skin tone
+1F9DD 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧝🏿‍♀️ E5.0 woman elf: dark skin tone
+1F9DD 1F3FF 200D 2640                                  ; minimally-qualified # 
🧝🏿‍♀ E5.0 woman elf: dark skin tone
+1F9DE                                                  ; fully-qualified     # 
🧞 E5.0 genie
+1F9DE 200D 2642 FE0F                                   ; fully-qualified     # 
🧞‍♂️ E5.0 man genie
+1F9DE 200D 2642                                        ; minimally-qualified # 
🧞‍♂ E5.0 man genie
+1F9DE 200D 2640 FE0F                                   ; fully-qualified     # 
🧞‍♀️ E5.0 woman genie
+1F9DE 200D 2640                                        ; minimally-qualified # 
🧞‍♀ E5.0 woman genie
+1F9DF                                                  ; fully-qualified     # 
🧟 E5.0 zombie
+1F9DF 200D 2642 FE0F                                   ; fully-qualified     # 
🧟‍♂️ E5.0 man zombie
+1F9DF 200D 2642                                        ; minimally-qualified # 
🧟‍♂ E5.0 man zombie
+1F9DF 200D 2640 FE0F                                   ; fully-qualified     # 
🧟‍♀️ E5.0 woman zombie
+1F9DF 200D 2640                                        ; minimally-qualified # 
🧟‍♀ E5.0 woman zombie
+1F9CC                                                  ; fully-qualified     # 
🧌 E14.0 troll
+
+# subgroup: person-activity
+1F486                                                  ; fully-qualified     # 
💆 E0.6 person getting massage
+1F486 1F3FB                                            ; fully-qualified     # 
💆🏻 E1.0 person getting massage: light skin tone
+1F486 1F3FC                                            ; fully-qualified     # 
💆🏼 E1.0 person getting massage: medium-light skin tone
+1F486 1F3FD                                            ; fully-qualified     # 
💆🏽 E1.0 person getting massage: medium skin tone
+1F486 1F3FE                                            ; fully-qualified     # 
💆🏾 E1.0 person getting massage: medium-dark skin tone
+1F486 1F3FF                                            ; fully-qualified     # 
💆🏿 E1.0 person getting massage: dark skin tone
+1F486 200D 2642 FE0F                                   ; fully-qualified     # 
💆‍♂️ E4.0 man getting massage
+1F486 200D 2642                                        ; minimally-qualified # 
💆‍♂ E4.0 man getting massage
+1F486 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
💆🏻‍♂️ E4.0 man getting massage: light skin tone
+1F486 1F3FB 200D 2642                                  ; minimally-qualified # 
💆🏻‍♂ E4.0 man getting massage: light skin tone
+1F486 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
💆🏼‍♂️ E4.0 man getting massage: medium-light skin tone
+1F486 1F3FC 200D 2642                                  ; minimally-qualified # 
💆🏼‍♂ E4.0 man getting massage: medium-light skin tone
+1F486 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
💆🏽‍♂️ E4.0 man getting massage: medium skin tone
+1F486 1F3FD 200D 2642                                  ; minimally-qualified # 
💆🏽‍♂ E4.0 man getting massage: medium skin tone
+1F486 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
💆🏾‍♂️ E4.0 man getting massage: medium-dark skin tone
+1F486 1F3FE 200D 2642                                  ; minimally-qualified # 
💆🏾‍♂ E4.0 man getting massage: medium-dark skin tone
+1F486 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
💆🏿‍♂️ E4.0 man getting massage: dark skin tone
+1F486 1F3FF 200D 2642                                  ; minimally-qualified # 
💆🏿‍♂ E4.0 man getting massage: dark skin tone
+1F486 200D 2640 FE0F                                   ; fully-qualified     # 
💆‍♀️ E4.0 woman getting massage
+1F486 200D 2640                                        ; minimally-qualified # 
💆‍♀ E4.0 woman getting massage
+1F486 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
💆🏻‍♀️ E4.0 woman getting massage: light skin tone
+1F486 1F3FB 200D 2640                                  ; minimally-qualified # 
💆🏻‍♀ E4.0 woman getting massage: light skin tone
+1F486 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
💆🏼‍♀️ E4.0 woman getting massage: medium-light skin tone
+1F486 1F3FC 200D 2640                                  ; minimally-qualified # 
💆🏼‍♀ E4.0 woman getting massage: medium-light skin tone
+1F486 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
💆🏽‍♀️ E4.0 woman getting massage: medium skin tone
+1F486 1F3FD 200D 2640                                  ; minimally-qualified # 
💆🏽‍♀ E4.0 woman getting massage: medium skin tone
+1F486 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
💆🏾‍♀️ E4.0 woman getting massage: medium-dark skin tone
+1F486 1F3FE 200D 2640                                  ; minimally-qualified # 
💆🏾‍♀ E4.0 woman getting massage: medium-dark skin tone
+1F486 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
💆🏿‍♀️ E4.0 woman getting massage: dark skin tone
+1F486 1F3FF 200D 2640                                  ; minimally-qualified # 
💆🏿‍♀ E4.0 woman getting massage: dark skin tone
+1F487                                                  ; fully-qualified     # 
💇 E0.6 person getting haircut
+1F487 1F3FB                                            ; fully-qualified     # 
💇🏻 E1.0 person getting haircut: light skin tone
+1F487 1F3FC                                            ; fully-qualified     # 
💇🏼 E1.0 person getting haircut: medium-light skin tone
+1F487 1F3FD                                            ; fully-qualified     # 
💇🏽 E1.0 person getting haircut: medium skin tone
+1F487 1F3FE                                            ; fully-qualified     # 
💇🏾 E1.0 person getting haircut: medium-dark skin tone
+1F487 1F3FF                                            ; fully-qualified     # 
💇🏿 E1.0 person getting haircut: dark skin tone
+1F487 200D 2642 FE0F                                   ; fully-qualified     # 
💇‍♂️ E4.0 man getting haircut
+1F487 200D 2642                                        ; minimally-qualified # 
💇‍♂ E4.0 man getting haircut
+1F487 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
💇🏻‍♂️ E4.0 man getting haircut: light skin tone
+1F487 1F3FB 200D 2642                                  ; minimally-qualified # 
💇🏻‍♂ E4.0 man getting haircut: light skin tone
+1F487 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
💇🏼‍♂️ E4.0 man getting haircut: medium-light skin tone
+1F487 1F3FC 200D 2642                                  ; minimally-qualified # 
💇🏼‍♂ E4.0 man getting haircut: medium-light skin tone
+1F487 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
💇🏽‍♂️ E4.0 man getting haircut: medium skin tone
+1F487 1F3FD 200D 2642                                  ; minimally-qualified # 
💇🏽‍♂ E4.0 man getting haircut: medium skin tone
+1F487 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
💇🏾‍♂️ E4.0 man getting haircut: medium-dark skin tone
+1F487 1F3FE 200D 2642                                  ; minimally-qualified # 
💇🏾‍♂ E4.0 man getting haircut: medium-dark skin tone
+1F487 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
💇🏿‍♂️ E4.0 man getting haircut: dark skin tone
+1F487 1F3FF 200D 2642                                  ; minimally-qualified # 
💇🏿‍♂ E4.0 man getting haircut: dark skin tone
+1F487 200D 2640 FE0F                                   ; fully-qualified     # 
💇‍♀️ E4.0 woman getting haircut
+1F487 200D 2640                                        ; minimally-qualified # 
💇‍♀ E4.0 woman getting haircut
+1F487 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
💇🏻‍♀️ E4.0 woman getting haircut: light skin tone
+1F487 1F3FB 200D 2640                                  ; minimally-qualified # 
💇🏻‍♀ E4.0 woman getting haircut: light skin tone
+1F487 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
💇🏼‍♀️ E4.0 woman getting haircut: medium-light skin tone
+1F487 1F3FC 200D 2640                                  ; minimally-qualified # 
💇🏼‍♀ E4.0 woman getting haircut: medium-light skin tone
+1F487 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
💇🏽‍♀️ E4.0 woman getting haircut: medium skin tone
+1F487 1F3FD 200D 2640                                  ; minimally-qualified # 
💇🏽‍♀ E4.0 woman getting haircut: medium skin tone
+1F487 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
💇🏾‍♀️ E4.0 woman getting haircut: medium-dark skin tone
+1F487 1F3FE 200D 2640                                  ; minimally-qualified # 
💇🏾‍♀ E4.0 woman getting haircut: medium-dark skin tone
+1F487 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
💇🏿‍♀️ E4.0 woman getting haircut: dark skin tone
+1F487 1F3FF 200D 2640                                  ; minimally-qualified # 
💇🏿‍♀ E4.0 woman getting haircut: dark skin tone
+1F6B6                                                  ; fully-qualified     # 
🚶 E0.6 person walking
+1F6B6 1F3FB                                            ; fully-qualified     # 
🚶🏻 E1.0 person walking: light skin tone
+1F6B6 1F3FC                                            ; fully-qualified     # 
🚶🏼 E1.0 person walking: medium-light skin tone
+1F6B6 1F3FD                                            ; fully-qualified     # 
🚶🏽 E1.0 person walking: medium skin tone
+1F6B6 1F3FE                                            ; fully-qualified     # 
🚶🏾 E1.0 person walking: medium-dark skin tone
+1F6B6 1F3FF                                            ; fully-qualified     # 
🚶🏿 E1.0 person walking: dark skin tone
+1F6B6 200D 2642 FE0F                                   ; fully-qualified     # 
🚶‍♂️ E4.0 man walking
+1F6B6 200D 2642                                        ; minimally-qualified # 
🚶‍♂ E4.0 man walking
+1F6B6 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🚶🏻‍♂️ E4.0 man walking: light skin tone
+1F6B6 1F3FB 200D 2642                                  ; minimally-qualified # 
🚶🏻‍♂ E4.0 man walking: light skin tone
+1F6B6 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🚶🏼‍♂️ E4.0 man walking: medium-light skin tone
+1F6B6 1F3FC 200D 2642                                  ; minimally-qualified # 
🚶🏼‍♂ E4.0 man walking: medium-light skin tone
+1F6B6 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🚶🏽‍♂️ E4.0 man walking: medium skin tone
+1F6B6 1F3FD 200D 2642                                  ; minimally-qualified # 
🚶🏽‍♂ E4.0 man walking: medium skin tone
+1F6B6 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🚶🏾‍♂️ E4.0 man walking: medium-dark skin tone
+1F6B6 1F3FE 200D 2642                                  ; minimally-qualified # 
🚶🏾‍♂ E4.0 man walking: medium-dark skin tone
+1F6B6 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🚶🏿‍♂️ E4.0 man walking: dark skin tone
+1F6B6 1F3FF 200D 2642                                  ; minimally-qualified # 
🚶🏿‍♂ E4.0 man walking: dark skin tone
+1F6B6 200D 2640 FE0F                                   ; fully-qualified     # 
🚶‍♀️ E4.0 woman walking
+1F6B6 200D 2640                                        ; minimally-qualified # 
🚶‍♀ E4.0 woman walking
+1F6B6 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🚶🏻‍♀️ E4.0 woman walking: light skin tone
+1F6B6 1F3FB 200D 2640                                  ; minimally-qualified # 
🚶🏻‍♀ E4.0 woman walking: light skin tone
+1F6B6 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🚶🏼‍♀️ E4.0 woman walking: medium-light skin tone
+1F6B6 1F3FC 200D 2640                                  ; minimally-qualified # 
🚶🏼‍♀ E4.0 woman walking: medium-light skin tone
+1F6B6 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🚶🏽‍♀️ E4.0 woman walking: medium skin tone
+1F6B6 1F3FD 200D 2640                                  ; minimally-qualified # 
🚶🏽‍♀ E4.0 woman walking: medium skin tone
+1F6B6 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🚶🏾‍♀️ E4.0 woman walking: medium-dark skin tone
+1F6B6 1F3FE 200D 2640                                  ; minimally-qualified # 
🚶🏾‍♀ E4.0 woman walking: medium-dark skin tone
+1F6B6 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🚶🏿‍♀️ E4.0 woman walking: dark skin tone
+1F6B6 1F3FF 200D 2640                                  ; minimally-qualified # 
🚶🏿‍♀ E4.0 woman walking: dark skin tone
+1F9CD                                                  ; fully-qualified     # 
🧍 E12.0 person standing
+1F9CD 1F3FB                                            ; fully-qualified     # 
🧍🏻 E12.0 person standing: light skin tone
+1F9CD 1F3FC                                            ; fully-qualified     # 
🧍🏼 E12.0 person standing: medium-light skin tone
+1F9CD 1F3FD                                            ; fully-qualified     # 
🧍🏽 E12.0 person standing: medium skin tone
+1F9CD 1F3FE                                            ; fully-qualified     # 
🧍🏾 E12.0 person standing: medium-dark skin tone
+1F9CD 1F3FF                                            ; fully-qualified     # 
🧍🏿 E12.0 person standing: dark skin tone
+1F9CD 200D 2642 FE0F                                   ; fully-qualified     # 
🧍‍♂️ E12.0 man standing
+1F9CD 200D 2642                                        ; minimally-qualified # 
🧍‍♂ E12.0 man standing
+1F9CD 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧍🏻‍♂️ E12.0 man standing: light skin tone
+1F9CD 1F3FB 200D 2642                                  ; minimally-qualified # 
🧍🏻‍♂ E12.0 man standing: light skin tone
+1F9CD 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧍🏼‍♂️ E12.0 man standing: medium-light skin tone
+1F9CD 1F3FC 200D 2642                                  ; minimally-qualified # 
🧍🏼‍♂ E12.0 man standing: medium-light skin tone
+1F9CD 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧍🏽‍♂️ E12.0 man standing: medium skin tone
+1F9CD 1F3FD 200D 2642                                  ; minimally-qualified # 
🧍🏽‍♂ E12.0 man standing: medium skin tone
+1F9CD 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧍🏾‍♂️ E12.0 man standing: medium-dark skin tone
+1F9CD 1F3FE 200D 2642                                  ; minimally-qualified # 
🧍🏾‍♂ E12.0 man standing: medium-dark skin tone
+1F9CD 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧍🏿‍♂️ E12.0 man standing: dark skin tone
+1F9CD 1F3FF 200D 2642                                  ; minimally-qualified # 
🧍🏿‍♂ E12.0 man standing: dark skin tone
+1F9CD 200D 2640 FE0F                                   ; fully-qualified     # 
🧍‍♀️ E12.0 woman standing
+1F9CD 200D 2640                                        ; minimally-qualified # 
🧍‍♀ E12.0 woman standing
+1F9CD 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧍🏻‍♀️ E12.0 woman standing: light skin tone
+1F9CD 1F3FB 200D 2640                                  ; minimally-qualified # 
🧍🏻‍♀ E12.0 woman standing: light skin tone
+1F9CD 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧍🏼‍♀️ E12.0 woman standing: medium-light skin tone
+1F9CD 1F3FC 200D 2640                                  ; minimally-qualified # 
🧍🏼‍♀ E12.0 woman standing: medium-light skin tone
+1F9CD 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧍🏽‍♀️ E12.0 woman standing: medium skin tone
+1F9CD 1F3FD 200D 2640                                  ; minimally-qualified # 
🧍🏽‍♀ E12.0 woman standing: medium skin tone
+1F9CD 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧍🏾‍♀️ E12.0 woman standing: medium-dark skin tone
+1F9CD 1F3FE 200D 2640                                  ; minimally-qualified # 
🧍🏾‍♀ E12.0 woman standing: medium-dark skin tone
+1F9CD 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧍🏿‍♀️ E12.0 woman standing: dark skin tone
+1F9CD 1F3FF 200D 2640                                  ; minimally-qualified # 
🧍🏿‍♀ E12.0 woman standing: dark skin tone
+1F9CE                                                  ; fully-qualified     # 
🧎 E12.0 person kneeling
+1F9CE 1F3FB                                            ; fully-qualified     # 
🧎🏻 E12.0 person kneeling: light skin tone
+1F9CE 1F3FC                                            ; fully-qualified     # 
🧎🏼 E12.0 person kneeling: medium-light skin tone
+1F9CE 1F3FD                                            ; fully-qualified     # 
🧎🏽 E12.0 person kneeling: medium skin tone
+1F9CE 1F3FE                                            ; fully-qualified     # 
🧎🏾 E12.0 person kneeling: medium-dark skin tone
+1F9CE 1F3FF                                            ; fully-qualified     # 
🧎🏿 E12.0 person kneeling: dark skin tone
+1F9CE 200D 2642 FE0F                                   ; fully-qualified     # 
🧎‍♂️ E12.0 man kneeling
+1F9CE 200D 2642                                        ; minimally-qualified # 
🧎‍♂ E12.0 man kneeling
+1F9CE 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧎🏻‍♂️ E12.0 man kneeling: light skin tone
+1F9CE 1F3FB 200D 2642                                  ; minimally-qualified # 
🧎🏻‍♂ E12.0 man kneeling: light skin tone
+1F9CE 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧎🏼‍♂️ E12.0 man kneeling: medium-light skin tone
+1F9CE 1F3FC 200D 2642                                  ; minimally-qualified # 
🧎🏼‍♂ E12.0 man kneeling: medium-light skin tone
+1F9CE 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧎🏽‍♂️ E12.0 man kneeling: medium skin tone
+1F9CE 1F3FD 200D 2642                                  ; minimally-qualified # 
🧎🏽‍♂ E12.0 man kneeling: medium skin tone
+1F9CE 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧎🏾‍♂️ E12.0 man kneeling: medium-dark skin tone
+1F9CE 1F3FE 200D 2642                                  ; minimally-qualified # 
🧎🏾‍♂ E12.0 man kneeling: medium-dark skin tone
+1F9CE 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧎🏿‍♂️ E12.0 man kneeling: dark skin tone
+1F9CE 1F3FF 200D 2642                                  ; minimally-qualified # 
🧎🏿‍♂ E12.0 man kneeling: dark skin tone
+1F9CE 200D 2640 FE0F                                   ; fully-qualified     # 
🧎‍♀️ E12.0 woman kneeling
+1F9CE 200D 2640                                        ; minimally-qualified # 
🧎‍♀ E12.0 woman kneeling
+1F9CE 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧎🏻‍♀️ E12.0 woman kneeling: light skin tone
+1F9CE 1F3FB 200D 2640                                  ; minimally-qualified # 
🧎🏻‍♀ E12.0 woman kneeling: light skin tone
+1F9CE 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧎🏼‍♀️ E12.0 woman kneeling: medium-light skin tone
+1F9CE 1F3FC 200D 2640                                  ; minimally-qualified # 
🧎🏼‍♀ E12.0 woman kneeling: medium-light skin tone
+1F9CE 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧎🏽‍♀️ E12.0 woman kneeling: medium skin tone
+1F9CE 1F3FD 200D 2640                                  ; minimally-qualified # 
🧎🏽‍♀ E12.0 woman kneeling: medium skin tone
+1F9CE 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧎🏾‍♀️ E12.0 woman kneeling: medium-dark skin tone
+1F9CE 1F3FE 200D 2640                                  ; minimally-qualified # 
🧎🏾‍♀ E12.0 woman kneeling: medium-dark skin tone
+1F9CE 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧎🏿‍♀️ E12.0 woman kneeling: dark skin tone
+1F9CE 1F3FF 200D 2640                                  ; minimally-qualified # 
🧎🏿‍♀ E12.0 woman kneeling: dark skin tone
+1F9D1 200D 1F9AF                                       ; fully-qualified     # 
🧑‍🦯 E12.1 person with white cane
+1F9D1 1F3FB 200D 1F9AF                                 ; fully-qualified     # 
🧑🏻‍🦯 E12.1 person with white cane: light skin tone
+1F9D1 1F3FC 200D 1F9AF                                 ; fully-qualified     # 
🧑🏼‍🦯 E12.1 person with white cane: medium-light skin tone
+1F9D1 1F3FD 200D 1F9AF                                 ; fully-qualified     # 
🧑🏽‍🦯 E12.1 person with white cane: medium skin tone
+1F9D1 1F3FE 200D 1F9AF                                 ; fully-qualified     # 
🧑🏾‍🦯 E12.1 person with white cane: medium-dark skin tone
+1F9D1 1F3FF 200D 1F9AF                                 ; fully-qualified     # 
🧑🏿‍🦯 E12.1 person with white cane: dark skin tone
+1F468 200D 1F9AF                                       ; fully-qualified     # 
👨‍🦯 E12.0 man with white cane
+1F468 1F3FB 200D 1F9AF                                 ; fully-qualified     # 
👨🏻‍🦯 E12.0 man with white cane: light skin tone
+1F468 1F3FC 200D 1F9AF                                 ; fully-qualified     # 
👨🏼‍🦯 E12.0 man with white cane: medium-light skin tone
+1F468 1F3FD 200D 1F9AF                                 ; fully-qualified     # 
👨🏽‍🦯 E12.0 man with white cane: medium skin tone
+1F468 1F3FE 200D 1F9AF                                 ; fully-qualified     # 
👨🏾‍🦯 E12.0 man with white cane: medium-dark skin tone
+1F468 1F3FF 200D 1F9AF                                 ; fully-qualified     # 
👨🏿‍🦯 E12.0 man with white cane: dark skin tone
+1F469 200D 1F9AF                                       ; fully-qualified     # 
👩‍🦯 E12.0 woman with white cane
+1F469 1F3FB 200D 1F9AF                                 ; fully-qualified     # 
👩🏻‍🦯 E12.0 woman with white cane: light skin tone
+1F469 1F3FC 200D 1F9AF                                 ; fully-qualified     # 
👩🏼‍🦯 E12.0 woman with white cane: medium-light skin tone
+1F469 1F3FD 200D 1F9AF                                 ; fully-qualified     # 
👩🏽‍🦯 E12.0 woman with white cane: medium skin tone
+1F469 1F3FE 200D 1F9AF                                 ; fully-qualified     # 
👩🏾‍🦯 E12.0 woman with white cane: medium-dark skin tone
+1F469 1F3FF 200D 1F9AF                                 ; fully-qualified     # 
👩🏿‍🦯 E12.0 woman with white cane: dark skin tone
+1F9D1 200D 1F9BC                                       ; fully-qualified     # 
🧑‍🦼 E12.1 person in motorized wheelchair
+1F9D1 1F3FB 200D 1F9BC                                 ; fully-qualified     # 
🧑🏻‍🦼 E12.1 person in motorized wheelchair: light skin tone
+1F9D1 1F3FC 200D 1F9BC                                 ; fully-qualified     # 
🧑🏼‍🦼 E12.1 person in motorized wheelchair: medium-light skin tone
+1F9D1 1F3FD 200D 1F9BC                                 ; fully-qualified     # 
🧑🏽‍🦼 E12.1 person in motorized wheelchair: medium skin tone
+1F9D1 1F3FE 200D 1F9BC                                 ; fully-qualified     # 
🧑🏾‍🦼 E12.1 person in motorized wheelchair: medium-dark skin tone
+1F9D1 1F3FF 200D 1F9BC                                 ; fully-qualified     # 
🧑🏿‍🦼 E12.1 person in motorized wheelchair: dark skin tone
+1F468 200D 1F9BC                                       ; fully-qualified     # 
👨‍🦼 E12.0 man in motorized wheelchair
+1F468 1F3FB 200D 1F9BC                                 ; fully-qualified     # 
👨🏻‍🦼 E12.0 man in motorized wheelchair: light skin tone
+1F468 1F3FC 200D 1F9BC                                 ; fully-qualified     # 
👨🏼‍🦼 E12.0 man in motorized wheelchair: medium-light skin tone
+1F468 1F3FD 200D 1F9BC                                 ; fully-qualified     # 
👨🏽‍🦼 E12.0 man in motorized wheelchair: medium skin tone
+1F468 1F3FE 200D 1F9BC                                 ; fully-qualified     # 
👨🏾‍🦼 E12.0 man in motorized wheelchair: medium-dark skin tone
+1F468 1F3FF 200D 1F9BC                                 ; fully-qualified     # 
👨🏿‍🦼 E12.0 man in motorized wheelchair: dark skin tone
+1F469 200D 1F9BC                                       ; fully-qualified     # 
👩‍🦼 E12.0 woman in motorized wheelchair
+1F469 1F3FB 200D 1F9BC                                 ; fully-qualified     # 
👩🏻‍🦼 E12.0 woman in motorized wheelchair: light skin tone
+1F469 1F3FC 200D 1F9BC                                 ; fully-qualified     # 
👩🏼‍🦼 E12.0 woman in motorized wheelchair: medium-light skin tone
+1F469 1F3FD 200D 1F9BC                                 ; fully-qualified     # 
👩🏽‍🦼 E12.0 woman in motorized wheelchair: medium skin tone
+1F469 1F3FE 200D 1F9BC                                 ; fully-qualified     # 
👩🏾‍🦼 E12.0 woman in motorized wheelchair: medium-dark skin tone
+1F469 1F3FF 200D 1F9BC                                 ; fully-qualified     # 
👩🏿‍🦼 E12.0 woman in motorized wheelchair: dark skin tone
+1F9D1 200D 1F9BD                                       ; fully-qualified     # 
🧑‍🦽 E12.1 person in manual wheelchair
+1F9D1 1F3FB 200D 1F9BD                                 ; fully-qualified     # 
🧑🏻‍🦽 E12.1 person in manual wheelchair: light skin tone
+1F9D1 1F3FC 200D 1F9BD                                 ; fully-qualified     # 
🧑🏼‍🦽 E12.1 person in manual wheelchair: medium-light skin tone
+1F9D1 1F3FD 200D 1F9BD                                 ; fully-qualified     # 
🧑🏽‍🦽 E12.1 person in manual wheelchair: medium skin tone
+1F9D1 1F3FE 200D 1F9BD                                 ; fully-qualified     # 
🧑🏾‍🦽 E12.1 person in manual wheelchair: medium-dark skin tone
+1F9D1 1F3FF 200D 1F9BD                                 ; fully-qualified     # 
🧑🏿‍🦽 E12.1 person in manual wheelchair: dark skin tone
+1F468 200D 1F9BD                                       ; fully-qualified     # 
👨‍🦽 E12.0 man in manual wheelchair
+1F468 1F3FB 200D 1F9BD                                 ; fully-qualified     # 
👨🏻‍🦽 E12.0 man in manual wheelchair: light skin tone
+1F468 1F3FC 200D 1F9BD                                 ; fully-qualified     # 
👨🏼‍🦽 E12.0 man in manual wheelchair: medium-light skin tone
+1F468 1F3FD 200D 1F9BD                                 ; fully-qualified     # 
👨🏽‍🦽 E12.0 man in manual wheelchair: medium skin tone
+1F468 1F3FE 200D 1F9BD                                 ; fully-qualified     # 
👨🏾‍🦽 E12.0 man in manual wheelchair: medium-dark skin tone
+1F468 1F3FF 200D 1F9BD                                 ; fully-qualified     # 
👨🏿‍🦽 E12.0 man in manual wheelchair: dark skin tone
+1F469 200D 1F9BD                                       ; fully-qualified     # 
👩‍🦽 E12.0 woman in manual wheelchair
+1F469 1F3FB 200D 1F9BD                                 ; fully-qualified     # 
👩🏻‍🦽 E12.0 woman in manual wheelchair: light skin tone
+1F469 1F3FC 200D 1F9BD                                 ; fully-qualified     # 
👩🏼‍🦽 E12.0 woman in manual wheelchair: medium-light skin tone
+1F469 1F3FD 200D 1F9BD                                 ; fully-qualified     # 
👩🏽‍🦽 E12.0 woman in manual wheelchair: medium skin tone
+1F469 1F3FE 200D 1F9BD                                 ; fully-qualified     # 
👩🏾‍🦽 E12.0 woman in manual wheelchair: medium-dark skin tone
+1F469 1F3FF 200D 1F9BD                                 ; fully-qualified     # 
👩🏿‍🦽 E12.0 woman in manual wheelchair: dark skin tone
+1F3C3                                                  ; fully-qualified     # 
🏃 E0.6 person running
+1F3C3 1F3FB                                            ; fully-qualified     # 
🏃🏻 E1.0 person running: light skin tone
+1F3C3 1F3FC                                            ; fully-qualified     # 
🏃🏼 E1.0 person running: medium-light skin tone
+1F3C3 1F3FD                                            ; fully-qualified     # 
🏃🏽 E1.0 person running: medium skin tone
+1F3C3 1F3FE                                            ; fully-qualified     # 
🏃🏾 E1.0 person running: medium-dark skin tone
+1F3C3 1F3FF                                            ; fully-qualified     # 
🏃🏿 E1.0 person running: dark skin tone
+1F3C3 200D 2642 FE0F                                   ; fully-qualified     # 
🏃‍♂️ E4.0 man running
+1F3C3 200D 2642                                        ; minimally-qualified # 
🏃‍♂ E4.0 man running
+1F3C3 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🏃🏻‍♂️ E4.0 man running: light skin tone
+1F3C3 1F3FB 200D 2642                                  ; minimally-qualified # 
🏃🏻‍♂ E4.0 man running: light skin tone
+1F3C3 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🏃🏼‍♂️ E4.0 man running: medium-light skin tone
+1F3C3 1F3FC 200D 2642                                  ; minimally-qualified # 
🏃🏼‍♂ E4.0 man running: medium-light skin tone
+1F3C3 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🏃🏽‍♂️ E4.0 man running: medium skin tone
+1F3C3 1F3FD 200D 2642                                  ; minimally-qualified # 
🏃🏽‍♂ E4.0 man running: medium skin tone
+1F3C3 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🏃🏾‍♂️ E4.0 man running: medium-dark skin tone
+1F3C3 1F3FE 200D 2642                                  ; minimally-qualified # 
🏃🏾‍♂ E4.0 man running: medium-dark skin tone
+1F3C3 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🏃🏿‍♂️ E4.0 man running: dark skin tone
+1F3C3 1F3FF 200D 2642                                  ; minimally-qualified # 
🏃🏿‍♂ E4.0 man running: dark skin tone
+1F3C3 200D 2640 FE0F                                   ; fully-qualified     # 
🏃‍♀️ E4.0 woman running
+1F3C3 200D 2640                                        ; minimally-qualified # 
🏃‍♀ E4.0 woman running
+1F3C3 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🏃🏻‍♀️ E4.0 woman running: light skin tone
+1F3C3 1F3FB 200D 2640                                  ; minimally-qualified # 
🏃🏻‍♀ E4.0 woman running: light skin tone
+1F3C3 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🏃🏼‍♀️ E4.0 woman running: medium-light skin tone
+1F3C3 1F3FC 200D 2640                                  ; minimally-qualified # 
🏃🏼‍♀ E4.0 woman running: medium-light skin tone
+1F3C3 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🏃🏽‍♀️ E4.0 woman running: medium skin tone
+1F3C3 1F3FD 200D 2640                                  ; minimally-qualified # 
🏃🏽‍♀ E4.0 woman running: medium skin tone
+1F3C3 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🏃🏾‍♀️ E4.0 woman running: medium-dark skin tone
+1F3C3 1F3FE 200D 2640                                  ; minimally-qualified # 
🏃🏾‍♀ E4.0 woman running: medium-dark skin tone
+1F3C3 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🏃🏿‍♀️ E4.0 woman running: dark skin tone
+1F3C3 1F3FF 200D 2640                                  ; minimally-qualified # 
🏃🏿‍♀ E4.0 woman running: dark skin tone
+1F483                                                  ; fully-qualified     # 
💃 E0.6 woman dancing
+1F483 1F3FB                                            ; fully-qualified     # 
💃🏻 E1.0 woman dancing: light skin tone
+1F483 1F3FC                                            ; fully-qualified     # 
💃🏼 E1.0 woman dancing: medium-light skin tone
+1F483 1F3FD                                            ; fully-qualified     # 
💃🏽 E1.0 woman dancing: medium skin tone
+1F483 1F3FE                                            ; fully-qualified     # 
💃🏾 E1.0 woman dancing: medium-dark skin tone
+1F483 1F3FF                                            ; fully-qualified     # 
💃🏿 E1.0 woman dancing: dark skin tone
+1F57A                                                  ; fully-qualified     # 
🕺 E3.0 man dancing
+1F57A 1F3FB                                            ; fully-qualified     # 
🕺🏻 E3.0 man dancing: light skin tone
+1F57A 1F3FC                                            ; fully-qualified     # 
🕺🏼 E3.0 man dancing: medium-light skin tone
+1F57A 1F3FD                                            ; fully-qualified     # 
🕺🏽 E3.0 man dancing: medium skin tone
+1F57A 1F3FE                                            ; fully-qualified     # 
🕺🏾 E3.0 man dancing: medium-dark skin tone
+1F57A 1F3FF                                            ; fully-qualified     # 
🕺🏿 E3.0 man dancing: dark skin tone
+1F574 FE0F                                             ; fully-qualified     # 
🕴️ E0.7 person in suit levitating
+1F574                                                  ; unqualified         # 
🕴 E0.7 person in suit levitating
+1F574 1F3FB                                            ; fully-qualified     # 
🕴🏻 E4.0 person in suit levitating: light skin tone
+1F574 1F3FC                                            ; fully-qualified     # 
🕴🏼 E4.0 person in suit levitating: medium-light skin tone
+1F574 1F3FD                                            ; fully-qualified     # 
🕴🏽 E4.0 person in suit levitating: medium skin tone
+1F574 1F3FE                                            ; fully-qualified     # 
🕴🏾 E4.0 person in suit levitating: medium-dark skin tone
+1F574 1F3FF                                            ; fully-qualified     # 
🕴🏿 E4.0 person in suit levitating: dark skin tone
+1F46F                                                  ; fully-qualified     # 
👯 E0.6 people with bunny ears
+1F46F 200D 2642 FE0F                                   ; fully-qualified     # 
👯‍♂️ E4.0 men with bunny ears
+1F46F 200D 2642                                        ; minimally-qualified # 
👯‍♂ E4.0 men with bunny ears
+1F46F 200D 2640 FE0F                                   ; fully-qualified     # 
👯‍♀️ E4.0 women with bunny ears
+1F46F 200D 2640                                        ; minimally-qualified # 
👯‍♀ E4.0 women with bunny ears
+1F9D6                                                  ; fully-qualified     # 
🧖 E5.0 person in steamy room
+1F9D6 1F3FB                                            ; fully-qualified     # 
🧖🏻 E5.0 person in steamy room: light skin tone
+1F9D6 1F3FC                                            ; fully-qualified     # 
🧖🏼 E5.0 person in steamy room: medium-light skin tone
+1F9D6 1F3FD                                            ; fully-qualified     # 
🧖🏽 E5.0 person in steamy room: medium skin tone
+1F9D6 1F3FE                                            ; fully-qualified     # 
🧖🏾 E5.0 person in steamy room: medium-dark skin tone
+1F9D6 1F3FF                                            ; fully-qualified     # 
🧖🏿 E5.0 person in steamy room: dark skin tone
+1F9D6 200D 2642 FE0F                                   ; fully-qualified     # 
🧖‍♂️ E5.0 man in steamy room
+1F9D6 200D 2642                                        ; minimally-qualified # 
🧖‍♂ E5.0 man in steamy room
+1F9D6 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧖🏻‍♂️ E5.0 man in steamy room: light skin tone
+1F9D6 1F3FB 200D 2642                                  ; minimally-qualified # 
🧖🏻‍♂ E5.0 man in steamy room: light skin tone
+1F9D6 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧖🏼‍♂️ E5.0 man in steamy room: medium-light skin tone
+1F9D6 1F3FC 200D 2642                                  ; minimally-qualified # 
🧖🏼‍♂ E5.0 man in steamy room: medium-light skin tone
+1F9D6 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧖🏽‍♂️ E5.0 man in steamy room: medium skin tone
+1F9D6 1F3FD 200D 2642                                  ; minimally-qualified # 
🧖🏽‍♂ E5.0 man in steamy room: medium skin tone
+1F9D6 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧖🏾‍♂️ E5.0 man in steamy room: medium-dark skin tone
+1F9D6 1F3FE 200D 2642                                  ; minimally-qualified # 
🧖🏾‍♂ E5.0 man in steamy room: medium-dark skin tone
+1F9D6 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧖🏿‍♂️ E5.0 man in steamy room: dark skin tone
+1F9D6 1F3FF 200D 2642                                  ; minimally-qualified # 
🧖🏿‍♂ E5.0 man in steamy room: dark skin tone
+1F9D6 200D 2640 FE0F                                   ; fully-qualified     # 
🧖‍♀️ E5.0 woman in steamy room
+1F9D6 200D 2640                                        ; minimally-qualified # 
🧖‍♀ E5.0 woman in steamy room
+1F9D6 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧖🏻‍♀️ E5.0 woman in steamy room: light skin tone
+1F9D6 1F3FB 200D 2640                                  ; minimally-qualified # 
🧖🏻‍♀ E5.0 woman in steamy room: light skin tone
+1F9D6 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧖🏼‍♀️ E5.0 woman in steamy room: medium-light skin tone
+1F9D6 1F3FC 200D 2640                                  ; minimally-qualified # 
🧖🏼‍♀ E5.0 woman in steamy room: medium-light skin tone
+1F9D6 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧖🏽‍♀️ E5.0 woman in steamy room: medium skin tone
+1F9D6 1F3FD 200D 2640                                  ; minimally-qualified # 
🧖🏽‍♀ E5.0 woman in steamy room: medium skin tone
+1F9D6 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧖🏾‍♀️ E5.0 woman in steamy room: medium-dark skin tone
+1F9D6 1F3FE 200D 2640                                  ; minimally-qualified # 
🧖🏾‍♀ E5.0 woman in steamy room: medium-dark skin tone
+1F9D6 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧖🏿‍♀️ E5.0 woman in steamy room: dark skin tone
+1F9D6 1F3FF 200D 2640                                  ; minimally-qualified # 
🧖🏿‍♀ E5.0 woman in steamy room: dark skin tone
+1F9D7                                                  ; fully-qualified     # 
🧗 E5.0 person climbing
+1F9D7 1F3FB                                            ; fully-qualified     # 
🧗🏻 E5.0 person climbing: light skin tone
+1F9D7 1F3FC                                            ; fully-qualified     # 
🧗🏼 E5.0 person climbing: medium-light skin tone
+1F9D7 1F3FD                                            ; fully-qualified     # 
🧗🏽 E5.0 person climbing: medium skin tone
+1F9D7 1F3FE                                            ; fully-qualified     # 
🧗🏾 E5.0 person climbing: medium-dark skin tone
+1F9D7 1F3FF                                            ; fully-qualified     # 
🧗🏿 E5.0 person climbing: dark skin tone
+1F9D7 200D 2642 FE0F                                   ; fully-qualified     # 
🧗‍♂️ E5.0 man climbing
+1F9D7 200D 2642                                        ; minimally-qualified # 
🧗‍♂ E5.0 man climbing
+1F9D7 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧗🏻‍♂️ E5.0 man climbing: light skin tone
+1F9D7 1F3FB 200D 2642                                  ; minimally-qualified # 
🧗🏻‍♂ E5.0 man climbing: light skin tone
+1F9D7 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧗🏼‍♂️ E5.0 man climbing: medium-light skin tone
+1F9D7 1F3FC 200D 2642                                  ; minimally-qualified # 
🧗🏼‍♂ E5.0 man climbing: medium-light skin tone
+1F9D7 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧗🏽‍♂️ E5.0 man climbing: medium skin tone
+1F9D7 1F3FD 200D 2642                                  ; minimally-qualified # 
🧗🏽‍♂ E5.0 man climbing: medium skin tone
+1F9D7 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧗🏾‍♂️ E5.0 man climbing: medium-dark skin tone
+1F9D7 1F3FE 200D 2642                                  ; minimally-qualified # 
🧗🏾‍♂ E5.0 man climbing: medium-dark skin tone
+1F9D7 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧗🏿‍♂️ E5.0 man climbing: dark skin tone
+1F9D7 1F3FF 200D 2642                                  ; minimally-qualified # 
🧗🏿‍♂ E5.0 man climbing: dark skin tone
+1F9D7 200D 2640 FE0F                                   ; fully-qualified     # 
🧗‍♀️ E5.0 woman climbing
+1F9D7 200D 2640                                        ; minimally-qualified # 
🧗‍♀ E5.0 woman climbing
+1F9D7 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧗🏻‍♀️ E5.0 woman climbing: light skin tone
+1F9D7 1F3FB 200D 2640                                  ; minimally-qualified # 
🧗🏻‍♀ E5.0 woman climbing: light skin tone
+1F9D7 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧗🏼‍♀️ E5.0 woman climbing: medium-light skin tone
+1F9D7 1F3FC 200D 2640                                  ; minimally-qualified # 
🧗🏼‍♀ E5.0 woman climbing: medium-light skin tone
+1F9D7 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧗🏽‍♀️ E5.0 woman climbing: medium skin tone
+1F9D7 1F3FD 200D 2640                                  ; minimally-qualified # 
🧗🏽‍♀ E5.0 woman climbing: medium skin tone
+1F9D7 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧗🏾‍♀️ E5.0 woman climbing: medium-dark skin tone
+1F9D7 1F3FE 200D 2640                                  ; minimally-qualified # 
🧗🏾‍♀ E5.0 woman climbing: medium-dark skin tone
+1F9D7 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧗🏿‍♀️ E5.0 woman climbing: dark skin tone
+1F9D7 1F3FF 200D 2640                                  ; minimally-qualified # 
🧗🏿‍♀ E5.0 woman climbing: dark skin tone
+
+# subgroup: person-sport
+1F93A                                                  ; fully-qualified     # 
🤺 E3.0 person fencing
+1F3C7                                                  ; fully-qualified     # 
🏇 E1.0 horse racing
+1F3C7 1F3FB                                            ; fully-qualified     # 
🏇🏻 E1.0 horse racing: light skin tone
+1F3C7 1F3FC                                            ; fully-qualified     # 
🏇🏼 E1.0 horse racing: medium-light skin tone
+1F3C7 1F3FD                                            ; fully-qualified     # 
🏇🏽 E1.0 horse racing: medium skin tone
+1F3C7 1F3FE                                            ; fully-qualified     # 
🏇🏾 E1.0 horse racing: medium-dark skin tone
+1F3C7 1F3FF                                            ; fully-qualified     # 
🏇🏿 E1.0 horse racing: dark skin tone
+26F7 FE0F                                              ; fully-qualified     # 
⛷️ E0.7 skier
+26F7                                                   ; unqualified         # 
⛷ E0.7 skier
+1F3C2                                                  ; fully-qualified     # 
🏂 E0.6 snowboarder
+1F3C2 1F3FB                                            ; fully-qualified     # 
🏂🏻 E1.0 snowboarder: light skin tone
+1F3C2 1F3FC                                            ; fully-qualified     # 
🏂🏼 E1.0 snowboarder: medium-light skin tone
+1F3C2 1F3FD                                            ; fully-qualified     # 
🏂🏽 E1.0 snowboarder: medium skin tone
+1F3C2 1F3FE                                            ; fully-qualified     # 
🏂🏾 E1.0 snowboarder: medium-dark skin tone
+1F3C2 1F3FF                                            ; fully-qualified     # 
🏂🏿 E1.0 snowboarder: dark skin tone
+1F3CC FE0F                                             ; fully-qualified     # 
🏌️ E0.7 person golfing
+1F3CC                                                  ; unqualified         # 
🏌 E0.7 person golfing
+1F3CC 1F3FB                                            ; fully-qualified     # 
🏌🏻 E4.0 person golfing: light skin tone
+1F3CC 1F3FC                                            ; fully-qualified     # 
🏌🏼 E4.0 person golfing: medium-light skin tone
+1F3CC 1F3FD                                            ; fully-qualified     # 
🏌🏽 E4.0 person golfing: medium skin tone
+1F3CC 1F3FE                                            ; fully-qualified     # 
🏌🏾 E4.0 person golfing: medium-dark skin tone
+1F3CC 1F3FF                                            ; fully-qualified     # 
🏌🏿 E4.0 person golfing: dark skin tone
+1F3CC FE0F 200D 2642 FE0F                              ; fully-qualified     # 
🏌️‍♂️ E4.0 man golfing
+1F3CC 200D 2642 FE0F                                   ; unqualified         # 
🏌‍♂️ E4.0 man golfing
+1F3CC FE0F 200D 2642                                   ; unqualified         # 
🏌️‍♂ E4.0 man golfing
+1F3CC 200D 2642                                        ; unqualified         # 
🏌‍♂ E4.0 man golfing
+1F3CC 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🏌🏻‍♂️ E4.0 man golfing: light skin tone
+1F3CC 1F3FB 200D 2642                                  ; minimally-qualified # 
🏌🏻‍♂ E4.0 man golfing: light skin tone
+1F3CC 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🏌🏼‍♂️ E4.0 man golfing: medium-light skin tone
+1F3CC 1F3FC 200D 2642                                  ; minimally-qualified # 
🏌🏼‍♂ E4.0 man golfing: medium-light skin tone
+1F3CC 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🏌🏽‍♂️ E4.0 man golfing: medium skin tone
+1F3CC 1F3FD 200D 2642                                  ; minimally-qualified # 
🏌🏽‍♂ E4.0 man golfing: medium skin tone
+1F3CC 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🏌🏾‍♂️ E4.0 man golfing: medium-dark skin tone
+1F3CC 1F3FE 200D 2642                                  ; minimally-qualified # 
🏌🏾‍♂ E4.0 man golfing: medium-dark skin tone
+1F3CC 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🏌🏿‍♂️ E4.0 man golfing: dark skin tone
+1F3CC 1F3FF 200D 2642                                  ; minimally-qualified # 
🏌🏿‍♂ E4.0 man golfing: dark skin tone
+1F3CC FE0F 200D 2640 FE0F                              ; fully-qualified     # 
🏌️‍♀️ E4.0 woman golfing
+1F3CC 200D 2640 FE0F                                   ; unqualified         # 
🏌‍♀️ E4.0 woman golfing
+1F3CC FE0F 200D 2640                                   ; unqualified         # 
🏌️‍♀ E4.0 woman golfing
+1F3CC 200D 2640                                        ; unqualified         # 
🏌‍♀ E4.0 woman golfing
+1F3CC 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🏌🏻‍♀️ E4.0 woman golfing: light skin tone
+1F3CC 1F3FB 200D 2640                                  ; minimally-qualified # 
🏌🏻‍♀ E4.0 woman golfing: light skin tone
+1F3CC 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🏌🏼‍♀️ E4.0 woman golfing: medium-light skin tone
+1F3CC 1F3FC 200D 2640                                  ; minimally-qualified # 
🏌🏼‍♀ E4.0 woman golfing: medium-light skin tone
+1F3CC 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🏌🏽‍♀️ E4.0 woman golfing: medium skin tone
+1F3CC 1F3FD 200D 2640                                  ; minimally-qualified # 
🏌🏽‍♀ E4.0 woman golfing: medium skin tone
+1F3CC 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🏌🏾‍♀️ E4.0 woman golfing: medium-dark skin tone
+1F3CC 1F3FE 200D 2640                                  ; minimally-qualified # 
🏌🏾‍♀ E4.0 woman golfing: medium-dark skin tone
+1F3CC 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🏌🏿‍♀️ E4.0 woman golfing: dark skin tone
+1F3CC 1F3FF 200D 2640                                  ; minimally-qualified # 
🏌🏿‍♀ E4.0 woman golfing: dark skin tone
+1F3C4                                                  ; fully-qualified     # 
🏄 E0.6 person surfing
+1F3C4 1F3FB                                            ; fully-qualified     # 
🏄🏻 E1.0 person surfing: light skin tone
+1F3C4 1F3FC                                            ; fully-qualified     # 
🏄🏼 E1.0 person surfing: medium-light skin tone
+1F3C4 1F3FD                                            ; fully-qualified     # 
🏄🏽 E1.0 person surfing: medium skin tone
+1F3C4 1F3FE                                            ; fully-qualified     # 
🏄🏾 E1.0 person surfing: medium-dark skin tone
+1F3C4 1F3FF                                            ; fully-qualified     # 
🏄🏿 E1.0 person surfing: dark skin tone
+1F3C4 200D 2642 FE0F                                   ; fully-qualified     # 
🏄‍♂️ E4.0 man surfing
+1F3C4 200D 2642                                        ; minimally-qualified # 
🏄‍♂ E4.0 man surfing
+1F3C4 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🏄🏻‍♂️ E4.0 man surfing: light skin tone
+1F3C4 1F3FB 200D 2642                                  ; minimally-qualified # 
🏄🏻‍♂ E4.0 man surfing: light skin tone
+1F3C4 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🏄🏼‍♂️ E4.0 man surfing: medium-light skin tone
+1F3C4 1F3FC 200D 2642                                  ; minimally-qualified # 
🏄🏼‍♂ E4.0 man surfing: medium-light skin tone
+1F3C4 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🏄🏽‍♂️ E4.0 man surfing: medium skin tone
+1F3C4 1F3FD 200D 2642                                  ; minimally-qualified # 
🏄🏽‍♂ E4.0 man surfing: medium skin tone
+1F3C4 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🏄🏾‍♂️ E4.0 man surfing: medium-dark skin tone
+1F3C4 1F3FE 200D 2642                                  ; minimally-qualified # 
🏄🏾‍♂ E4.0 man surfing: medium-dark skin tone
+1F3C4 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🏄🏿‍♂️ E4.0 man surfing: dark skin tone
+1F3C4 1F3FF 200D 2642                                  ; minimally-qualified # 
🏄🏿‍♂ E4.0 man surfing: dark skin tone
+1F3C4 200D 2640 FE0F                                   ; fully-qualified     # 
🏄‍♀️ E4.0 woman surfing
+1F3C4 200D 2640                                        ; minimally-qualified # 
🏄‍♀ E4.0 woman surfing
+1F3C4 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🏄🏻‍♀️ E4.0 woman surfing: light skin tone
+1F3C4 1F3FB 200D 2640                                  ; minimally-qualified # 
🏄🏻‍♀ E4.0 woman surfing: light skin tone
+1F3C4 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🏄🏼‍♀️ E4.0 woman surfing: medium-light skin tone
+1F3C4 1F3FC 200D 2640                                  ; minimally-qualified # 
🏄🏼‍♀ E4.0 woman surfing: medium-light skin tone
+1F3C4 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🏄🏽‍♀️ E4.0 woman surfing: medium skin tone
+1F3C4 1F3FD 200D 2640                                  ; minimally-qualified # 
🏄🏽‍♀ E4.0 woman surfing: medium skin tone
+1F3C4 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🏄🏾‍♀️ E4.0 woman surfing: medium-dark skin tone
+1F3C4 1F3FE 200D 2640                                  ; minimally-qualified # 
🏄🏾‍♀ E4.0 woman surfing: medium-dark skin tone
+1F3C4 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🏄🏿‍♀️ E4.0 woman surfing: dark skin tone
+1F3C4 1F3FF 200D 2640                                  ; minimally-qualified # 
🏄🏿‍♀ E4.0 woman surfing: dark skin tone
+1F6A3                                                  ; fully-qualified     # 
🚣 E1.0 person rowing boat
+1F6A3 1F3FB                                            ; fully-qualified     # 
🚣🏻 E1.0 person rowing boat: light skin tone
+1F6A3 1F3FC                                            ; fully-qualified     # 
🚣🏼 E1.0 person rowing boat: medium-light skin tone
+1F6A3 1F3FD                                            ; fully-qualified     # 
🚣🏽 E1.0 person rowing boat: medium skin tone
+1F6A3 1F3FE                                            ; fully-qualified     # 
🚣🏾 E1.0 person rowing boat: medium-dark skin tone
+1F6A3 1F3FF                                            ; fully-qualified     # 
🚣🏿 E1.0 person rowing boat: dark skin tone
+1F6A3 200D 2642 FE0F                                   ; fully-qualified     # 
🚣‍♂️ E4.0 man rowing boat
+1F6A3 200D 2642                                        ; minimally-qualified # 
🚣‍♂ E4.0 man rowing boat
+1F6A3 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🚣🏻‍♂️ E4.0 man rowing boat: light skin tone
+1F6A3 1F3FB 200D 2642                                  ; minimally-qualified # 
🚣🏻‍♂ E4.0 man rowing boat: light skin tone
+1F6A3 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🚣🏼‍♂️ E4.0 man rowing boat: medium-light skin tone
+1F6A3 1F3FC 200D 2642                                  ; minimally-qualified # 
🚣🏼‍♂ E4.0 man rowing boat: medium-light skin tone
+1F6A3 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🚣🏽‍♂️ E4.0 man rowing boat: medium skin tone
+1F6A3 1F3FD 200D 2642                                  ; minimally-qualified # 
🚣🏽‍♂ E4.0 man rowing boat: medium skin tone
+1F6A3 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🚣🏾‍♂️ E4.0 man rowing boat: medium-dark skin tone
+1F6A3 1F3FE 200D 2642                                  ; minimally-qualified # 
🚣🏾‍♂ E4.0 man rowing boat: medium-dark skin tone
+1F6A3 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🚣🏿‍♂️ E4.0 man rowing boat: dark skin tone
+1F6A3 1F3FF 200D 2642                                  ; minimally-qualified # 
🚣🏿‍♂ E4.0 man rowing boat: dark skin tone
+1F6A3 200D 2640 FE0F                                   ; fully-qualified     # 
🚣‍♀️ E4.0 woman rowing boat
+1F6A3 200D 2640                                        ; minimally-qualified # 
🚣‍♀ E4.0 woman rowing boat
+1F6A3 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🚣🏻‍♀️ E4.0 woman rowing boat: light skin tone
+1F6A3 1F3FB 200D 2640                                  ; minimally-qualified # 
🚣🏻‍♀ E4.0 woman rowing boat: light skin tone
+1F6A3 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🚣🏼‍♀️ E4.0 woman rowing boat: medium-light skin tone
+1F6A3 1F3FC 200D 2640                                  ; minimally-qualified # 
🚣🏼‍♀ E4.0 woman rowing boat: medium-light skin tone
+1F6A3 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🚣🏽‍♀️ E4.0 woman rowing boat: medium skin tone
+1F6A3 1F3FD 200D 2640                                  ; minimally-qualified # 
🚣🏽‍♀ E4.0 woman rowing boat: medium skin tone
+1F6A3 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🚣🏾‍♀️ E4.0 woman rowing boat: medium-dark skin tone
+1F6A3 1F3FE 200D 2640                                  ; minimally-qualified # 
🚣🏾‍♀ E4.0 woman rowing boat: medium-dark skin tone
+1F6A3 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🚣🏿‍♀️ E4.0 woman rowing boat: dark skin tone
+1F6A3 1F3FF 200D 2640                                  ; minimally-qualified # 
🚣🏿‍♀ E4.0 woman rowing boat: dark skin tone
+1F3CA                                                  ; fully-qualified     # 
🏊 E0.6 person swimming
+1F3CA 1F3FB                                            ; fully-qualified     # 
🏊🏻 E1.0 person swimming: light skin tone
+1F3CA 1F3FC                                            ; fully-qualified     # 
🏊🏼 E1.0 person swimming: medium-light skin tone
+1F3CA 1F3FD                                            ; fully-qualified     # 
🏊🏽 E1.0 person swimming: medium skin tone
+1F3CA 1F3FE                                            ; fully-qualified     # 
🏊🏾 E1.0 person swimming: medium-dark skin tone
+1F3CA 1F3FF                                            ; fully-qualified     # 
🏊🏿 E1.0 person swimming: dark skin tone
+1F3CA 200D 2642 FE0F                                   ; fully-qualified     # 
🏊‍♂️ E4.0 man swimming
+1F3CA 200D 2642                                        ; minimally-qualified # 
🏊‍♂ E4.0 man swimming
+1F3CA 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🏊🏻‍♂️ E4.0 man swimming: light skin tone
+1F3CA 1F3FB 200D 2642                                  ; minimally-qualified # 
🏊🏻‍♂ E4.0 man swimming: light skin tone
+1F3CA 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🏊🏼‍♂️ E4.0 man swimming: medium-light skin tone
+1F3CA 1F3FC 200D 2642                                  ; minimally-qualified # 
🏊🏼‍♂ E4.0 man swimming: medium-light skin tone
+1F3CA 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🏊🏽‍♂️ E4.0 man swimming: medium skin tone
+1F3CA 1F3FD 200D 2642                                  ; minimally-qualified # 
🏊🏽‍♂ E4.0 man swimming: medium skin tone
+1F3CA 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🏊🏾‍♂️ E4.0 man swimming: medium-dark skin tone
+1F3CA 1F3FE 200D 2642                                  ; minimally-qualified # 
🏊🏾‍♂ E4.0 man swimming: medium-dark skin tone
+1F3CA 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🏊🏿‍♂️ E4.0 man swimming: dark skin tone
+1F3CA 1F3FF 200D 2642                                  ; minimally-qualified # 
🏊🏿‍♂ E4.0 man swimming: dark skin tone
+1F3CA 200D 2640 FE0F                                   ; fully-qualified     # 
🏊‍♀️ E4.0 woman swimming
+1F3CA 200D 2640                                        ; minimally-qualified # 
🏊‍♀ E4.0 woman swimming
+1F3CA 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🏊🏻‍♀️ E4.0 woman swimming: light skin tone
+1F3CA 1F3FB 200D 2640                                  ; minimally-qualified # 
🏊🏻‍♀ E4.0 woman swimming: light skin tone
+1F3CA 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🏊🏼‍♀️ E4.0 woman swimming: medium-light skin tone
+1F3CA 1F3FC 200D 2640                                  ; minimally-qualified # 
🏊🏼‍♀ E4.0 woman swimming: medium-light skin tone
+1F3CA 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🏊🏽‍♀️ E4.0 woman swimming: medium skin tone
+1F3CA 1F3FD 200D 2640                                  ; minimally-qualified # 
🏊🏽‍♀ E4.0 woman swimming: medium skin tone
+1F3CA 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🏊🏾‍♀️ E4.0 woman swimming: medium-dark skin tone
+1F3CA 1F3FE 200D 2640                                  ; minimally-qualified # 
🏊🏾‍♀ E4.0 woman swimming: medium-dark skin tone
+1F3CA 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🏊🏿‍♀️ E4.0 woman swimming: dark skin tone
+1F3CA 1F3FF 200D 2640                                  ; minimally-qualified # 
🏊🏿‍♀ E4.0 woman swimming: dark skin tone
+26F9 FE0F                                              ; fully-qualified     # 
⛹️ E0.7 person bouncing ball
+26F9                                                   ; unqualified         # 
⛹ E0.7 person bouncing ball
+26F9 1F3FB                                             ; fully-qualified     # 
⛹🏻 E2.0 person bouncing ball: light skin tone
+26F9 1F3FC                                             ; fully-qualified     # 
⛹🏼 E2.0 person bouncing ball: medium-light skin tone
+26F9 1F3FD                                             ; fully-qualified     # 
⛹🏽 E2.0 person bouncing ball: medium skin tone
+26F9 1F3FE                                             ; fully-qualified     # 
⛹🏾 E2.0 person bouncing ball: medium-dark skin tone
+26F9 1F3FF                                             ; fully-qualified     # 
⛹🏿 E2.0 person bouncing ball: dark skin tone
+26F9 FE0F 200D 2642 FE0F                               ; fully-qualified     # 
⛹️‍♂️ E4.0 man bouncing ball
+26F9 200D 2642 FE0F                                    ; unqualified         # 
⛹‍♂️ E4.0 man bouncing ball
+26F9 FE0F 200D 2642                                    ; unqualified         # 
⛹️‍♂ E4.0 man bouncing ball
+26F9 200D 2642                                         ; unqualified         # 
⛹‍♂ E4.0 man bouncing ball
+26F9 1F3FB 200D 2642 FE0F                              ; fully-qualified     # 
⛹🏻‍♂️ E4.0 man bouncing ball: light skin tone
+26F9 1F3FB 200D 2642                                   ; minimally-qualified # 
⛹🏻‍♂ E4.0 man bouncing ball: light skin tone
+26F9 1F3FC 200D 2642 FE0F                              ; fully-qualified     # 
⛹🏼‍♂️ E4.0 man bouncing ball: medium-light skin tone
+26F9 1F3FC 200D 2642                                   ; minimally-qualified # 
⛹🏼‍♂ E4.0 man bouncing ball: medium-light skin tone
+26F9 1F3FD 200D 2642 FE0F                              ; fully-qualified     # 
⛹🏽‍♂️ E4.0 man bouncing ball: medium skin tone
+26F9 1F3FD 200D 2642                                   ; minimally-qualified # 
⛹🏽‍♂ E4.0 man bouncing ball: medium skin tone
+26F9 1F3FE 200D 2642 FE0F                              ; fully-qualified     # 
⛹🏾‍♂️ E4.0 man bouncing ball: medium-dark skin tone
+26F9 1F3FE 200D 2642                                   ; minimally-qualified # 
⛹🏾‍♂ E4.0 man bouncing ball: medium-dark skin tone
+26F9 1F3FF 200D 2642 FE0F                              ; fully-qualified     # 
⛹🏿‍♂️ E4.0 man bouncing ball: dark skin tone
+26F9 1F3FF 200D 2642                                   ; minimally-qualified # 
⛹🏿‍♂ E4.0 man bouncing ball: dark skin tone
+26F9 FE0F 200D 2640 FE0F                               ; fully-qualified     # 
⛹️‍♀️ E4.0 woman bouncing ball
+26F9 200D 2640 FE0F                                    ; unqualified         # 
⛹‍♀️ E4.0 woman bouncing ball
+26F9 FE0F 200D 2640                                    ; unqualified         # 
⛹️‍♀ E4.0 woman bouncing ball
+26F9 200D 2640                                         ; unqualified         # 
⛹‍♀ E4.0 woman bouncing ball
+26F9 1F3FB 200D 2640 FE0F                              ; fully-qualified     # 
⛹🏻‍♀️ E4.0 woman bouncing ball: light skin tone
+26F9 1F3FB 200D 2640                                   ; minimally-qualified # 
⛹🏻‍♀ E4.0 woman bouncing ball: light skin tone
+26F9 1F3FC 200D 2640 FE0F                              ; fully-qualified     # 
⛹🏼‍♀️ E4.0 woman bouncing ball: medium-light skin tone
+26F9 1F3FC 200D 2640                                   ; minimally-qualified # 
⛹🏼‍♀ E4.0 woman bouncing ball: medium-light skin tone
+26F9 1F3FD 200D 2640 FE0F                              ; fully-qualified     # 
⛹🏽‍♀️ E4.0 woman bouncing ball: medium skin tone
+26F9 1F3FD 200D 2640                                   ; minimally-qualified # 
⛹🏽‍♀ E4.0 woman bouncing ball: medium skin tone
+26F9 1F3FE 200D 2640 FE0F                              ; fully-qualified     # 
⛹🏾‍♀️ E4.0 woman bouncing ball: medium-dark skin tone
+26F9 1F3FE 200D 2640                                   ; minimally-qualified # 
⛹🏾‍♀ E4.0 woman bouncing ball: medium-dark skin tone
+26F9 1F3FF 200D 2640 FE0F                              ; fully-qualified     # 
⛹🏿‍♀️ E4.0 woman bouncing ball: dark skin tone
+26F9 1F3FF 200D 2640                                   ; minimally-qualified # 
⛹🏿‍♀ E4.0 woman bouncing ball: dark skin tone
+1F3CB FE0F                                             ; fully-qualified     # 
🏋️ E0.7 person lifting weights
+1F3CB                                                  ; unqualified         # 
🏋 E0.7 person lifting weights
+1F3CB 1F3FB                                            ; fully-qualified     # 
🏋🏻 E2.0 person lifting weights: light skin tone
+1F3CB 1F3FC                                            ; fully-qualified     # 
🏋🏼 E2.0 person lifting weights: medium-light skin tone
+1F3CB 1F3FD                                            ; fully-qualified     # 
🏋🏽 E2.0 person lifting weights: medium skin tone
+1F3CB 1F3FE                                            ; fully-qualified     # 
🏋🏾 E2.0 person lifting weights: medium-dark skin tone
+1F3CB 1F3FF                                            ; fully-qualified     # 
🏋🏿 E2.0 person lifting weights: dark skin tone
+1F3CB FE0F 200D 2642 FE0F                              ; fully-qualified     # 
🏋️‍♂️ E4.0 man lifting weights
+1F3CB 200D 2642 FE0F                                   ; unqualified         # 
🏋‍♂️ E4.0 man lifting weights
+1F3CB FE0F 200D 2642                                   ; unqualified         # 
🏋️‍♂ E4.0 man lifting weights
+1F3CB 200D 2642                                        ; unqualified         # 
🏋‍♂ E4.0 man lifting weights
+1F3CB 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🏋🏻‍♂️ E4.0 man lifting weights: light skin tone
+1F3CB 1F3FB 200D 2642                                  ; minimally-qualified # 
🏋🏻‍♂ E4.0 man lifting weights: light skin tone
+1F3CB 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🏋🏼‍♂️ E4.0 man lifting weights: medium-light skin tone
+1F3CB 1F3FC 200D 2642                                  ; minimally-qualified # 
🏋🏼‍♂ E4.0 man lifting weights: medium-light skin tone
+1F3CB 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🏋🏽‍♂️ E4.0 man lifting weights: medium skin tone
+1F3CB 1F3FD 200D 2642                                  ; minimally-qualified # 
🏋🏽‍♂ E4.0 man lifting weights: medium skin tone
+1F3CB 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🏋🏾‍♂️ E4.0 man lifting weights: medium-dark skin tone
+1F3CB 1F3FE 200D 2642                                  ; minimally-qualified # 
🏋🏾‍♂ E4.0 man lifting weights: medium-dark skin tone
+1F3CB 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🏋🏿‍♂️ E4.0 man lifting weights: dark skin tone
+1F3CB 1F3FF 200D 2642                                  ; minimally-qualified # 
🏋🏿‍♂ E4.0 man lifting weights: dark skin tone
+1F3CB FE0F 200D 2640 FE0F                              ; fully-qualified     # 
🏋️‍♀️ E4.0 woman lifting weights
+1F3CB 200D 2640 FE0F                                   ; unqualified         # 
🏋‍♀️ E4.0 woman lifting weights
+1F3CB FE0F 200D 2640                                   ; unqualified         # 
🏋️‍♀ E4.0 woman lifting weights
+1F3CB 200D 2640                                        ; unqualified         # 
🏋‍♀ E4.0 woman lifting weights
+1F3CB 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🏋🏻‍♀️ E4.0 woman lifting weights: light skin tone
+1F3CB 1F3FB 200D 2640                                  ; minimally-qualified # 
🏋🏻‍♀ E4.0 woman lifting weights: light skin tone
+1F3CB 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🏋🏼‍♀️ E4.0 woman lifting weights: medium-light skin tone
+1F3CB 1F3FC 200D 2640                                  ; minimally-qualified # 
🏋🏼‍♀ E4.0 woman lifting weights: medium-light skin tone
+1F3CB 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🏋🏽‍♀️ E4.0 woman lifting weights: medium skin tone
+1F3CB 1F3FD 200D 2640                                  ; minimally-qualified # 
🏋🏽‍♀ E4.0 woman lifting weights: medium skin tone
+1F3CB 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🏋🏾‍♀️ E4.0 woman lifting weights: medium-dark skin tone
+1F3CB 1F3FE 200D 2640                                  ; minimally-qualified # 
🏋🏾‍♀ E4.0 woman lifting weights: medium-dark skin tone
+1F3CB 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🏋🏿‍♀️ E4.0 woman lifting weights: dark skin tone
+1F3CB 1F3FF 200D 2640                                  ; minimally-qualified # 
🏋🏿‍♀ E4.0 woman lifting weights: dark skin tone
+1F6B4                                                  ; fully-qualified     # 
🚴 E1.0 person biking
+1F6B4 1F3FB                                            ; fully-qualified     # 
🚴🏻 E1.0 person biking: light skin tone
+1F6B4 1F3FC                                            ; fully-qualified     # 
🚴🏼 E1.0 person biking: medium-light skin tone
+1F6B4 1F3FD                                            ; fully-qualified     # 
🚴🏽 E1.0 person biking: medium skin tone
+1F6B4 1F3FE                                            ; fully-qualified     # 
🚴🏾 E1.0 person biking: medium-dark skin tone
+1F6B4 1F3FF                                            ; fully-qualified     # 
🚴🏿 E1.0 person biking: dark skin tone
+1F6B4 200D 2642 FE0F                                   ; fully-qualified     # 
🚴‍♂️ E4.0 man biking
+1F6B4 200D 2642                                        ; minimally-qualified # 
🚴‍♂ E4.0 man biking
+1F6B4 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🚴🏻‍♂️ E4.0 man biking: light skin tone
+1F6B4 1F3FB 200D 2642                                  ; minimally-qualified # 
🚴🏻‍♂ E4.0 man biking: light skin tone
+1F6B4 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🚴🏼‍♂️ E4.0 man biking: medium-light skin tone
+1F6B4 1F3FC 200D 2642                                  ; minimally-qualified # 
🚴🏼‍♂ E4.0 man biking: medium-light skin tone
+1F6B4 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🚴🏽‍♂️ E4.0 man biking: medium skin tone
+1F6B4 1F3FD 200D 2642                                  ; minimally-qualified # 
🚴🏽‍♂ E4.0 man biking: medium skin tone
+1F6B4 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🚴🏾‍♂️ E4.0 man biking: medium-dark skin tone
+1F6B4 1F3FE 200D 2642                                  ; minimally-qualified # 
🚴🏾‍♂ E4.0 man biking: medium-dark skin tone
+1F6B4 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🚴🏿‍♂️ E4.0 man biking: dark skin tone
+1F6B4 1F3FF 200D 2642                                  ; minimally-qualified # 
🚴🏿‍♂ E4.0 man biking: dark skin tone
+1F6B4 200D 2640 FE0F                                   ; fully-qualified     # 
🚴‍♀️ E4.0 woman biking
+1F6B4 200D 2640                                        ; minimally-qualified # 
🚴‍♀ E4.0 woman biking
+1F6B4 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🚴🏻‍♀️ E4.0 woman biking: light skin tone
+1F6B4 1F3FB 200D 2640                                  ; minimally-qualified # 
🚴🏻‍♀ E4.0 woman biking: light skin tone
+1F6B4 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🚴🏼‍♀️ E4.0 woman biking: medium-light skin tone
+1F6B4 1F3FC 200D 2640                                  ; minimally-qualified # 
🚴🏼‍♀ E4.0 woman biking: medium-light skin tone
+1F6B4 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🚴🏽‍♀️ E4.0 woman biking: medium skin tone
+1F6B4 1F3FD 200D 2640                                  ; minimally-qualified # 
🚴🏽‍♀ E4.0 woman biking: medium skin tone
+1F6B4 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🚴🏾‍♀️ E4.0 woman biking: medium-dark skin tone
+1F6B4 1F3FE 200D 2640                                  ; minimally-qualified # 
🚴🏾‍♀ E4.0 woman biking: medium-dark skin tone
+1F6B4 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🚴🏿‍♀️ E4.0 woman biking: dark skin tone
+1F6B4 1F3FF 200D 2640                                  ; minimally-qualified # 
🚴🏿‍♀ E4.0 woman biking: dark skin tone
+1F6B5                                                  ; fully-qualified     # 
🚵 E1.0 person mountain biking
+1F6B5 1F3FB                                            ; fully-qualified     # 
🚵🏻 E1.0 person mountain biking: light skin tone
+1F6B5 1F3FC                                            ; fully-qualified     # 
🚵🏼 E1.0 person mountain biking: medium-light skin tone
+1F6B5 1F3FD                                            ; fully-qualified     # 
🚵🏽 E1.0 person mountain biking: medium skin tone
+1F6B5 1F3FE                                            ; fully-qualified     # 
🚵🏾 E1.0 person mountain biking: medium-dark skin tone
+1F6B5 1F3FF                                            ; fully-qualified     # 
🚵🏿 E1.0 person mountain biking: dark skin tone
+1F6B5 200D 2642 FE0F                                   ; fully-qualified     # 
🚵‍♂️ E4.0 man mountain biking
+1F6B5 200D 2642                                        ; minimally-qualified # 
🚵‍♂ E4.0 man mountain biking
+1F6B5 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🚵🏻‍♂️ E4.0 man mountain biking: light skin tone
+1F6B5 1F3FB 200D 2642                                  ; minimally-qualified # 
🚵🏻‍♂ E4.0 man mountain biking: light skin tone
+1F6B5 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🚵🏼‍♂️ E4.0 man mountain biking: medium-light skin tone
+1F6B5 1F3FC 200D 2642                                  ; minimally-qualified # 
🚵🏼‍♂ E4.0 man mountain biking: medium-light skin tone
+1F6B5 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🚵🏽‍♂️ E4.0 man mountain biking: medium skin tone
+1F6B5 1F3FD 200D 2642                                  ; minimally-qualified # 
🚵🏽‍♂ E4.0 man mountain biking: medium skin tone
+1F6B5 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🚵🏾‍♂️ E4.0 man mountain biking: medium-dark skin tone
+1F6B5 1F3FE 200D 2642                                  ; minimally-qualified # 
🚵🏾‍♂ E4.0 man mountain biking: medium-dark skin tone
+1F6B5 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🚵🏿‍♂️ E4.0 man mountain biking: dark skin tone
+1F6B5 1F3FF 200D 2642                                  ; minimally-qualified # 
🚵🏿‍♂ E4.0 man mountain biking: dark skin tone
+1F6B5 200D 2640 FE0F                                   ; fully-qualified     # 
🚵‍♀️ E4.0 woman mountain biking
+1F6B5 200D 2640                                        ; minimally-qualified # 
🚵‍♀ E4.0 woman mountain biking
+1F6B5 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🚵🏻‍♀️ E4.0 woman mountain biking: light skin tone
+1F6B5 1F3FB 200D 2640                                  ; minimally-qualified # 
🚵🏻‍♀ E4.0 woman mountain biking: light skin tone
+1F6B5 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🚵🏼‍♀️ E4.0 woman mountain biking: medium-light skin tone
+1F6B5 1F3FC 200D 2640                                  ; minimally-qualified # 
🚵🏼‍♀ E4.0 woman mountain biking: medium-light skin tone
+1F6B5 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🚵🏽‍♀️ E4.0 woman mountain biking: medium skin tone
+1F6B5 1F3FD 200D 2640                                  ; minimally-qualified # 
🚵🏽‍♀ E4.0 woman mountain biking: medium skin tone
+1F6B5 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🚵🏾‍♀️ E4.0 woman mountain biking: medium-dark skin tone
+1F6B5 1F3FE 200D 2640                                  ; minimally-qualified # 
🚵🏾‍♀ E4.0 woman mountain biking: medium-dark skin tone
+1F6B5 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🚵🏿‍♀️ E4.0 woman mountain biking: dark skin tone
+1F6B5 1F3FF 200D 2640                                  ; minimally-qualified # 
🚵🏿‍♀ E4.0 woman mountain biking: dark skin tone
+1F938                                                  ; fully-qualified     # 
🤸 E3.0 person cartwheeling
+1F938 1F3FB                                            ; fully-qualified     # 
🤸🏻 E3.0 person cartwheeling: light skin tone
+1F938 1F3FC                                            ; fully-qualified     # 
🤸🏼 E3.0 person cartwheeling: medium-light skin tone
+1F938 1F3FD                                            ; fully-qualified     # 
🤸🏽 E3.0 person cartwheeling: medium skin tone
+1F938 1F3FE                                            ; fully-qualified     # 
🤸🏾 E3.0 person cartwheeling: medium-dark skin tone
+1F938 1F3FF                                            ; fully-qualified     # 
🤸🏿 E3.0 person cartwheeling: dark skin tone
+1F938 200D 2642 FE0F                                   ; fully-qualified     # 
🤸‍♂️ E4.0 man cartwheeling
+1F938 200D 2642                                        ; minimally-qualified # 
🤸‍♂ E4.0 man cartwheeling
+1F938 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤸🏻‍♂️ E4.0 man cartwheeling: light skin tone
+1F938 1F3FB 200D 2642                                  ; minimally-qualified # 
🤸🏻‍♂ E4.0 man cartwheeling: light skin tone
+1F938 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤸🏼‍♂️ E4.0 man cartwheeling: medium-light skin tone
+1F938 1F3FC 200D 2642                                  ; minimally-qualified # 
🤸🏼‍♂ E4.0 man cartwheeling: medium-light skin tone
+1F938 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤸🏽‍♂️ E4.0 man cartwheeling: medium skin tone
+1F938 1F3FD 200D 2642                                  ; minimally-qualified # 
🤸🏽‍♂ E4.0 man cartwheeling: medium skin tone
+1F938 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤸🏾‍♂️ E4.0 man cartwheeling: medium-dark skin tone
+1F938 1F3FE 200D 2642                                  ; minimally-qualified # 
🤸🏾‍♂ E4.0 man cartwheeling: medium-dark skin tone
+1F938 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤸🏿‍♂️ E4.0 man cartwheeling: dark skin tone
+1F938 1F3FF 200D 2642                                  ; minimally-qualified # 
🤸🏿‍♂ E4.0 man cartwheeling: dark skin tone
+1F938 200D 2640 FE0F                                   ; fully-qualified     # 
🤸‍♀️ E4.0 woman cartwheeling
+1F938 200D 2640                                        ; minimally-qualified # 
🤸‍♀ E4.0 woman cartwheeling
+1F938 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤸🏻‍♀️ E4.0 woman cartwheeling: light skin tone
+1F938 1F3FB 200D 2640                                  ; minimally-qualified # 
🤸🏻‍♀ E4.0 woman cartwheeling: light skin tone
+1F938 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤸🏼‍♀️ E4.0 woman cartwheeling: medium-light skin tone
+1F938 1F3FC 200D 2640                                  ; minimally-qualified # 
🤸🏼‍♀ E4.0 woman cartwheeling: medium-light skin tone
+1F938 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤸🏽‍♀️ E4.0 woman cartwheeling: medium skin tone
+1F938 1F3FD 200D 2640                                  ; minimally-qualified # 
🤸🏽‍♀ E4.0 woman cartwheeling: medium skin tone
+1F938 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤸🏾‍♀️ E4.0 woman cartwheeling: medium-dark skin tone
+1F938 1F3FE 200D 2640                                  ; minimally-qualified # 
🤸🏾‍♀ E4.0 woman cartwheeling: medium-dark skin tone
+1F938 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤸🏿‍♀️ E4.0 woman cartwheeling: dark skin tone
+1F938 1F3FF 200D 2640                                  ; minimally-qualified # 
🤸🏿‍♀ E4.0 woman cartwheeling: dark skin tone
+1F93C                                                  ; fully-qualified     # 
🤼 E3.0 people wrestling
+1F93C 200D 2642 FE0F                                   ; fully-qualified     # 
🤼‍♂️ E4.0 men wrestling
+1F93C 200D 2642                                        ; minimally-qualified # 
🤼‍♂ E4.0 men wrestling
+1F93C 200D 2640 FE0F                                   ; fully-qualified     # 
🤼‍♀️ E4.0 women wrestling
+1F93C 200D 2640                                        ; minimally-qualified # 
🤼‍♀ E4.0 women wrestling
+1F93D                                                  ; fully-qualified     # 
🤽 E3.0 person playing water polo
+1F93D 1F3FB                                            ; fully-qualified     # 
🤽🏻 E3.0 person playing water polo: light skin tone
+1F93D 1F3FC                                            ; fully-qualified     # 
🤽🏼 E3.0 person playing water polo: medium-light skin tone
+1F93D 1F3FD                                            ; fully-qualified     # 
🤽🏽 E3.0 person playing water polo: medium skin tone
+1F93D 1F3FE                                            ; fully-qualified     # 
🤽🏾 E3.0 person playing water polo: medium-dark skin tone
+1F93D 1F3FF                                            ; fully-qualified     # 
🤽🏿 E3.0 person playing water polo: dark skin tone
+1F93D 200D 2642 FE0F                                   ; fully-qualified     # 
🤽‍♂️ E4.0 man playing water polo
+1F93D 200D 2642                                        ; minimally-qualified # 
🤽‍♂ E4.0 man playing water polo
+1F93D 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤽🏻‍♂️ E4.0 man playing water polo: light skin tone
+1F93D 1F3FB 200D 2642                                  ; minimally-qualified # 
🤽🏻‍♂ E4.0 man playing water polo: light skin tone
+1F93D 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤽🏼‍♂️ E4.0 man playing water polo: medium-light skin tone
+1F93D 1F3FC 200D 2642                                  ; minimally-qualified # 
🤽🏼‍♂ E4.0 man playing water polo: medium-light skin tone
+1F93D 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤽🏽‍♂️ E4.0 man playing water polo: medium skin tone
+1F93D 1F3FD 200D 2642                                  ; minimally-qualified # 
🤽🏽‍♂ E4.0 man playing water polo: medium skin tone
+1F93D 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤽🏾‍♂️ E4.0 man playing water polo: medium-dark skin tone
+1F93D 1F3FE 200D 2642                                  ; minimally-qualified # 
🤽🏾‍♂ E4.0 man playing water polo: medium-dark skin tone
+1F93D 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤽🏿‍♂️ E4.0 man playing water polo: dark skin tone
+1F93D 1F3FF 200D 2642                                  ; minimally-qualified # 
🤽🏿‍♂ E4.0 man playing water polo: dark skin tone
+1F93D 200D 2640 FE0F                                   ; fully-qualified     # 
🤽‍♀️ E4.0 woman playing water polo
+1F93D 200D 2640                                        ; minimally-qualified # 
🤽‍♀ E4.0 woman playing water polo
+1F93D 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤽🏻‍♀️ E4.0 woman playing water polo: light skin tone
+1F93D 1F3FB 200D 2640                                  ; minimally-qualified # 
🤽🏻‍♀ E4.0 woman playing water polo: light skin tone
+1F93D 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤽🏼‍♀️ E4.0 woman playing water polo: medium-light skin tone
+1F93D 1F3FC 200D 2640                                  ; minimally-qualified # 
🤽🏼‍♀ E4.0 woman playing water polo: medium-light skin tone
+1F93D 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤽🏽‍♀️ E4.0 woman playing water polo: medium skin tone
+1F93D 1F3FD 200D 2640                                  ; minimally-qualified # 
🤽🏽‍♀ E4.0 woman playing water polo: medium skin tone
+1F93D 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤽🏾‍♀️ E4.0 woman playing water polo: medium-dark skin tone
+1F93D 1F3FE 200D 2640                                  ; minimally-qualified # 
🤽🏾‍♀ E4.0 woman playing water polo: medium-dark skin tone
+1F93D 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤽🏿‍♀️ E4.0 woman playing water polo: dark skin tone
+1F93D 1F3FF 200D 2640                                  ; minimally-qualified # 
🤽🏿‍♀ E4.0 woman playing water polo: dark skin tone
+1F93E                                                  ; fully-qualified     # 
🤾 E3.0 person playing handball
+1F93E 1F3FB                                            ; fully-qualified     # 
🤾🏻 E3.0 person playing handball: light skin tone
+1F93E 1F3FC                                            ; fully-qualified     # 
🤾🏼 E3.0 person playing handball: medium-light skin tone
+1F93E 1F3FD                                            ; fully-qualified     # 
🤾🏽 E3.0 person playing handball: medium skin tone
+1F93E 1F3FE                                            ; fully-qualified     # 
🤾🏾 E3.0 person playing handball: medium-dark skin tone
+1F93E 1F3FF                                            ; fully-qualified     # 
🤾🏿 E3.0 person playing handball: dark skin tone
+1F93E 200D 2642 FE0F                                   ; fully-qualified     # 
🤾‍♂️ E4.0 man playing handball
+1F93E 200D 2642                                        ; minimally-qualified # 
🤾‍♂ E4.0 man playing handball
+1F93E 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤾🏻‍♂️ E4.0 man playing handball: light skin tone
+1F93E 1F3FB 200D 2642                                  ; minimally-qualified # 
🤾🏻‍♂ E4.0 man playing handball: light skin tone
+1F93E 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤾🏼‍♂️ E4.0 man playing handball: medium-light skin tone
+1F93E 1F3FC 200D 2642                                  ; minimally-qualified # 
🤾🏼‍♂ E4.0 man playing handball: medium-light skin tone
+1F93E 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤾🏽‍♂️ E4.0 man playing handball: medium skin tone
+1F93E 1F3FD 200D 2642                                  ; minimally-qualified # 
🤾🏽‍♂ E4.0 man playing handball: medium skin tone
+1F93E 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤾🏾‍♂️ E4.0 man playing handball: medium-dark skin tone
+1F93E 1F3FE 200D 2642                                  ; minimally-qualified # 
🤾🏾‍♂ E4.0 man playing handball: medium-dark skin tone
+1F93E 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤾🏿‍♂️ E4.0 man playing handball: dark skin tone
+1F93E 1F3FF 200D 2642                                  ; minimally-qualified # 
🤾🏿‍♂ E4.0 man playing handball: dark skin tone
+1F93E 200D 2640 FE0F                                   ; fully-qualified     # 
🤾‍♀️ E4.0 woman playing handball
+1F93E 200D 2640                                        ; minimally-qualified # 
🤾‍♀ E4.0 woman playing handball
+1F93E 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤾🏻‍♀️ E4.0 woman playing handball: light skin tone
+1F93E 1F3FB 200D 2640                                  ; minimally-qualified # 
🤾🏻‍♀ E4.0 woman playing handball: light skin tone
+1F93E 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤾🏼‍♀️ E4.0 woman playing handball: medium-light skin tone
+1F93E 1F3FC 200D 2640                                  ; minimally-qualified # 
🤾🏼‍♀ E4.0 woman playing handball: medium-light skin tone
+1F93E 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤾🏽‍♀️ E4.0 woman playing handball: medium skin tone
+1F93E 1F3FD 200D 2640                                  ; minimally-qualified # 
🤾🏽‍♀ E4.0 woman playing handball: medium skin tone
+1F93E 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤾🏾‍♀️ E4.0 woman playing handball: medium-dark skin tone
+1F93E 1F3FE 200D 2640                                  ; minimally-qualified # 
🤾🏾‍♀ E4.0 woman playing handball: medium-dark skin tone
+1F93E 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤾🏿‍♀️ E4.0 woman playing handball: dark skin tone
+1F93E 1F3FF 200D 2640                                  ; minimally-qualified # 
🤾🏿‍♀ E4.0 woman playing handball: dark skin tone
+1F939                                                  ; fully-qualified     # 
🤹 E3.0 person juggling
+1F939 1F3FB                                            ; fully-qualified     # 
🤹🏻 E3.0 person juggling: light skin tone
+1F939 1F3FC                                            ; fully-qualified     # 
🤹🏼 E3.0 person juggling: medium-light skin tone
+1F939 1F3FD                                            ; fully-qualified     # 
🤹🏽 E3.0 person juggling: medium skin tone
+1F939 1F3FE                                            ; fully-qualified     # 
🤹🏾 E3.0 person juggling: medium-dark skin tone
+1F939 1F3FF                                            ; fully-qualified     # 
🤹🏿 E3.0 person juggling: dark skin tone
+1F939 200D 2642 FE0F                                   ; fully-qualified     # 
🤹‍♂️ E4.0 man juggling
+1F939 200D 2642                                        ; minimally-qualified # 
🤹‍♂ E4.0 man juggling
+1F939 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🤹🏻‍♂️ E4.0 man juggling: light skin tone
+1F939 1F3FB 200D 2642                                  ; minimally-qualified # 
🤹🏻‍♂ E4.0 man juggling: light skin tone
+1F939 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🤹🏼‍♂️ E4.0 man juggling: medium-light skin tone
+1F939 1F3FC 200D 2642                                  ; minimally-qualified # 
🤹🏼‍♂ E4.0 man juggling: medium-light skin tone
+1F939 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🤹🏽‍♂️ E4.0 man juggling: medium skin tone
+1F939 1F3FD 200D 2642                                  ; minimally-qualified # 
🤹🏽‍♂ E4.0 man juggling: medium skin tone
+1F939 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🤹🏾‍♂️ E4.0 man juggling: medium-dark skin tone
+1F939 1F3FE 200D 2642                                  ; minimally-qualified # 
🤹🏾‍♂ E4.0 man juggling: medium-dark skin tone
+1F939 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🤹🏿‍♂️ E4.0 man juggling: dark skin tone
+1F939 1F3FF 200D 2642                                  ; minimally-qualified # 
🤹🏿‍♂ E4.0 man juggling: dark skin tone
+1F939 200D 2640 FE0F                                   ; fully-qualified     # 
🤹‍♀️ E4.0 woman juggling
+1F939 200D 2640                                        ; minimally-qualified # 
🤹‍♀ E4.0 woman juggling
+1F939 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🤹🏻‍♀️ E4.0 woman juggling: light skin tone
+1F939 1F3FB 200D 2640                                  ; minimally-qualified # 
🤹🏻‍♀ E4.0 woman juggling: light skin tone
+1F939 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🤹🏼‍♀️ E4.0 woman juggling: medium-light skin tone
+1F939 1F3FC 200D 2640                                  ; minimally-qualified # 
🤹🏼‍♀ E4.0 woman juggling: medium-light skin tone
+1F939 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🤹🏽‍♀️ E4.0 woman juggling: medium skin tone
+1F939 1F3FD 200D 2640                                  ; minimally-qualified # 
🤹🏽‍♀ E4.0 woman juggling: medium skin tone
+1F939 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🤹🏾‍♀️ E4.0 woman juggling: medium-dark skin tone
+1F939 1F3FE 200D 2640                                  ; minimally-qualified # 
🤹🏾‍♀ E4.0 woman juggling: medium-dark skin tone
+1F939 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🤹🏿‍♀️ E4.0 woman juggling: dark skin tone
+1F939 1F3FF 200D 2640                                  ; minimally-qualified # 
🤹🏿‍♀ E4.0 woman juggling: dark skin tone
+
+# subgroup: person-resting
+1F9D8                                                  ; fully-qualified     # 
🧘 E5.0 person in lotus position
+1F9D8 1F3FB                                            ; fully-qualified     # 
🧘🏻 E5.0 person in lotus position: light skin tone
+1F9D8 1F3FC                                            ; fully-qualified     # 
🧘🏼 E5.0 person in lotus position: medium-light skin tone
+1F9D8 1F3FD                                            ; fully-qualified     # 
🧘🏽 E5.0 person in lotus position: medium skin tone
+1F9D8 1F3FE                                            ; fully-qualified     # 
🧘🏾 E5.0 person in lotus position: medium-dark skin tone
+1F9D8 1F3FF                                            ; fully-qualified     # 
🧘🏿 E5.0 person in lotus position: dark skin tone
+1F9D8 200D 2642 FE0F                                   ; fully-qualified     # 
🧘‍♂️ E5.0 man in lotus position
+1F9D8 200D 2642                                        ; minimally-qualified # 
🧘‍♂ E5.0 man in lotus position
+1F9D8 1F3FB 200D 2642 FE0F                             ; fully-qualified     # 
🧘🏻‍♂️ E5.0 man in lotus position: light skin tone
+1F9D8 1F3FB 200D 2642                                  ; minimally-qualified # 
🧘🏻‍♂ E5.0 man in lotus position: light skin tone
+1F9D8 1F3FC 200D 2642 FE0F                             ; fully-qualified     # 
🧘🏼‍♂️ E5.0 man in lotus position: medium-light skin tone
+1F9D8 1F3FC 200D 2642                                  ; minimally-qualified # 
🧘🏼‍♂ E5.0 man in lotus position: medium-light skin tone
+1F9D8 1F3FD 200D 2642 FE0F                             ; fully-qualified     # 
🧘🏽‍♂️ E5.0 man in lotus position: medium skin tone
+1F9D8 1F3FD 200D 2642                                  ; minimally-qualified # 
🧘🏽‍♂ E5.0 man in lotus position: medium skin tone
+1F9D8 1F3FE 200D 2642 FE0F                             ; fully-qualified     # 
🧘🏾‍♂️ E5.0 man in lotus position: medium-dark skin tone
+1F9D8 1F3FE 200D 2642                                  ; minimally-qualified # 
🧘🏾‍♂ E5.0 man in lotus position: medium-dark skin tone
+1F9D8 1F3FF 200D 2642 FE0F                             ; fully-qualified     # 
🧘🏿‍♂️ E5.0 man in lotus position: dark skin tone
+1F9D8 1F3FF 200D 2642                                  ; minimally-qualified # 
🧘🏿‍♂ E5.0 man in lotus position: dark skin tone
+1F9D8 200D 2640 FE0F                                   ; fully-qualified     # 
🧘‍♀️ E5.0 woman in lotus position
+1F9D8 200D 2640                                        ; minimally-qualified # 
🧘‍♀ E5.0 woman in lotus position
+1F9D8 1F3FB 200D 2640 FE0F                             ; fully-qualified     # 
🧘🏻‍♀️ E5.0 woman in lotus position: light skin tone
+1F9D8 1F3FB 200D 2640                                  ; minimally-qualified # 
🧘🏻‍♀ E5.0 woman in lotus position: light skin tone
+1F9D8 1F3FC 200D 2640 FE0F                             ; fully-qualified     # 
🧘🏼‍♀️ E5.0 woman in lotus position: medium-light skin tone
+1F9D8 1F3FC 200D 2640                                  ; minimally-qualified # 
🧘🏼‍♀ E5.0 woman in lotus position: medium-light skin tone
+1F9D8 1F3FD 200D 2640 FE0F                             ; fully-qualified     # 
🧘🏽‍♀️ E5.0 woman in lotus position: medium skin tone
+1F9D8 1F3FD 200D 2640                                  ; minimally-qualified # 
🧘🏽‍♀ E5.0 woman in lotus position: medium skin tone
+1F9D8 1F3FE 200D 2640 FE0F                             ; fully-qualified     # 
🧘🏾‍♀️ E5.0 woman in lotus position: medium-dark skin tone
+1F9D8 1F3FE 200D 2640                                  ; minimally-qualified # 
🧘🏾‍♀ E5.0 woman in lotus position: medium-dark skin tone
+1F9D8 1F3FF 200D 2640 FE0F                             ; fully-qualified     # 
🧘🏿‍♀️ E5.0 woman in lotus position: dark skin tone
+1F9D8 1F3FF 200D 2640                                  ; minimally-qualified # 
🧘🏿‍♀ E5.0 woman in lotus position: dark skin tone
+1F6C0                                                  ; fully-qualified     # 
🛀 E0.6 person taking bath
+1F6C0 1F3FB                                            ; fully-qualified     # 
🛀🏻 E1.0 person taking bath: light skin tone
+1F6C0 1F3FC                                            ; fully-qualified     # 
🛀🏼 E1.0 person taking bath: medium-light skin tone
+1F6C0 1F3FD                                            ; fully-qualified     # 
🛀🏽 E1.0 person taking bath: medium skin tone
+1F6C0 1F3FE                                            ; fully-qualified     # 
🛀🏾 E1.0 person taking bath: medium-dark skin tone
+1F6C0 1F3FF                                            ; fully-qualified     # 
🛀🏿 E1.0 person taking bath: dark skin tone
+1F6CC                                                  ; fully-qualified     # 
🛌 E1.0 person in bed
+1F6CC 1F3FB                                            ; fully-qualified     # 
🛌🏻 E4.0 person in bed: light skin tone
+1F6CC 1F3FC                                            ; fully-qualified     # 
🛌🏼 E4.0 person in bed: medium-light skin tone
+1F6CC 1F3FD                                            ; fully-qualified     # 
🛌🏽 E4.0 person in bed: medium skin tone
+1F6CC 1F3FE                                            ; fully-qualified     # 
🛌🏾 E4.0 person in bed: medium-dark skin tone
+1F6CC 1F3FF                                            ; fully-qualified     # 
🛌🏿 E4.0 person in bed: dark skin tone
+
+# subgroup: family
+1F9D1 200D 1F91D 200D 1F9D1                            ; fully-qualified     # 
🧑‍🤝‍🧑 E12.0 people holding hands
+1F9D1 1F3FB 200D 1F91D 200D 1F9D1 1F3FB                ; fully-qualified     # 
🧑🏻‍🤝‍🧑🏻 E12.0 people holding hands: light skin tone
+1F9D1 1F3FB 200D 1F91D 200D 1F9D1 1F3FC                ; fully-qualified     # 
🧑🏻‍🤝‍🧑🏼 E12.1 people holding hands: light skin tone, medium-light skin tone
+1F9D1 1F3FB 200D 1F91D 200D 1F9D1 1F3FD                ; fully-qualified     # 
🧑🏻‍🤝‍🧑🏽 E12.1 people holding hands: light skin tone, medium skin tone
+1F9D1 1F3FB 200D 1F91D 200D 1F9D1 1F3FE                ; fully-qualified     # 
🧑🏻‍🤝‍🧑🏾 E12.1 people holding hands: light skin tone, medium-dark skin tone
+1F9D1 1F3FB 200D 1F91D 200D 1F9D1 1F3FF                ; fully-qualified     # 
🧑🏻‍🤝‍🧑🏿 E12.1 people holding hands: light skin tone, dark skin tone
+1F9D1 1F3FC 200D 1F91D 200D 1F9D1 1F3FB                ; fully-qualified     # 
🧑🏼‍🤝‍🧑🏻 E12.0 people holding hands: medium-light skin tone, light skin tone
+1F9D1 1F3FC 200D 1F91D 200D 1F9D1 1F3FC                ; fully-qualified     # 
🧑🏼‍🤝‍🧑🏼 E12.0 people holding hands: medium-light skin tone
+1F9D1 1F3FC 200D 1F91D 200D 1F9D1 1F3FD                ; fully-qualified     # 
🧑🏼‍🤝‍🧑🏽 E12.1 people holding hands: medium-light skin tone, medium skin tone
+1F9D1 1F3FC 200D 1F91D 200D 1F9D1 1F3FE                ; fully-qualified     # 
🧑🏼‍🤝‍🧑🏾 E12.1 people holding hands: medium-light skin tone, medium-dark skin 
tone
+1F9D1 1F3FC 200D 1F91D 200D 1F9D1 1F3FF                ; fully-qualified     # 
🧑🏼‍🤝‍🧑🏿 E12.1 people holding hands: medium-light skin tone, dark skin tone
+1F9D1 1F3FD 200D 1F91D 200D 1F9D1 1F3FB                ; fully-qualified     # 
🧑🏽‍🤝‍🧑🏻 E12.0 people holding hands: medium skin tone, light skin tone
+1F9D1 1F3FD 200D 1F91D 200D 1F9D1 1F3FC                ; fully-qualified     # 
🧑🏽‍🤝‍🧑🏼 E12.0 people holding hands: medium skin tone, medium-light skin tone
+1F9D1 1F3FD 200D 1F91D 200D 1F9D1 1F3FD                ; fully-qualified     # 
🧑🏽‍🤝‍🧑🏽 E12.0 people holding hands: medium skin tone
+1F9D1 1F3FD 200D 1F91D 200D 1F9D1 1F3FE                ; fully-qualified     # 
🧑🏽‍🤝‍🧑🏾 E12.1 people holding hands: medium skin tone, medium-dark skin tone
+1F9D1 1F3FD 200D 1F91D 200D 1F9D1 1F3FF                ; fully-qualified     # 
🧑🏽‍🤝‍🧑🏿 E12.1 people holding hands: medium skin tone, dark skin tone
+1F9D1 1F3FE 200D 1F91D 200D 1F9D1 1F3FB                ; fully-qualified     # 
🧑🏾‍🤝‍🧑🏻 E12.0 people holding hands: medium-dark skin tone, light skin tone
+1F9D1 1F3FE 200D 1F91D 200D 1F9D1 1F3FC                ; fully-qualified     # 
🧑🏾‍🤝‍🧑🏼 E12.0 people holding hands: medium-dark skin tone, medium-light skin 
tone
+1F9D1 1F3FE 200D 1F91D 200D 1F9D1 1F3FD                ; fully-qualified     # 
🧑🏾‍🤝‍🧑🏽 E12.0 people holding hands: medium-dark skin tone, medium skin tone
+1F9D1 1F3FE 200D 1F91D 200D 1F9D1 1F3FE                ; fully-qualified     # 
🧑🏾‍🤝‍🧑🏾 E12.0 people holding hands: medium-dark skin tone
+1F9D1 1F3FE 200D 1F91D 200D 1F9D1 1F3FF                ; fully-qualified     # 
🧑🏾‍🤝‍🧑🏿 E12.1 people holding hands: medium-dark skin tone, dark skin tone
+1F9D1 1F3FF 200D 1F91D 200D 1F9D1 1F3FB                ; fully-qualified     # 
🧑🏿‍🤝‍🧑🏻 E12.0 people holding hands: dark skin tone, light skin tone
+1F9D1 1F3FF 200D 1F91D 200D 1F9D1 1F3FC                ; fully-qualified     # 
🧑🏿‍🤝‍🧑🏼 E12.0 people holding hands: dark skin tone, medium-light skin tone
+1F9D1 1F3FF 200D 1F91D 200D 1F9D1 1F3FD                ; fully-qualified     # 
🧑🏿‍🤝‍🧑🏽 E12.0 people holding hands: dark skin tone, medium skin tone
+1F9D1 1F3FF 200D 1F91D 200D 1F9D1 1F3FE                ; fully-qualified     # 
🧑🏿‍🤝‍🧑🏾 E12.0 people holding hands: dark skin tone, medium-dark skin tone
+1F9D1 1F3FF 200D 1F91D 200D 1F9D1 1F3FF                ; fully-qualified     # 
🧑🏿‍🤝‍🧑🏿 E12.0 people holding hands: dark skin tone
+1F46D                                                  ; fully-qualified     # 
👭 E1.0 women holding hands
+1F46D 1F3FB                                            ; fully-qualified     # 
👭🏻 E12.0 women holding hands: light skin tone
+1F469 1F3FB 200D 1F91D 200D 1F469 1F3FC                ; fully-qualified     # 
👩🏻‍🤝‍👩🏼 E12.1 women holding hands: light skin tone, medium-light skin tone
+1F469 1F3FB 200D 1F91D 200D 1F469 1F3FD                ; fully-qualified     # 
👩🏻‍🤝‍👩🏽 E12.1 women holding hands: light skin tone, medium skin tone
+1F469 1F3FB 200D 1F91D 200D 1F469 1F3FE                ; fully-qualified     # 
👩🏻‍🤝‍👩🏾 E12.1 women holding hands: light skin tone, medium-dark skin tone
+1F469 1F3FB 200D 1F91D 200D 1F469 1F3FF                ; fully-qualified     # 
👩🏻‍🤝‍👩🏿 E12.1 women holding hands: light skin tone, dark skin tone
+1F469 1F3FC 200D 1F91D 200D 1F469 1F3FB                ; fully-qualified     # 
👩🏼‍🤝‍👩🏻 E12.0 women holding hands: medium-light skin tone, light skin tone
+1F46D 1F3FC                                            ; fully-qualified     # 
👭🏼 E12.0 women holding hands: medium-light skin tone
+1F469 1F3FC 200D 1F91D 200D 1F469 1F3FD                ; fully-qualified     # 
👩🏼‍🤝‍👩🏽 E12.1 women holding hands: medium-light skin tone, medium skin tone
+1F469 1F3FC 200D 1F91D 200D 1F469 1F3FE                ; fully-qualified     # 
👩🏼‍🤝‍👩🏾 E12.1 women holding hands: medium-light skin tone, medium-dark skin tone
+1F469 1F3FC 200D 1F91D 200D 1F469 1F3FF                ; fully-qualified     # 
👩🏼‍🤝‍👩🏿 E12.1 women holding hands: medium-light skin tone, dark skin tone
+1F469 1F3FD 200D 1F91D 200D 1F469 1F3FB                ; fully-qualified     # 
👩🏽‍🤝‍👩🏻 E12.0 women holding hands: medium skin tone, light skin tone
+1F469 1F3FD 200D 1F91D 200D 1F469 1F3FC                ; fully-qualified     # 
👩🏽‍🤝‍👩🏼 E12.0 women holding hands: medium skin tone, medium-light skin tone
+1F46D 1F3FD                                            ; fully-qualified     # 
👭🏽 E12.0 women holding hands: medium skin tone
+1F469 1F3FD 200D 1F91D 200D 1F469 1F3FE                ; fully-qualified     # 
👩🏽‍🤝‍👩🏾 E12.1 women holding hands: medium skin tone, medium-dark skin tone
+1F469 1F3FD 200D 1F91D 200D 1F469 1F3FF                ; fully-qualified     # 
👩🏽‍🤝‍👩🏿 E12.1 women holding hands: medium skin tone, dark skin tone
+1F469 1F3FE 200D 1F91D 200D 1F469 1F3FB                ; fully-qualified     # 
👩🏾‍🤝‍👩🏻 E12.0 women holding hands: medium-dark skin tone, light skin tone
+1F469 1F3FE 200D 1F91D 200D 1F469 1F3FC                ; fully-qualified     # 
👩🏾‍🤝‍👩🏼 E12.0 women holding hands: medium-dark skin tone, medium-light skin tone
+1F469 1F3FE 200D 1F91D 200D 1F469 1F3FD                ; fully-qualified     # 
👩🏾‍🤝‍👩🏽 E12.0 women holding hands: medium-dark skin tone, medium skin tone
+1F46D 1F3FE                                            ; fully-qualified     # 
👭🏾 E12.0 women holding hands: medium-dark skin tone
+1F469 1F3FE 200D 1F91D 200D 1F469 1F3FF                ; fully-qualified     # 
👩🏾‍🤝‍👩🏿 E12.1 women holding hands: medium-dark skin tone, dark skin tone
+1F469 1F3FF 200D 1F91D 200D 1F469 1F3FB                ; fully-qualified     # 
👩🏿‍🤝‍👩🏻 E12.0 women holding hands: dark skin tone, light skin tone
+1F469 1F3FF 200D 1F91D 200D 1F469 1F3FC                ; fully-qualified     # 
👩🏿‍🤝‍👩🏼 E12.0 women holding hands: dark skin tone, medium-light skin tone
+1F469 1F3FF 200D 1F91D 200D 1F469 1F3FD                ; fully-qualified     # 
👩🏿‍🤝‍👩🏽 E12.0 women holding hands: dark skin tone, medium skin tone
+1F469 1F3FF 200D 1F91D 200D 1F469 1F3FE                ; fully-qualified     # 
👩🏿‍🤝‍👩🏾 E12.0 women holding hands: dark skin tone, medium-dark skin tone
+1F46D 1F3FF                                            ; fully-qualified     # 
👭🏿 E12.0 women holding hands: dark skin tone
+1F46B                                                  ; fully-qualified     # 
👫 E0.6 woman and man holding hands
+1F46B 1F3FB                                            ; fully-qualified     # 
👫🏻 E12.0 woman and man holding hands: light skin tone
+1F469 1F3FB 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👩🏻‍🤝‍👨🏼 E12.0 woman and man holding hands: light skin tone, medium-light skin 
tone
+1F469 1F3FB 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👩🏻‍🤝‍👨🏽 E12.0 woman and man holding hands: light skin tone, medium skin tone
+1F469 1F3FB 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👩🏻‍🤝‍👨🏾 E12.0 woman and man holding hands: light skin tone, medium-dark skin 
tone
+1F469 1F3FB 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👩🏻‍🤝‍👨🏿 E12.0 woman and man holding hands: light skin tone, dark skin tone
+1F469 1F3FC 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👩🏼‍🤝‍👨🏻 E12.0 woman and man holding hands: medium-light skin tone, light skin 
tone
+1F46B 1F3FC                                            ; fully-qualified     # 
👫🏼 E12.0 woman and man holding hands: medium-light skin tone
+1F469 1F3FC 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👩🏼‍🤝‍👨🏽 E12.0 woman and man holding hands: medium-light skin tone, medium skin 
tone
+1F469 1F3FC 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👩🏼‍🤝‍👨🏾 E12.0 woman and man holding hands: medium-light skin tone, medium-dark 
skin tone
+1F469 1F3FC 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👩🏼‍🤝‍👨🏿 E12.0 woman and man holding hands: medium-light skin tone, dark skin 
tone
+1F469 1F3FD 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👩🏽‍🤝‍👨🏻 E12.0 woman and man holding hands: medium skin tone, light skin tone
+1F469 1F3FD 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👩🏽‍🤝‍👨🏼 E12.0 woman and man holding hands: medium skin tone, medium-light skin 
tone
+1F46B 1F3FD                                            ; fully-qualified     # 
👫🏽 E12.0 woman and man holding hands: medium skin tone
+1F469 1F3FD 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👩🏽‍🤝‍👨🏾 E12.0 woman and man holding hands: medium skin tone, medium-dark skin 
tone
+1F469 1F3FD 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👩🏽‍🤝‍👨🏿 E12.0 woman and man holding hands: medium skin tone, dark skin tone
+1F469 1F3FE 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👩🏾‍🤝‍👨🏻 E12.0 woman and man holding hands: medium-dark skin tone, light skin 
tone
+1F469 1F3FE 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👩🏾‍🤝‍👨🏼 E12.0 woman and man holding hands: medium-dark skin tone, medium-light 
skin tone
+1F469 1F3FE 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👩🏾‍🤝‍👨🏽 E12.0 woman and man holding hands: medium-dark skin tone, medium skin 
tone
+1F46B 1F3FE                                            ; fully-qualified     # 
👫🏾 E12.0 woman and man holding hands: medium-dark skin tone
+1F469 1F3FE 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👩🏾‍🤝‍👨🏿 E12.0 woman and man holding hands: medium-dark skin tone, dark skin tone
+1F469 1F3FF 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👩🏿‍🤝‍👨🏻 E12.0 woman and man holding hands: dark skin tone, light skin tone
+1F469 1F3FF 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👩🏿‍🤝‍👨🏼 E12.0 woman and man holding hands: dark skin tone, medium-light skin 
tone
+1F469 1F3FF 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👩🏿‍🤝‍👨🏽 E12.0 woman and man holding hands: dark skin tone, medium skin tone
+1F469 1F3FF 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👩🏿‍🤝‍👨🏾 E12.0 woman and man holding hands: dark skin tone, medium-dark skin tone
+1F46B 1F3FF                                            ; fully-qualified     # 
👫🏿 E12.0 woman and man holding hands: dark skin tone
+1F46C                                                  ; fully-qualified     # 
👬 E1.0 men holding hands
+1F46C 1F3FB                                            ; fully-qualified     # 
👬🏻 E12.0 men holding hands: light skin tone
+1F468 1F3FB 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👨🏻‍🤝‍👨🏼 E12.1 men holding hands: light skin tone, medium-light skin tone
+1F468 1F3FB 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👨🏻‍🤝‍👨🏽 E12.1 men holding hands: light skin tone, medium skin tone
+1F468 1F3FB 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👨🏻‍🤝‍👨🏾 E12.1 men holding hands: light skin tone, medium-dark skin tone
+1F468 1F3FB 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👨🏻‍🤝‍👨🏿 E12.1 men holding hands: light skin tone, dark skin tone
+1F468 1F3FC 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👨🏼‍🤝‍👨🏻 E12.0 men holding hands: medium-light skin tone, light skin tone
+1F46C 1F3FC                                            ; fully-qualified     # 
👬🏼 E12.0 men holding hands: medium-light skin tone
+1F468 1F3FC 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👨🏼‍🤝‍👨🏽 E12.1 men holding hands: medium-light skin tone, medium skin tone
+1F468 1F3FC 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👨🏼‍🤝‍👨🏾 E12.1 men holding hands: medium-light skin tone, medium-dark skin tone
+1F468 1F3FC 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👨🏼‍🤝‍👨🏿 E12.1 men holding hands: medium-light skin tone, dark skin tone
+1F468 1F3FD 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👨🏽‍🤝‍👨🏻 E12.0 men holding hands: medium skin tone, light skin tone
+1F468 1F3FD 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👨🏽‍🤝‍👨🏼 E12.0 men holding hands: medium skin tone, medium-light skin tone
+1F46C 1F3FD                                            ; fully-qualified     # 
👬🏽 E12.0 men holding hands: medium skin tone
+1F468 1F3FD 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👨🏽‍🤝‍👨🏾 E12.1 men holding hands: medium skin tone, medium-dark skin tone
+1F468 1F3FD 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👨🏽‍🤝‍👨🏿 E12.1 men holding hands: medium skin tone, dark skin tone
+1F468 1F3FE 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👨🏾‍🤝‍👨🏻 E12.0 men holding hands: medium-dark skin tone, light skin tone
+1F468 1F3FE 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👨🏾‍🤝‍👨🏼 E12.0 men holding hands: medium-dark skin tone, medium-light skin tone
+1F468 1F3FE 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👨🏾‍🤝‍👨🏽 E12.0 men holding hands: medium-dark skin tone, medium skin tone
+1F46C 1F3FE                                            ; fully-qualified     # 
👬🏾 E12.0 men holding hands: medium-dark skin tone
+1F468 1F3FE 200D 1F91D 200D 1F468 1F3FF                ; fully-qualified     # 
👨🏾‍🤝‍👨🏿 E12.1 men holding hands: medium-dark skin tone, dark skin tone
+1F468 1F3FF 200D 1F91D 200D 1F468 1F3FB                ; fully-qualified     # 
👨🏿‍🤝‍👨🏻 E12.0 men holding hands: dark skin tone, light skin tone
+1F468 1F3FF 200D 1F91D 200D 1F468 1F3FC                ; fully-qualified     # 
👨🏿‍🤝‍👨🏼 E12.0 men holding hands: dark skin tone, medium-light skin tone
+1F468 1F3FF 200D 1F91D 200D 1F468 1F3FD                ; fully-qualified     # 
👨🏿‍🤝‍👨🏽 E12.0 men holding hands: dark skin tone, medium skin tone
+1F468 1F3FF 200D 1F91D 200D 1F468 1F3FE                ; fully-qualified     # 
👨🏿‍🤝‍👨🏾 E12.0 men holding hands: dark skin tone, medium-dark skin tone
+1F46C 1F3FF                                            ; fully-qualified     # 
👬🏿 E12.0 men holding hands: dark skin tone
+1F48F                                                  ; fully-qualified     # 
💏 E0.6 kiss
+1F48F 1F3FB                                            ; fully-qualified     # 
💏🏻 E13.1 kiss: light skin tone
+1F48F 1F3FC                                            ; fully-qualified     # 
💏🏼 E13.1 kiss: medium-light skin tone
+1F48F 1F3FD                                            ; fully-qualified     # 
💏🏽 E13.1 kiss: medium skin tone
+1F48F 1F3FE                                            ; fully-qualified     # 
💏🏾 E13.1 kiss: medium-dark skin tone
+1F48F 1F3FF                                            ; fully-qualified     # 
💏🏿 E13.1 kiss: dark skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FC ; fully-qualified     # 
🧑🏻‍❤️‍💋‍🧑🏼 E13.1 kiss: person, person, light skin tone, medium-light skin tone
+1F9D1 1F3FB 200D 2764 200D 1F48B 200D 1F9D1 1F3FC      ; minimally-qualified # 
🧑🏻‍❤‍💋‍🧑🏼 E13.1 kiss: person, person, light skin tone, medium-light skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FD ; fully-qualified     # 
🧑🏻‍❤️‍💋‍🧑🏽 E13.1 kiss: person, person, light skin tone, medium skin tone
+1F9D1 1F3FB 200D 2764 200D 1F48B 200D 1F9D1 1F3FD      ; minimally-qualified # 
🧑🏻‍❤‍💋‍🧑🏽 E13.1 kiss: person, person, light skin tone, medium skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FE ; fully-qualified     # 
🧑🏻‍❤️‍💋‍🧑🏾 E13.1 kiss: person, person, light skin tone, medium-dark skin tone
+1F9D1 1F3FB 200D 2764 200D 1F48B 200D 1F9D1 1F3FE      ; minimally-qualified # 
🧑🏻‍❤‍💋‍🧑🏾 E13.1 kiss: person, person, light skin tone, medium-dark skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FF ; fully-qualified     # 
🧑🏻‍❤️‍💋‍🧑🏿 E13.1 kiss: person, person, light skin tone, dark skin tone
+1F9D1 1F3FB 200D 2764 200D 1F48B 200D 1F9D1 1F3FF      ; minimally-qualified # 
🧑🏻‍❤‍💋‍🧑🏿 E13.1 kiss: person, person, light skin tone, dark skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FB ; fully-qualified     # 
🧑🏼‍❤️‍💋‍🧑🏻 E13.1 kiss: person, person, medium-light skin tone, light skin tone
+1F9D1 1F3FC 200D 2764 200D 1F48B 200D 1F9D1 1F3FB      ; minimally-qualified # 
🧑🏼‍❤‍💋‍🧑🏻 E13.1 kiss: person, person, medium-light skin tone, light skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FD ; fully-qualified     # 
🧑🏼‍❤️‍💋‍🧑🏽 E13.1 kiss: person, person, medium-light skin tone, medium skin tone
+1F9D1 1F3FC 200D 2764 200D 1F48B 200D 1F9D1 1F3FD      ; minimally-qualified # 
🧑🏼‍❤‍💋‍🧑🏽 E13.1 kiss: person, person, medium-light skin tone, medium skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FE ; fully-qualified     # 
🧑🏼‍❤️‍💋‍🧑🏾 E13.1 kiss: person, person, medium-light skin tone, medium-dark skin 
tone
+1F9D1 1F3FC 200D 2764 200D 1F48B 200D 1F9D1 1F3FE      ; minimally-qualified # 
🧑🏼‍❤‍💋‍🧑🏾 E13.1 kiss: person, person, medium-light skin tone, medium-dark skin 
tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FF ; fully-qualified     # 
🧑🏼‍❤️‍💋‍🧑🏿 E13.1 kiss: person, person, medium-light skin tone, dark skin tone
+1F9D1 1F3FC 200D 2764 200D 1F48B 200D 1F9D1 1F3FF      ; minimally-qualified # 
🧑🏼‍❤‍💋‍🧑🏿 E13.1 kiss: person, person, medium-light skin tone, dark skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FB ; fully-qualified     # 
🧑🏽‍❤️‍💋‍🧑🏻 E13.1 kiss: person, person, medium skin tone, light skin tone
+1F9D1 1F3FD 200D 2764 200D 1F48B 200D 1F9D1 1F3FB      ; minimally-qualified # 
🧑🏽‍❤‍💋‍🧑🏻 E13.1 kiss: person, person, medium skin tone, light skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FC ; fully-qualified     # 
🧑🏽‍❤️‍💋‍🧑🏼 E13.1 kiss: person, person, medium skin tone, medium-light skin tone
+1F9D1 1F3FD 200D 2764 200D 1F48B 200D 1F9D1 1F3FC      ; minimally-qualified # 
🧑🏽‍❤‍💋‍🧑🏼 E13.1 kiss: person, person, medium skin tone, medium-light skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FE ; fully-qualified     # 
🧑🏽‍❤️‍💋‍🧑🏾 E13.1 kiss: person, person, medium skin tone, medium-dark skin tone
+1F9D1 1F3FD 200D 2764 200D 1F48B 200D 1F9D1 1F3FE      ; minimally-qualified # 
🧑🏽‍❤‍💋‍🧑🏾 E13.1 kiss: person, person, medium skin tone, medium-dark skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FF ; fully-qualified     # 
🧑🏽‍❤️‍💋‍🧑🏿 E13.1 kiss: person, person, medium skin tone, dark skin tone
+1F9D1 1F3FD 200D 2764 200D 1F48B 200D 1F9D1 1F3FF      ; minimally-qualified # 
🧑🏽‍❤‍💋‍🧑🏿 E13.1 kiss: person, person, medium skin tone, dark skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FB ; fully-qualified     # 
🧑🏾‍❤️‍💋‍🧑🏻 E13.1 kiss: person, person, medium-dark skin tone, light skin tone
+1F9D1 1F3FE 200D 2764 200D 1F48B 200D 1F9D1 1F3FB      ; minimally-qualified # 
🧑🏾‍❤‍💋‍🧑🏻 E13.1 kiss: person, person, medium-dark skin tone, light skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FC ; fully-qualified     # 
🧑🏾‍❤️‍💋‍🧑🏼 E13.1 kiss: person, person, medium-dark skin tone, medium-light skin 
tone
+1F9D1 1F3FE 200D 2764 200D 1F48B 200D 1F9D1 1F3FC      ; minimally-qualified # 
🧑🏾‍❤‍💋‍🧑🏼 E13.1 kiss: person, person, medium-dark skin tone, medium-light skin 
tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FD ; fully-qualified     # 
🧑🏾‍❤️‍💋‍🧑🏽 E13.1 kiss: person, person, medium-dark skin tone, medium skin tone
+1F9D1 1F3FE 200D 2764 200D 1F48B 200D 1F9D1 1F3FD      ; minimally-qualified # 
🧑🏾‍❤‍💋‍🧑🏽 E13.1 kiss: person, person, medium-dark skin tone, medium skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FF ; fully-qualified     # 
🧑🏾‍❤️‍💋‍🧑🏿 E13.1 kiss: person, person, medium-dark skin tone, dark skin tone
+1F9D1 1F3FE 200D 2764 200D 1F48B 200D 1F9D1 1F3FF      ; minimally-qualified # 
🧑🏾‍❤‍💋‍🧑🏿 E13.1 kiss: person, person, medium-dark skin tone, dark skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FB ; fully-qualified     # 
🧑🏿‍❤️‍💋‍🧑🏻 E13.1 kiss: person, person, dark skin tone, light skin tone
+1F9D1 1F3FF 200D 2764 200D 1F48B 200D 1F9D1 1F3FB      ; minimally-qualified # 
🧑🏿‍❤‍💋‍🧑🏻 E13.1 kiss: person, person, dark skin tone, light skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FC ; fully-qualified     # 
🧑🏿‍❤️‍💋‍🧑🏼 E13.1 kiss: person, person, dark skin tone, medium-light skin tone
+1F9D1 1F3FF 200D 2764 200D 1F48B 200D 1F9D1 1F3FC      ; minimally-qualified # 
🧑🏿‍❤‍💋‍🧑🏼 E13.1 kiss: person, person, dark skin tone, medium-light skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FD ; fully-qualified     # 
🧑🏿‍❤️‍💋‍🧑🏽 E13.1 kiss: person, person, dark skin tone, medium skin tone
+1F9D1 1F3FF 200D 2764 200D 1F48B 200D 1F9D1 1F3FD      ; minimally-qualified # 
🧑🏿‍❤‍💋‍🧑🏽 E13.1 kiss: person, person, dark skin tone, medium skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F9D1 1F3FE ; fully-qualified     # 
🧑🏿‍❤️‍💋‍🧑🏾 E13.1 kiss: person, person, dark skin tone, medium-dark skin tone
+1F9D1 1F3FF 200D 2764 200D 1F48B 200D 1F9D1 1F3FE      ; minimally-qualified # 
🧑🏿‍❤‍💋‍🧑🏾 E13.1 kiss: person, person, dark skin tone, medium-dark skin tone
+1F469 200D 2764 FE0F 200D 1F48B 200D 1F468             ; fully-qualified     # 
👩‍❤️‍💋‍👨 E2.0 kiss: woman, man
+1F469 200D 2764 200D 1F48B 200D 1F468                  ; minimally-qualified # 
👩‍❤‍💋‍👨 E2.0 kiss: woman, man
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👩🏻‍❤️‍💋‍👨🏻 E13.1 kiss: woman, man, light skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👩🏻‍❤‍💋‍👨🏻 E13.1 kiss: woman, man, light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👩🏻‍❤️‍💋‍👨🏼 E13.1 kiss: woman, man, light skin tone, medium-light skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👩🏻‍❤‍💋‍👨🏼 E13.1 kiss: woman, man, light skin tone, medium-light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👩🏻‍❤️‍💋‍👨🏽 E13.1 kiss: woman, man, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👩🏻‍❤‍💋‍👨🏽 E13.1 kiss: woman, man, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👩🏻‍❤️‍💋‍👨🏾 E13.1 kiss: woman, man, light skin tone, medium-dark skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👩🏻‍❤‍💋‍👨🏾 E13.1 kiss: woman, man, light skin tone, medium-dark skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👩🏻‍❤️‍💋‍👨🏿 E13.1 kiss: woman, man, light skin tone, dark skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👩🏻‍❤‍💋‍👨🏿 E13.1 kiss: woman, man, light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👩🏼‍❤️‍💋‍👨🏻 E13.1 kiss: woman, man, medium-light skin tone, light skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👩🏼‍❤‍💋‍👨🏻 E13.1 kiss: woman, man, medium-light skin tone, light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👩🏼‍❤️‍💋‍👨🏼 E13.1 kiss: woman, man, medium-light skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👩🏼‍❤‍💋‍👨🏼 E13.1 kiss: woman, man, medium-light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👩🏼‍❤️‍💋‍👨🏽 E13.1 kiss: woman, man, medium-light skin tone, medium skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👩🏼‍❤‍💋‍👨🏽 E13.1 kiss: woman, man, medium-light skin tone, medium skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👩🏼‍❤️‍💋‍👨🏾 E13.1 kiss: woman, man, medium-light skin tone, medium-dark skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👩🏼‍❤‍💋‍👨🏾 E13.1 kiss: woman, man, medium-light skin tone, medium-dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👩🏼‍❤️‍💋‍👨🏿 E13.1 kiss: woman, man, medium-light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👩🏼‍❤‍💋‍👨🏿 E13.1 kiss: woman, man, medium-light skin tone, dark skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👩🏽‍❤️‍💋‍👨🏻 E13.1 kiss: woman, man, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👩🏽‍❤‍💋‍👨🏻 E13.1 kiss: woman, man, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👩🏽‍❤️‍💋‍👨🏼 E13.1 kiss: woman, man, medium skin tone, medium-light skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👩🏽‍❤‍💋‍👨🏼 E13.1 kiss: woman, man, medium skin tone, medium-light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👩🏽‍❤️‍💋‍👨🏽 E13.1 kiss: woman, man, medium skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👩🏽‍❤‍💋‍👨🏽 E13.1 kiss: woman, man, medium skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👩🏽‍❤️‍💋‍👨🏾 E13.1 kiss: woman, man, medium skin tone, medium-dark skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👩🏽‍❤‍💋‍👨🏾 E13.1 kiss: woman, man, medium skin tone, medium-dark skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👩🏽‍❤️‍💋‍👨🏿 E13.1 kiss: woman, man, medium skin tone, dark skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👩🏽‍❤‍💋‍👨🏿 E13.1 kiss: woman, man, medium skin tone, dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👩🏾‍❤️‍💋‍👨🏻 E13.1 kiss: woman, man, medium-dark skin tone, light skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👩🏾‍❤‍💋‍👨🏻 E13.1 kiss: woman, man, medium-dark skin tone, light skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👩🏾‍❤️‍💋‍👨🏼 E13.1 kiss: woman, man, medium-dark skin tone, medium-light skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👩🏾‍❤‍💋‍👨🏼 E13.1 kiss: woman, man, medium-dark skin tone, medium-light skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👩🏾‍❤️‍💋‍👨🏽 E13.1 kiss: woman, man, medium-dark skin tone, medium skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👩🏾‍❤‍💋‍👨🏽 E13.1 kiss: woman, man, medium-dark skin tone, medium skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👩🏾‍❤️‍💋‍👨🏾 E13.1 kiss: woman, man, medium-dark skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👩🏾‍❤‍💋‍👨🏾 E13.1 kiss: woman, man, medium-dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👩🏾‍❤️‍💋‍👨🏿 E13.1 kiss: woman, man, medium-dark skin tone, dark skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👩🏾‍❤‍💋‍👨🏿 E13.1 kiss: woman, man, medium-dark skin tone, dark skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👩🏿‍❤️‍💋‍👨🏻 E13.1 kiss: woman, man, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👩🏿‍❤‍💋‍👨🏻 E13.1 kiss: woman, man, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👩🏿‍❤️‍💋‍👨🏼 E13.1 kiss: woman, man, dark skin tone, medium-light skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👩🏿‍❤‍💋‍👨🏼 E13.1 kiss: woman, man, dark skin tone, medium-light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👩🏿‍❤️‍💋‍👨🏽 E13.1 kiss: woman, man, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👩🏿‍❤‍💋‍👨🏽 E13.1 kiss: woman, man, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👩🏿‍❤️‍💋‍👨🏾 E13.1 kiss: woman, man, dark skin tone, medium-dark skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👩🏿‍❤‍💋‍👨🏾 E13.1 kiss: woman, man, dark skin tone, medium-dark skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👩🏿‍❤️‍💋‍👨🏿 E13.1 kiss: woman, man, dark skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👩🏿‍❤‍💋‍👨🏿 E13.1 kiss: woman, man, dark skin tone
+1F468 200D 2764 FE0F 200D 1F48B 200D 1F468             ; fully-qualified     # 
👨‍❤️‍💋‍👨 E2.0 kiss: man, man
+1F468 200D 2764 200D 1F48B 200D 1F468                  ; minimally-qualified # 
👨‍❤‍💋‍👨 E2.0 kiss: man, man
+1F468 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👨🏻‍❤️‍💋‍👨🏻 E13.1 kiss: man, man, light skin tone
+1F468 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👨🏻‍❤‍💋‍👨🏻 E13.1 kiss: man, man, light skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👨🏻‍❤️‍💋‍👨🏼 E13.1 kiss: man, man, light skin tone, medium-light skin tone
+1F468 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👨🏻‍❤‍💋‍👨🏼 E13.1 kiss: man, man, light skin tone, medium-light skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👨🏻‍❤️‍💋‍👨🏽 E13.1 kiss: man, man, light skin tone, medium skin tone
+1F468 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👨🏻‍❤‍💋‍👨🏽 E13.1 kiss: man, man, light skin tone, medium skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👨🏻‍❤️‍💋‍👨🏾 E13.1 kiss: man, man, light skin tone, medium-dark skin tone
+1F468 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👨🏻‍❤‍💋‍👨🏾 E13.1 kiss: man, man, light skin tone, medium-dark skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👨🏻‍❤️‍💋‍👨🏿 E13.1 kiss: man, man, light skin tone, dark skin tone
+1F468 1F3FB 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👨🏻‍❤‍💋‍👨🏿 E13.1 kiss: man, man, light skin tone, dark skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👨🏼‍❤️‍💋‍👨🏻 E13.1 kiss: man, man, medium-light skin tone, light skin tone
+1F468 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👨🏼‍❤‍💋‍👨🏻 E13.1 kiss: man, man, medium-light skin tone, light skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👨🏼‍❤️‍💋‍👨🏼 E13.1 kiss: man, man, medium-light skin tone
+1F468 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👨🏼‍❤‍💋‍👨🏼 E13.1 kiss: man, man, medium-light skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👨🏼‍❤️‍💋‍👨🏽 E13.1 kiss: man, man, medium-light skin tone, medium skin tone
+1F468 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👨🏼‍❤‍💋‍👨🏽 E13.1 kiss: man, man, medium-light skin tone, medium skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👨🏼‍❤️‍💋‍👨🏾 E13.1 kiss: man, man, medium-light skin tone, medium-dark skin tone
+1F468 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👨🏼‍❤‍💋‍👨🏾 E13.1 kiss: man, man, medium-light skin tone, medium-dark skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👨🏼‍❤️‍💋‍👨🏿 E13.1 kiss: man, man, medium-light skin tone, dark skin tone
+1F468 1F3FC 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👨🏼‍❤‍💋‍👨🏿 E13.1 kiss: man, man, medium-light skin tone, dark skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👨🏽‍❤️‍💋‍👨🏻 E13.1 kiss: man, man, medium skin tone, light skin tone
+1F468 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👨🏽‍❤‍💋‍👨🏻 E13.1 kiss: man, man, medium skin tone, light skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👨🏽‍❤️‍💋‍👨🏼 E13.1 kiss: man, man, medium skin tone, medium-light skin tone
+1F468 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👨🏽‍❤‍💋‍👨🏼 E13.1 kiss: man, man, medium skin tone, medium-light skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👨🏽‍❤️‍💋‍👨🏽 E13.1 kiss: man, man, medium skin tone
+1F468 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👨🏽‍❤‍💋‍👨🏽 E13.1 kiss: man, man, medium skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👨🏽‍❤️‍💋‍👨🏾 E13.1 kiss: man, man, medium skin tone, medium-dark skin tone
+1F468 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👨🏽‍❤‍💋‍👨🏾 E13.1 kiss: man, man, medium skin tone, medium-dark skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👨🏽‍❤️‍💋‍👨🏿 E13.1 kiss: man, man, medium skin tone, dark skin tone
+1F468 1F3FD 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👨🏽‍❤‍💋‍👨🏿 E13.1 kiss: man, man, medium skin tone, dark skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👨🏾‍❤️‍💋‍👨🏻 E13.1 kiss: man, man, medium-dark skin tone, light skin tone
+1F468 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👨🏾‍❤‍💋‍👨🏻 E13.1 kiss: man, man, medium-dark skin tone, light skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👨🏾‍❤️‍💋‍👨🏼 E13.1 kiss: man, man, medium-dark skin tone, medium-light skin tone
+1F468 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👨🏾‍❤‍💋‍👨🏼 E13.1 kiss: man, man, medium-dark skin tone, medium-light skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👨🏾‍❤️‍💋‍👨🏽 E13.1 kiss: man, man, medium-dark skin tone, medium skin tone
+1F468 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👨🏾‍❤‍💋‍👨🏽 E13.1 kiss: man, man, medium-dark skin tone, medium skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👨🏾‍❤️‍💋‍👨🏾 E13.1 kiss: man, man, medium-dark skin tone
+1F468 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👨🏾‍❤‍💋‍👨🏾 E13.1 kiss: man, man, medium-dark skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👨🏾‍❤️‍💋‍👨🏿 E13.1 kiss: man, man, medium-dark skin tone, dark skin tone
+1F468 1F3FE 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👨🏾‍❤‍💋‍👨🏿 E13.1 kiss: man, man, medium-dark skin tone, dark skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FB ; fully-qualified     # 
👨🏿‍❤️‍💋‍👨🏻 E13.1 kiss: man, man, dark skin tone, light skin tone
+1F468 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FB      ; minimally-qualified # 
👨🏿‍❤‍💋‍👨🏻 E13.1 kiss: man, man, dark skin tone, light skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FC ; fully-qualified     # 
👨🏿‍❤️‍💋‍👨🏼 E13.1 kiss: man, man, dark skin tone, medium-light skin tone
+1F468 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FC      ; minimally-qualified # 
👨🏿‍❤‍💋‍👨🏼 E13.1 kiss: man, man, dark skin tone, medium-light skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FD ; fully-qualified     # 
👨🏿‍❤️‍💋‍👨🏽 E13.1 kiss: man, man, dark skin tone, medium skin tone
+1F468 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FD      ; minimally-qualified # 
👨🏿‍❤‍💋‍👨🏽 E13.1 kiss: man, man, dark skin tone, medium skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FE ; fully-qualified     # 
👨🏿‍❤️‍💋‍👨🏾 E13.1 kiss: man, man, dark skin tone, medium-dark skin tone
+1F468 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FE      ; minimally-qualified # 
👨🏿‍❤‍💋‍👨🏾 E13.1 kiss: man, man, dark skin tone, medium-dark skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F468 1F3FF ; fully-qualified     # 
👨🏿‍❤️‍💋‍👨🏿 E13.1 kiss: man, man, dark skin tone
+1F468 1F3FF 200D 2764 200D 1F48B 200D 1F468 1F3FF      ; minimally-qualified # 
👨🏿‍❤‍💋‍👨🏿 E13.1 kiss: man, man, dark skin tone
+1F469 200D 2764 FE0F 200D 1F48B 200D 1F469             ; fully-qualified     # 
👩‍❤️‍💋‍👩 E2.0 kiss: woman, woman
+1F469 200D 2764 200D 1F48B 200D 1F469                  ; minimally-qualified # 
👩‍❤‍💋‍👩 E2.0 kiss: woman, woman
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FB ; fully-qualified     # 
👩🏻‍❤️‍💋‍👩🏻 E13.1 kiss: woman, woman, light skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F469 1F3FB      ; minimally-qualified # 
👩🏻‍❤‍💋‍👩🏻 E13.1 kiss: woman, woman, light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FC ; fully-qualified     # 
👩🏻‍❤️‍💋‍👩🏼 E13.1 kiss: woman, woman, light skin tone, medium-light skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F469 1F3FC      ; minimally-qualified # 
👩🏻‍❤‍💋‍👩🏼 E13.1 kiss: woman, woman, light skin tone, medium-light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FD ; fully-qualified     # 
👩🏻‍❤️‍💋‍👩🏽 E13.1 kiss: woman, woman, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F469 1F3FD      ; minimally-qualified # 
👩🏻‍❤‍💋‍👩🏽 E13.1 kiss: woman, woman, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FE ; fully-qualified     # 
👩🏻‍❤️‍💋‍👩🏾 E13.1 kiss: woman, woman, light skin tone, medium-dark skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F469 1F3FE      ; minimally-qualified # 
👩🏻‍❤‍💋‍👩🏾 E13.1 kiss: woman, woman, light skin tone, medium-dark skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FF ; fully-qualified     # 
👩🏻‍❤️‍💋‍👩🏿 E13.1 kiss: woman, woman, light skin tone, dark skin tone
+1F469 1F3FB 200D 2764 200D 1F48B 200D 1F469 1F3FF      ; minimally-qualified # 
👩🏻‍❤‍💋‍👩🏿 E13.1 kiss: woman, woman, light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FB ; fully-qualified     # 
👩🏼‍❤️‍💋‍👩🏻 E13.1 kiss: woman, woman, medium-light skin tone, light skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F469 1F3FB      ; minimally-qualified # 
👩🏼‍❤‍💋‍👩🏻 E13.1 kiss: woman, woman, medium-light skin tone, light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FC ; fully-qualified     # 
👩🏼‍❤️‍💋‍👩🏼 E13.1 kiss: woman, woman, medium-light skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F469 1F3FC      ; minimally-qualified # 
👩🏼‍❤‍💋‍👩🏼 E13.1 kiss: woman, woman, medium-light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FD ; fully-qualified     # 
👩🏼‍❤️‍💋‍👩🏽 E13.1 kiss: woman, woman, medium-light skin tone, medium skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F469 1F3FD      ; minimally-qualified # 
👩🏼‍❤‍💋‍👩🏽 E13.1 kiss: woman, woman, medium-light skin tone, medium skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FE ; fully-qualified     # 
👩🏼‍❤️‍💋‍👩🏾 E13.1 kiss: woman, woman, medium-light skin tone, medium-dark skin 
tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F469 1F3FE      ; minimally-qualified # 
👩🏼‍❤‍💋‍👩🏾 E13.1 kiss: woman, woman, medium-light skin tone, medium-dark skin 
tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FF ; fully-qualified     # 
👩🏼‍❤️‍💋‍👩🏿 E13.1 kiss: woman, woman, medium-light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 200D 1F48B 200D 1F469 1F3FF      ; minimally-qualified # 
👩🏼‍❤‍💋‍👩🏿 E13.1 kiss: woman, woman, medium-light skin tone, dark skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FB ; fully-qualified     # 
👩🏽‍❤️‍💋‍👩🏻 E13.1 kiss: woman, woman, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F469 1F3FB      ; minimally-qualified # 
👩🏽‍❤‍💋‍👩🏻 E13.1 kiss: woman, woman, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FC ; fully-qualified     # 
👩🏽‍❤️‍💋‍👩🏼 E13.1 kiss: woman, woman, medium skin tone, medium-light skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F469 1F3FC      ; minimally-qualified # 
👩🏽‍❤‍💋‍👩🏼 E13.1 kiss: woman, woman, medium skin tone, medium-light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FD ; fully-qualified     # 
👩🏽‍❤️‍💋‍👩🏽 E13.1 kiss: woman, woman, medium skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F469 1F3FD      ; minimally-qualified # 
👩🏽‍❤‍💋‍👩🏽 E13.1 kiss: woman, woman, medium skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FE ; fully-qualified     # 
👩🏽‍❤️‍💋‍👩🏾 E13.1 kiss: woman, woman, medium skin tone, medium-dark skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F469 1F3FE      ; minimally-qualified # 
👩🏽‍❤‍💋‍👩🏾 E13.1 kiss: woman, woman, medium skin tone, medium-dark skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FF ; fully-qualified     # 
👩🏽‍❤️‍💋‍👩🏿 E13.1 kiss: woman, woman, medium skin tone, dark skin tone
+1F469 1F3FD 200D 2764 200D 1F48B 200D 1F469 1F3FF      ; minimally-qualified # 
👩🏽‍❤‍💋‍👩🏿 E13.1 kiss: woman, woman, medium skin tone, dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FB ; fully-qualified     # 
👩🏾‍❤️‍💋‍👩🏻 E13.1 kiss: woman, woman, medium-dark skin tone, light skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F469 1F3FB      ; minimally-qualified # 
👩🏾‍❤‍💋‍👩🏻 E13.1 kiss: woman, woman, medium-dark skin tone, light skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FC ; fully-qualified     # 
👩🏾‍❤️‍💋‍👩🏼 E13.1 kiss: woman, woman, medium-dark skin tone, medium-light skin 
tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F469 1F3FC      ; minimally-qualified # 
👩🏾‍❤‍💋‍👩🏼 E13.1 kiss: woman, woman, medium-dark skin tone, medium-light skin 
tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FD ; fully-qualified     # 
👩🏾‍❤️‍💋‍👩🏽 E13.1 kiss: woman, woman, medium-dark skin tone, medium skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F469 1F3FD      ; minimally-qualified # 
👩🏾‍❤‍💋‍👩🏽 E13.1 kiss: woman, woman, medium-dark skin tone, medium skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FE ; fully-qualified     # 
👩🏾‍❤️‍💋‍👩🏾 E13.1 kiss: woman, woman, medium-dark skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F469 1F3FE      ; minimally-qualified # 
👩🏾‍❤‍💋‍👩🏾 E13.1 kiss: woman, woman, medium-dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FF ; fully-qualified     # 
👩🏾‍❤️‍💋‍👩🏿 E13.1 kiss: woman, woman, medium-dark skin tone, dark skin tone
+1F469 1F3FE 200D 2764 200D 1F48B 200D 1F469 1F3FF      ; minimally-qualified # 
👩🏾‍❤‍💋‍👩🏿 E13.1 kiss: woman, woman, medium-dark skin tone, dark skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FB ; fully-qualified     # 
👩🏿‍❤️‍💋‍👩🏻 E13.1 kiss: woman, woman, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F469 1F3FB      ; minimally-qualified # 
👩🏿‍❤‍💋‍👩🏻 E13.1 kiss: woman, woman, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FC ; fully-qualified     # 
👩🏿‍❤️‍💋‍👩🏼 E13.1 kiss: woman, woman, dark skin tone, medium-light skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F469 1F3FC      ; minimally-qualified # 
👩🏿‍❤‍💋‍👩🏼 E13.1 kiss: woman, woman, dark skin tone, medium-light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FD ; fully-qualified     # 
👩🏿‍❤️‍💋‍👩🏽 E13.1 kiss: woman, woman, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F469 1F3FD      ; minimally-qualified # 
👩🏿‍❤‍💋‍👩🏽 E13.1 kiss: woman, woman, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FE ; fully-qualified     # 
👩🏿‍❤️‍💋‍👩🏾 E13.1 kiss: woman, woman, dark skin tone, medium-dark skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F469 1F3FE      ; minimally-qualified # 
👩🏿‍❤‍💋‍👩🏾 E13.1 kiss: woman, woman, dark skin tone, medium-dark skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F48B 200D 1F469 1F3FF ; fully-qualified     # 
👩🏿‍❤️‍💋‍👩🏿 E13.1 kiss: woman, woman, dark skin tone
+1F469 1F3FF 200D 2764 200D 1F48B 200D 1F469 1F3FF      ; minimally-qualified # 
👩🏿‍❤‍💋‍👩🏿 E13.1 kiss: woman, woman, dark skin tone
+1F491                                                  ; fully-qualified     # 
💑 E0.6 couple with heart
+1F491 1F3FB                                            ; fully-qualified     # 
💑🏻 E13.1 couple with heart: light skin tone
+1F491 1F3FC                                            ; fully-qualified     # 
💑🏼 E13.1 couple with heart: medium-light skin tone
+1F491 1F3FD                                            ; fully-qualified     # 
💑🏽 E13.1 couple with heart: medium skin tone
+1F491 1F3FE                                            ; fully-qualified     # 
💑🏾 E13.1 couple with heart: medium-dark skin tone
+1F491 1F3FF                                            ; fully-qualified     # 
💑🏿 E13.1 couple with heart: dark skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F9D1 1F3FC            ; fully-qualified     # 
🧑🏻‍❤️‍🧑🏼 E13.1 couple with heart: person, person, light skin tone, medium-light 
skin tone
+1F9D1 1F3FB 200D 2764 200D 1F9D1 1F3FC                 ; minimally-qualified # 
🧑🏻‍❤‍🧑🏼 E13.1 couple with heart: person, person, light skin tone, medium-light 
skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F9D1 1F3FD            ; fully-qualified     # 
🧑🏻‍❤️‍🧑🏽 E13.1 couple with heart: person, person, light skin tone, medium skin 
tone
+1F9D1 1F3FB 200D 2764 200D 1F9D1 1F3FD                 ; minimally-qualified # 
🧑🏻‍❤‍🧑🏽 E13.1 couple with heart: person, person, light skin tone, medium skin 
tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F9D1 1F3FE            ; fully-qualified     # 
🧑🏻‍❤️‍🧑🏾 E13.1 couple with heart: person, person, light skin tone, medium-dark 
skin tone
+1F9D1 1F3FB 200D 2764 200D 1F9D1 1F3FE                 ; minimally-qualified # 
🧑🏻‍❤‍🧑🏾 E13.1 couple with heart: person, person, light skin tone, medium-dark 
skin tone
+1F9D1 1F3FB 200D 2764 FE0F 200D 1F9D1 1F3FF            ; fully-qualified     # 
🧑🏻‍❤️‍🧑🏿 E13.1 couple with heart: person, person, light skin tone, dark skin 
tone
+1F9D1 1F3FB 200D 2764 200D 1F9D1 1F3FF                 ; minimally-qualified # 
🧑🏻‍❤‍🧑🏿 E13.1 couple with heart: person, person, light skin tone, dark skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F9D1 1F3FB            ; fully-qualified     # 
🧑🏼‍❤️‍🧑🏻 E13.1 couple with heart: person, person, medium-light skin tone, light 
skin tone
+1F9D1 1F3FC 200D 2764 200D 1F9D1 1F3FB                 ; minimally-qualified # 
🧑🏼‍❤‍🧑🏻 E13.1 couple with heart: person, person, medium-light skin tone, light 
skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F9D1 1F3FD            ; fully-qualified     # 
🧑🏼‍❤️‍🧑🏽 E13.1 couple with heart: person, person, medium-light skin tone, 
medium skin tone
+1F9D1 1F3FC 200D 2764 200D 1F9D1 1F3FD                 ; minimally-qualified # 
🧑🏼‍❤‍🧑🏽 E13.1 couple with heart: person, person, medium-light skin tone, medium 
skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F9D1 1F3FE            ; fully-qualified     # 
🧑🏼‍❤️‍🧑🏾 E13.1 couple with heart: person, person, medium-light skin tone, 
medium-dark skin tone
+1F9D1 1F3FC 200D 2764 200D 1F9D1 1F3FE                 ; minimally-qualified # 
🧑🏼‍❤‍🧑🏾 E13.1 couple with heart: person, person, medium-light skin tone, 
medium-dark skin tone
+1F9D1 1F3FC 200D 2764 FE0F 200D 1F9D1 1F3FF            ; fully-qualified     # 
🧑🏼‍❤️‍🧑🏿 E13.1 couple with heart: person, person, medium-light skin tone, dark 
skin tone
+1F9D1 1F3FC 200D 2764 200D 1F9D1 1F3FF                 ; minimally-qualified # 
🧑🏼‍❤‍🧑🏿 E13.1 couple with heart: person, person, medium-light skin tone, dark 
skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F9D1 1F3FB            ; fully-qualified     # 
🧑🏽‍❤️‍🧑🏻 E13.1 couple with heart: person, person, medium skin tone, light skin 
tone
+1F9D1 1F3FD 200D 2764 200D 1F9D1 1F3FB                 ; minimally-qualified # 
🧑🏽‍❤‍🧑🏻 E13.1 couple with heart: person, person, medium skin tone, light skin 
tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F9D1 1F3FC            ; fully-qualified     # 
🧑🏽‍❤️‍🧑🏼 E13.1 couple with heart: person, person, medium skin tone, 
medium-light skin tone
+1F9D1 1F3FD 200D 2764 200D 1F9D1 1F3FC                 ; minimally-qualified # 
🧑🏽‍❤‍🧑🏼 E13.1 couple with heart: person, person, medium skin tone, medium-light 
skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F9D1 1F3FE            ; fully-qualified     # 
🧑🏽‍❤️‍🧑🏾 E13.1 couple with heart: person, person, medium skin tone, medium-dark 
skin tone
+1F9D1 1F3FD 200D 2764 200D 1F9D1 1F3FE                 ; minimally-qualified # 
🧑🏽‍❤‍🧑🏾 E13.1 couple with heart: person, person, medium skin tone, medium-dark 
skin tone
+1F9D1 1F3FD 200D 2764 FE0F 200D 1F9D1 1F3FF            ; fully-qualified     # 
🧑🏽‍❤️‍🧑🏿 E13.1 couple with heart: person, person, medium skin tone, dark skin 
tone
+1F9D1 1F3FD 200D 2764 200D 1F9D1 1F3FF                 ; minimally-qualified # 
🧑🏽‍❤‍🧑🏿 E13.1 couple with heart: person, person, medium skin tone, dark skin 
tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F9D1 1F3FB            ; fully-qualified     # 
🧑🏾‍❤️‍🧑🏻 E13.1 couple with heart: person, person, medium-dark skin tone, light 
skin tone
+1F9D1 1F3FE 200D 2764 200D 1F9D1 1F3FB                 ; minimally-qualified # 
🧑🏾‍❤‍🧑🏻 E13.1 couple with heart: person, person, medium-dark skin tone, light 
skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F9D1 1F3FC            ; fully-qualified     # 
🧑🏾‍❤️‍🧑🏼 E13.1 couple with heart: person, person, medium-dark skin tone, 
medium-light skin tone
+1F9D1 1F3FE 200D 2764 200D 1F9D1 1F3FC                 ; minimally-qualified # 
🧑🏾‍❤‍🧑🏼 E13.1 couple with heart: person, person, medium-dark skin tone, 
medium-light skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F9D1 1F3FD            ; fully-qualified     # 
🧑🏾‍❤️‍🧑🏽 E13.1 couple with heart: person, person, medium-dark skin tone, medium 
skin tone
+1F9D1 1F3FE 200D 2764 200D 1F9D1 1F3FD                 ; minimally-qualified # 
🧑🏾‍❤‍🧑🏽 E13.1 couple with heart: person, person, medium-dark skin tone, medium 
skin tone
+1F9D1 1F3FE 200D 2764 FE0F 200D 1F9D1 1F3FF            ; fully-qualified     # 
🧑🏾‍❤️‍🧑🏿 E13.1 couple with heart: person, person, medium-dark skin tone, dark 
skin tone
+1F9D1 1F3FE 200D 2764 200D 1F9D1 1F3FF                 ; minimally-qualified # 
🧑🏾‍❤‍🧑🏿 E13.1 couple with heart: person, person, medium-dark skin tone, dark 
skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F9D1 1F3FB            ; fully-qualified     # 
🧑🏿‍❤️‍🧑🏻 E13.1 couple with heart: person, person, dark skin tone, light skin 
tone
+1F9D1 1F3FF 200D 2764 200D 1F9D1 1F3FB                 ; minimally-qualified # 
🧑🏿‍❤‍🧑🏻 E13.1 couple with heart: person, person, dark skin tone, light skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F9D1 1F3FC            ; fully-qualified     # 
🧑🏿‍❤️‍🧑🏼 E13.1 couple with heart: person, person, dark skin tone, medium-light 
skin tone
+1F9D1 1F3FF 200D 2764 200D 1F9D1 1F3FC                 ; minimally-qualified # 
🧑🏿‍❤‍🧑🏼 E13.1 couple with heart: person, person, dark skin tone, medium-light 
skin tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F9D1 1F3FD            ; fully-qualified     # 
🧑🏿‍❤️‍🧑🏽 E13.1 couple with heart: person, person, dark skin tone, medium skin 
tone
+1F9D1 1F3FF 200D 2764 200D 1F9D1 1F3FD                 ; minimally-qualified # 
🧑🏿‍❤‍🧑🏽 E13.1 couple with heart: person, person, dark skin tone, medium skin 
tone
+1F9D1 1F3FF 200D 2764 FE0F 200D 1F9D1 1F3FE            ; fully-qualified     # 
🧑🏿‍❤️‍🧑🏾 E13.1 couple with heart: person, person, dark skin tone, medium-dark 
skin tone
+1F9D1 1F3FF 200D 2764 200D 1F9D1 1F3FE                 ; minimally-qualified # 
🧑🏿‍❤‍🧑🏾 E13.1 couple with heart: person, person, dark skin tone, medium-dark 
skin tone
+1F469 200D 2764 FE0F 200D 1F468                        ; fully-qualified     # 
👩‍❤️‍👨 E2.0 couple with heart: woman, man
+1F469 200D 2764 200D 1F468                             ; minimally-qualified # 
👩‍❤‍👨 E2.0 couple with heart: woman, man
+1F469 1F3FB 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👩🏻‍❤️‍👨🏻 E13.1 couple with heart: woman, man, light skin tone
+1F469 1F3FB 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👩🏻‍❤‍👨🏻 E13.1 couple with heart: woman, man, light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👩🏻‍❤️‍👨🏼 E13.1 couple with heart: woman, man, light skin tone, medium-light 
skin tone
+1F469 1F3FB 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👩🏻‍❤‍👨🏼 E13.1 couple with heart: woman, man, light skin tone, medium-light skin 
tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👩🏻‍❤️‍👨🏽 E13.1 couple with heart: woman, man, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👩🏻‍❤‍👨🏽 E13.1 couple with heart: woman, man, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👩🏻‍❤️‍👨🏾 E13.1 couple with heart: woman, man, light skin tone, medium-dark skin 
tone
+1F469 1F3FB 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👩🏻‍❤‍👨🏾 E13.1 couple with heart: woman, man, light skin tone, medium-dark skin 
tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👩🏻‍❤️‍👨🏿 E13.1 couple with heart: woman, man, light skin tone, dark skin tone
+1F469 1F3FB 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👩🏻‍❤‍👨🏿 E13.1 couple with heart: woman, man, light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👩🏼‍❤️‍👨🏻 E13.1 couple with heart: woman, man, medium-light skin tone, light 
skin tone
+1F469 1F3FC 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👩🏼‍❤‍👨🏻 E13.1 couple with heart: woman, man, medium-light skin tone, light skin 
tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👩🏼‍❤️‍👨🏼 E13.1 couple with heart: woman, man, medium-light skin tone
+1F469 1F3FC 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👩🏼‍❤‍👨🏼 E13.1 couple with heart: woman, man, medium-light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👩🏼‍❤️‍👨🏽 E13.1 couple with heart: woman, man, medium-light skin tone, medium 
skin tone
+1F469 1F3FC 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👩🏼‍❤‍👨🏽 E13.1 couple with heart: woman, man, medium-light skin tone, medium 
skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👩🏼‍❤️‍👨🏾 E13.1 couple with heart: woman, man, medium-light skin tone, 
medium-dark skin tone
+1F469 1F3FC 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👩🏼‍❤‍👨🏾 E13.1 couple with heart: woman, man, medium-light skin tone, 
medium-dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👩🏼‍❤️‍👨🏿 E13.1 couple with heart: woman, man, medium-light skin tone, dark skin 
tone
+1F469 1F3FC 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👩🏼‍❤‍👨🏿 E13.1 couple with heart: woman, man, medium-light skin tone, dark skin 
tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👩🏽‍❤️‍👨🏻 E13.1 couple with heart: woman, man, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👩🏽‍❤‍👨🏻 E13.1 couple with heart: woman, man, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👩🏽‍❤️‍👨🏼 E13.1 couple with heart: woman, man, medium skin tone, medium-light 
skin tone
+1F469 1F3FD 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👩🏽‍❤‍👨🏼 E13.1 couple with heart: woman, man, medium skin tone, medium-light 
skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👩🏽‍❤️‍👨🏽 E13.1 couple with heart: woman, man, medium skin tone
+1F469 1F3FD 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👩🏽‍❤‍👨🏽 E13.1 couple with heart: woman, man, medium skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👩🏽‍❤️‍👨🏾 E13.1 couple with heart: woman, man, medium skin tone, medium-dark 
skin tone
+1F469 1F3FD 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👩🏽‍❤‍👨🏾 E13.1 couple with heart: woman, man, medium skin tone, medium-dark skin 
tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👩🏽‍❤️‍👨🏿 E13.1 couple with heart: woman, man, medium skin tone, dark skin tone
+1F469 1F3FD 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👩🏽‍❤‍👨🏿 E13.1 couple with heart: woman, man, medium skin tone, dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👩🏾‍❤️‍👨🏻 E13.1 couple with heart: woman, man, medium-dark skin tone, light skin 
tone
+1F469 1F3FE 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👩🏾‍❤‍👨🏻 E13.1 couple with heart: woman, man, medium-dark skin tone, light skin 
tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👩🏾‍❤️‍👨🏼 E13.1 couple with heart: woman, man, medium-dark skin tone, 
medium-light skin tone
+1F469 1F3FE 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👩🏾‍❤‍👨🏼 E13.1 couple with heart: woman, man, medium-dark skin tone, 
medium-light skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👩🏾‍❤️‍👨🏽 E13.1 couple with heart: woman, man, medium-dark skin tone, medium 
skin tone
+1F469 1F3FE 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👩🏾‍❤‍👨🏽 E13.1 couple with heart: woman, man, medium-dark skin tone, medium skin 
tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👩🏾‍❤️‍👨🏾 E13.1 couple with heart: woman, man, medium-dark skin tone
+1F469 1F3FE 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👩🏾‍❤‍👨🏾 E13.1 couple with heart: woman, man, medium-dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👩🏾‍❤️‍👨🏿 E13.1 couple with heart: woman, man, medium-dark skin tone, dark skin 
tone
+1F469 1F3FE 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👩🏾‍❤‍👨🏿 E13.1 couple with heart: woman, man, medium-dark skin tone, dark skin 
tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👩🏿‍❤️‍👨🏻 E13.1 couple with heart: woman, man, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👩🏿‍❤‍👨🏻 E13.1 couple with heart: woman, man, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👩🏿‍❤️‍👨🏼 E13.1 couple with heart: woman, man, dark skin tone, medium-light skin 
tone
+1F469 1F3FF 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👩🏿‍❤‍👨🏼 E13.1 couple with heart: woman, man, dark skin tone, medium-light skin 
tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👩🏿‍❤️‍👨🏽 E13.1 couple with heart: woman, man, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👩🏿‍❤‍👨🏽 E13.1 couple with heart: woman, man, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👩🏿‍❤️‍👨🏾 E13.1 couple with heart: woman, man, dark skin tone, medium-dark skin 
tone
+1F469 1F3FF 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👩🏿‍❤‍👨🏾 E13.1 couple with heart: woman, man, dark skin tone, medium-dark skin 
tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👩🏿‍❤️‍👨🏿 E13.1 couple with heart: woman, man, dark skin tone
+1F469 1F3FF 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👩🏿‍❤‍👨🏿 E13.1 couple with heart: woman, man, dark skin tone
+1F468 200D 2764 FE0F 200D 1F468                        ; fully-qualified     # 
👨‍❤️‍👨 E2.0 couple with heart: man, man
+1F468 200D 2764 200D 1F468                             ; minimally-qualified # 
👨‍❤‍👨 E2.0 couple with heart: man, man
+1F468 1F3FB 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👨🏻‍❤️‍👨🏻 E13.1 couple with heart: man, man, light skin tone
+1F468 1F3FB 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👨🏻‍❤‍👨🏻 E13.1 couple with heart: man, man, light skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👨🏻‍❤️‍👨🏼 E13.1 couple with heart: man, man, light skin tone, medium-light skin 
tone
+1F468 1F3FB 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👨🏻‍❤‍👨🏼 E13.1 couple with heart: man, man, light skin tone, medium-light skin 
tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👨🏻‍❤️‍👨🏽 E13.1 couple with heart: man, man, light skin tone, medium skin tone
+1F468 1F3FB 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👨🏻‍❤‍👨🏽 E13.1 couple with heart: man, man, light skin tone, medium skin tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👨🏻‍❤️‍👨🏾 E13.1 couple with heart: man, man, light skin tone, medium-dark skin 
tone
+1F468 1F3FB 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👨🏻‍❤‍👨🏾 E13.1 couple with heart: man, man, light skin tone, medium-dark skin 
tone
+1F468 1F3FB 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👨🏻‍❤️‍👨🏿 E13.1 couple with heart: man, man, light skin tone, dark skin tone
+1F468 1F3FB 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👨🏻‍❤‍👨🏿 E13.1 couple with heart: man, man, light skin tone, dark skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👨🏼‍❤️‍👨🏻 E13.1 couple with heart: man, man, medium-light skin tone, light skin 
tone
+1F468 1F3FC 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👨🏼‍❤‍👨🏻 E13.1 couple with heart: man, man, medium-light skin tone, light skin 
tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👨🏼‍❤️‍👨🏼 E13.1 couple with heart: man, man, medium-light skin tone
+1F468 1F3FC 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👨🏼‍❤‍👨🏼 E13.1 couple with heart: man, man, medium-light skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👨🏼‍❤️‍👨🏽 E13.1 couple with heart: man, man, medium-light skin tone, medium skin 
tone
+1F468 1F3FC 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👨🏼‍❤‍👨🏽 E13.1 couple with heart: man, man, medium-light skin tone, medium skin 
tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👨🏼‍❤️‍👨🏾 E13.1 couple with heart: man, man, medium-light skin tone, medium-dark 
skin tone
+1F468 1F3FC 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👨🏼‍❤‍👨🏾 E13.1 couple with heart: man, man, medium-light skin tone, medium-dark 
skin tone
+1F468 1F3FC 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👨🏼‍❤️‍👨🏿 E13.1 couple with heart: man, man, medium-light skin tone, dark skin 
tone
+1F468 1F3FC 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👨🏼‍❤‍👨🏿 E13.1 couple with heart: man, man, medium-light skin tone, dark skin 
tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👨🏽‍❤️‍👨🏻 E13.1 couple with heart: man, man, medium skin tone, light skin tone
+1F468 1F3FD 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👨🏽‍❤‍👨🏻 E13.1 couple with heart: man, man, medium skin tone, light skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👨🏽‍❤️‍👨🏼 E13.1 couple with heart: man, man, medium skin tone, medium-light skin 
tone
+1F468 1F3FD 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👨🏽‍❤‍👨🏼 E13.1 couple with heart: man, man, medium skin tone, medium-light skin 
tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👨🏽‍❤️‍👨🏽 E13.1 couple with heart: man, man, medium skin tone
+1F468 1F3FD 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👨🏽‍❤‍👨🏽 E13.1 couple with heart: man, man, medium skin tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👨🏽‍❤️‍👨🏾 E13.1 couple with heart: man, man, medium skin tone, medium-dark skin 
tone
+1F468 1F3FD 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👨🏽‍❤‍👨🏾 E13.1 couple with heart: man, man, medium skin tone, medium-dark skin 
tone
+1F468 1F3FD 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👨🏽‍❤️‍👨🏿 E13.1 couple with heart: man, man, medium skin tone, dark skin tone
+1F468 1F3FD 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👨🏽‍❤‍👨🏿 E13.1 couple with heart: man, man, medium skin tone, dark skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👨🏾‍❤️‍👨🏻 E13.1 couple with heart: man, man, medium-dark skin tone, light skin 
tone
+1F468 1F3FE 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👨🏾‍❤‍👨🏻 E13.1 couple with heart: man, man, medium-dark skin tone, light skin 
tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👨🏾‍❤️‍👨🏼 E13.1 couple with heart: man, man, medium-dark skin tone, medium-light 
skin tone
+1F468 1F3FE 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👨🏾‍❤‍👨🏼 E13.1 couple with heart: man, man, medium-dark skin tone, medium-light 
skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👨🏾‍❤️‍👨🏽 E13.1 couple with heart: man, man, medium-dark skin tone, medium skin 
tone
+1F468 1F3FE 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👨🏾‍❤‍👨🏽 E13.1 couple with heart: man, man, medium-dark skin tone, medium skin 
tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👨🏾‍❤️‍👨🏾 E13.1 couple with heart: man, man, medium-dark skin tone
+1F468 1F3FE 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👨🏾‍❤‍👨🏾 E13.1 couple with heart: man, man, medium-dark skin tone
+1F468 1F3FE 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👨🏾‍❤️‍👨🏿 E13.1 couple with heart: man, man, medium-dark skin tone, dark skin 
tone
+1F468 1F3FE 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👨🏾‍❤‍👨🏿 E13.1 couple with heart: man, man, medium-dark skin tone, dark skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F468 1F3FB            ; fully-qualified     # 
👨🏿‍❤️‍👨🏻 E13.1 couple with heart: man, man, dark skin tone, light skin tone
+1F468 1F3FF 200D 2764 200D 1F468 1F3FB                 ; minimally-qualified # 
👨🏿‍❤‍👨🏻 E13.1 couple with heart: man, man, dark skin tone, light skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F468 1F3FC            ; fully-qualified     # 
👨🏿‍❤️‍👨🏼 E13.1 couple with heart: man, man, dark skin tone, medium-light skin 
tone
+1F468 1F3FF 200D 2764 200D 1F468 1F3FC                 ; minimally-qualified # 
👨🏿‍❤‍👨🏼 E13.1 couple with heart: man, man, dark skin tone, medium-light skin 
tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F468 1F3FD            ; fully-qualified     # 
👨🏿‍❤️‍👨🏽 E13.1 couple with heart: man, man, dark skin tone, medium skin tone
+1F468 1F3FF 200D 2764 200D 1F468 1F3FD                 ; minimally-qualified # 
👨🏿‍❤‍👨🏽 E13.1 couple with heart: man, man, dark skin tone, medium skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F468 1F3FE            ; fully-qualified     # 
👨🏿‍❤️‍👨🏾 E13.1 couple with heart: man, man, dark skin tone, medium-dark skin 
tone
+1F468 1F3FF 200D 2764 200D 1F468 1F3FE                 ; minimally-qualified # 
👨🏿‍❤‍👨🏾 E13.1 couple with heart: man, man, dark skin tone, medium-dark skin tone
+1F468 1F3FF 200D 2764 FE0F 200D 1F468 1F3FF            ; fully-qualified     # 
👨🏿‍❤️‍👨🏿 E13.1 couple with heart: man, man, dark skin tone
+1F468 1F3FF 200D 2764 200D 1F468 1F3FF                 ; minimally-qualified # 
👨🏿‍❤‍👨🏿 E13.1 couple with heart: man, man, dark skin tone
+1F469 200D 2764 FE0F 200D 1F469                        ; fully-qualified     # 
👩‍❤️‍👩 E2.0 couple with heart: woman, woman
+1F469 200D 2764 200D 1F469                             ; minimally-qualified # 
👩‍❤‍👩 E2.0 couple with heart: woman, woman
+1F469 1F3FB 200D 2764 FE0F 200D 1F469 1F3FB            ; fully-qualified     # 
👩🏻‍❤️‍👩🏻 E13.1 couple with heart: woman, woman, light skin tone
+1F469 1F3FB 200D 2764 200D 1F469 1F3FB                 ; minimally-qualified # 
👩🏻‍❤‍👩🏻 E13.1 couple with heart: woman, woman, light skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F469 1F3FC            ; fully-qualified     # 
👩🏻‍❤️‍👩🏼 E13.1 couple with heart: woman, woman, light skin tone, medium-light 
skin tone
+1F469 1F3FB 200D 2764 200D 1F469 1F3FC                 ; minimally-qualified # 
👩🏻‍❤‍👩🏼 E13.1 couple with heart: woman, woman, light skin tone, medium-light 
skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F469 1F3FD            ; fully-qualified     # 
👩🏻‍❤️‍👩🏽 E13.1 couple with heart: woman, woman, light skin tone, medium skin 
tone
+1F469 1F3FB 200D 2764 200D 1F469 1F3FD                 ; minimally-qualified # 
👩🏻‍❤‍👩🏽 E13.1 couple with heart: woman, woman, light skin tone, medium skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F469 1F3FE            ; fully-qualified     # 
👩🏻‍❤️‍👩🏾 E13.1 couple with heart: woman, woman, light skin tone, medium-dark 
skin tone
+1F469 1F3FB 200D 2764 200D 1F469 1F3FE                 ; minimally-qualified # 
👩🏻‍❤‍👩🏾 E13.1 couple with heart: woman, woman, light skin tone, medium-dark 
skin tone
+1F469 1F3FB 200D 2764 FE0F 200D 1F469 1F3FF            ; fully-qualified     # 
👩🏻‍❤️‍👩🏿 E13.1 couple with heart: woman, woman, light skin tone, dark skin tone
+1F469 1F3FB 200D 2764 200D 1F469 1F3FF                 ; minimally-qualified # 
👩🏻‍❤‍👩🏿 E13.1 couple with heart: woman, woman, light skin tone, dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F469 1F3FB            ; fully-qualified     # 
👩🏼‍❤️‍👩🏻 E13.1 couple with heart: woman, woman, medium-light skin tone, light 
skin tone
+1F469 1F3FC 200D 2764 200D 1F469 1F3FB                 ; minimally-qualified # 
👩🏼‍❤‍👩🏻 E13.1 couple with heart: woman, woman, medium-light skin tone, light 
skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F469 1F3FC            ; fully-qualified     # 
👩🏼‍❤️‍👩🏼 E13.1 couple with heart: woman, woman, medium-light skin tone
+1F469 1F3FC 200D 2764 200D 1F469 1F3FC                 ; minimally-qualified # 
👩🏼‍❤‍👩🏼 E13.1 couple with heart: woman, woman, medium-light skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F469 1F3FD            ; fully-qualified     # 
👩🏼‍❤️‍👩🏽 E13.1 couple with heart: woman, woman, medium-light skin tone, medium 
skin tone
+1F469 1F3FC 200D 2764 200D 1F469 1F3FD                 ; minimally-qualified # 
👩🏼‍❤‍👩🏽 E13.1 couple with heart: woman, woman, medium-light skin tone, medium 
skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F469 1F3FE            ; fully-qualified     # 
👩🏼‍❤️‍👩🏾 E13.1 couple with heart: woman, woman, medium-light skin tone, 
medium-dark skin tone
+1F469 1F3FC 200D 2764 200D 1F469 1F3FE                 ; minimally-qualified # 
👩🏼‍❤‍👩🏾 E13.1 couple with heart: woman, woman, medium-light skin tone, 
medium-dark skin tone
+1F469 1F3FC 200D 2764 FE0F 200D 1F469 1F3FF            ; fully-qualified     # 
👩🏼‍❤️‍👩🏿 E13.1 couple with heart: woman, woman, medium-light skin tone, dark 
skin tone
+1F469 1F3FC 200D 2764 200D 1F469 1F3FF                 ; minimally-qualified # 
👩🏼‍❤‍👩🏿 E13.1 couple with heart: woman, woman, medium-light skin tone, dark 
skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F469 1F3FB            ; fully-qualified     # 
👩🏽‍❤️‍👩🏻 E13.1 couple with heart: woman, woman, medium skin tone, light skin 
tone
+1F469 1F3FD 200D 2764 200D 1F469 1F3FB                 ; minimally-qualified # 
👩🏽‍❤‍👩🏻 E13.1 couple with heart: woman, woman, medium skin tone, light skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F469 1F3FC            ; fully-qualified     # 
👩🏽‍❤️‍👩🏼 E13.1 couple with heart: woman, woman, medium skin tone, medium-light 
skin tone
+1F469 1F3FD 200D 2764 200D 1F469 1F3FC                 ; minimally-qualified # 
👩🏽‍❤‍👩🏼 E13.1 couple with heart: woman, woman, medium skin tone, medium-light 
skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F469 1F3FD            ; fully-qualified     # 
👩🏽‍❤️‍👩🏽 E13.1 couple with heart: woman, woman, medium skin tone
+1F469 1F3FD 200D 2764 200D 1F469 1F3FD                 ; minimally-qualified # 
👩🏽‍❤‍👩🏽 E13.1 couple with heart: woman, woman, medium skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F469 1F3FE            ; fully-qualified     # 
👩🏽‍❤️‍👩🏾 E13.1 couple with heart: woman, woman, medium skin tone, medium-dark 
skin tone
+1F469 1F3FD 200D 2764 200D 1F469 1F3FE                 ; minimally-qualified # 
👩🏽‍❤‍👩🏾 E13.1 couple with heart: woman, woman, medium skin tone, medium-dark 
skin tone
+1F469 1F3FD 200D 2764 FE0F 200D 1F469 1F3FF            ; fully-qualified     # 
👩🏽‍❤️‍👩🏿 E13.1 couple with heart: woman, woman, medium skin tone, dark skin tone
+1F469 1F3FD 200D 2764 200D 1F469 1F3FF                 ; minimally-qualified # 
👩🏽‍❤‍👩🏿 E13.1 couple with heart: woman, woman, medium skin tone, dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F469 1F3FB            ; fully-qualified     # 
👩🏾‍❤️‍👩🏻 E13.1 couple with heart: woman, woman, medium-dark skin tone, light 
skin tone
+1F469 1F3FE 200D 2764 200D 1F469 1F3FB                 ; minimally-qualified # 
👩🏾‍❤‍👩🏻 E13.1 couple with heart: woman, woman, medium-dark skin tone, light 
skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F469 1F3FC            ; fully-qualified     # 
👩🏾‍❤️‍👩🏼 E13.1 couple with heart: woman, woman, medium-dark skin tone, 
medium-light skin tone
+1F469 1F3FE 200D 2764 200D 1F469 1F3FC                 ; minimally-qualified # 
👩🏾‍❤‍👩🏼 E13.1 couple with heart: woman, woman, medium-dark skin tone, 
medium-light skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F469 1F3FD            ; fully-qualified     # 
👩🏾‍❤️‍👩🏽 E13.1 couple with heart: woman, woman, medium-dark skin tone, medium 
skin tone
+1F469 1F3FE 200D 2764 200D 1F469 1F3FD                 ; minimally-qualified # 
👩🏾‍❤‍👩🏽 E13.1 couple with heart: woman, woman, medium-dark skin tone, medium 
skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F469 1F3FE            ; fully-qualified     # 
👩🏾‍❤️‍👩🏾 E13.1 couple with heart: woman, woman, medium-dark skin tone
+1F469 1F3FE 200D 2764 200D 1F469 1F3FE                 ; minimally-qualified # 
👩🏾‍❤‍👩🏾 E13.1 couple with heart: woman, woman, medium-dark skin tone
+1F469 1F3FE 200D 2764 FE0F 200D 1F469 1F3FF            ; fully-qualified     # 
👩🏾‍❤️‍👩🏿 E13.1 couple with heart: woman, woman, medium-dark skin tone, dark 
skin tone
+1F469 1F3FE 200D 2764 200D 1F469 1F3FF                 ; minimally-qualified # 
👩🏾‍❤‍👩🏿 E13.1 couple with heart: woman, woman, medium-dark skin tone, dark skin 
tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F469 1F3FB            ; fully-qualified     # 
👩🏿‍❤️‍👩🏻 E13.1 couple with heart: woman, woman, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 200D 1F469 1F3FB                 ; minimally-qualified # 
👩🏿‍❤‍👩🏻 E13.1 couple with heart: woman, woman, dark skin tone, light skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F469 1F3FC            ; fully-qualified     # 
👩🏿‍❤️‍👩🏼 E13.1 couple with heart: woman, woman, dark skin tone, medium-light 
skin tone
+1F469 1F3FF 200D 2764 200D 1F469 1F3FC                 ; minimally-qualified # 
👩🏿‍❤‍👩🏼 E13.1 couple with heart: woman, woman, dark skin tone, medium-light 
skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F469 1F3FD            ; fully-qualified     # 
👩🏿‍❤️‍👩🏽 E13.1 couple with heart: woman, woman, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 200D 1F469 1F3FD                 ; minimally-qualified # 
👩🏿‍❤‍👩🏽 E13.1 couple with heart: woman, woman, dark skin tone, medium skin tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F469 1F3FE            ; fully-qualified     # 
👩🏿‍❤️‍👩🏾 E13.1 couple with heart: woman, woman, dark skin tone, medium-dark 
skin tone
+1F469 1F3FF 200D 2764 200D 1F469 1F3FE                 ; minimally-qualified # 
👩🏿‍❤‍👩🏾 E13.1 couple with heart: woman, woman, dark skin tone, medium-dark skin 
tone
+1F469 1F3FF 200D 2764 FE0F 200D 1F469 1F3FF            ; fully-qualified     # 
👩🏿‍❤️‍👩🏿 E13.1 couple with heart: woman, woman, dark skin tone
+1F469 1F3FF 200D 2764 200D 1F469 1F3FF                 ; minimally-qualified # 
👩🏿‍❤‍👩🏿 E13.1 couple with heart: woman, woman, dark skin tone
+1F46A                                                  ; fully-qualified     # 
👪 E0.6 family
+1F468 200D 1F469 200D 1F466                            ; fully-qualified     # 
👨‍👩‍👦 E2.0 family: man, woman, boy
+1F468 200D 1F469 200D 1F467                            ; fully-qualified     # 
👨‍👩‍👧 E2.0 family: man, woman, girl
+1F468 200D 1F469 200D 1F467 200D 1F466                 ; fully-qualified     # 
👨‍👩‍👧‍👦 E2.0 family: man, woman, girl, boy
+1F468 200D 1F469 200D 1F466 200D 1F466                 ; fully-qualified     # 
👨‍👩‍👦‍👦 E2.0 family: man, woman, boy, boy
+1F468 200D 1F469 200D 1F467 200D 1F467                 ; fully-qualified     # 
👨‍👩‍👧‍👧 E2.0 family: man, woman, girl, girl
+1F468 200D 1F468 200D 1F466                            ; fully-qualified     # 
👨‍👨‍👦 E2.0 family: man, man, boy
+1F468 200D 1F468 200D 1F467                            ; fully-qualified     # 
👨‍👨‍👧 E2.0 family: man, man, girl
+1F468 200D 1F468 200D 1F467 200D 1F466                 ; fully-qualified     # 
👨‍👨‍👧‍👦 E2.0 family: man, man, girl, boy
+1F468 200D 1F468 200D 1F466 200D 1F466                 ; fully-qualified     # 
👨‍👨‍👦‍👦 E2.0 family: man, man, boy, boy
+1F468 200D 1F468 200D 1F467 200D 1F467                 ; fully-qualified     # 
👨‍👨‍👧‍👧 E2.0 family: man, man, girl, girl
+1F469 200D 1F469 200D 1F466                            ; fully-qualified     # 
👩‍👩‍👦 E2.0 family: woman, woman, boy
+1F469 200D 1F469 200D 1F467                            ; fully-qualified     # 
👩‍👩‍👧 E2.0 family: woman, woman, girl
+1F469 200D 1F469 200D 1F467 200D 1F466                 ; fully-qualified     # 
👩‍👩‍👧‍👦 E2.0 family: woman, woman, girl, boy
+1F469 200D 1F469 200D 1F466 200D 1F466                 ; fully-qualified     # 
👩‍👩‍👦‍👦 E2.0 family: woman, woman, boy, boy
+1F469 200D 1F469 200D 1F467 200D 1F467                 ; fully-qualified     # 
👩‍👩‍👧‍👧 E2.0 family: woman, woman, girl, girl
+1F468 200D 1F466                                       ; fully-qualified     # 
👨‍👦 E4.0 family: man, boy
+1F468 200D 1F466 200D 1F466                            ; fully-qualified     # 
👨‍👦‍👦 E4.0 family: man, boy, boy
+1F468 200D 1F467                                       ; fully-qualified     # 
👨‍👧 E4.0 family: man, girl
+1F468 200D 1F467 200D 1F466                            ; fully-qualified     # 
👨‍👧‍👦 E4.0 family: man, girl, boy
+1F468 200D 1F467 200D 1F467                            ; fully-qualified     # 
👨‍👧‍👧 E4.0 family: man, girl, girl
+1F469 200D 1F466                                       ; fully-qualified     # 
👩‍👦 E4.0 family: woman, boy
+1F469 200D 1F466 200D 1F466                            ; fully-qualified     # 
👩‍👦‍👦 E4.0 family: woman, boy, boy
+1F469 200D 1F467                                       ; fully-qualified     # 
👩‍👧 E4.0 family: woman, girl
+1F469 200D 1F467 200D 1F466                            ; fully-qualified     # 
👩‍👧‍👦 E4.0 family: woman, girl, boy
+1F469 200D 1F467 200D 1F467                            ; fully-qualified     # 
👩‍👧‍👧 E4.0 family: woman, girl, girl
+
+# subgroup: person-symbol
+1F5E3 FE0F                                             ; fully-qualified     # 
🗣️ E0.7 speaking head
+1F5E3                                                  ; unqualified         # 
🗣 E0.7 speaking head
+1F464                                                  ; fully-qualified     # 
👤 E0.6 bust in silhouette
+1F465                                                  ; fully-qualified     # 
👥 E1.0 busts in silhouette
+1FAC2                                                  ; fully-qualified     # 
🫂 E13.0 people hugging
+1F463                                                  ; fully-qualified     # 
👣 E0.6 footprints
+
+# People & Body subtotal:              2986
+# People & Body subtotal:              506     w/o modifiers
+
+# group: Component
+
+# subgroup: skin-tone
+1F3FB                                                  ; component           # 
🏻 E1.0 light skin tone
+1F3FC                                                  ; component           # 
🏼 E1.0 medium-light skin tone
+1F3FD                                                  ; component           # 
🏽 E1.0 medium skin tone
+1F3FE                                                  ; component           # 
🏾 E1.0 medium-dark skin tone
+1F3FF                                                  ; component           # 
🏿 E1.0 dark skin tone
+
+# subgroup: hair-style
+1F9B0                                                  ; component           # 
🦰 E11.0 red hair
+1F9B1                                                  ; component           # 
🦱 E11.0 curly hair
+1F9B3                                                  ; component           # 
🦳 E11.0 white hair
+1F9B2                                                  ; component           # 
🦲 E11.0 bald
+
+# Component subtotal:          9
+# Component subtotal:          4       w/o modifiers
+
+# group: Animals & Nature
+
+# subgroup: animal-mammal
+1F435                                                  ; fully-qualified     # 
🐵 E0.6 monkey face
+1F412                                                  ; fully-qualified     # 
🐒 E0.6 monkey
+1F98D                                                  ; fully-qualified     # 
🦍 E3.0 gorilla
+1F9A7                                                  ; fully-qualified     # 
🦧 E12.0 orangutan
+1F436                                                  ; fully-qualified     # 
🐶 E0.6 dog face
+1F415                                                  ; fully-qualified     # 
🐕 E0.7 dog
+1F9AE                                                  ; fully-qualified     # 
🦮 E12.0 guide dog
+1F415 200D 1F9BA                                       ; fully-qualified     # 
🐕‍🦺 E12.0 service dog
+1F429                                                  ; fully-qualified     # 
🐩 E0.6 poodle
+1F43A                                                  ; fully-qualified     # 
🐺 E0.6 wolf
+1F98A                                                  ; fully-qualified     # 
🦊 E3.0 fox
+1F99D                                                  ; fully-qualified     # 
🦝 E11.0 raccoon
+1F431                                                  ; fully-qualified     # 
🐱 E0.6 cat face
+1F408                                                  ; fully-qualified     # 
🐈 E0.7 cat
+1F408 200D 2B1B                                        ; fully-qualified     # 
🐈‍⬛ E13.0 black cat
+1F981                                                  ; fully-qualified     # 
🦁 E1.0 lion
+1F42F                                                  ; fully-qualified     # 
🐯 E0.6 tiger face
+1F405                                                  ; fully-qualified     # 
🐅 E1.0 tiger
+1F406                                                  ; fully-qualified     # 
🐆 E1.0 leopard
+1F434                                                  ; fully-qualified     # 
🐴 E0.6 horse face
+1F40E                                                  ; fully-qualified     # 
🐎 E0.6 horse
+1F984                                                  ; fully-qualified     # 
🦄 E1.0 unicorn
+1F993                                                  ; fully-qualified     # 
🦓 E5.0 zebra
+1F98C                                                  ; fully-qualified     # 
🦌 E3.0 deer
+1F9AC                                                  ; fully-qualified     # 
🦬 E13.0 bison
+1F42E                                                  ; fully-qualified     # 
🐮 E0.6 cow face
+1F402                                                  ; fully-qualified     # 
🐂 E1.0 ox
+1F403                                                  ; fully-qualified     # 
🐃 E1.0 water buffalo
+1F404                                                  ; fully-qualified     # 
🐄 E1.0 cow
+1F437                                                  ; fully-qualified     # 
🐷 E0.6 pig face
+1F416                                                  ; fully-qualified     # 
🐖 E1.0 pig
+1F417                                                  ; fully-qualified     # 
🐗 E0.6 boar
+1F43D                                                  ; fully-qualified     # 
🐽 E0.6 pig nose
+1F40F                                                  ; fully-qualified     # 
🐏 E1.0 ram
+1F411                                                  ; fully-qualified     # 
🐑 E0.6 ewe
+1F410                                                  ; fully-qualified     # 
🐐 E1.0 goat
+1F42A                                                  ; fully-qualified     # 
🐪 E1.0 camel
+1F42B                                                  ; fully-qualified     # 
🐫 E0.6 two-hump camel
+1F999                                                  ; fully-qualified     # 
🦙 E11.0 llama
+1F992                                                  ; fully-qualified     # 
🦒 E5.0 giraffe
+1F418                                                  ; fully-qualified     # 
🐘 E0.6 elephant
+1F9A3                                                  ; fully-qualified     # 
🦣 E13.0 mammoth
+1F98F                                                  ; fully-qualified     # 
🦏 E3.0 rhinoceros
+1F99B                                                  ; fully-qualified     # 
🦛 E11.0 hippopotamus
+1F42D                                                  ; fully-qualified     # 
🐭 E0.6 mouse face
+1F401                                                  ; fully-qualified     # 
🐁 E1.0 mouse
+1F400                                                  ; fully-qualified     # 
🐀 E1.0 rat
+1F439                                                  ; fully-qualified     # 
🐹 E0.6 hamster
+1F430                                                  ; fully-qualified     # 
🐰 E0.6 rabbit face
+1F407                                                  ; fully-qualified     # 
🐇 E1.0 rabbit
+1F43F FE0F                                             ; fully-qualified     # 
🐿️ E0.7 chipmunk
+1F43F                                                  ; unqualified         # 
🐿 E0.7 chipmunk
+1F9AB                                                  ; fully-qualified     # 
🦫 E13.0 beaver
+1F994                                                  ; fully-qualified     # 
🦔 E5.0 hedgehog
+1F987                                                  ; fully-qualified     # 
🦇 E3.0 bat
+1F43B                                                  ; fully-qualified     # 
🐻 E0.6 bear
+1F43B 200D 2744 FE0F                                   ; fully-qualified     # 
🐻‍❄️ E13.0 polar bear
+1F43B 200D 2744                                        ; minimally-qualified # 
🐻‍❄ E13.0 polar bear
+1F428                                                  ; fully-qualified     # 
🐨 E0.6 koala
+1F43C                                                  ; fully-qualified     # 
🐼 E0.6 panda
+1F9A5                                                  ; fully-qualified     # 
🦥 E12.0 sloth
+1F9A6                                                  ; fully-qualified     # 
🦦 E12.0 otter
+1F9A8                                                  ; fully-qualified     # 
🦨 E12.0 skunk
+1F998                                                  ; fully-qualified     # 
🦘 E11.0 kangaroo
+1F9A1                                                  ; fully-qualified     # 
🦡 E11.0 badger
+1F43E                                                  ; fully-qualified     # 
🐾 E0.6 paw prints
+
+# subgroup: animal-bird
+1F983                                                  ; fully-qualified     # 
🦃 E1.0 turkey
+1F414                                                  ; fully-qualified     # 
🐔 E0.6 chicken
+1F413                                                  ; fully-qualified     # 
🐓 E1.0 rooster
+1F423                                                  ; fully-qualified     # 
🐣 E0.6 hatching chick
+1F424                                                  ; fully-qualified     # 
🐤 E0.6 baby chick
+1F425                                                  ; fully-qualified     # 
🐥 E0.6 front-facing baby chick
+1F426                                                  ; fully-qualified     # 
🐦 E0.6 bird
+1F427                                                  ; fully-qualified     # 
🐧 E0.6 penguin
+1F54A FE0F                                             ; fully-qualified     # 
🕊️ E0.7 dove
+1F54A                                                  ; unqualified         # 
🕊 E0.7 dove
+1F985                                                  ; fully-qualified     # 
🦅 E3.0 eagle
+1F986                                                  ; fully-qualified     # 
🦆 E3.0 duck
+1F9A2                                                  ; fully-qualified     # 
🦢 E11.0 swan
+1F989                                                  ; fully-qualified     # 
🦉 E3.0 owl
+1F9A4                                                  ; fully-qualified     # 
🦤 E13.0 dodo
+1FAB6                                                  ; fully-qualified     # 
🪶 E13.0 feather
+1F9A9                                                  ; fully-qualified     # 
🦩 E12.0 flamingo
+1F99A                                                  ; fully-qualified     # 
🦚 E11.0 peacock
+1F99C                                                  ; fully-qualified     # 
🦜 E11.0 parrot
+
+# subgroup: animal-amphibian
+1F438                                                  ; fully-qualified     # 
🐸 E0.6 frog
+
+# subgroup: animal-reptile
+1F40A                                                  ; fully-qualified     # 
🐊 E1.0 crocodile
+1F422                                                  ; fully-qualified     # 
🐢 E0.6 turtle
+1F98E                                                  ; fully-qualified     # 
🦎 E3.0 lizard
+1F40D                                                  ; fully-qualified     # 
🐍 E0.6 snake
+1F432                                                  ; fully-qualified     # 
🐲 E0.6 dragon face
+1F409                                                  ; fully-qualified     # 
🐉 E1.0 dragon
+1F995                                                  ; fully-qualified     # 
🦕 E5.0 sauropod
+1F996                                                  ; fully-qualified     # 
🦖 E5.0 T-Rex
+
+# subgroup: animal-marine
+1F433                                                  ; fully-qualified     # 
🐳 E0.6 spouting whale
+1F40B                                                  ; fully-qualified     # 
🐋 E1.0 whale
+1F42C                                                  ; fully-qualified     # 
🐬 E0.6 dolphin
+1F9AD                                                  ; fully-qualified     # 
🦭 E13.0 seal
+1F41F                                                  ; fully-qualified     # 
🐟 E0.6 fish
+1F420                                                  ; fully-qualified     # 
🐠 E0.6 tropical fish
+1F421                                                  ; fully-qualified     # 
🐡 E0.6 blowfish
+1F988                                                  ; fully-qualified     # 
🦈 E3.0 shark
+1F419                                                  ; fully-qualified     # 
🐙 E0.6 octopus
+1F41A                                                  ; fully-qualified     # 
🐚 E0.6 spiral shell
+1FAB8                                                  ; fully-qualified     # 
🪸 E14.0 coral
+
+# subgroup: animal-bug
+1F40C                                                  ; fully-qualified     # 
🐌 E0.6 snail
+1F98B                                                  ; fully-qualified     # 
🦋 E3.0 butterfly
+1F41B                                                  ; fully-qualified     # 
🐛 E0.6 bug
+1F41C                                                  ; fully-qualified     # 
🐜 E0.6 ant
+1F41D                                                  ; fully-qualified     # 
🐝 E0.6 honeybee
+1FAB2                                                  ; fully-qualified     # 
🪲 E13.0 beetle
+1F41E                                                  ; fully-qualified     # 
🐞 E0.6 lady beetle
+1F997                                                  ; fully-qualified     # 
🦗 E5.0 cricket
+1FAB3                                                  ; fully-qualified     # 
🪳 E13.0 cockroach
+1F577 FE0F                                             ; fully-qualified     # 
🕷️ E0.7 spider
+1F577                                                  ; unqualified         # 
🕷 E0.7 spider
+1F578 FE0F                                             ; fully-qualified     # 
🕸️ E0.7 spider web
+1F578                                                  ; unqualified         # 
🕸 E0.7 spider web
+1F982                                                  ; fully-qualified     # 
🦂 E1.0 scorpion
+1F99F                                                  ; fully-qualified     # 
🦟 E11.0 mosquito
+1FAB0                                                  ; fully-qualified     # 
🪰 E13.0 fly
+1FAB1                                                  ; fully-qualified     # 
🪱 E13.0 worm
+1F9A0                                                  ; fully-qualified     # 
🦠 E11.0 microbe
+
+# subgroup: plant-flower
+1F490                                                  ; fully-qualified     # 
💐 E0.6 bouquet
+1F338                                                  ; fully-qualified     # 
🌸 E0.6 cherry blossom
+1F4AE                                                  ; fully-qualified     # 
💮 E0.6 white flower
+1FAB7                                                  ; fully-qualified     # 
🪷 E14.0 lotus
+1F3F5 FE0F                                             ; fully-qualified     # 
🏵️ E0.7 rosette
+1F3F5                                                  ; unqualified         # 
🏵 E0.7 rosette
+1F339                                                  ; fully-qualified     # 
🌹 E0.6 rose
+1F940                                                  ; fully-qualified     # 
🥀 E3.0 wilted flower
+1F33A                                                  ; fully-qualified     # 
🌺 E0.6 hibiscus
+1F33B                                                  ; fully-qualified     # 
🌻 E0.6 sunflower
+1F33C                                                  ; fully-qualified     # 
🌼 E0.6 blossom
+1F337                                                  ; fully-qualified     # 
🌷 E0.6 tulip
+
+# subgroup: plant-other
+1F331                                                  ; fully-qualified     # 
🌱 E0.6 seedling
+1FAB4                                                  ; fully-qualified     # 
🪴 E13.0 potted plant
+1F332                                                  ; fully-qualified     # 
🌲 E1.0 evergreen tree
+1F333                                                  ; fully-qualified     # 
🌳 E1.0 deciduous tree
+1F334                                                  ; fully-qualified     # 
🌴 E0.6 palm tree
+1F335                                                  ; fully-qualified     # 
🌵 E0.6 cactus
+1F33E                                                  ; fully-qualified     # 
🌾 E0.6 sheaf of rice
+1F33F                                                  ; fully-qualified     # 
🌿 E0.6 herb
+2618 FE0F                                              ; fully-qualified     # 
☘️ E1.0 shamrock
+2618                                                   ; unqualified         # 
☘ E1.0 shamrock
+1F340                                                  ; fully-qualified     # 
🍀 E0.6 four leaf clover
+1F341                                                  ; fully-qualified     # 
🍁 E0.6 maple leaf
+1F342                                                  ; fully-qualified     # 
🍂 E0.6 fallen leaf
+1F343                                                  ; fully-qualified     # 
🍃 E0.6 leaf fluttering in wind
+1FAB9                                                  ; fully-qualified     # 
🪹 E14.0 empty nest
+1FABA                                                  ; fully-qualified     # 
🪺 E14.0 nest with eggs
+
+# Animals & Nature subtotal:           151
+# Animals & Nature subtotal:           151     w/o modifiers
+
+# group: Food & Drink
+
+# subgroup: food-fruit
+1F347                                                  ; fully-qualified     # 
🍇 E0.6 grapes
+1F348                                                  ; fully-qualified     # 
🍈 E0.6 melon
+1F349                                                  ; fully-qualified     # 
🍉 E0.6 watermelon
+1F34A                                                  ; fully-qualified     # 
🍊 E0.6 tangerine
+1F34B                                                  ; fully-qualified     # 
🍋 E1.0 lemon
+1F34C                                                  ; fully-qualified     # 
🍌 E0.6 banana
+1F34D                                                  ; fully-qualified     # 
🍍 E0.6 pineapple
+1F96D                                                  ; fully-qualified     # 
🥭 E11.0 mango
+1F34E                                                  ; fully-qualified     # 
🍎 E0.6 red apple
+1F34F                                                  ; fully-qualified     # 
🍏 E0.6 green apple
+1F350                                                  ; fully-qualified     # 
🍐 E1.0 pear
+1F351                                                  ; fully-qualified     # 
🍑 E0.6 peach
+1F352                                                  ; fully-qualified     # 
🍒 E0.6 cherries
+1F353                                                  ; fully-qualified     # 
🍓 E0.6 strawberry
+1FAD0                                                  ; fully-qualified     # 
🫐 E13.0 blueberries
+1F95D                                                  ; fully-qualified     # 
🥝 E3.0 kiwi fruit
+1F345                                                  ; fully-qualified     # 
🍅 E0.6 tomato
+1FAD2                                                  ; fully-qualified     # 
🫒 E13.0 olive
+1F965                                                  ; fully-qualified     # 
🥥 E5.0 coconut
+
+# subgroup: food-vegetable
+1F951                                                  ; fully-qualified     # 
🥑 E3.0 avocado
+1F346                                                  ; fully-qualified     # 
🍆 E0.6 eggplant
+1F954                                                  ; fully-qualified     # 
🥔 E3.0 potato
+1F955                                                  ; fully-qualified     # 
🥕 E3.0 carrot
+1F33D                                                  ; fully-qualified     # 
🌽 E0.6 ear of corn
+1F336 FE0F                                             ; fully-qualified     # 
🌶️ E0.7 hot pepper
+1F336                                                  ; unqualified         # 
🌶 E0.7 hot pepper
+1FAD1                                                  ; fully-qualified     # 
🫑 E13.0 bell pepper
+1F952                                                  ; fully-qualified     # 
🥒 E3.0 cucumber
+1F96C                                                  ; fully-qualified     # 
🥬 E11.0 leafy green
+1F966                                                  ; fully-qualified     # 
🥦 E5.0 broccoli
+1F9C4                                                  ; fully-qualified     # 
🧄 E12.0 garlic
+1F9C5                                                  ; fully-qualified     # 
🧅 E12.0 onion
+1F344                                                  ; fully-qualified     # 
🍄 E0.6 mushroom
+1F95C                                                  ; fully-qualified     # 
🥜 E3.0 peanuts
+1FAD8                                                  ; fully-qualified     # 
🫘 E14.0 beans
+1F330                                                  ; fully-qualified     # 
🌰 E0.6 chestnut
+
+# subgroup: food-prepared
+1F35E                                                  ; fully-qualified     # 
🍞 E0.6 bread
+1F950                                                  ; fully-qualified     # 
🥐 E3.0 croissant
+1F956                                                  ; fully-qualified     # 
🥖 E3.0 baguette bread
+1FAD3                                                  ; fully-qualified     # 
🫓 E13.0 flatbread
+1F968                                                  ; fully-qualified     # 
🥨 E5.0 pretzel
+1F96F                                                  ; fully-qualified     # 
🥯 E11.0 bagel
+1F95E                                                  ; fully-qualified     # 
🥞 E3.0 pancakes
+1F9C7                                                  ; fully-qualified     # 
🧇 E12.0 waffle
+1F9C0                                                  ; fully-qualified     # 
🧀 E1.0 cheese wedge
+1F356                                                  ; fully-qualified     # 
🍖 E0.6 meat on bone
+1F357                                                  ; fully-qualified     # 
🍗 E0.6 poultry leg
+1F969                                                  ; fully-qualified     # 
🥩 E5.0 cut of meat
+1F953                                                  ; fully-qualified     # 
🥓 E3.0 bacon
+1F354                                                  ; fully-qualified     # 
🍔 E0.6 hamburger
+1F35F                                                  ; fully-qualified     # 
🍟 E0.6 french fries
+1F355                                                  ; fully-qualified     # 
🍕 E0.6 pizza
+1F32D                                                  ; fully-qualified     # 
🌭 E1.0 hot dog
+1F96A                                                  ; fully-qualified     # 
🥪 E5.0 sandwich
+1F32E                                                  ; fully-qualified     # 
🌮 E1.0 taco
+1F32F                                                  ; fully-qualified     # 
🌯 E1.0 burrito
+1FAD4                                                  ; fully-qualified     # 
🫔 E13.0 tamale
+1F959                                                  ; fully-qualified     # 
🥙 E3.0 stuffed flatbread
+1F9C6                                                  ; fully-qualified     # 
🧆 E12.0 falafel
+1F95A                                                  ; fully-qualified     # 
🥚 E3.0 egg
+1F373                                                  ; fully-qualified     # 
🍳 E0.6 cooking
+1F958                                                  ; fully-qualified     # 
🥘 E3.0 shallow pan of food
+1F372                                                  ; fully-qualified     # 
🍲 E0.6 pot of food
+1FAD5                                                  ; fully-qualified     # 
🫕 E13.0 fondue
+1F963                                                  ; fully-qualified     # 
🥣 E5.0 bowl with spoon
+1F957                                                  ; fully-qualified     # 
🥗 E3.0 green salad
+1F37F                                                  ; fully-qualified     # 
🍿 E1.0 popcorn
+1F9C8                                                  ; fully-qualified     # 
🧈 E12.0 butter
+1F9C2                                                  ; fully-qualified     # 
🧂 E11.0 salt
+1F96B                                                  ; fully-qualified     # 
🥫 E5.0 canned food
+
+# subgroup: food-asian
+1F371                                                  ; fully-qualified     # 
🍱 E0.6 bento box
+1F358                                                  ; fully-qualified     # 
🍘 E0.6 rice cracker
+1F359                                                  ; fully-qualified     # 
🍙 E0.6 rice ball
+1F35A                                                  ; fully-qualified     # 
🍚 E0.6 cooked rice
+1F35B                                                  ; fully-qualified     # 
🍛 E0.6 curry rice
+1F35C                                                  ; fully-qualified     # 
🍜 E0.6 steaming bowl
+1F35D                                                  ; fully-qualified     # 
🍝 E0.6 spaghetti
+1F360                                                  ; fully-qualified     # 
🍠 E0.6 roasted sweet potato
+1F362                                                  ; fully-qualified     # 
🍢 E0.6 oden
+1F363                                                  ; fully-qualified     # 
🍣 E0.6 sushi
+1F364                                                  ; fully-qualified     # 
🍤 E0.6 fried shrimp
+1F365                                                  ; fully-qualified     # 
🍥 E0.6 fish cake with swirl
+1F96E                                                  ; fully-qualified     # 
🥮 E11.0 moon cake
+1F361                                                  ; fully-qualified     # 
🍡 E0.6 dango
+1F95F                                                  ; fully-qualified     # 
🥟 E5.0 dumpling
+1F960                                                  ; fully-qualified     # 
🥠 E5.0 fortune cookie
+1F961                                                  ; fully-qualified     # 
🥡 E5.0 takeout box
+
+# subgroup: food-marine
+1F980                                                  ; fully-qualified     # 
🦀 E1.0 crab
+1F99E                                                  ; fully-qualified     # 
🦞 E11.0 lobster
+1F990                                                  ; fully-qualified     # 
🦐 E3.0 shrimp
+1F991                                                  ; fully-qualified     # 
🦑 E3.0 squid
+1F9AA                                                  ; fully-qualified     # 
🦪 E12.0 oyster
+
+# subgroup: food-sweet
+1F366                                                  ; fully-qualified     # 
🍦 E0.6 soft ice cream
+1F367                                                  ; fully-qualified     # 
🍧 E0.6 shaved ice
+1F368                                                  ; fully-qualified     # 
🍨 E0.6 ice cream
+1F369                                                  ; fully-qualified     # 
🍩 E0.6 doughnut
+1F36A                                                  ; fully-qualified     # 
🍪 E0.6 cookie
+1F382                                                  ; fully-qualified     # 
🎂 E0.6 birthday cake
+1F370                                                  ; fully-qualified     # 
🍰 E0.6 shortcake
+1F9C1                                                  ; fully-qualified     # 
🧁 E11.0 cupcake
+1F967                                                  ; fully-qualified     # 
🥧 E5.0 pie
+1F36B                                                  ; fully-qualified     # 
🍫 E0.6 chocolate bar
+1F36C                                                  ; fully-qualified     # 
🍬 E0.6 candy
+1F36D                                                  ; fully-qualified     # 
🍭 E0.6 lollipop
+1F36E                                                  ; fully-qualified     # 
🍮 E0.6 custard
+1F36F                                                  ; fully-qualified     # 
🍯 E0.6 honey pot
+
+# subgroup: drink
+1F37C                                                  ; fully-qualified     # 
🍼 E1.0 baby bottle
+1F95B                                                  ; fully-qualified     # 
🥛 E3.0 glass of milk
+2615                                                   ; fully-qualified     # 
☕ E0.6 hot beverage
+1FAD6                                                  ; fully-qualified     # 
🫖 E13.0 teapot
+1F375                                                  ; fully-qualified     # 
🍵 E0.6 teacup without handle
+1F376                                                  ; fully-qualified     # 
🍶 E0.6 sake
+1F37E                                                  ; fully-qualified     # 
🍾 E1.0 bottle with popping cork
+1F377                                                  ; fully-qualified     # 
🍷 E0.6 wine glass
+1F378                                                  ; fully-qualified     # 
🍸 E0.6 cocktail glass
+1F379                                                  ; fully-qualified     # 
🍹 E0.6 tropical drink
+1F37A                                                  ; fully-qualified     # 
🍺 E0.6 beer mug
+1F37B                                                  ; fully-qualified     # 
🍻 E0.6 clinking beer mugs
+1F942                                                  ; fully-qualified     # 
🥂 E3.0 clinking glasses
+1F943                                                  ; fully-qualified     # 
🥃 E3.0 tumbler glass
+1FAD7                                                  ; fully-qualified     # 
🫗 E14.0 pouring liquid
+1F964                                                  ; fully-qualified     # 
🥤 E5.0 cup with straw
+1F9CB                                                  ; fully-qualified     # 
🧋 E13.0 bubble tea
+1F9C3                                                  ; fully-qualified     # 
🧃 E12.0 beverage box
+1F9C9                                                  ; fully-qualified     # 
🧉 E12.0 mate
+1F9CA                                                  ; fully-qualified     # 
🧊 E12.0 ice
+
+# subgroup: dishware
+1F962                                                  ; fully-qualified     # 
🥢 E5.0 chopsticks
+1F37D FE0F                                             ; fully-qualified     # 
🍽️ E0.7 fork and knife with plate
+1F37D                                                  ; unqualified         # 
🍽 E0.7 fork and knife with plate
+1F374                                                  ; fully-qualified     # 
🍴 E0.6 fork and knife
+1F944                                                  ; fully-qualified     # 
🥄 E3.0 spoon
+1F52A                                                  ; fully-qualified     # 
🔪 E0.6 kitchen knife
+1FAD9                                                  ; fully-qualified     # 
🫙 E14.0 jar
+1F3FA                                                  ; fully-qualified     # 
🏺 E1.0 amphora
+
+# Food & Drink subtotal:               134
+# Food & Drink subtotal:               134     w/o modifiers
+
+# group: Travel & Places
+
+# subgroup: place-map
+1F30D                                                  ; fully-qualified     # 
🌍 E0.7 globe showing Europe-Africa
+1F30E                                                  ; fully-qualified     # 
🌎 E0.7 globe showing Americas
+1F30F                                                  ; fully-qualified     # 
🌏 E0.6 globe showing Asia-Australia
+1F310                                                  ; fully-qualified     # 
🌐 E1.0 globe with meridians
+1F5FA FE0F                                             ; fully-qualified     # 
🗺️ E0.7 world map
+1F5FA                                                  ; unqualified         # 
🗺 E0.7 world map
+1F5FE                                                  ; fully-qualified     # 
🗾 E0.6 map of Japan
+1F9ED                                                  ; fully-qualified     # 
🧭 E11.0 compass
+
+# subgroup: place-geographic
+1F3D4 FE0F                                             ; fully-qualified     # 
🏔️ E0.7 snow-capped mountain
+1F3D4                                                  ; unqualified         # 
🏔 E0.7 snow-capped mountain
+26F0 FE0F                                              ; fully-qualified     # 
⛰️ E0.7 mountain
+26F0                                                   ; unqualified         # 
⛰ E0.7 mountain
+1F30B                                                  ; fully-qualified     # 
🌋 E0.6 volcano
+1F5FB                                                  ; fully-qualified     # 
🗻 E0.6 mount fuji
+1F3D5 FE0F                                             ; fully-qualified     # 
🏕️ E0.7 camping
+1F3D5                                                  ; unqualified         # 
🏕 E0.7 camping
+1F3D6 FE0F                                             ; fully-qualified     # 
🏖️ E0.7 beach with umbrella
+1F3D6                                                  ; unqualified         # 
🏖 E0.7 beach with umbrella
+1F3DC FE0F                                             ; fully-qualified     # 
🏜️ E0.7 desert
+1F3DC                                                  ; unqualified         # 
🏜 E0.7 desert
+1F3DD FE0F                                             ; fully-qualified     # 
🏝️ E0.7 desert island
+1F3DD                                                  ; unqualified         # 
🏝 E0.7 desert island
+1F3DE FE0F                                             ; fully-qualified     # 
🏞️ E0.7 national park
+1F3DE                                                  ; unqualified         # 
🏞 E0.7 national park
+
+# subgroup: place-building
+1F3DF FE0F                                             ; fully-qualified     # 
🏟️ E0.7 stadium
+1F3DF                                                  ; unqualified         # 
🏟 E0.7 stadium
+1F3DB FE0F                                             ; fully-qualified     # 
🏛️ E0.7 classical building
+1F3DB                                                  ; unqualified         # 
🏛 E0.7 classical building
+1F3D7 FE0F                                             ; fully-qualified     # 
🏗️ E0.7 building construction
+1F3D7                                                  ; unqualified         # 
🏗 E0.7 building construction
+1F9F1                                                  ; fully-qualified     # 
🧱 E11.0 brick
+1FAA8                                                  ; fully-qualified     # 
🪨 E13.0 rock
+1FAB5                                                  ; fully-qualified     # 
🪵 E13.0 wood
+1F6D6                                                  ; fully-qualified     # 
🛖 E13.0 hut
+1F3D8 FE0F                                             ; fully-qualified     # 
🏘️ E0.7 houses
+1F3D8                                                  ; unqualified         # 
🏘 E0.7 houses
+1F3DA FE0F                                             ; fully-qualified     # 
🏚️ E0.7 derelict house
+1F3DA                                                  ; unqualified         # 
🏚 E0.7 derelict house
+1F3E0                                                  ; fully-qualified     # 
🏠 E0.6 house
+1F3E1                                                  ; fully-qualified     # 
🏡 E0.6 house with garden
+1F3E2                                                  ; fully-qualified     # 
🏢 E0.6 office building
+1F3E3                                                  ; fully-qualified     # 
🏣 E0.6 Japanese post office
+1F3E4                                                  ; fully-qualified     # 
🏤 E1.0 post office
+1F3E5                                                  ; fully-qualified     # 
🏥 E0.6 hospital
+1F3E6                                                  ; fully-qualified     # 
🏦 E0.6 bank
+1F3E8                                                  ; fully-qualified     # 
🏨 E0.6 hotel
+1F3E9                                                  ; fully-qualified     # 
🏩 E0.6 love hotel
+1F3EA                                                  ; fully-qualified     # 
🏪 E0.6 convenience store
+1F3EB                                                  ; fully-qualified     # 
🏫 E0.6 school
+1F3EC                                                  ; fully-qualified     # 
🏬 E0.6 department store
+1F3ED                                                  ; fully-qualified     # 
🏭 E0.6 factory
+1F3EF                                                  ; fully-qualified     # 
🏯 E0.6 Japanese castle
+1F3F0                                                  ; fully-qualified     # 
🏰 E0.6 castle
+1F492                                                  ; fully-qualified     # 
💒 E0.6 wedding
+1F5FC                                                  ; fully-qualified     # 
🗼 E0.6 Tokyo tower
+1F5FD                                                  ; fully-qualified     # 
🗽 E0.6 Statue of Liberty
+
+# subgroup: place-religious
+26EA                                                   ; fully-qualified     # 
⛪ E0.6 church
+1F54C                                                  ; fully-qualified     # 
🕌 E1.0 mosque
+1F6D5                                                  ; fully-qualified     # 
🛕 E12.0 hindu temple
+1F54D                                                  ; fully-qualified     # 
🕍 E1.0 synagogue
+26E9 FE0F                                              ; fully-qualified     # 
⛩️ E0.7 shinto shrine
+26E9                                                   ; unqualified         # 
⛩ E0.7 shinto shrine
+1F54B                                                  ; fully-qualified     # 
🕋 E1.0 kaaba
+
+# subgroup: place-other
+26F2                                                   ; fully-qualified     # 
⛲ E0.6 fountain
+26FA                                                   ; fully-qualified     # 
⛺ E0.6 tent
+1F301                                                  ; fully-qualified     # 
🌁 E0.6 foggy
+1F303                                                  ; fully-qualified     # 
🌃 E0.6 night with stars
+1F3D9 FE0F                                             ; fully-qualified     # 
🏙️ E0.7 cityscape
+1F3D9                                                  ; unqualified         # 
🏙 E0.7 cityscape
+1F304                                                  ; fully-qualified     # 
🌄 E0.6 sunrise over mountains
+1F305                                                  ; fully-qualified     # 
🌅 E0.6 sunrise
+1F306                                                  ; fully-qualified     # 
🌆 E0.6 cityscape at dusk
+1F307                                                  ; fully-qualified     # 
🌇 E0.6 sunset
+1F309                                                  ; fully-qualified     # 
🌉 E0.6 bridge at night
+2668 FE0F                                              ; fully-qualified     # 
♨️ E0.6 hot springs
+2668                                                   ; unqualified         # 
♨ E0.6 hot springs
+1F3A0                                                  ; fully-qualified     # 
🎠 E0.6 carousel horse
+1F6DD                                                  ; fully-qualified     # 
🛝 E14.0 playground slide
+1F3A1                                                  ; fully-qualified     # 
🎡 E0.6 ferris wheel
+1F3A2                                                  ; fully-qualified     # 
🎢 E0.6 roller coaster
+1F488                                                  ; fully-qualified     # 
💈 E0.6 barber pole
+1F3AA                                                  ; fully-qualified     # 
🎪 E0.6 circus tent
+
+# subgroup: transport-ground
+1F682                                                  ; fully-qualified     # 
🚂 E1.0 locomotive
+1F683                                                  ; fully-qualified     # 
🚃 E0.6 railway car
+1F684                                                  ; fully-qualified     # 
🚄 E0.6 high-speed train
+1F685                                                  ; fully-qualified     # 
🚅 E0.6 bullet train
+1F686                                                  ; fully-qualified     # 
🚆 E1.0 train
+1F687                                                  ; fully-qualified     # 
🚇 E0.6 metro
+1F688                                                  ; fully-qualified     # 
🚈 E1.0 light rail
+1F689                                                  ; fully-qualified     # 
🚉 E0.6 station
+1F68A                                                  ; fully-qualified     # 
🚊 E1.0 tram
+1F69D                                                  ; fully-qualified     # 
🚝 E1.0 monorail
+1F69E                                                  ; fully-qualified     # 
🚞 E1.0 mountain railway
+1F68B                                                  ; fully-qualified     # 
🚋 E1.0 tram car
+1F68C                                                  ; fully-qualified     # 
🚌 E0.6 bus
+1F68D                                                  ; fully-qualified     # 
🚍 E0.7 oncoming bus
+1F68E                                                  ; fully-qualified     # 
🚎 E1.0 trolleybus
+1F690                                                  ; fully-qualified     # 
🚐 E1.0 minibus
+1F691                                                  ; fully-qualified     # 
🚑 E0.6 ambulance
+1F692                                                  ; fully-qualified     # 
🚒 E0.6 fire engine
+1F693                                                  ; fully-qualified     # 
🚓 E0.6 police car
+1F694                                                  ; fully-qualified     # 
🚔 E0.7 oncoming police car
+1F695                                                  ; fully-qualified     # 
🚕 E0.6 taxi
+1F696                                                  ; fully-qualified     # 
🚖 E1.0 oncoming taxi
+1F697                                                  ; fully-qualified     # 
🚗 E0.6 automobile
+1F698                                                  ; fully-qualified     # 
🚘 E0.7 oncoming automobile
+1F699                                                  ; fully-qualified     # 
🚙 E0.6 sport utility vehicle
+1F6FB                                                  ; fully-qualified     # 
🛻 E13.0 pickup truck
+1F69A                                                  ; fully-qualified     # 
🚚 E0.6 delivery truck
+1F69B                                                  ; fully-qualified     # 
🚛 E1.0 articulated lorry
+1F69C                                                  ; fully-qualified     # 
🚜 E1.0 tractor
+1F3CE FE0F                                             ; fully-qualified     # 
🏎️ E0.7 racing car
+1F3CE                                                  ; unqualified         # 
🏎 E0.7 racing car
+1F3CD FE0F                                             ; fully-qualified     # 
🏍️ E0.7 motorcycle
+1F3CD                                                  ; unqualified         # 
🏍 E0.7 motorcycle
+1F6F5                                                  ; fully-qualified     # 
🛵 E3.0 motor scooter
+1F9BD                                                  ; fully-qualified     # 
🦽 E12.0 manual wheelchair
+1F9BC                                                  ; fully-qualified     # 
🦼 E12.0 motorized wheelchair
+1F6FA                                                  ; fully-qualified     # 
🛺 E12.0 auto rickshaw
+1F6B2                                                  ; fully-qualified     # 
🚲 E0.6 bicycle
+1F6F4                                                  ; fully-qualified     # 
🛴 E3.0 kick scooter
+1F6F9                                                  ; fully-qualified     # 
🛹 E11.0 skateboard
+1F6FC                                                  ; fully-qualified     # 
🛼 E13.0 roller skate
+1F68F                                                  ; fully-qualified     # 
🚏 E0.6 bus stop
+1F6E3 FE0F                                             ; fully-qualified     # 
🛣️ E0.7 motorway
+1F6E3                                                  ; unqualified         # 
🛣 E0.7 motorway
+1F6E4 FE0F                                             ; fully-qualified     # 
🛤️ E0.7 railway track
+1F6E4                                                  ; unqualified         # 
🛤 E0.7 railway track
+1F6E2 FE0F                                             ; fully-qualified     # 
🛢️ E0.7 oil drum
+1F6E2                                                  ; unqualified         # 
🛢 E0.7 oil drum
+26FD                                                   ; fully-qualified     # 
⛽ E0.6 fuel pump
+1F6DE                                                  ; fully-qualified     # 
🛞 E14.0 wheel
+1F6A8                                                  ; fully-qualified     # 
🚨 E0.6 police car light
+1F6A5                                                  ; fully-qualified     # 
🚥 E0.6 horizontal traffic light
+1F6A6                                                  ; fully-qualified     # 
🚦 E1.0 vertical traffic light
+1F6D1                                                  ; fully-qualified     # 
🛑 E3.0 stop sign
+1F6A7                                                  ; fully-qualified     # 
🚧 E0.6 construction
+
+# subgroup: transport-water
+2693                                                   ; fully-qualified     # 
⚓ E0.6 anchor
+1F6DF                                                  ; fully-qualified     # 
🛟 E14.0 ring buoy
+26F5                                                   ; fully-qualified     # 
⛵ E0.6 sailboat
+1F6F6                                                  ; fully-qualified     # 
🛶 E3.0 canoe
+1F6A4                                                  ; fully-qualified     # 
🚤 E0.6 speedboat
+1F6F3 FE0F                                             ; fully-qualified     # 
🛳️ E0.7 passenger ship
+1F6F3                                                  ; unqualified         # 
🛳 E0.7 passenger ship
+26F4 FE0F                                              ; fully-qualified     # 
⛴️ E0.7 ferry
+26F4                                                   ; unqualified         # 
⛴ E0.7 ferry
+1F6E5 FE0F                                             ; fully-qualified     # 
🛥️ E0.7 motor boat
+1F6E5                                                  ; unqualified         # 
🛥 E0.7 motor boat
+1F6A2                                                  ; fully-qualified     # 
🚢 E0.6 ship
+
+# subgroup: transport-air
+2708 FE0F                                              ; fully-qualified     # 
✈️ E0.6 airplane
+2708                                                   ; unqualified         # 
✈ E0.6 airplane
+1F6E9 FE0F                                             ; fully-qualified     # 
🛩️ E0.7 small airplane
+1F6E9                                                  ; unqualified         # 
🛩 E0.7 small airplane
+1F6EB                                                  ; fully-qualified     # 
🛫 E1.0 airplane departure
+1F6EC                                                  ; fully-qualified     # 
🛬 E1.0 airplane arrival
+1FA82                                                  ; fully-qualified     # 
🪂 E12.0 parachute
+1F4BA                                                  ; fully-qualified     # 
💺 E0.6 seat
+1F681                                                  ; fully-qualified     # 
🚁 E1.0 helicopter
+1F69F                                                  ; fully-qualified     # 
🚟 E1.0 suspension railway
+1F6A0                                                  ; fully-qualified     # 
🚠 E1.0 mountain cableway
+1F6A1                                                  ; fully-qualified     # 
🚡 E1.0 aerial tramway
+1F6F0 FE0F                                             ; fully-qualified     # 
🛰️ E0.7 satellite
+1F6F0                                                  ; unqualified         # 
🛰 E0.7 satellite
+1F680                                                  ; fully-qualified     # 
🚀 E0.6 rocket
+1F6F8                                                  ; fully-qualified     # 
🛸 E5.0 flying saucer
+
+# subgroup: hotel
+1F6CE FE0F                                             ; fully-qualified     # 
🛎️ E0.7 bellhop bell
+1F6CE                                                  ; unqualified         # 
🛎 E0.7 bellhop bell
+1F9F3                                                  ; fully-qualified     # 
🧳 E11.0 luggage
+
+# subgroup: time
+231B                                                   ; fully-qualified     # 
⌛ E0.6 hourglass done
+23F3                                                   ; fully-qualified     # 
⏳ E0.6 hourglass not done
+231A                                                   ; fully-qualified     # 
⌚ E0.6 watch
+23F0                                                   ; fully-qualified     # 
⏰ E0.6 alarm clock
+23F1 FE0F                                              ; fully-qualified     # 
⏱️ E1.0 stopwatch
+23F1                                                   ; unqualified         # 
⏱ E1.0 stopwatch
+23F2 FE0F                                              ; fully-qualified     # 
⏲️ E1.0 timer clock
+23F2                                                   ; unqualified         # 
⏲ E1.0 timer clock
+1F570 FE0F                                             ; fully-qualified     # 
🕰️ E0.7 mantelpiece clock
+1F570                                                  ; unqualified         # 
🕰 E0.7 mantelpiece clock
+1F55B                                                  ; fully-qualified     # 
🕛 E0.6 twelve o’clock
+1F567                                                  ; fully-qualified     # 
🕧 E0.7 twelve-thirty
+1F550                                                  ; fully-qualified     # 
🕐 E0.6 one o’clock
+1F55C                                                  ; fully-qualified     # 
🕜 E0.7 one-thirty
+1F551                                                  ; fully-qualified     # 
🕑 E0.6 two o’clock
+1F55D                                                  ; fully-qualified     # 
🕝 E0.7 two-thirty
+1F552                                                  ; fully-qualified     # 
🕒 E0.6 three o’clock
+1F55E                                                  ; fully-qualified     # 
🕞 E0.7 three-thirty
+1F553                                                  ; fully-qualified     # 
🕓 E0.6 four o’clock
+1F55F                                                  ; fully-qualified     # 
🕟 E0.7 four-thirty
+1F554                                                  ; fully-qualified     # 
🕔 E0.6 five o’clock
+1F560                                                  ; fully-qualified     # 
🕠 E0.7 five-thirty
+1F555                                                  ; fully-qualified     # 
🕕 E0.6 six o’clock
+1F561                                                  ; fully-qualified     # 
🕡 E0.7 six-thirty
+1F556                                                  ; fully-qualified     # 
🕖 E0.6 seven o’clock
+1F562                                                  ; fully-qualified     # 
🕢 E0.7 seven-thirty
+1F557                                                  ; fully-qualified     # 
🕗 E0.6 eight o’clock
+1F563                                                  ; fully-qualified     # 
🕣 E0.7 eight-thirty
+1F558                                                  ; fully-qualified     # 
🕘 E0.6 nine o’clock
+1F564                                                  ; fully-qualified     # 
🕤 E0.7 nine-thirty
+1F559                                                  ; fully-qualified     # 
🕙 E0.6 ten o’clock
+1F565                                                  ; fully-qualified     # 
🕥 E0.7 ten-thirty
+1F55A                                                  ; fully-qualified     # 
🕚 E0.6 eleven o’clock
+1F566                                                  ; fully-qualified     # 
🕦 E0.7 eleven-thirty
+
+# subgroup: sky & weather
+1F311                                                  ; fully-qualified     # 
🌑 E0.6 new moon
+1F312                                                  ; fully-qualified     # 
🌒 E1.0 waxing crescent moon
+1F313                                                  ; fully-qualified     # 
🌓 E0.6 first quarter moon
+1F314                                                  ; fully-qualified     # 
🌔 E0.6 waxing gibbous moon
+1F315                                                  ; fully-qualified     # 
🌕 E0.6 full moon
+1F316                                                  ; fully-qualified     # 
🌖 E1.0 waning gibbous moon
+1F317                                                  ; fully-qualified     # 
🌗 E1.0 last quarter moon
+1F318                                                  ; fully-qualified     # 
🌘 E1.0 waning crescent moon
+1F319                                                  ; fully-qualified     # 
🌙 E0.6 crescent moon
+1F31A                                                  ; fully-qualified     # 
🌚 E1.0 new moon face
+1F31B                                                  ; fully-qualified     # 
🌛 E0.6 first quarter moon face
+1F31C                                                  ; fully-qualified     # 
🌜 E0.7 last quarter moon face
+1F321 FE0F                                             ; fully-qualified     # 
🌡️ E0.7 thermometer
+1F321                                                  ; unqualified         # 
🌡 E0.7 thermometer
+2600 FE0F                                              ; fully-qualified     # 
☀️ E0.6 sun
+2600                                                   ; unqualified         # 
☀ E0.6 sun
+1F31D                                                  ; fully-qualified     # 
🌝 E1.0 full moon face
+1F31E                                                  ; fully-qualified     # 
🌞 E1.0 sun with face
+1FA90                                                  ; fully-qualified     # 
🪐 E12.0 ringed planet
+2B50                                                   ; fully-qualified     # 
⭐ E0.6 star
+1F31F                                                  ; fully-qualified     # 
🌟 E0.6 glowing star
+1F320                                                  ; fully-qualified     # 
🌠 E0.6 shooting star
+1F30C                                                  ; fully-qualified     # 
🌌 E0.6 milky way
+2601 FE0F                                              ; fully-qualified     # 
☁️ E0.6 cloud
+2601                                                   ; unqualified         # 
☁ E0.6 cloud
+26C5                                                   ; fully-qualified     # 
⛅ E0.6 sun behind cloud
+26C8 FE0F                                              ; fully-qualified     # 
⛈️ E0.7 cloud with lightning and rain
+26C8                                                   ; unqualified         # 
⛈ E0.7 cloud with lightning and rain
+1F324 FE0F                                             ; fully-qualified     # 
🌤️ E0.7 sun behind small cloud
+1F324                                                  ; unqualified         # 
🌤 E0.7 sun behind small cloud
+1F325 FE0F                                             ; fully-qualified     # 
🌥️ E0.7 sun behind large cloud
+1F325                                                  ; unqualified         # 
🌥 E0.7 sun behind large cloud
+1F326 FE0F                                             ; fully-qualified     # 
🌦️ E0.7 sun behind rain cloud
+1F326                                                  ; unqualified         # 
🌦 E0.7 sun behind rain cloud
+1F327 FE0F                                             ; fully-qualified     # 
🌧️ E0.7 cloud with rain
+1F327                                                  ; unqualified         # 
🌧 E0.7 cloud with rain
+1F328 FE0F                                             ; fully-qualified     # 
🌨️ E0.7 cloud with snow
+1F328                                                  ; unqualified         # 
🌨 E0.7 cloud with snow
+1F329 FE0F                                             ; fully-qualified     # 
🌩️ E0.7 cloud with lightning
+1F329                                                  ; unqualified         # 
🌩 E0.7 cloud with lightning
+1F32A FE0F                                             ; fully-qualified     # 
🌪️ E0.7 tornado
+1F32A                                                  ; unqualified         # 
🌪 E0.7 tornado
+1F32B FE0F                                             ; fully-qualified     # 
🌫️ E0.7 fog
+1F32B                                                  ; unqualified         # 
🌫 E0.7 fog
+1F32C FE0F                                             ; fully-qualified     # 
🌬️ E0.7 wind face
+1F32C                                                  ; unqualified         # 
🌬 E0.7 wind face
+1F300                                                  ; fully-qualified     # 
🌀 E0.6 cyclone
+1F308                                                  ; fully-qualified     # 
🌈 E0.6 rainbow
+1F302                                                  ; fully-qualified     # 
🌂 E0.6 closed umbrella
+2602 FE0F                                              ; fully-qualified     # 
☂️ E0.7 umbrella
+2602                                                   ; unqualified         # 
☂ E0.7 umbrella
+2614                                                   ; fully-qualified     # 
☔ E0.6 umbrella with rain drops
+26F1 FE0F                                              ; fully-qualified     # 
⛱️ E0.7 umbrella on ground
+26F1                                                   ; unqualified         # 
⛱ E0.7 umbrella on ground
+26A1                                                   ; fully-qualified     # 
⚡ E0.6 high voltage
+2744 FE0F                                              ; fully-qualified     # 
❄️ E0.6 snowflake
+2744                                                   ; unqualified         # 
❄ E0.6 snowflake
+2603 FE0F                                              ; fully-qualified     # 
☃️ E0.7 snowman
+2603                                                   ; unqualified         # 
☃ E0.7 snowman
+26C4                                                   ; fully-qualified     # 
⛄ E0.6 snowman without snow
+2604 FE0F                                              ; fully-qualified     # 
☄️ E1.0 comet
+2604                                                   ; unqualified         # 
☄ E1.0 comet
+1F525                                                  ; fully-qualified     # 
🔥 E0.6 fire
+1F4A7                                                  ; fully-qualified     # 
💧 E0.6 droplet
+1F30A                                                  ; fully-qualified     # 
🌊 E0.6 water wave
+
+# Travel & Places subtotal:            267
+# Travel & Places subtotal:            267     w/o modifiers
+
+# group: Activities
+
+# subgroup: event
+1F383                                                  ; fully-qualified     # 
🎃 E0.6 jack-o-lantern
+1F384                                                  ; fully-qualified     # 
🎄 E0.6 Christmas tree
+1F386                                                  ; fully-qualified     # 
🎆 E0.6 fireworks
+1F387                                                  ; fully-qualified     # 
🎇 E0.6 sparkler
+1F9E8                                                  ; fully-qualified     # 
🧨 E11.0 firecracker
+2728                                                   ; fully-qualified     # 
✨ E0.6 sparkles
+1F388                                                  ; fully-qualified     # 
🎈 E0.6 balloon
+1F389                                                  ; fully-qualified     # 
🎉 E0.6 party popper
+1F38A                                                  ; fully-qualified     # 
🎊 E0.6 confetti ball
+1F38B                                                  ; fully-qualified     # 
🎋 E0.6 tanabata tree
+1F38D                                                  ; fully-qualified     # 
🎍 E0.6 pine decoration
+1F38E                                                  ; fully-qualified     # 
🎎 E0.6 Japanese dolls
+1F38F                                                  ; fully-qualified     # 
🎏 E0.6 carp streamer
+1F390                                                  ; fully-qualified     # 
🎐 E0.6 wind chime
+1F391                                                  ; fully-qualified     # 
🎑 E0.6 moon viewing ceremony
+1F9E7                                                  ; fully-qualified     # 
🧧 E11.0 red envelope
+1F380                                                  ; fully-qualified     # 
🎀 E0.6 ribbon
+1F381                                                  ; fully-qualified     # 
🎁 E0.6 wrapped gift
+1F397 FE0F                                             ; fully-qualified     # 
🎗️ E0.7 reminder ribbon
+1F397                                                  ; unqualified         # 
🎗 E0.7 reminder ribbon
+1F39F FE0F                                             ; fully-qualified     # 
🎟️ E0.7 admission tickets
+1F39F                                                  ; unqualified         # 
🎟 E0.7 admission tickets
+1F3AB                                                  ; fully-qualified     # 
🎫 E0.6 ticket
+
+# subgroup: award-medal
+1F396 FE0F                                             ; fully-qualified     # 
🎖️ E0.7 military medal
+1F396                                                  ; unqualified         # 
🎖 E0.7 military medal
+1F3C6                                                  ; fully-qualified     # 
🏆 E0.6 trophy
+1F3C5                                                  ; fully-qualified     # 
🏅 E1.0 sports medal
+1F947                                                  ; fully-qualified     # 
🥇 E3.0 1st place medal
+1F948                                                  ; fully-qualified     # 
🥈 E3.0 2nd place medal
+1F949                                                  ; fully-qualified     # 
🥉 E3.0 3rd place medal
+
+# subgroup: sport
+26BD                                                   ; fully-qualified     # 
⚽ E0.6 soccer ball
+26BE                                                   ; fully-qualified     # 
⚾ E0.6 baseball
+1F94E                                                  ; fully-qualified     # 
🥎 E11.0 softball
+1F3C0                                                  ; fully-qualified     # 
🏀 E0.6 basketball
+1F3D0                                                  ; fully-qualified     # 
🏐 E1.0 volleyball
+1F3C8                                                  ; fully-qualified     # 
🏈 E0.6 american football
+1F3C9                                                  ; fully-qualified     # 
🏉 E1.0 rugby football
+1F3BE                                                  ; fully-qualified     # 
🎾 E0.6 tennis
+1F94F                                                  ; fully-qualified     # 
🥏 E11.0 flying disc
+1F3B3                                                  ; fully-qualified     # 
🎳 E0.6 bowling
+1F3CF                                                  ; fully-qualified     # 
🏏 E1.0 cricket game
+1F3D1                                                  ; fully-qualified     # 
🏑 E1.0 field hockey
+1F3D2                                                  ; fully-qualified     # 
🏒 E1.0 ice hockey
+1F94D                                                  ; fully-qualified     # 
🥍 E11.0 lacrosse
+1F3D3                                                  ; fully-qualified     # 
🏓 E1.0 ping pong
+1F3F8                                                  ; fully-qualified     # 
🏸 E1.0 badminton
+1F94A                                                  ; fully-qualified     # 
🥊 E3.0 boxing glove
+1F94B                                                  ; fully-qualified     # 
🥋 E3.0 martial arts uniform
+1F945                                                  ; fully-qualified     # 
🥅 E3.0 goal net
+26F3                                                   ; fully-qualified     # 
⛳ E0.6 flag in hole
+26F8 FE0F                                              ; fully-qualified     # 
⛸️ E0.7 ice skate
+26F8                                                   ; unqualified         # 
⛸ E0.7 ice skate
+1F3A3                                                  ; fully-qualified     # 
🎣 E0.6 fishing pole
+1F93F                                                  ; fully-qualified     # 
🤿 E12.0 diving mask
+1F3BD                                                  ; fully-qualified     # 
🎽 E0.6 running shirt
+1F3BF                                                  ; fully-qualified     # 
🎿 E0.6 skis
+1F6F7                                                  ; fully-qualified     # 
🛷 E5.0 sled
+1F94C                                                  ; fully-qualified     # 
🥌 E5.0 curling stone
+
+# subgroup: game
+1F3AF                                                  ; fully-qualified     # 
🎯 E0.6 bullseye
+1FA80                                                  ; fully-qualified     # 
🪀 E12.0 yo-yo
+1FA81                                                  ; fully-qualified     # 
🪁 E12.0 kite
+1F3B1                                                  ; fully-qualified     # 
🎱 E0.6 pool 8 ball
+1F52E                                                  ; fully-qualified     # 
🔮 E0.6 crystal ball
+1FA84                                                  ; fully-qualified     # 
🪄 E13.0 magic wand
+1F9FF                                                  ; fully-qualified     # 
🧿 E11.0 nazar amulet
+1FAAC                                                  ; fully-qualified     # 
🪬 E14.0 hamsa
+1F3AE                                                  ; fully-qualified     # 
🎮 E0.6 video game
+1F579 FE0F                                             ; fully-qualified     # 
🕹️ E0.7 joystick
+1F579                                                  ; unqualified         # 
🕹 E0.7 joystick
+1F3B0                                                  ; fully-qualified     # 
🎰 E0.6 slot machine
+1F3B2                                                  ; fully-qualified     # 
🎲 E0.6 game die
+1F9E9                                                  ; fully-qualified     # 
🧩 E11.0 puzzle piece
+1F9F8                                                  ; fully-qualified     # 
🧸 E11.0 teddy bear
+1FA85                                                  ; fully-qualified     # 
🪅 E13.0 piñata
+1FAA9                                                  ; fully-qualified     # 
🪩 E14.0 mirror ball
+1FA86                                                  ; fully-qualified     # 
🪆 E13.0 nesting dolls
+2660 FE0F                                              ; fully-qualified     # 
♠️ E0.6 spade suit
+2660                                                   ; unqualified         # 
♠ E0.6 spade suit
+2665 FE0F                                              ; fully-qualified     # 
♥️ E0.6 heart suit
+2665                                                   ; unqualified         # 
♥ E0.6 heart suit
+2666 FE0F                                              ; fully-qualified     # 
♦️ E0.6 diamond suit
+2666                                                   ; unqualified         # 
♦ E0.6 diamond suit
+2663 FE0F                                              ; fully-qualified     # 
♣️ E0.6 club suit
+2663                                                   ; unqualified         # 
♣ E0.6 club suit
+265F FE0F                                              ; fully-qualified     # 
♟️ E11.0 chess pawn
+265F                                                   ; unqualified         # 
♟ E11.0 chess pawn
+1F0CF                                                  ; fully-qualified     # 
🃏 E0.6 joker
+1F004                                                  ; fully-qualified     # 
🀄 E0.6 mahjong red dragon
+1F3B4                                                  ; fully-qualified     # 
🎴 E0.6 flower playing cards
+
+# subgroup: arts & crafts
+1F3AD                                                  ; fully-qualified     # 
🎭 E0.6 performing arts
+1F5BC FE0F                                             ; fully-qualified     # 
🖼️ E0.7 framed picture
+1F5BC                                                  ; unqualified         # 
🖼 E0.7 framed picture
+1F3A8                                                  ; fully-qualified     # 
🎨 E0.6 artist palette
+1F9F5                                                  ; fully-qualified     # 
🧵 E11.0 thread
+1FAA1                                                  ; fully-qualified     # 
🪡 E13.0 sewing needle
+1F9F6                                                  ; fully-qualified     # 
🧶 E11.0 yarn
+1FAA2                                                  ; fully-qualified     # 
🪢 E13.0 knot
+
+# Activities subtotal:         97
+# Activities subtotal:         97      w/o modifiers
+
+# group: Objects
+
+# subgroup: clothing
+1F453                                                  ; fully-qualified     # 
👓 E0.6 glasses
+1F576 FE0F                                             ; fully-qualified     # 
🕶️ E0.7 sunglasses
+1F576                                                  ; unqualified         # 
🕶 E0.7 sunglasses
+1F97D                                                  ; fully-qualified     # 
🥽 E11.0 goggles
+1F97C                                                  ; fully-qualified     # 
🥼 E11.0 lab coat
+1F9BA                                                  ; fully-qualified     # 
🦺 E12.0 safety vest
+1F454                                                  ; fully-qualified     # 
👔 E0.6 necktie
+1F455                                                  ; fully-qualified     # 
👕 E0.6 t-shirt
+1F456                                                  ; fully-qualified     # 
👖 E0.6 jeans
+1F9E3                                                  ; fully-qualified     # 
🧣 E5.0 scarf
+1F9E4                                                  ; fully-qualified     # 
🧤 E5.0 gloves
+1F9E5                                                  ; fully-qualified     # 
🧥 E5.0 coat
+1F9E6                                                  ; fully-qualified     # 
🧦 E5.0 socks
+1F457                                                  ; fully-qualified     # 
👗 E0.6 dress
+1F458                                                  ; fully-qualified     # 
👘 E0.6 kimono
+1F97B                                                  ; fully-qualified     # 
🥻 E12.0 sari
+1FA71                                                  ; fully-qualified     # 
🩱 E12.0 one-piece swimsuit
+1FA72                                                  ; fully-qualified     # 
🩲 E12.0 briefs
+1FA73                                                  ; fully-qualified     # 
🩳 E12.0 shorts
+1F459                                                  ; fully-qualified     # 
👙 E0.6 bikini
+1F45A                                                  ; fully-qualified     # 
👚 E0.6 woman’s clothes
+1F45B                                                  ; fully-qualified     # 
👛 E0.6 purse
+1F45C                                                  ; fully-qualified     # 
👜 E0.6 handbag
+1F45D                                                  ; fully-qualified     # 
👝 E0.6 clutch bag
+1F6CD FE0F                                             ; fully-qualified     # 
🛍️ E0.7 shopping bags
+1F6CD                                                  ; unqualified         # 
🛍 E0.7 shopping bags
+1F392                                                  ; fully-qualified     # 
🎒 E0.6 backpack
+1FA74                                                  ; fully-qualified     # 
🩴 E13.0 thong sandal
+1F45E                                                  ; fully-qualified     # 
👞 E0.6 man’s shoe
+1F45F                                                  ; fully-qualified     # 
👟 E0.6 running shoe
+1F97E                                                  ; fully-qualified     # 
🥾 E11.0 hiking boot
+1F97F                                                  ; fully-qualified     # 
🥿 E11.0 flat shoe
+1F460                                                  ; fully-qualified     # 
👠 E0.6 high-heeled shoe
+1F461                                                  ; fully-qualified     # 
👡 E0.6 woman’s sandal
+1FA70                                                  ; fully-qualified     # 
🩰 E12.0 ballet shoes
+1F462                                                  ; fully-qualified     # 
👢 E0.6 woman’s boot
+1F451                                                  ; fully-qualified     # 
👑 E0.6 crown
+1F452                                                  ; fully-qualified     # 
👒 E0.6 woman’s hat
+1F3A9                                                  ; fully-qualified     # 
🎩 E0.6 top hat
+1F393                                                  ; fully-qualified     # 
🎓 E0.6 graduation cap
+1F9E2                                                  ; fully-qualified     # 
🧢 E5.0 billed cap
+1FA96                                                  ; fully-qualified     # 
🪖 E13.0 military helmet
+26D1 FE0F                                              ; fully-qualified     # 
⛑️ E0.7 rescue worker’s helmet
+26D1                                                   ; unqualified         # 
⛑ E0.7 rescue worker’s helmet
+1F4FF                                                  ; fully-qualified     # 
📿 E1.0 prayer beads
+1F484                                                  ; fully-qualified     # 
💄 E0.6 lipstick
+1F48D                                                  ; fully-qualified     # 
💍 E0.6 ring
+1F48E                                                  ; fully-qualified     # 
💎 E0.6 gem stone
+
+# subgroup: sound
+1F507                                                  ; fully-qualified     # 
🔇 E1.0 muted speaker
+1F508                                                  ; fully-qualified     # 
🔈 E0.7 speaker low volume
+1F509                                                  ; fully-qualified     # 
🔉 E1.0 speaker medium volume
+1F50A                                                  ; fully-qualified     # 
🔊 E0.6 speaker high volume
+1F4E2                                                  ; fully-qualified     # 
📢 E0.6 loudspeaker
+1F4E3                                                  ; fully-qualified     # 
📣 E0.6 megaphone
+1F4EF                                                  ; fully-qualified     # 
📯 E1.0 postal horn
+1F514                                                  ; fully-qualified     # 
🔔 E0.6 bell
+1F515                                                  ; fully-qualified     # 
🔕 E1.0 bell with slash
+
+# subgroup: music
+1F3BC                                                  ; fully-qualified     # 
🎼 E0.6 musical score
+1F3B5                                                  ; fully-qualified     # 
🎵 E0.6 musical note
+1F3B6                                                  ; fully-qualified     # 
🎶 E0.6 musical notes
+1F399 FE0F                                             ; fully-qualified     # 
🎙️ E0.7 studio microphone
+1F399                                                  ; unqualified         # 
🎙 E0.7 studio microphone
+1F39A FE0F                                             ; fully-qualified     # 
🎚️ E0.7 level slider
+1F39A                                                  ; unqualified         # 
🎚 E0.7 level slider
+1F39B FE0F                                             ; fully-qualified     # 
🎛️ E0.7 control knobs
+1F39B                                                  ; unqualified         # 
🎛 E0.7 control knobs
+1F3A4                                                  ; fully-qualified     # 
🎤 E0.6 microphone
+1F3A7                                                  ; fully-qualified     # 
🎧 E0.6 headphone
+1F4FB                                                  ; fully-qualified     # 
📻 E0.6 radio
+
+# subgroup: musical-instrument
+1F3B7                                                  ; fully-qualified     # 
🎷 E0.6 saxophone
+1FA97                                                  ; fully-qualified     # 
🪗 E13.0 accordion
+1F3B8                                                  ; fully-qualified     # 
🎸 E0.6 guitar
+1F3B9                                                  ; fully-qualified     # 
🎹 E0.6 musical keyboard
+1F3BA                                                  ; fully-qualified     # 
🎺 E0.6 trumpet
+1F3BB                                                  ; fully-qualified     # 
🎻 E0.6 violin
+1FA95                                                  ; fully-qualified     # 
🪕 E12.0 banjo
+1F941                                                  ; fully-qualified     # 
🥁 E3.0 drum
+1FA98                                                  ; fully-qualified     # 
🪘 E13.0 long drum
+
+# subgroup: phone
+1F4F1                                                  ; fully-qualified     # 
📱 E0.6 mobile phone
+1F4F2                                                  ; fully-qualified     # 
📲 E0.6 mobile phone with arrow
+260E FE0F                                              ; fully-qualified     # 
☎️ E0.6 telephone
+260E                                                   ; unqualified         # 
☎ E0.6 telephone
+1F4DE                                                  ; fully-qualified     # 
📞 E0.6 telephone receiver
+1F4DF                                                  ; fully-qualified     # 
📟 E0.6 pager
+1F4E0                                                  ; fully-qualified     # 
📠 E0.6 fax machine
+
+# subgroup: computer
+1F50B                                                  ; fully-qualified     # 
🔋 E0.6 battery
+1FAAB                                                  ; fully-qualified     # 
🪫 E14.0 low battery
+1F50C                                                  ; fully-qualified     # 
🔌 E0.6 electric plug
+1F4BB                                                  ; fully-qualified     # 
💻 E0.6 laptop
+1F5A5 FE0F                                             ; fully-qualified     # 
🖥️ E0.7 desktop computer
+1F5A5                                                  ; unqualified         # 
🖥 E0.7 desktop computer
+1F5A8 FE0F                                             ; fully-qualified     # 
🖨️ E0.7 printer
+1F5A8                                                  ; unqualified         # 
🖨 E0.7 printer
+2328 FE0F                                              ; fully-qualified     # 
⌨️ E1.0 keyboard
+2328                                                   ; unqualified         # 
⌨ E1.0 keyboard
+1F5B1 FE0F                                             ; fully-qualified     # 
🖱️ E0.7 computer mouse
+1F5B1                                                  ; unqualified         # 
🖱 E0.7 computer mouse
+1F5B2 FE0F                                             ; fully-qualified     # 
🖲️ E0.7 trackball
+1F5B2                                                  ; unqualified         # 
🖲 E0.7 trackball
+1F4BD                                                  ; fully-qualified     # 
💽 E0.6 computer disk
+1F4BE                                                  ; fully-qualified     # 
💾 E0.6 floppy disk
+1F4BF                                                  ; fully-qualified     # 
💿 E0.6 optical disk
+1F4C0                                                  ; fully-qualified     # 
📀 E0.6 dvd
+1F9EE                                                  ; fully-qualified     # 
🧮 E11.0 abacus
+
+# subgroup: light & video
+1F3A5                                                  ; fully-qualified     # 
🎥 E0.6 movie camera
+1F39E FE0F                                             ; fully-qualified     # 
🎞️ E0.7 film frames
+1F39E                                                  ; unqualified         # 
🎞 E0.7 film frames
+1F4FD FE0F                                             ; fully-qualified     # 
📽️ E0.7 film projector
+1F4FD                                                  ; unqualified         # 
📽 E0.7 film projector
+1F3AC                                                  ; fully-qualified     # 
🎬 E0.6 clapper board
+1F4FA                                                  ; fully-qualified     # 
📺 E0.6 television
+1F4F7                                                  ; fully-qualified     # 
📷 E0.6 camera
+1F4F8                                                  ; fully-qualified     # 
📸 E1.0 camera with flash
+1F4F9                                                  ; fully-qualified     # 
📹 E0.6 video camera
+1F4FC                                                  ; fully-qualified     # 
📼 E0.6 videocassette
+1F50D                                                  ; fully-qualified     # 
🔍 E0.6 magnifying glass tilted left
+1F50E                                                  ; fully-qualified     # 
🔎 E0.6 magnifying glass tilted right
+1F56F FE0F                                             ; fully-qualified     # 
🕯️ E0.7 candle
+1F56F                                                  ; unqualified         # 
🕯 E0.7 candle
+1F4A1                                                  ; fully-qualified     # 
💡 E0.6 light bulb
+1F526                                                  ; fully-qualified     # 
🔦 E0.6 flashlight
+1F3EE                                                  ; fully-qualified     # 
🏮 E0.6 red paper lantern
+1FA94                                                  ; fully-qualified     # 
🪔 E12.0 diya lamp
+
+# subgroup: book-paper
+1F4D4                                                  ; fully-qualified     # 
📔 E0.6 notebook with decorative cover
+1F4D5                                                  ; fully-qualified     # 
📕 E0.6 closed book
+1F4D6                                                  ; fully-qualified     # 
📖 E0.6 open book
+1F4D7                                                  ; fully-qualified     # 
📗 E0.6 green book
+1F4D8                                                  ; fully-qualified     # 
📘 E0.6 blue book
+1F4D9                                                  ; fully-qualified     # 
📙 E0.6 orange book
+1F4DA                                                  ; fully-qualified     # 
📚 E0.6 books
+1F4D3                                                  ; fully-qualified     # 
📓 E0.6 notebook
+1F4D2                                                  ; fully-qualified     # 
📒 E0.6 ledger
+1F4C3                                                  ; fully-qualified     # 
📃 E0.6 page with curl
+1F4DC                                                  ; fully-qualified     # 
📜 E0.6 scroll
+1F4C4                                                  ; fully-qualified     # 
📄 E0.6 page facing up
+1F4F0                                                  ; fully-qualified     # 
📰 E0.6 newspaper
+1F5DE FE0F                                             ; fully-qualified     # 
🗞️ E0.7 rolled-up newspaper
+1F5DE                                                  ; unqualified         # 
🗞 E0.7 rolled-up newspaper
+1F4D1                                                  ; fully-qualified     # 
📑 E0.6 bookmark tabs
+1F516                                                  ; fully-qualified     # 
🔖 E0.6 bookmark
+1F3F7 FE0F                                             ; fully-qualified     # 
🏷️ E0.7 label
+1F3F7                                                  ; unqualified         # 
🏷 E0.7 label
+
+# subgroup: money
+1F4B0                                                  ; fully-qualified     # 
💰 E0.6 money bag
+1FA99                                                  ; fully-qualified     # 
🪙 E13.0 coin
+1F4B4                                                  ; fully-qualified     # 
💴 E0.6 yen banknote
+1F4B5                                                  ; fully-qualified     # 
💵 E0.6 dollar banknote
+1F4B6                                                  ; fully-qualified     # 
💶 E1.0 euro banknote
+1F4B7                                                  ; fully-qualified     # 
💷 E1.0 pound banknote
+1F4B8                                                  ; fully-qualified     # 
💸 E0.6 money with wings
+1F4B3                                                  ; fully-qualified     # 
💳 E0.6 credit card
+1F9FE                                                  ; fully-qualified     # 
🧾 E11.0 receipt
+1F4B9                                                  ; fully-qualified     # 
💹 E0.6 chart increasing with yen
+
+# subgroup: mail
+2709 FE0F                                              ; fully-qualified     # 
✉️ E0.6 envelope
+2709                                                   ; unqualified         # 
✉ E0.6 envelope
+1F4E7                                                  ; fully-qualified     # 
📧 E0.6 e-mail
+1F4E8                                                  ; fully-qualified     # 
📨 E0.6 incoming envelope
+1F4E9                                                  ; fully-qualified     # 
📩 E0.6 envelope with arrow
+1F4E4                                                  ; fully-qualified     # 
📤 E0.6 outbox tray
+1F4E5                                                  ; fully-qualified     # 
📥 E0.6 inbox tray
+1F4E6                                                  ; fully-qualified     # 
📦 E0.6 package
+1F4EB                                                  ; fully-qualified     # 
📫 E0.6 closed mailbox with raised flag
+1F4EA                                                  ; fully-qualified     # 
📪 E0.6 closed mailbox with lowered flag
+1F4EC                                                  ; fully-qualified     # 
📬 E0.7 open mailbox with raised flag
+1F4ED                                                  ; fully-qualified     # 
📭 E0.7 open mailbox with lowered flag
+1F4EE                                                  ; fully-qualified     # 
📮 E0.6 postbox
+1F5F3 FE0F                                             ; fully-qualified     # 
🗳️ E0.7 ballot box with ballot
+1F5F3                                                  ; unqualified         # 
🗳 E0.7 ballot box with ballot
+
+# subgroup: writing
+270F FE0F                                              ; fully-qualified     # 
✏️ E0.6 pencil
+270F                                                   ; unqualified         # 
✏ E0.6 pencil
+2712 FE0F                                              ; fully-qualified     # 
✒️ E0.6 black nib
+2712                                                   ; unqualified         # 
✒ E0.6 black nib
+1F58B FE0F                                             ; fully-qualified     # 
🖋️ E0.7 fountain pen
+1F58B                                                  ; unqualified         # 
🖋 E0.7 fountain pen
+1F58A FE0F                                             ; fully-qualified     # 
🖊️ E0.7 pen
+1F58A                                                  ; unqualified         # 
🖊 E0.7 pen
+1F58C FE0F                                             ; fully-qualified     # 
🖌️ E0.7 paintbrush
+1F58C                                                  ; unqualified         # 
🖌 E0.7 paintbrush
+1F58D FE0F                                             ; fully-qualified     # 
🖍️ E0.7 crayon
+1F58D                                                  ; unqualified         # 
🖍 E0.7 crayon
+1F4DD                                                  ; fully-qualified     # 
📝 E0.6 memo
+
+# subgroup: office
+1F4BC                                                  ; fully-qualified     # 
💼 E0.6 briefcase
+1F4C1                                                  ; fully-qualified     # 
📁 E0.6 file folder
+1F4C2                                                  ; fully-qualified     # 
📂 E0.6 open file folder
+1F5C2 FE0F                                             ; fully-qualified     # 
🗂️ E0.7 card index dividers
+1F5C2                                                  ; unqualified         # 
🗂 E0.7 card index dividers
+1F4C5                                                  ; fully-qualified     # 
📅 E0.6 calendar
+1F4C6                                                  ; fully-qualified     # 
📆 E0.6 tear-off calendar
+1F5D2 FE0F                                             ; fully-qualified     # 
🗒️ E0.7 spiral notepad
+1F5D2                                                  ; unqualified         # 
🗒 E0.7 spiral notepad
+1F5D3 FE0F                                             ; fully-qualified     # 
🗓️ E0.7 spiral calendar
+1F5D3                                                  ; unqualified         # 
🗓 E0.7 spiral calendar
+1F4C7                                                  ; fully-qualified     # 
📇 E0.6 card index
+1F4C8                                                  ; fully-qualified     # 
📈 E0.6 chart increasing
+1F4C9                                                  ; fully-qualified     # 
📉 E0.6 chart decreasing
+1F4CA                                                  ; fully-qualified     # 
📊 E0.6 bar chart
+1F4CB                                                  ; fully-qualified     # 
📋 E0.6 clipboard
+1F4CC                                                  ; fully-qualified     # 
📌 E0.6 pushpin
+1F4CD                                                  ; fully-qualified     # 
📍 E0.6 round pushpin
+1F4CE                                                  ; fully-qualified     # 
📎 E0.6 paperclip
+1F587 FE0F                                             ; fully-qualified     # 
🖇️ E0.7 linked paperclips
+1F587                                                  ; unqualified         # 
🖇 E0.7 linked paperclips
+1F4CF                                                  ; fully-qualified     # 
📏 E0.6 straight ruler
+1F4D0                                                  ; fully-qualified     # 
📐 E0.6 triangular ruler
+2702 FE0F                                              ; fully-qualified     # 
✂️ E0.6 scissors
+2702                                                   ; unqualified         # 
✂ E0.6 scissors
+1F5C3 FE0F                                             ; fully-qualified     # 
🗃️ E0.7 card file box
+1F5C3                                                  ; unqualified         # 
🗃 E0.7 card file box
+1F5C4 FE0F                                             ; fully-qualified     # 
🗄️ E0.7 file cabinet
+1F5C4                                                  ; unqualified         # 
🗄 E0.7 file cabinet
+1F5D1 FE0F                                             ; fully-qualified     # 
🗑️ E0.7 wastebasket
+1F5D1                                                  ; unqualified         # 
🗑 E0.7 wastebasket
+
+# subgroup: lock
+1F512                                                  ; fully-qualified     # 
🔒 E0.6 locked
+1F513                                                  ; fully-qualified     # 
🔓 E0.6 unlocked
+1F50F                                                  ; fully-qualified     # 
🔏 E0.6 locked with pen
+1F510                                                  ; fully-qualified     # 
🔐 E0.6 locked with key
+1F511                                                  ; fully-qualified     # 
🔑 E0.6 key
+1F5DD FE0F                                             ; fully-qualified     # 
🗝️ E0.7 old key
+1F5DD                                                  ; unqualified         # 
🗝 E0.7 old key
+
+# subgroup: tool
+1F528                                                  ; fully-qualified     # 
🔨 E0.6 hammer
+1FA93                                                  ; fully-qualified     # 
🪓 E12.0 axe
+26CF FE0F                                              ; fully-qualified     # 
⛏️ E0.7 pick
+26CF                                                   ; unqualified         # 
⛏ E0.7 pick
+2692 FE0F                                              ; fully-qualified     # 
⚒️ E1.0 hammer and pick
+2692                                                   ; unqualified         # 
⚒ E1.0 hammer and pick
+1F6E0 FE0F                                             ; fully-qualified     # 
🛠️ E0.7 hammer and wrench
+1F6E0                                                  ; unqualified         # 
🛠 E0.7 hammer and wrench
+1F5E1 FE0F                                             ; fully-qualified     # 
🗡️ E0.7 dagger
+1F5E1                                                  ; unqualified         # 
🗡 E0.7 dagger
+2694 FE0F                                              ; fully-qualified     # 
⚔️ E1.0 crossed swords
+2694                                                   ; unqualified         # 
⚔ E1.0 crossed swords
+1F52B                                                  ; fully-qualified     # 
🔫 E0.6 water pistol
+1FA83                                                  ; fully-qualified     # 
🪃 E13.0 boomerang
+1F3F9                                                  ; fully-qualified     # 
🏹 E1.0 bow and arrow
+1F6E1 FE0F                                             ; fully-qualified     # 
🛡️ E0.7 shield
+1F6E1                                                  ; unqualified         # 
🛡 E0.7 shield
+1FA9A                                                  ; fully-qualified     # 
🪚 E13.0 carpentry saw
+1F527                                                  ; fully-qualified     # 
🔧 E0.6 wrench
+1FA9B                                                  ; fully-qualified     # 
🪛 E13.0 screwdriver
+1F529                                                  ; fully-qualified     # 
🔩 E0.6 nut and bolt
+2699 FE0F                                              ; fully-qualified     # 
⚙️ E1.0 gear
+2699                                                   ; unqualified         # 
⚙ E1.0 gear
+1F5DC FE0F                                             ; fully-qualified     # 
🗜️ E0.7 clamp
+1F5DC                                                  ; unqualified         # 
🗜 E0.7 clamp
+2696 FE0F                                              ; fully-qualified     # 
⚖️ E1.0 balance scale
+2696                                                   ; unqualified         # 
⚖ E1.0 balance scale
+1F9AF                                                  ; fully-qualified     # 
🦯 E12.0 white cane
+1F517                                                  ; fully-qualified     # 
🔗 E0.6 link
+26D3 FE0F                                              ; fully-qualified     # 
⛓️ E0.7 chains
+26D3                                                   ; unqualified         # 
⛓ E0.7 chains
+1FA9D                                                  ; fully-qualified     # 
🪝 E13.0 hook
+1F9F0                                                  ; fully-qualified     # 
🧰 E11.0 toolbox
+1F9F2                                                  ; fully-qualified     # 
🧲 E11.0 magnet
+1FA9C                                                  ; fully-qualified     # 
🪜 E13.0 ladder
+
+# subgroup: science
+2697 FE0F                                              ; fully-qualified     # 
⚗️ E1.0 alembic
+2697                                                   ; unqualified         # 
⚗ E1.0 alembic
+1F9EA                                                  ; fully-qualified     # 
🧪 E11.0 test tube
+1F9EB                                                  ; fully-qualified     # 
🧫 E11.0 petri dish
+1F9EC                                                  ; fully-qualified     # 
🧬 E11.0 dna
+1F52C                                                  ; fully-qualified     # 
🔬 E1.0 microscope
+1F52D                                                  ; fully-qualified     # 
🔭 E1.0 telescope
+1F4E1                                                  ; fully-qualified     # 
📡 E0.6 satellite antenna
+
+# subgroup: medical
+1F489                                                  ; fully-qualified     # 
💉 E0.6 syringe
+1FA78                                                  ; fully-qualified     # 
🩸 E12.0 drop of blood
+1F48A                                                  ; fully-qualified     # 
💊 E0.6 pill
+1FA79                                                  ; fully-qualified     # 
🩹 E12.0 adhesive bandage
+1FA7C                                                  ; fully-qualified     # 
🩼 E14.0 crutch
+1FA7A                                                  ; fully-qualified     # 
🩺 E12.0 stethoscope
+1FA7B                                                  ; fully-qualified     # 
🩻 E14.0 x-ray
+
+# subgroup: household
+1F6AA                                                  ; fully-qualified     # 
🚪 E0.6 door
+1F6D7                                                  ; fully-qualified     # 
🛗 E13.0 elevator
+1FA9E                                                  ; fully-qualified     # 
🪞 E13.0 mirror
+1FA9F                                                  ; fully-qualified     # 
🪟 E13.0 window
+1F6CF FE0F                                             ; fully-qualified     # 
🛏️ E0.7 bed
+1F6CF                                                  ; unqualified         # 
🛏 E0.7 bed
+1F6CB FE0F                                             ; fully-qualified     # 
🛋️ E0.7 couch and lamp
+1F6CB                                                  ; unqualified         # 
🛋 E0.7 couch and lamp
+1FA91                                                  ; fully-qualified     # 
🪑 E12.0 chair
+1F6BD                                                  ; fully-qualified     # 
🚽 E0.6 toilet
+1FAA0                                                  ; fully-qualified     # 
🪠 E13.0 plunger
+1F6BF                                                  ; fully-qualified     # 
🚿 E1.0 shower
+1F6C1                                                  ; fully-qualified     # 
🛁 E1.0 bathtub
+1FAA4                                                  ; fully-qualified     # 
🪤 E13.0 mouse trap
+1FA92                                                  ; fully-qualified     # 
🪒 E12.0 razor
+1F9F4                                                  ; fully-qualified     # 
🧴 E11.0 lotion bottle
+1F9F7                                                  ; fully-qualified     # 
🧷 E11.0 safety pin
+1F9F9                                                  ; fully-qualified     # 
🧹 E11.0 broom
+1F9FA                                                  ; fully-qualified     # 
🧺 E11.0 basket
+1F9FB                                                  ; fully-qualified     # 
🧻 E11.0 roll of paper
+1FAA3                                                  ; fully-qualified     # 
🪣 E13.0 bucket
+1F9FC                                                  ; fully-qualified     # 
🧼 E11.0 soap
+1FAE7                                                  ; fully-qualified     # 
🫧 E14.0 bubbles
+1FAA5                                                  ; fully-qualified     # 
🪥 E13.0 toothbrush
+1F9FD                                                  ; fully-qualified     # 
🧽 E11.0 sponge
+1F9EF                                                  ; fully-qualified     # 
🧯 E11.0 fire extinguisher
+1F6D2                                                  ; fully-qualified     # 
🛒 E3.0 shopping cart
+
+# subgroup: other-object
+1F6AC                                                  ; fully-qualified     # 
🚬 E0.6 cigarette
+26B0 FE0F                                              ; fully-qualified     # 
⚰️ E1.0 coffin
+26B0                                                   ; unqualified         # 
⚰ E1.0 coffin
+1FAA6                                                  ; fully-qualified     # 
🪦 E13.0 headstone
+26B1 FE0F                                              ; fully-qualified     # 
⚱️ E1.0 funeral urn
+26B1                                                   ; unqualified         # 
⚱ E1.0 funeral urn
+1F5FF                                                  ; fully-qualified     # 
🗿 E0.6 moai
+1FAA7                                                  ; fully-qualified     # 
🪧 E13.0 placard
+1FAAA                                                  ; fully-qualified     # 
🪪 E14.0 identification card
+
+# Objects subtotal:            304
+# Objects subtotal:            304     w/o modifiers
+
+# group: Symbols
+
+# subgroup: transport-sign
+1F3E7                                                  ; fully-qualified     # 
🏧 E0.6 ATM sign
+1F6AE                                                  ; fully-qualified     # 
🚮 E1.0 litter in bin sign
+1F6B0                                                  ; fully-qualified     # 
🚰 E1.0 potable water
+267F                                                   ; fully-qualified     # 
♿ E0.6 wheelchair symbol
+1F6B9                                                  ; fully-qualified     # 
🚹 E0.6 men’s room
+1F6BA                                                  ; fully-qualified     # 
🚺 E0.6 women’s room
+1F6BB                                                  ; fully-qualified     # 
🚻 E0.6 restroom
+1F6BC                                                  ; fully-qualified     # 
🚼 E0.6 baby symbol
+1F6BE                                                  ; fully-qualified     # 
🚾 E0.6 water closet
+1F6C2                                                  ; fully-qualified     # 
🛂 E1.0 passport control
+1F6C3                                                  ; fully-qualified     # 
🛃 E1.0 customs
+1F6C4                                                  ; fully-qualified     # 
🛄 E1.0 baggage claim
+1F6C5                                                  ; fully-qualified     # 
🛅 E1.0 left luggage
+
+# subgroup: warning
+26A0 FE0F                                              ; fully-qualified     # 
⚠️ E0.6 warning
+26A0                                                   ; unqualified         # 
⚠ E0.6 warning
+1F6B8                                                  ; fully-qualified     # 
🚸 E1.0 children crossing
+26D4                                                   ; fully-qualified     # 
⛔ E0.6 no entry
+1F6AB                                                  ; fully-qualified     # 
🚫 E0.6 prohibited
+1F6B3                                                  ; fully-qualified     # 
🚳 E1.0 no bicycles
+1F6AD                                                  ; fully-qualified     # 
🚭 E0.6 no smoking
+1F6AF                                                  ; fully-qualified     # 
🚯 E1.0 no littering
+1F6B1                                                  ; fully-qualified     # 
🚱 E1.0 non-potable water
+1F6B7                                                  ; fully-qualified     # 
🚷 E1.0 no pedestrians
+1F4F5                                                  ; fully-qualified     # 
📵 E1.0 no mobile phones
+1F51E                                                  ; fully-qualified     # 
🔞 E0.6 no one under eighteen
+2622 FE0F                                              ; fully-qualified     # 
☢️ E1.0 radioactive
+2622                                                   ; unqualified         # 
☢ E1.0 radioactive
+2623 FE0F                                              ; fully-qualified     # 
☣️ E1.0 biohazard
+2623                                                   ; unqualified         # 
☣ E1.0 biohazard
+
+# subgroup: arrow
+2B06 FE0F                                              ; fully-qualified     # 
⬆️ E0.6 up arrow
+2B06                                                   ; unqualified         # 
⬆ E0.6 up arrow
+2197 FE0F                                              ; fully-qualified     # 
↗️ E0.6 up-right arrow
+2197                                                   ; unqualified         # 
↗ E0.6 up-right arrow
+27A1 FE0F                                              ; fully-qualified     # 
➡️ E0.6 right arrow
+27A1                                                   ; unqualified         # 
➡ E0.6 right arrow
+2198 FE0F                                              ; fully-qualified     # 
↘️ E0.6 down-right arrow
+2198                                                   ; unqualified         # 
↘ E0.6 down-right arrow
+2B07 FE0F                                              ; fully-qualified     # 
⬇️ E0.6 down arrow
+2B07                                                   ; unqualified         # 
⬇ E0.6 down arrow
+2199 FE0F                                              ; fully-qualified     # 
↙️ E0.6 down-left arrow
+2199                                                   ; unqualified         # 
↙ E0.6 down-left arrow
+2B05 FE0F                                              ; fully-qualified     # 
⬅️ E0.6 left arrow
+2B05                                                   ; unqualified         # 
⬅ E0.6 left arrow
+2196 FE0F                                              ; fully-qualified     # 
↖️ E0.6 up-left arrow
+2196                                                   ; unqualified         # 
↖ E0.6 up-left arrow
+2195 FE0F                                              ; fully-qualified     # 
↕️ E0.6 up-down arrow
+2195                                                   ; unqualified         # 
↕ E0.6 up-down arrow
+2194 FE0F                                              ; fully-qualified     # 
↔️ E0.6 left-right arrow
+2194                                                   ; unqualified         # 
↔ E0.6 left-right arrow
+21A9 FE0F                                              ; fully-qualified     # 
↩️ E0.6 right arrow curving left
+21A9                                                   ; unqualified         # 
↩ E0.6 right arrow curving left
+21AA FE0F                                              ; fully-qualified     # 
↪️ E0.6 left arrow curving right
+21AA                                                   ; unqualified         # 
↪ E0.6 left arrow curving right
+2934 FE0F                                              ; fully-qualified     # 
⤴️ E0.6 right arrow curving up
+2934                                                   ; unqualified         # 
⤴ E0.6 right arrow curving up
+2935 FE0F                                              ; fully-qualified     # 
⤵️ E0.6 right arrow curving down
+2935                                                   ; unqualified         # 
⤵ E0.6 right arrow curving down
+1F503                                                  ; fully-qualified     # 
🔃 E0.6 clockwise vertical arrows
+1F504                                                  ; fully-qualified     # 
🔄 E1.0 counterclockwise arrows button
+1F519                                                  ; fully-qualified     # 
🔙 E0.6 BACK arrow
+1F51A                                                  ; fully-qualified     # 
🔚 E0.6 END arrow
+1F51B                                                  ; fully-qualified     # 
🔛 E0.6 ON! arrow
+1F51C                                                  ; fully-qualified     # 
🔜 E0.6 SOON arrow
+1F51D                                                  ; fully-qualified     # 
🔝 E0.6 TOP arrow
+
+# subgroup: religion
+1F6D0                                                  ; fully-qualified     # 
🛐 E1.0 place of worship
+269B FE0F                                              ; fully-qualified     # 
⚛️ E1.0 atom symbol
+269B                                                   ; unqualified         # 
⚛ E1.0 atom symbol
+1F549 FE0F                                             ; fully-qualified     # 
🕉️ E0.7 om
+1F549                                                  ; unqualified         # 
🕉 E0.7 om
+2721 FE0F                                              ; fully-qualified     # 
✡️ E0.7 star of David
+2721                                                   ; unqualified         # 
✡ E0.7 star of David
+2638 FE0F                                              ; fully-qualified     # 
☸️ E0.7 wheel of dharma
+2638                                                   ; unqualified         # 
☸ E0.7 wheel of dharma
+262F FE0F                                              ; fully-qualified     # 
☯️ E0.7 yin yang
+262F                                                   ; unqualified         # 
☯ E0.7 yin yang
+271D FE0F                                              ; fully-qualified     # 
✝️ E0.7 latin cross
+271D                                                   ; unqualified         # 
✝ E0.7 latin cross
+2626 FE0F                                              ; fully-qualified     # 
☦️ E1.0 orthodox cross
+2626                                                   ; unqualified         # 
☦ E1.0 orthodox cross
+262A FE0F                                              ; fully-qualified     # 
☪️ E0.7 star and crescent
+262A                                                   ; unqualified         # 
☪ E0.7 star and crescent
+262E FE0F                                              ; fully-qualified     # 
☮️ E1.0 peace symbol
+262E                                                   ; unqualified         # 
☮ E1.0 peace symbol
+1F54E                                                  ; fully-qualified     # 
🕎 E1.0 menorah
+1F52F                                                  ; fully-qualified     # 
🔯 E0.6 dotted six-pointed star
+
+# subgroup: zodiac
+2648                                                   ; fully-qualified     # 
♈ E0.6 Aries
+2649                                                   ; fully-qualified     # 
♉ E0.6 Taurus
+264A                                                   ; fully-qualified     # 
♊ E0.6 Gemini
+264B                                                   ; fully-qualified     # 
♋ E0.6 Cancer
+264C                                                   ; fully-qualified     # 
♌ E0.6 Leo
+264D                                                   ; fully-qualified     # 
♍ E0.6 Virgo
+264E                                                   ; fully-qualified     # 
♎ E0.6 Libra
+264F                                                   ; fully-qualified     # 
♏ E0.6 Scorpio
+2650                                                   ; fully-qualified     # 
♐ E0.6 Sagittarius
+2651                                                   ; fully-qualified     # 
♑ E0.6 Capricorn
+2652                                                   ; fully-qualified     # 
♒ E0.6 Aquarius
+2653                                                   ; fully-qualified     # 
♓ E0.6 Pisces
+26CE                                                   ; fully-qualified     # 
⛎ E0.6 Ophiuchus
+
+# subgroup: av-symbol
+1F500                                                  ; fully-qualified     # 
🔀 E1.0 shuffle tracks button
+1F501                                                  ; fully-qualified     # 
🔁 E1.0 repeat button
+1F502                                                  ; fully-qualified     # 
🔂 E1.0 repeat single button
+25B6 FE0F                                              ; fully-qualified     # 
▶️ E0.6 play button
+25B6                                                   ; unqualified         # 
▶ E0.6 play button
+23E9                                                   ; fully-qualified     # 
⏩ E0.6 fast-forward button
+23ED FE0F                                              ; fully-qualified     # 
⏭️ E0.7 next track button
+23ED                                                   ; unqualified         # 
⏭ E0.7 next track button
+23EF FE0F                                              ; fully-qualified     # 
⏯️ E1.0 play or pause button
+23EF                                                   ; unqualified         # 
⏯ E1.0 play or pause button
+25C0 FE0F                                              ; fully-qualified     # 
◀️ E0.6 reverse button
+25C0                                                   ; unqualified         # 
◀ E0.6 reverse button
+23EA                                                   ; fully-qualified     # 
⏪ E0.6 fast reverse button
+23EE FE0F                                              ; fully-qualified     # 
⏮️ E0.7 last track button
+23EE                                                   ; unqualified         # 
⏮ E0.7 last track button
+1F53C                                                  ; fully-qualified     # 
🔼 E0.6 upwards button
+23EB                                                   ; fully-qualified     # 
⏫ E0.6 fast up button
+1F53D                                                  ; fully-qualified     # 
🔽 E0.6 downwards button
+23EC                                                   ; fully-qualified     # 
⏬ E0.6 fast down button
+23F8 FE0F                                              ; fully-qualified     # 
⏸️ E0.7 pause button
+23F8                                                   ; unqualified         # 
⏸ E0.7 pause button
+23F9 FE0F                                              ; fully-qualified     # 
⏹️ E0.7 stop button
+23F9                                                   ; unqualified         # 
⏹ E0.7 stop button
+23FA FE0F                                              ; fully-qualified     # 
⏺️ E0.7 record button
+23FA                                                   ; unqualified         # 
⏺ E0.7 record button
+23CF FE0F                                              ; fully-qualified     # 
⏏️ E1.0 eject button
+23CF                                                   ; unqualified         # 
⏏ E1.0 eject button
+1F3A6                                                  ; fully-qualified     # 
🎦 E0.6 cinema
+1F505                                                  ; fully-qualified     # 
🔅 E1.0 dim button
+1F506                                                  ; fully-qualified     # 
🔆 E1.0 bright button
+1F4F6                                                  ; fully-qualified     # 
📶 E0.6 antenna bars
+1F4F3                                                  ; fully-qualified     # 
📳 E0.6 vibration mode
+1F4F4                                                  ; fully-qualified     # 
📴 E0.6 mobile phone off
+
+# subgroup: gender
+2640 FE0F                                              ; fully-qualified     # 
♀️ E4.0 female sign
+2640                                                   ; unqualified         # 
♀ E4.0 female sign
+2642 FE0F                                              ; fully-qualified     # 
♂️ E4.0 male sign
+2642                                                   ; unqualified         # 
♂ E4.0 male sign
+26A7 FE0F                                              ; fully-qualified     # 
⚧️ E13.0 transgender symbol
+26A7                                                   ; unqualified         # 
⚧ E13.0 transgender symbol
+
+# subgroup: math
+2716 FE0F                                              ; fully-qualified     # 
✖️ E0.6 multiply
+2716                                                   ; unqualified         # 
✖ E0.6 multiply
+2795                                                   ; fully-qualified     # 
➕ E0.6 plus
+2796                                                   ; fully-qualified     # 
➖ E0.6 minus
+2797                                                   ; fully-qualified     # 
➗ E0.6 divide
+1F7F0                                                  ; fully-qualified     # 
🟰 E14.0 heavy equals sign
+267E FE0F                                              ; fully-qualified     # 
♾️ E11.0 infinity
+267E                                                   ; unqualified         # 
♾ E11.0 infinity
+
+# subgroup: punctuation
+203C FE0F                                              ; fully-qualified     # 
‼️ E0.6 double exclamation mark
+203C                                                   ; unqualified         # 
‼ E0.6 double exclamation mark
+2049 FE0F                                              ; fully-qualified     # 
⁉️ E0.6 exclamation question mark
+2049                                                   ; unqualified         # 
⁉ E0.6 exclamation question mark
+2753                                                   ; fully-qualified     # 
❓ E0.6 red question mark
+2754                                                   ; fully-qualified     # 
❔ E0.6 white question mark
+2755                                                   ; fully-qualified     # 
❕ E0.6 white exclamation mark
+2757                                                   ; fully-qualified     # 
❗ E0.6 red exclamation mark
+3030 FE0F                                              ; fully-qualified     # 
〰️ E0.6 wavy dash
+3030                                                   ; unqualified         # 
〰 E0.6 wavy dash
+
+# subgroup: currency
+1F4B1                                                  ; fully-qualified     # 
💱 E0.6 currency exchange
+1F4B2                                                  ; fully-qualified     # 
💲 E0.6 heavy dollar sign
+
+# subgroup: other-symbol
+2695 FE0F                                              ; fully-qualified     # 
⚕️ E4.0 medical symbol
+2695                                                   ; unqualified         # 
⚕ E4.0 medical symbol
+267B FE0F                                              ; fully-qualified     # 
♻️ E0.6 recycling symbol
+267B                                                   ; unqualified         # 
♻ E0.6 recycling symbol
+269C FE0F                                              ; fully-qualified     # 
⚜️ E1.0 fleur-de-lis
+269C                                                   ; unqualified         # 
⚜ E1.0 fleur-de-lis
+1F531                                                  ; fully-qualified     # 
🔱 E0.6 trident emblem
+1F4DB                                                  ; fully-qualified     # 
📛 E0.6 name badge
+1F530                                                  ; fully-qualified     # 
🔰 E0.6 Japanese symbol for beginner
+2B55                                                   ; fully-qualified     # 
⭕ E0.6 hollow red circle
+2705                                                   ; fully-qualified     # 
✅ E0.6 check mark button
+2611 FE0F                                              ; fully-qualified     # 
☑️ E0.6 check box with check
+2611                                                   ; unqualified         # 
☑ E0.6 check box with check
+2714 FE0F                                              ; fully-qualified     # 
✔️ E0.6 check mark
+2714                                                   ; unqualified         # 
✔ E0.6 check mark
+274C                                                   ; fully-qualified     # 
❌ E0.6 cross mark
+274E                                                   ; fully-qualified     # 
❎ E0.6 cross mark button
+27B0                                                   ; fully-qualified     # 
➰ E0.6 curly loop
+27BF                                                   ; fully-qualified     # 
➿ E1.0 double curly loop
+303D FE0F                                              ; fully-qualified     # 
〽️ E0.6 part alternation mark
+303D                                                   ; unqualified         # 
〽 E0.6 part alternation mark
+2733 FE0F                                              ; fully-qualified     # 
✳️ E0.6 eight-spoked asterisk
+2733                                                   ; unqualified         # 
✳ E0.6 eight-spoked asterisk
+2734 FE0F                                              ; fully-qualified     # 
✴️ E0.6 eight-pointed star
+2734                                                   ; unqualified         # 
✴ E0.6 eight-pointed star
+2747 FE0F                                              ; fully-qualified     # 
❇️ E0.6 sparkle
+2747                                                   ; unqualified         # 
❇ E0.6 sparkle
+00A9 FE0F                                              ; fully-qualified     # 
©️ E0.6 copyright
+00A9                                                   ; unqualified         # 
© E0.6 copyright
+00AE FE0F                                              ; fully-qualified     # 
®️ E0.6 registered
+00AE                                                   ; unqualified         # 
® E0.6 registered
+2122 FE0F                                              ; fully-qualified     # 
™️ E0.6 trade mark
+2122                                                   ; unqualified         # 
™ E0.6 trade mark
+
+# subgroup: keycap
+0023 FE0F 20E3                                         ; fully-qualified     # 
#️⃣ E0.6 keycap: #
+0023 20E3                                              ; unqualified         # 
#⃣ E0.6 keycap: #
+002A FE0F 20E3                                         ; fully-qualified     # 
*️⃣ E2.0 keycap: *
+002A 20E3                                              ; unqualified         # 
*⃣ E2.0 keycap: *
+0030 FE0F 20E3                                         ; fully-qualified     # 
0️⃣ E0.6 keycap: 0
+0030 20E3                                              ; unqualified         # 
0⃣ E0.6 keycap: 0
+0031 FE0F 20E3                                         ; fully-qualified     # 
1️⃣ E0.6 keycap: 1
+0031 20E3                                              ; unqualified         # 
1⃣ E0.6 keycap: 1
+0032 FE0F 20E3                                         ; fully-qualified     # 
2️⃣ E0.6 keycap: 2
+0032 20E3                                              ; unqualified         # 
2⃣ E0.6 keycap: 2
+0033 FE0F 20E3                                         ; fully-qualified     # 
3️⃣ E0.6 keycap: 3
+0033 20E3                                              ; unqualified         # 
3⃣ E0.6 keycap: 3
+0034 FE0F 20E3                                         ; fully-qualified     # 
4️⃣ E0.6 keycap: 4
+0034 20E3                                              ; unqualified         # 
4⃣ E0.6 keycap: 4
+0035 FE0F 20E3                                         ; fully-qualified     # 
5️⃣ E0.6 keycap: 5
+0035 20E3                                              ; unqualified         # 
5⃣ E0.6 keycap: 5
+0036 FE0F 20E3                                         ; fully-qualified     # 
6️⃣ E0.6 keycap: 6
+0036 20E3                                              ; unqualified         # 
6⃣ E0.6 keycap: 6
+0037 FE0F 20E3                                         ; fully-qualified     # 
7️⃣ E0.6 keycap: 7
+0037 20E3                                              ; unqualified         # 
7⃣ E0.6 keycap: 7
+0038 FE0F 20E3                                         ; fully-qualified     # 
8️⃣ E0.6 keycap: 8
+0038 20E3                                              ; unqualified         # 
8⃣ E0.6 keycap: 8
+0039 FE0F 20E3                                         ; fully-qualified     # 
9️⃣ E0.6 keycap: 9
+0039 20E3                                              ; unqualified         # 
9⃣ E0.6 keycap: 9
+1F51F                                                  ; fully-qualified     # 
🔟 E0.6 keycap: 10
+
+# subgroup: alphanum
+1F520                                                  ; fully-qualified     # 
🔠 E0.6 input latin uppercase
+1F521                                                  ; fully-qualified     # 
🔡 E0.6 input latin lowercase
+1F522                                                  ; fully-qualified     # 
🔢 E0.6 input numbers
+1F523                                                  ; fully-qualified     # 
🔣 E0.6 input symbols
+1F524                                                  ; fully-qualified     # 
🔤 E0.6 input latin letters
+1F170 FE0F                                             ; fully-qualified     # 
🅰️ E0.6 A button (blood type)
+1F170                                                  ; unqualified         # 
🅰 E0.6 A button (blood type)
+1F18E                                                  ; fully-qualified     # 
🆎 E0.6 AB button (blood type)
+1F171 FE0F                                             ; fully-qualified     # 
🅱️ E0.6 B button (blood type)
+1F171                                                  ; unqualified         # 
🅱 E0.6 B button (blood type)
+1F191                                                  ; fully-qualified     # 
🆑 E0.6 CL button
+1F192                                                  ; fully-qualified     # 
🆒 E0.6 COOL button
+1F193                                                  ; fully-qualified     # 
🆓 E0.6 FREE button
+2139 FE0F                                              ; fully-qualified     # 
ℹ️ E0.6 information
+2139                                                   ; unqualified         # 
ℹ E0.6 information
+1F194                                                  ; fully-qualified     # 
🆔 E0.6 ID button
+24C2 FE0F                                              ; fully-qualified     # 
Ⓜ️ E0.6 circled M
+24C2                                                   ; unqualified         # 
Ⓜ E0.6 circled M
+1F195                                                  ; fully-qualified     # 
🆕 E0.6 NEW button
+1F196                                                  ; fully-qualified     # 
🆖 E0.6 NG button
+1F17E FE0F                                             ; fully-qualified     # 
🅾️ E0.6 O button (blood type)
+1F17E                                                  ; unqualified         # 
🅾 E0.6 O button (blood type)
+1F197                                                  ; fully-qualified     # 
🆗 E0.6 OK button
+1F17F FE0F                                             ; fully-qualified     # 
🅿️ E0.6 P button
+1F17F                                                  ; unqualified         # 
🅿 E0.6 P button
+1F198                                                  ; fully-qualified     # 
🆘 E0.6 SOS button
+1F199                                                  ; fully-qualified     # 
🆙 E0.6 UP! button
+1F19A                                                  ; fully-qualified     # 
🆚 E0.6 VS button
+1F201                                                  ; fully-qualified     # 
🈁 E0.6 Japanese “here” button
+1F202 FE0F                                             ; fully-qualified     # 
🈂️ E0.6 Japanese “service charge” button
+1F202                                                  ; unqualified         # 
🈂 E0.6 Japanese “service charge” button
+1F237 FE0F                                             ; fully-qualified     # 
🈷️ E0.6 Japanese “monthly amount” button
+1F237                                                  ; unqualified         # 
🈷 E0.6 Japanese “monthly amount” button
+1F236                                                  ; fully-qualified     # 
🈶 E0.6 Japanese “not free of charge” button
+1F22F                                                  ; fully-qualified     # 
🈯 E0.6 Japanese “reserved” button
+1F250                                                  ; fully-qualified     # 
🉐 E0.6 Japanese “bargain” button
+1F239                                                  ; fully-qualified     # 
🈹 E0.6 Japanese “discount” button
+1F21A                                                  ; fully-qualified     # 
🈚 E0.6 Japanese “free of charge” button
+1F232                                                  ; fully-qualified     # 
🈲 E0.6 Japanese “prohibited” button
+1F251                                                  ; fully-qualified     # 
🉑 E0.6 Japanese “acceptable” button
+1F238                                                  ; fully-qualified     # 
🈸 E0.6 Japanese “application” button
+1F234                                                  ; fully-qualified     # 
🈴 E0.6 Japanese “passing grade” button
+1F233                                                  ; fully-qualified     # 
🈳 E0.6 Japanese “vacancy” button
+3297 FE0F                                              ; fully-qualified     # 
㊗️ E0.6 Japanese “congratulations” button
+3297                                                   ; unqualified         # 
㊗ E0.6 Japanese “congratulations” button
+3299 FE0F                                              ; fully-qualified     # 
㊙️ E0.6 Japanese “secret” button
+3299                                                   ; unqualified         # 
㊙ E0.6 Japanese “secret” button
+1F23A                                                  ; fully-qualified     # 
🈺 E0.6 Japanese “open for business” button
+1F235                                                  ; fully-qualified     # 
🈵 E0.6 Japanese “no vacancy” button
+
+# subgroup: geometric
+1F534                                                  ; fully-qualified     # 
🔴 E0.6 red circle
+1F7E0                                                  ; fully-qualified     # 
🟠 E12.0 orange circle
+1F7E1                                                  ; fully-qualified     # 
🟡 E12.0 yellow circle
+1F7E2                                                  ; fully-qualified     # 
🟢 E12.0 green circle
+1F535                                                  ; fully-qualified     # 
🔵 E0.6 blue circle
+1F7E3                                                  ; fully-qualified     # 
🟣 E12.0 purple circle
+1F7E4                                                  ; fully-qualified     # 
🟤 E12.0 brown circle
+26AB                                                   ; fully-qualified     # 
⚫ E0.6 black circle
+26AA                                                   ; fully-qualified     # 
⚪ E0.6 white circle
+1F7E5                                                  ; fully-qualified     # 
🟥 E12.0 red square
+1F7E7                                                  ; fully-qualified     # 
🟧 E12.0 orange square
+1F7E8                                                  ; fully-qualified     # 
🟨 E12.0 yellow square
+1F7E9                                                  ; fully-qualified     # 
🟩 E12.0 green square
+1F7E6                                                  ; fully-qualified     # 
🟦 E12.0 blue square
+1F7EA                                                  ; fully-qualified     # 
🟪 E12.0 purple square
+1F7EB                                                  ; fully-qualified     # 
🟫 E12.0 brown square
+2B1B                                                   ; fully-qualified     # 
⬛ E0.6 black large square
+2B1C                                                   ; fully-qualified     # 
⬜ E0.6 white large square
+25FC FE0F                                              ; fully-qualified     # 
◼️ E0.6 black medium square
+25FC                                                   ; unqualified         # 
◼ E0.6 black medium square
+25FB FE0F                                              ; fully-qualified     # 
◻️ E0.6 white medium square
+25FB                                                   ; unqualified         # 
◻ E0.6 white medium square
+25FE                                                   ; fully-qualified     # 
◾ E0.6 black medium-small square
+25FD                                                   ; fully-qualified     # 
◽ E0.6 white medium-small square
+25AA FE0F                                              ; fully-qualified     # 
▪️ E0.6 black small square
+25AA                                                   ; unqualified         # 
▪ E0.6 black small square
+25AB FE0F                                              ; fully-qualified     # 
▫️ E0.6 white small square
+25AB                                                   ; unqualified         # 
▫ E0.6 white small square
+1F536                                                  ; fully-qualified     # 
🔶 E0.6 large orange diamond
+1F537                                                  ; fully-qualified     # 
🔷 E0.6 large blue diamond
+1F538                                                  ; fully-qualified     # 
🔸 E0.6 small orange diamond
+1F539                                                  ; fully-qualified     # 
🔹 E0.6 small blue diamond
+1F53A                                                  ; fully-qualified     # 
🔺 E0.6 red triangle pointed up
+1F53B                                                  ; fully-qualified     # 
🔻 E0.6 red triangle pointed down
+1F4A0                                                  ; fully-qualified     # 
💠 E0.6 diamond with a dot
+1F518                                                  ; fully-qualified     # 
🔘 E0.6 radio button
+1F533                                                  ; fully-qualified     # 
🔳 E0.6 white square button
+1F532                                                  ; fully-qualified     # 
🔲 E0.6 black square button
+
+# Symbols subtotal:            302
+# Symbols subtotal:            302     w/o modifiers
+
+# group: Flags
+
+# subgroup: flag
+1F3C1                                                  ; fully-qualified     # 
🏁 E0.6 chequered flag
+1F6A9                                                  ; fully-qualified     # 
🚩 E0.6 triangular flag
+1F38C                                                  ; fully-qualified     # 
🎌 E0.6 crossed flags
+1F3F4                                                  ; fully-qualified     # 
🏴 E1.0 black flag
+1F3F3 FE0F                                             ; fully-qualified     # 
🏳️ E0.7 white flag
+1F3F3                                                  ; unqualified         # 
🏳 E0.7 white flag
+1F3F3 FE0F 200D 1F308                                  ; fully-qualified     # 
🏳️‍🌈 E4.0 rainbow flag
+1F3F3 200D 1F308                                       ; unqualified         # 
🏳‍🌈 E4.0 rainbow flag
+1F3F3 FE0F 200D 26A7 FE0F                              ; fully-qualified     # 
🏳️‍⚧️ E13.0 transgender flag
+1F3F3 200D 26A7 FE0F                                   ; unqualified         # 
🏳‍⚧️ E13.0 transgender flag
+1F3F3 FE0F 200D 26A7                                   ; unqualified         # 
🏳️‍⚧ E13.0 transgender flag
+1F3F3 200D 26A7                                        ; unqualified         # 
🏳‍⚧ E13.0 transgender flag
+1F3F4 200D 2620 FE0F                                   ; fully-qualified     # 
🏴‍☠️ E11.0 pirate flag
+1F3F4 200D 2620                                        ; minimally-qualified # 
🏴‍☠ E11.0 pirate flag
+
+# subgroup: country-flag
+1F1E6 1F1E8                                            ; fully-qualified     # 
🇦🇨 E2.0 flag: Ascension Island
+1F1E6 1F1E9                                            ; fully-qualified     # 
🇦🇩 E2.0 flag: Andorra
+1F1E6 1F1EA                                            ; fully-qualified     # 
🇦🇪 E2.0 flag: United Arab Emirates
+1F1E6 1F1EB                                            ; fully-qualified     # 
🇦🇫 E2.0 flag: Afghanistan
+1F1E6 1F1EC                                            ; fully-qualified     # 
🇦🇬 E2.0 flag: Antigua & Barbuda
+1F1E6 1F1EE                                            ; fully-qualified     # 
🇦🇮 E2.0 flag: Anguilla
+1F1E6 1F1F1                                            ; fully-qualified     # 
🇦🇱 E2.0 flag: Albania
+1F1E6 1F1F2                                            ; fully-qualified     # 
🇦🇲 E2.0 flag: Armenia
+1F1E6 1F1F4                                            ; fully-qualified     # 
🇦🇴 E2.0 flag: Angola
+1F1E6 1F1F6                                            ; fully-qualified     # 
🇦🇶 E2.0 flag: Antarctica
+1F1E6 1F1F7                                            ; fully-qualified     # 
🇦🇷 E2.0 flag: Argentina
+1F1E6 1F1F8                                            ; fully-qualified     # 
🇦🇸 E2.0 flag: American Samoa
+1F1E6 1F1F9                                            ; fully-qualified     # 
🇦🇹 E2.0 flag: Austria
+1F1E6 1F1FA                                            ; fully-qualified     # 
🇦🇺 E2.0 flag: Australia
+1F1E6 1F1FC                                            ; fully-qualified     # 
🇦🇼 E2.0 flag: Aruba
+1F1E6 1F1FD                                            ; fully-qualified     # 
🇦🇽 E2.0 flag: Åland Islands
+1F1E6 1F1FF                                            ; fully-qualified     # 
🇦🇿 E2.0 flag: Azerbaijan
+1F1E7 1F1E6                                            ; fully-qualified     # 
🇧🇦 E2.0 flag: Bosnia & Herzegovina
+1F1E7 1F1E7                                            ; fully-qualified     # 
🇧🇧 E2.0 flag: Barbados
+1F1E7 1F1E9                                            ; fully-qualified     # 
🇧🇩 E2.0 flag: Bangladesh
+1F1E7 1F1EA                                            ; fully-qualified     # 
🇧🇪 E2.0 flag: Belgium
+1F1E7 1F1EB                                            ; fully-qualified     # 
🇧🇫 E2.0 flag: Burkina Faso
+1F1E7 1F1EC                                            ; fully-qualified     # 
🇧🇬 E2.0 flag: Bulgaria
+1F1E7 1F1ED                                            ; fully-qualified     # 
🇧🇭 E2.0 flag: Bahrain
+1F1E7 1F1EE                                            ; fully-qualified     # 
🇧🇮 E2.0 flag: Burundi
+1F1E7 1F1EF                                            ; fully-qualified     # 
🇧🇯 E2.0 flag: Benin
+1F1E7 1F1F1                                            ; fully-qualified     # 
🇧🇱 E2.0 flag: St. Barthélemy
+1F1E7 1F1F2                                            ; fully-qualified     # 
🇧🇲 E2.0 flag: Bermuda
+1F1E7 1F1F3                                            ; fully-qualified     # 
🇧🇳 E2.0 flag: Brunei
+1F1E7 1F1F4                                            ; fully-qualified     # 
🇧🇴 E2.0 flag: Bolivia
+1F1E7 1F1F6                                            ; fully-qualified     # 
🇧🇶 E2.0 flag: Caribbean Netherlands
+1F1E7 1F1F7                                            ; fully-qualified     # 
🇧🇷 E2.0 flag: Brazil
+1F1E7 1F1F8                                            ; fully-qualified     # 
🇧🇸 E2.0 flag: Bahamas
+1F1E7 1F1F9                                            ; fully-qualified     # 
🇧🇹 E2.0 flag: Bhutan
+1F1E7 1F1FB                                            ; fully-qualified     # 
🇧🇻 E2.0 flag: Bouvet Island
+1F1E7 1F1FC                                            ; fully-qualified     # 
🇧🇼 E2.0 flag: Botswana
+1F1E7 1F1FE                                            ; fully-qualified     # 
🇧🇾 E2.0 flag: Belarus
+1F1E7 1F1FF                                            ; fully-qualified     # 
🇧🇿 E2.0 flag: Belize
+1F1E8 1F1E6                                            ; fully-qualified     # 
🇨🇦 E2.0 flag: Canada
+1F1E8 1F1E8                                            ; fully-qualified     # 
🇨🇨 E2.0 flag: Cocos (Keeling) Islands
+1F1E8 1F1E9                                            ; fully-qualified     # 
🇨🇩 E2.0 flag: Congo - Kinshasa
+1F1E8 1F1EB                                            ; fully-qualified     # 
🇨🇫 E2.0 flag: Central African Republic
+1F1E8 1F1EC                                            ; fully-qualified     # 
🇨🇬 E2.0 flag: Congo - Brazzaville
+1F1E8 1F1ED                                            ; fully-qualified     # 
🇨🇭 E2.0 flag: Switzerland
+1F1E8 1F1EE                                            ; fully-qualified     # 
🇨🇮 E2.0 flag: Côte d’Ivoire
+1F1E8 1F1F0                                            ; fully-qualified     # 
🇨🇰 E2.0 flag: Cook Islands
+1F1E8 1F1F1                                            ; fully-qualified     # 
🇨🇱 E2.0 flag: Chile
+1F1E8 1F1F2                                            ; fully-qualified     # 
🇨🇲 E2.0 flag: Cameroon
+1F1E8 1F1F3                                            ; fully-qualified     # 
🇨🇳 E0.6 flag: China
+1F1E8 1F1F4                                            ; fully-qualified     # 
🇨🇴 E2.0 flag: Colombia
+1F1E8 1F1F5                                            ; fully-qualified     # 
🇨🇵 E2.0 flag: Clipperton Island
+1F1E8 1F1F7                                            ; fully-qualified     # 
🇨🇷 E2.0 flag: Costa Rica
+1F1E8 1F1FA                                            ; fully-qualified     # 
🇨🇺 E2.0 flag: Cuba
+1F1E8 1F1FB                                            ; fully-qualified     # 
🇨🇻 E2.0 flag: Cape Verde
+1F1E8 1F1FC                                            ; fully-qualified     # 
🇨🇼 E2.0 flag: Curaçao
+1F1E8 1F1FD                                            ; fully-qualified     # 
🇨🇽 E2.0 flag: Christmas Island
+1F1E8 1F1FE                                            ; fully-qualified     # 
🇨🇾 E2.0 flag: Cyprus
+1F1E8 1F1FF                                            ; fully-qualified     # 
🇨🇿 E2.0 flag: Czechia
+1F1E9 1F1EA                                            ; fully-qualified     # 
🇩🇪 E0.6 flag: Germany
+1F1E9 1F1EC                                            ; fully-qualified     # 
🇩🇬 E2.0 flag: Diego Garcia
+1F1E9 1F1EF                                            ; fully-qualified     # 
🇩🇯 E2.0 flag: Djibouti
+1F1E9 1F1F0                                            ; fully-qualified     # 
🇩🇰 E2.0 flag: Denmark
+1F1E9 1F1F2                                            ; fully-qualified     # 
🇩🇲 E2.0 flag: Dominica
+1F1E9 1F1F4                                            ; fully-qualified     # 
🇩🇴 E2.0 flag: Dominican Republic
+1F1E9 1F1FF                                            ; fully-qualified     # 
🇩🇿 E2.0 flag: Algeria
+1F1EA 1F1E6                                            ; fully-qualified     # 
🇪🇦 E2.0 flag: Ceuta & Melilla
+1F1EA 1F1E8                                            ; fully-qualified     # 
🇪🇨 E2.0 flag: Ecuador
+1F1EA 1F1EA                                            ; fully-qualified     # 
🇪🇪 E2.0 flag: Estonia
+1F1EA 1F1EC                                            ; fully-qualified     # 
🇪🇬 E2.0 flag: Egypt
+1F1EA 1F1ED                                            ; fully-qualified     # 
🇪🇭 E2.0 flag: Western Sahara
+1F1EA 1F1F7                                            ; fully-qualified     # 
🇪🇷 E2.0 flag: Eritrea
+1F1EA 1F1F8                                            ; fully-qualified     # 
🇪🇸 E0.6 flag: Spain
+1F1EA 1F1F9                                            ; fully-qualified     # 
🇪🇹 E2.0 flag: Ethiopia
+1F1EA 1F1FA                                            ; fully-qualified     # 
🇪🇺 E2.0 flag: European Union
+1F1EB 1F1EE                                            ; fully-qualified     # 
🇫🇮 E2.0 flag: Finland
+1F1EB 1F1EF                                            ; fully-qualified     # 
🇫🇯 E2.0 flag: Fiji
+1F1EB 1F1F0                                            ; fully-qualified     # 
🇫🇰 E2.0 flag: Falkland Islands
+1F1EB 1F1F2                                            ; fully-qualified     # 
🇫🇲 E2.0 flag: Micronesia
+1F1EB 1F1F4                                            ; fully-qualified     # 
🇫🇴 E2.0 flag: Faroe Islands
+1F1EB 1F1F7                                            ; fully-qualified     # 
🇫🇷 E0.6 flag: France
+1F1EC 1F1E6                                            ; fully-qualified     # 
🇬🇦 E2.0 flag: Gabon
+1F1EC 1F1E7                                            ; fully-qualified     # 
🇬🇧 E0.6 flag: United Kingdom
+1F1EC 1F1E9                                            ; fully-qualified     # 
🇬🇩 E2.0 flag: Grenada
+1F1EC 1F1EA                                            ; fully-qualified     # 
🇬🇪 E2.0 flag: Georgia
+1F1EC 1F1EB                                            ; fully-qualified     # 
🇬🇫 E2.0 flag: French Guiana
+1F1EC 1F1EC                                            ; fully-qualified     # 
🇬🇬 E2.0 flag: Guernsey
+1F1EC 1F1ED                                            ; fully-qualified     # 
🇬🇭 E2.0 flag: Ghana
+1F1EC 1F1EE                                            ; fully-qualified     # 
🇬🇮 E2.0 flag: Gibraltar
+1F1EC 1F1F1                                            ; fully-qualified     # 
🇬🇱 E2.0 flag: Greenland
+1F1EC 1F1F2                                            ; fully-qualified     # 
🇬🇲 E2.0 flag: Gambia
+1F1EC 1F1F3                                            ; fully-qualified     # 
🇬🇳 E2.0 flag: Guinea
+1F1EC 1F1F5                                            ; fully-qualified     # 
🇬🇵 E2.0 flag: Guadeloupe
+1F1EC 1F1F6                                            ; fully-qualified     # 
🇬🇶 E2.0 flag: Equatorial Guinea
+1F1EC 1F1F7                                            ; fully-qualified     # 
🇬🇷 E2.0 flag: Greece
+1F1EC 1F1F8                                            ; fully-qualified     # 
🇬🇸 E2.0 flag: South Georgia & South Sandwich Islands
+1F1EC 1F1F9                                            ; fully-qualified     # 
🇬🇹 E2.0 flag: Guatemala
+1F1EC 1F1FA                                            ; fully-qualified     # 
🇬🇺 E2.0 flag: Guam
+1F1EC 1F1FC                                            ; fully-qualified     # 
🇬🇼 E2.0 flag: Guinea-Bissau
+1F1EC 1F1FE                                            ; fully-qualified     # 
🇬🇾 E2.0 flag: Guyana
+1F1ED 1F1F0                                            ; fully-qualified     # 
🇭🇰 E2.0 flag: Hong Kong SAR China
+1F1ED 1F1F2                                            ; fully-qualified     # 
🇭🇲 E2.0 flag: Heard & McDonald Islands
+1F1ED 1F1F3                                            ; fully-qualified     # 
🇭🇳 E2.0 flag: Honduras
+1F1ED 1F1F7                                            ; fully-qualified     # 
🇭🇷 E2.0 flag: Croatia
+1F1ED 1F1F9                                            ; fully-qualified     # 
🇭🇹 E2.0 flag: Haiti
+1F1ED 1F1FA                                            ; fully-qualified     # 
🇭🇺 E2.0 flag: Hungary
+1F1EE 1F1E8                                            ; fully-qualified     # 
🇮🇨 E2.0 flag: Canary Islands
+1F1EE 1F1E9                                            ; fully-qualified     # 
🇮🇩 E2.0 flag: Indonesia
+1F1EE 1F1EA                                            ; fully-qualified     # 
🇮🇪 E2.0 flag: Ireland
+1F1EE 1F1F1                                            ; fully-qualified     # 
🇮🇱 E2.0 flag: Israel
+1F1EE 1F1F2                                            ; fully-qualified     # 
🇮🇲 E2.0 flag: Isle of Man
+1F1EE 1F1F3                                            ; fully-qualified     # 
🇮🇳 E2.0 flag: India
+1F1EE 1F1F4                                            ; fully-qualified     # 
🇮🇴 E2.0 flag: British Indian Ocean Territory
+1F1EE 1F1F6                                            ; fully-qualified     # 
🇮🇶 E2.0 flag: Iraq
+1F1EE 1F1F7                                            ; fully-qualified     # 
🇮🇷 E2.0 flag: Iran
+1F1EE 1F1F8                                            ; fully-qualified     # 
🇮🇸 E2.0 flag: Iceland
+1F1EE 1F1F9                                            ; fully-qualified     # 
🇮🇹 E0.6 flag: Italy
+1F1EF 1F1EA                                            ; fully-qualified     # 
🇯🇪 E2.0 flag: Jersey
+1F1EF 1F1F2                                            ; fully-qualified     # 
🇯🇲 E2.0 flag: Jamaica
+1F1EF 1F1F4                                            ; fully-qualified     # 
🇯🇴 E2.0 flag: Jordan
+1F1EF 1F1F5                                            ; fully-qualified     # 
🇯🇵 E0.6 flag: Japan
+1F1F0 1F1EA                                            ; fully-qualified     # 
🇰🇪 E2.0 flag: Kenya
+1F1F0 1F1EC                                            ; fully-qualified     # 
🇰🇬 E2.0 flag: Kyrgyzstan
+1F1F0 1F1ED                                            ; fully-qualified     # 
🇰🇭 E2.0 flag: Cambodia
+1F1F0 1F1EE                                            ; fully-qualified     # 
🇰🇮 E2.0 flag: Kiribati
+1F1F0 1F1F2                                            ; fully-qualified     # 
🇰🇲 E2.0 flag: Comoros
+1F1F0 1F1F3                                            ; fully-qualified     # 
🇰🇳 E2.0 flag: St. Kitts & Nevis
+1F1F0 1F1F5                                            ; fully-qualified     # 
🇰🇵 E2.0 flag: North Korea
+1F1F0 1F1F7                                            ; fully-qualified     # 
🇰🇷 E0.6 flag: South Korea
+1F1F0 1F1FC                                            ; fully-qualified     # 
🇰🇼 E2.0 flag: Kuwait
+1F1F0 1F1FE                                            ; fully-qualified     # 
🇰🇾 E2.0 flag: Cayman Islands
+1F1F0 1F1FF                                            ; fully-qualified     # 
🇰🇿 E2.0 flag: Kazakhstan
+1F1F1 1F1E6                                            ; fully-qualified     # 
🇱🇦 E2.0 flag: Laos
+1F1F1 1F1E7                                            ; fully-qualified     # 
🇱🇧 E2.0 flag: Lebanon
+1F1F1 1F1E8                                            ; fully-qualified     # 
🇱🇨 E2.0 flag: St. Lucia
+1F1F1 1F1EE                                            ; fully-qualified     # 
🇱🇮 E2.0 flag: Liechtenstein
+1F1F1 1F1F0                                            ; fully-qualified     # 
🇱🇰 E2.0 flag: Sri Lanka
+1F1F1 1F1F7                                            ; fully-qualified     # 
🇱🇷 E2.0 flag: Liberia
+1F1F1 1F1F8                                            ; fully-qualified     # 
🇱🇸 E2.0 flag: Lesotho
+1F1F1 1F1F9                                            ; fully-qualified     # 
🇱🇹 E2.0 flag: Lithuania
+1F1F1 1F1FA                                            ; fully-qualified     # 
🇱🇺 E2.0 flag: Luxembourg
+1F1F1 1F1FB                                            ; fully-qualified     # 
🇱🇻 E2.0 flag: Latvia
+1F1F1 1F1FE                                            ; fully-qualified     # 
🇱🇾 E2.0 flag: Libya
+1F1F2 1F1E6                                            ; fully-qualified     # 
🇲🇦 E2.0 flag: Morocco
+1F1F2 1F1E8                                            ; fully-qualified     # 
🇲🇨 E2.0 flag: Monaco
+1F1F2 1F1E9                                            ; fully-qualified     # 
🇲🇩 E2.0 flag: Moldova
+1F1F2 1F1EA                                            ; fully-qualified     # 
🇲🇪 E2.0 flag: Montenegro
+1F1F2 1F1EB                                            ; fully-qualified     # 
🇲🇫 E2.0 flag: St. Martin
+1F1F2 1F1EC                                            ; fully-qualified     # 
🇲🇬 E2.0 flag: Madagascar
+1F1F2 1F1ED                                            ; fully-qualified     # 
🇲🇭 E2.0 flag: Marshall Islands
+1F1F2 1F1F0                                            ; fully-qualified     # 
🇲🇰 E2.0 flag: North Macedonia
+1F1F2 1F1F1                                            ; fully-qualified     # 
🇲🇱 E2.0 flag: Mali
+1F1F2 1F1F2                                            ; fully-qualified     # 
🇲🇲 E2.0 flag: Myanmar (Burma)
+1F1F2 1F1F3                                            ; fully-qualified     # 
🇲🇳 E2.0 flag: Mongolia
+1F1F2 1F1F4                                            ; fully-qualified     # 
🇲🇴 E2.0 flag: Macao SAR China
+1F1F2 1F1F5                                            ; fully-qualified     # 
🇲🇵 E2.0 flag: Northern Mariana Islands
+1F1F2 1F1F6                                            ; fully-qualified     # 
🇲🇶 E2.0 flag: Martinique
+1F1F2 1F1F7                                            ; fully-qualified     # 
🇲🇷 E2.0 flag: Mauritania
+1F1F2 1F1F8                                            ; fully-qualified     # 
🇲🇸 E2.0 flag: Montserrat
+1F1F2 1F1F9                                            ; fully-qualified     # 
🇲🇹 E2.0 flag: Malta
+1F1F2 1F1FA                                            ; fully-qualified     # 
🇲🇺 E2.0 flag: Mauritius
+1F1F2 1F1FB                                            ; fully-qualified     # 
🇲🇻 E2.0 flag: Maldives
+1F1F2 1F1FC                                            ; fully-qualified     # 
🇲🇼 E2.0 flag: Malawi
+1F1F2 1F1FD                                            ; fully-qualified     # 
🇲🇽 E2.0 flag: Mexico
+1F1F2 1F1FE                                            ; fully-qualified     # 
🇲🇾 E2.0 flag: Malaysia
+1F1F2 1F1FF                                            ; fully-qualified     # 
🇲🇿 E2.0 flag: Mozambique
+1F1F3 1F1E6                                            ; fully-qualified     # 
🇳🇦 E2.0 flag: Namibia
+1F1F3 1F1E8                                            ; fully-qualified     # 
🇳🇨 E2.0 flag: New Caledonia
+1F1F3 1F1EA                                            ; fully-qualified     # 
🇳🇪 E2.0 flag: Niger
+1F1F3 1F1EB                                            ; fully-qualified     # 
🇳🇫 E2.0 flag: Norfolk Island
+1F1F3 1F1EC                                            ; fully-qualified     # 
🇳🇬 E2.0 flag: Nigeria
+1F1F3 1F1EE                                            ; fully-qualified     # 
🇳🇮 E2.0 flag: Nicaragua
+1F1F3 1F1F1                                            ; fully-qualified     # 
🇳🇱 E2.0 flag: Netherlands
+1F1F3 1F1F4                                            ; fully-qualified     # 
🇳🇴 E2.0 flag: Norway
+1F1F3 1F1F5                                            ; fully-qualified     # 
🇳🇵 E2.0 flag: Nepal
+1F1F3 1F1F7                                            ; fully-qualified     # 
🇳🇷 E2.0 flag: Nauru
+1F1F3 1F1FA                                            ; fully-qualified     # 
🇳🇺 E2.0 flag: Niue
+1F1F3 1F1FF                                            ; fully-qualified     # 
🇳🇿 E2.0 flag: New Zealand
+1F1F4 1F1F2                                            ; fully-qualified     # 
🇴🇲 E2.0 flag: Oman
+1F1F5 1F1E6                                            ; fully-qualified     # 
🇵🇦 E2.0 flag: Panama
+1F1F5 1F1EA                                            ; fully-qualified     # 
🇵🇪 E2.0 flag: Peru
+1F1F5 1F1EB                                            ; fully-qualified     # 
🇵🇫 E2.0 flag: French Polynesia
+1F1F5 1F1EC                                            ; fully-qualified     # 
🇵🇬 E2.0 flag: Papua New Guinea
+1F1F5 1F1ED                                            ; fully-qualified     # 
🇵🇭 E2.0 flag: Philippines
+1F1F5 1F1F0                                            ; fully-qualified     # 
🇵🇰 E2.0 flag: Pakistan
+1F1F5 1F1F1                                            ; fully-qualified     # 
🇵🇱 E2.0 flag: Poland
+1F1F5 1F1F2                                            ; fully-qualified     # 
🇵🇲 E2.0 flag: St. Pierre & Miquelon
+1F1F5 1F1F3                                            ; fully-qualified     # 
🇵🇳 E2.0 flag: Pitcairn Islands
+1F1F5 1F1F7                                            ; fully-qualified     # 
🇵🇷 E2.0 flag: Puerto Rico
+1F1F5 1F1F8                                            ; fully-qualified     # 
🇵🇸 E2.0 flag: Palestinian Territories
+1F1F5 1F1F9                                            ; fully-qualified     # 
🇵🇹 E2.0 flag: Portugal
+1F1F5 1F1FC                                            ; fully-qualified     # 
🇵🇼 E2.0 flag: Palau
+1F1F5 1F1FE                                            ; fully-qualified     # 
🇵🇾 E2.0 flag: Paraguay
+1F1F6 1F1E6                                            ; fully-qualified     # 
🇶🇦 E2.0 flag: Qatar
+1F1F7 1F1EA                                            ; fully-qualified     # 
🇷🇪 E2.0 flag: Réunion
+1F1F7 1F1F4                                            ; fully-qualified     # 
🇷🇴 E2.0 flag: Romania
+1F1F7 1F1F8                                            ; fully-qualified     # 
🇷🇸 E2.0 flag: Serbia
+1F1F7 1F1FA                                            ; fully-qualified     # 
🇷🇺 E0.6 flag: Russia
+1F1F7 1F1FC                                            ; fully-qualified     # 
🇷🇼 E2.0 flag: Rwanda
+1F1F8 1F1E6                                            ; fully-qualified     # 
🇸🇦 E2.0 flag: Saudi Arabia
+1F1F8 1F1E7                                            ; fully-qualified     # 
🇸🇧 E2.0 flag: Solomon Islands
+1F1F8 1F1E8                                            ; fully-qualified     # 
🇸🇨 E2.0 flag: Seychelles
+1F1F8 1F1E9                                            ; fully-qualified     # 
🇸🇩 E2.0 flag: Sudan
+1F1F8 1F1EA                                            ; fully-qualified     # 
🇸🇪 E2.0 flag: Sweden
+1F1F8 1F1EC                                            ; fully-qualified     # 
🇸🇬 E2.0 flag: Singapore
+1F1F8 1F1ED                                            ; fully-qualified     # 
🇸🇭 E2.0 flag: St. Helena
+1F1F8 1F1EE                                            ; fully-qualified     # 
🇸🇮 E2.0 flag: Slovenia
+1F1F8 1F1EF                                            ; fully-qualified     # 
🇸🇯 E2.0 flag: Svalbard & Jan Mayen
+1F1F8 1F1F0                                            ; fully-qualified     # 
🇸🇰 E2.0 flag: Slovakia
+1F1F8 1F1F1                                            ; fully-qualified     # 
🇸🇱 E2.0 flag: Sierra Leone
+1F1F8 1F1F2                                            ; fully-qualified     # 
🇸🇲 E2.0 flag: San Marino
+1F1F8 1F1F3                                            ; fully-qualified     # 
🇸🇳 E2.0 flag: Senegal
+1F1F8 1F1F4                                            ; fully-qualified     # 
🇸🇴 E2.0 flag: Somalia
+1F1F8 1F1F7                                            ; fully-qualified     # 
🇸🇷 E2.0 flag: Suriname
+1F1F8 1F1F8                                            ; fully-qualified     # 
🇸🇸 E2.0 flag: South Sudan
+1F1F8 1F1F9                                            ; fully-qualified     # 
🇸🇹 E2.0 flag: São Tomé & Príncipe
+1F1F8 1F1FB                                            ; fully-qualified     # 
🇸🇻 E2.0 flag: El Salvador
+1F1F8 1F1FD                                            ; fully-qualified     # 
🇸🇽 E2.0 flag: Sint Maarten
+1F1F8 1F1FE                                            ; fully-qualified     # 
🇸🇾 E2.0 flag: Syria
+1F1F8 1F1FF                                            ; fully-qualified     # 
🇸🇿 E2.0 flag: Eswatini
+1F1F9 1F1E6                                            ; fully-qualified     # 
🇹🇦 E2.0 flag: Tristan da Cunha
+1F1F9 1F1E8                                            ; fully-qualified     # 
🇹🇨 E2.0 flag: Turks & Caicos Islands
+1F1F9 1F1E9                                            ; fully-qualified     # 
🇹🇩 E2.0 flag: Chad
+1F1F9 1F1EB                                            ; fully-qualified     # 
🇹🇫 E2.0 flag: French Southern Territories
+1F1F9 1F1EC                                            ; fully-qualified     # 
🇹🇬 E2.0 flag: Togo
+1F1F9 1F1ED                                            ; fully-qualified     # 
🇹🇭 E2.0 flag: Thailand
+1F1F9 1F1EF                                            ; fully-qualified     # 
🇹🇯 E2.0 flag: Tajikistan
+1F1F9 1F1F0                                            ; fully-qualified     # 
🇹🇰 E2.0 flag: Tokelau
+1F1F9 1F1F1                                            ; fully-qualified     # 
🇹🇱 E2.0 flag: Timor-Leste
+1F1F9 1F1F2                                            ; fully-qualified     # 
🇹🇲 E2.0 flag: Turkmenistan
+1F1F9 1F1F3                                            ; fully-qualified     # 
🇹🇳 E2.0 flag: Tunisia
+1F1F9 1F1F4                                            ; fully-qualified     # 
🇹🇴 E2.0 flag: Tonga
+1F1F9 1F1F7                                            ; fully-qualified     # 
🇹🇷 E2.0 flag: Turkey
+1F1F9 1F1F9                                            ; fully-qualified     # 
🇹🇹 E2.0 flag: Trinidad & Tobago
+1F1F9 1F1FB                                            ; fully-qualified     # 
🇹🇻 E2.0 flag: Tuvalu
+1F1F9 1F1FC                                            ; fully-qualified     # 
🇹🇼 E2.0 flag: Taiwan
+1F1F9 1F1FF                                            ; fully-qualified     # 
🇹🇿 E2.0 flag: Tanzania
+1F1FA 1F1E6                                            ; fully-qualified     # 
🇺🇦 E2.0 flag: Ukraine
+1F1FA 1F1EC                                            ; fully-qualified     # 
🇺🇬 E2.0 flag: Uganda
+1F1FA 1F1F2                                            ; fully-qualified     # 
🇺🇲 E2.0 flag: U.S. Outlying Islands
+1F1FA 1F1F3                                            ; fully-qualified     # 
🇺🇳 E4.0 flag: United Nations
+1F1FA 1F1F8                                            ; fully-qualified     # 
🇺🇸 E0.6 flag: United States
+1F1FA 1F1FE                                            ; fully-qualified     # 
🇺🇾 E2.0 flag: Uruguay
+1F1FA 1F1FF                                            ; fully-qualified     # 
🇺🇿 E2.0 flag: Uzbekistan
+1F1FB 1F1E6                                            ; fully-qualified     # 
🇻🇦 E2.0 flag: Vatican City
+1F1FB 1F1E8                                            ; fully-qualified     # 
🇻🇨 E2.0 flag: St. Vincent & Grenadines
+1F1FB 1F1EA                                            ; fully-qualified     # 
🇻🇪 E2.0 flag: Venezuela
+1F1FB 1F1EC                                            ; fully-qualified     # 
🇻🇬 E2.0 flag: British Virgin Islands
+1F1FB 1F1EE                                            ; fully-qualified     # 
🇻🇮 E2.0 flag: U.S. Virgin Islands
+1F1FB 1F1F3                                            ; fully-qualified     # 
🇻🇳 E2.0 flag: Vietnam
+1F1FB 1F1FA                                            ; fully-qualified     # 
🇻🇺 E2.0 flag: Vanuatu
+1F1FC 1F1EB                                            ; fully-qualified     # 
🇼🇫 E2.0 flag: Wallis & Futuna
+1F1FC 1F1F8                                            ; fully-qualified     # 
🇼🇸 E2.0 flag: Samoa
+1F1FD 1F1F0                                            ; fully-qualified     # 
🇽🇰 E2.0 flag: Kosovo
+1F1FE 1F1EA                                            ; fully-qualified     # 
🇾🇪 E2.0 flag: Yemen
+1F1FE 1F1F9                                            ; fully-qualified     # 
🇾🇹 E2.0 flag: Mayotte
+1F1FF 1F1E6                                            ; fully-qualified     # 
🇿🇦 E2.0 flag: South Africa
+1F1FF 1F1F2                                            ; fully-qualified     # 
🇿🇲 E2.0 flag: Zambia
+1F1FF 1F1FC                                            ; fully-qualified     # 
🇿🇼 E2.0 flag: Zimbabwe
+
+# subgroup: subdivision-flag
+1F3F4 E0067 E0062 E0065 E006E E0067 E007F              ; fully-qualified     # 
🏴󠁧󠁢󠁥󠁮󠁧󠁿 E5.0 flag: England
+1F3F4 E0067 E0062 E0073 E0063 E0074 E007F              ; fully-qualified     # 
🏴󠁧󠁢󠁳󠁣󠁴󠁿 E5.0 flag: Scotland
+1F3F4 E0067 E0062 E0077 E006C E0073 E007F              ; fully-qualified     # 
🏴󠁧󠁢󠁷󠁬󠁳󠁿 E5.0 flag: Wales
+
+# Flags subtotal:              275
+# Flags subtotal:              275     w/o modifiers
+
+# Status Counts
+# fully-qualified : 3624
+# minimally-qualified : 817
+# unqualified : 252
+# component : 9
+
+#EOF
diff --git a/admin/unidata/emoji-zwj.awk b/admin/unidata/emoji-zwj.awk
index bdc50f5047..d4e2944ca3 100644
--- a/admin/unidata/emoji-zwj.awk
+++ b/admin/unidata/emoji-zwj.awk
@@ -39,7 +39,7 @@
 
 ### Code:
 
-/^[0-9A-F]/ {
+/^[0-9A-F].*; RGI_Emoji_(ZWJ|Modifier)_Sequence/ {
     sub(/ *;.*/, "", $0)
     num = split($0, elts)
     if (ch[elts[1]] == "")
@@ -62,8 +62,46 @@
 
 END {
      print ";;; emoji-zwj.el --- emoji zwj character composition table  -*- 
lexical-binding:t -*-"
-     print ";;; Automatically generated from 
admin/unidata/emoji-zwj-sequences.txt"
+     print ";;; Automatically generated from 
admin/unidata/emoji-{zwj-,}sequences.txt"
      print "(eval-when-compile (require 'regexp-opt))"
+
+     # The following codepoints are not emoji, but they are part of
+     # emoji sequences.  We have code in font.c:font_range that will
+     # try to display them with the emoji font anyway.
+
+     trigger_codepoints[1] = "261D"
+     trigger_codepoints[2] = "26F9"
+     trigger_codepoints[3] = "270C"
+     trigger_codepoints[4] = "270D"
+     trigger_codepoints[5] = "2764"
+     trigger_codepoints[6] = "1F3CB"
+     trigger_codepoints[7] = "1F3CC"
+     trigger_codepoints[8] = "1F3F3"
+     trigger_codepoints[9] = "1F3F4"
+     trigger_codepoints[10] = "1F441"
+     trigger_codepoints[11] = "1F574"
+     trigger_codepoints[12] = "1F575"
+     trigger_codepoints[13] = "1F590"
+
+     printf "(setq auto-composition-emoji-eligible-codepoints\n"
+     printf "'("
+
+     for (trig in trigger_codepoints)
+     {
+         printf("\n?\\N{U+%s}", trigger_codepoints[trig])
+     }
+     printf "\n))\n\n"
+
+     #  We add entries for 'codepoint U+FE0F' here to ensure that the
+     # code in font_range is triggered.
+
+     for (trig in trigger_codepoints)
+     {
+         codepoint = trigger_codepoints[trig]
+         c = sprintf("\\N{U+%s}", codepoint)
+         vec[codepoint] = vec[codepoint] "\n\"" c "\\N{U+FE0F}\""
+     }
+
      print "(dolist (elt `("
 
      for (elt in ch)
@@ -78,7 +116,7 @@ END {
      print "                                             0"
      print "                                             
'compose-gstring-for-graphic)))))"
 
-     print ";; The following three blocks are derived by hand from 
emoji-sequences.txt"
+     print ";; The following two blocks are derived by hand from 
emoji-sequences.txt"
      print ";; FIXME: add support for Emoji_Keycap_Sequence once we learn how 
to respect FE0F/VS-16"
      print ";; for ASCII characters."
 
@@ -98,14 +136,5 @@ END {
      print "                                           0"
      print "                                    
'compose-gstring-for-graphic))))"
 
-     print ";; Skin tones"
-     print "(set-char-table-range composition-function-table"
-     print "                      '(#x1F3FB . #x1F3FF)"
-     print "                      (nconc (char-table-range 
composition-function-table '(#x1F3FB . #x1F3FF))"
-     print "                             (list (vector 
\".[\\U0001F3FB-\\U0001F3FF]\""
-     print "                                           1"
-     print "                                    
'compose-gstring-for-graphic))))"
-
-     print "\n"
-     print "(provide 'emoji-zwj)"
+     printf "\n(provide 'emoji-zwj)"
 }
diff --git a/build-aux/config.guess b/build-aux/config.guess
index f7727026b7..e81d3ae7c2 100755
--- a/build-aux/config.guess
+++ b/build-aux/config.guess
@@ -2,7 +2,9 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2021 Free Software Foundation, Inc.
 
-timestamp='2021-01-01'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2021-06-03'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -32,7 +34,15 @@ timestamp='2021-01-01'
 # Please send patches to <config-patches@gnu.org>.
 
 
-me=$(echo "$0" | sed -e 's,.*/,,')
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX.  However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
 Usage: $0 [OPTION]
@@ -84,6 +94,9 @@ if test $# != 0; then
   exit 1
 fi
 
+# Just in case it came from the environment.
+GUESS=
+
 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a
 # compiler to aid in system detection is discouraged as it requires
 # temporary files to be created and, as you can see below, it is a
@@ -102,8 +115,8 @@ set_cc_for_build() {
     # prevent multiple calls if $tmp is already set
     test "$tmp" && return 0
     : "${TMPDIR=/tmp}"
-    # shellcheck disable=SC2039
-    { tmp=$( (umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null) && test 
-n "$tmp" && test -d "$tmp" ; } ||
+    # shellcheck disable=SC2039,SC3028
+    { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n 
"$tmp" && test -d "$tmp" ; } ||
        { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir 
"$tmp" 2>/dev/null) ; } ||
        { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo 
"Warning: creating insecure temp directory" >&2 ; } ||
        { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 
1 ; }
@@ -112,7 +125,7 @@ set_cc_for_build() {
        ,,)    echo "int x;" > "$dummy.c"
               for driver in cc gcc c89 c99 ; do
                   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; 
then
-                      CC_FOR_BUILD="$driver"
+                      CC_FOR_BUILD=$driver
                       break
                   fi
               done
@@ -131,12 +144,12 @@ if test -f /.attbin/uname ; then
        PATH=$PATH:/.attbin ; export PATH
 fi
 
-UNAME_MACHINE=$( (uname -m) 2>/dev/null) || UNAME_MACHINE=unknown
-UNAME_RELEASE=$( (uname -r) 2>/dev/null) || UNAME_RELEASE=unknown
-UNAME_SYSTEM=$( (uname -s) 2>/dev/null) || UNAME_SYSTEM=unknown
-UNAME_VERSION=$( (uname -v) 2>/dev/null) || UNAME_VERSION=unknown
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
-case "$UNAME_SYSTEM" in
+case $UNAME_SYSTEM in
 Linux|GNU|GNU/*)
        LIBC=unknown
 
@@ -157,7 +170,8 @@ Linux|GNU|GNU/*)
        #endif
        #endif
        EOF
-       eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 
's, ,,g')"
+       cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | 
sed 's, ,,g'`
+       eval "$cc_set_libc"
 
        # Second heuristic to detect musl libc.
        if [ "$LIBC" = unknown ] &&
@@ -176,7 +190,7 @@ esac
 
 # Note: order is significant - the case branches are not exclusive.
 
-case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
     *:NetBSD:*:*)
        # NetBSD (nbsd) targets should (where applicable) match one or
        # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -188,12 +202,11 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        #
        # Note: NetBSD doesn't particularly care about the vendor
        # portion of the name.  We always set it to "unknown".
-       sysctl="sysctl -n hw.machine_arch"
-       UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
-           "/sbin/$sysctl" 2>/dev/null || \
-           "/usr/sbin/$sysctl" 2>/dev/null || \
-           echo unknown))
-       case "$UNAME_MACHINE_ARCH" in
+       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+           /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+           /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+           echo unknown)`
+       case $UNAME_MACHINE_ARCH in
            aarch64eb) machine=aarch64_be-unknown ;;
            armeb) machine=armeb-unknown ;;
            arm*) machine=arm-unknown ;;
@@ -201,15 +214,15 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
            sh3eb) machine=sh-unknown ;;
            sh5el) machine=sh5le-unknown ;;
            earmv*)
-               arch=$(echo "$UNAME_MACHINE_ARCH" | sed -e 
's,^e\(armv[0-9]\).*$,\1,')
-               endian=$(echo "$UNAME_MACHINE_ARCH" | sed -ne 
's,^.*\(eb\)$,\1,p')
-               machine="${arch}${endian}"-unknown
+               arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 
's,^e\(armv[0-9]\).*$,\1,'`
+               endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 
's,^.*\(eb\)$,\1,p'`
+               machine=${arch}${endian}-unknown
                ;;
-           *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+           *) machine=$UNAME_MACHINE_ARCH-unknown ;;
        esac
        # The Operating System including object format, if it has switched
        # to ELF recently (or will in the future) and ABI.
-       case "$UNAME_MACHINE_ARCH" in
+       case $UNAME_MACHINE_ARCH in
            earm*)
                os=netbsdelf
                ;;
@@ -230,10 +243,10 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
                ;;
        esac
        # Determine ABI tags.
-       case "$UNAME_MACHINE_ARCH" in
+       case $UNAME_MACHINE_ARCH in
            earm*)
                expr='s/^earmv[0-9]/-eabi/;s/eb$//'
-               abi=$(echo "$UNAME_MACHINE_ARCH" | sed -e "$expr")
+               abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
                ;;
        esac
        # The OS release
@@ -241,76 +254,82 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # thus, need a distinct triplet. However, they do not need
        # kernel version information, so it can be replaced with a
        # suitable tag, in the style of linux-gnu.
-       case "$UNAME_VERSION" in
+       case $UNAME_VERSION in
            Debian*)
                release='-gnu'
                ;;
            *)
-               release=$(echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. 
-f1,2)
+               release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. 
-f1,2`
                ;;
        esac
        # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
        # contains redundant information, the shorter form:
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "$machine-${os}${release}${abi-}"
-       exit ;;
+       GUESS=$machine-${os}${release}${abi-}
+       ;;
     *:Bitrig:*:*)
-       UNAME_MACHINE_ARCH=$(arch | sed 's/Bitrig.//')
-       echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
-       exit ;;
+       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+       GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+       ;;
     *:OpenBSD:*:*)
-       UNAME_MACHINE_ARCH=$(arch | sed 's/OpenBSD.//')
-       echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
-       exit ;;
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+       ;;
+    *:SecBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+       GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+       ;;
     *:LibertyBSD:*:*)
-       UNAME_MACHINE_ARCH=$(arch | sed 's/^.*BSD\.//')
-       echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
-       exit ;;
+       UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+       GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+       ;;
     *:MidnightBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+       ;;
     *:ekkoBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+       ;;
     *:SolidBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+       ;;
     *:OS108:*:*)
-       echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+       ;;
     macppc:MirBSD:*:*)
-       echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+       ;;
     *:MirBSD:*:*)
-       echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+       ;;
     *:Sortix:*:*)
-       echo "$UNAME_MACHINE"-unknown-sortix
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-sortix
+       ;;
     *:Twizzler:*:*)
-       echo "$UNAME_MACHINE"-unknown-twizzler
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-twizzler
+       ;;
     *:Redox:*:*)
-       echo "$UNAME_MACHINE"-unknown-redox
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-redox
+       ;;
     mips:OSF1:*.*)
-       echo mips-dec-osf1
-       exit ;;
+       GUESS=mips-dec-osf1
+       ;;
     alpha:OSF1:*:*)
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       trap '' 0
        case $UNAME_RELEASE in
        *4.0)
-               UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $3}')
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
                ;;
        *5.*)
-               UNAME_RELEASE=$(/usr/sbin/sizer -v | awk '{print $4}')
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
                ;;
        esac
        # According to Compaq, /usr/sbin/psrinfo has been available on
        # OSF/1 and Tru64 systems produced since 1995.  I hope that
        # covers most systems running today.  This code pipes the CPU
        # types through head -n 1, so we only detect the type of CPU 0.
-       ALPHA_CPU_TYPE=$(/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha 
\(.*\) processor.*$/\1/p' | head -n 1)
-       case "$ALPHA_CPU_TYPE" in
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) 
processor.*$/\1/p' | head -n 1`
+       case $ALPHA_CPU_TYPE in
            "EV4 (21064)")
                UNAME_MACHINE=alpha ;;
            "EV4.5 (21064)")
@@ -347,68 +366,69 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        # A Tn.n version is a released field test version.
        # A Xn.n version is an unreleased experimental baselevel.
        # 1.2 uses "1.2" for uname -r.
-       echo "$UNAME_MACHINE"-dec-osf"$(echo "$UNAME_RELEASE" | sed -e 
's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)"
-       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
-       exitcode=$?
-       trap '' 0
-       exit $exitcode ;;
+       OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr 
ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+       GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+       ;;
     Amiga*:UNIX_System_V:4.0:*)
-       echo m68k-unknown-sysv4
-       exit ;;
+       GUESS=m68k-unknown-sysv4
+       ;;
     *:[Aa]miga[Oo][Ss]:*:*)
-       echo "$UNAME_MACHINE"-unknown-amigaos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-amigaos
+       ;;
     *:[Mm]orph[Oo][Ss]:*:*)
-       echo "$UNAME_MACHINE"-unknown-morphos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-morphos
+       ;;
     *:OS/390:*:*)
-       echo i370-ibm-openedition
-       exit ;;
+       GUESS=i370-ibm-openedition
+       ;;
     *:z/VM:*:*)
-       echo s390-ibm-zvmoe
-       exit ;;
+       GUESS=s390-ibm-zvmoe
+       ;;
     *:OS400:*:*)
-       echo powerpc-ibm-os400
-       exit ;;
+       GUESS=powerpc-ibm-os400
+       ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-       echo arm-acorn-riscix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=arm-acorn-riscix$UNAME_RELEASE
+       ;;
     arm*:riscos:*:*|arm*:RISCOS:*:*)
-       echo arm-unknown-riscos
-       exit ;;
+       GUESS=arm-unknown-riscos
+       ;;
     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
-       echo hppa1.1-hitachi-hiuxmpp
-       exit ;;
+       GUESS=hppa1.1-hitachi-hiuxmpp
+       ;;
     Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
        # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-       if test "$( (/bin/universe) 2>/dev/null)" = att ; then
-               echo pyramid-pyramid-sysv3
-       else
-               echo pyramid-pyramid-bsd
-       fi
-       exit ;;
+       case `(/bin/universe) 2>/dev/null` in
+           att) GUESS=pyramid-pyramid-sysv3 ;;
+           *)   GUESS=pyramid-pyramid-bsd   ;;
+       esac
+       ;;
     NILE*:*:*:dcosx)
-       echo pyramid-pyramid-svr4
-       exit ;;
+       GUESS=pyramid-pyramid-svr4
+       ;;
     DRS?6000:unix:4.0:6*)
-       echo sparc-icl-nx6
-       exit ;;
+       GUESS=sparc-icl-nx6
+       ;;
     DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
-       case $(/usr/bin/uname -p) in
-           sparc) echo sparc-icl-nx7; exit ;;
-       esac ;;
+       case `/usr/bin/uname -p` in
+           sparc) GUESS=sparc-icl-nx7 ;;
+       esac
+       ;;
     s390x:SunOS:*:*)
-       echo "$UNAME_MACHINE"-ibm-solaris2"$(echo "$UNAME_RELEASE" | sed -e 
's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+       ;;
     sun4H:SunOS:5.*:*)
-       echo sparc-hal-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-hal-solaris2$SUN_REL
+       ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-       echo sparc-sun-solaris2"$(echo "$UNAME_RELEASE" | sed -e 's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-sun-solaris2$SUN_REL
+       ;;
     i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
-       echo i386-pc-auroraux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=i386-pc-auroraux$UNAME_RELEASE
+       ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
        set_cc_for_build
        SUN_ARCH=i386
@@ -423,41 +443,44 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
                SUN_ARCH=x86_64
            fi
        fi
-       echo "$SUN_ARCH"-pc-solaris2"$(echo "$UNAME_RELEASE"|sed -e 
's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+       ;;
     sun4*:SunOS:6*:*)
        # According to config.sub, this is the proper way to canonicalize
        # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
        # it's likely to be more like Solaris than SunOS4.
-       echo sparc-sun-solaris3"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=sparc-sun-solaris3$SUN_REL
+       ;;
     sun4*:SunOS:*:*)
-       case "$(/usr/bin/arch -k)" in
+       case `/usr/bin/arch -k` in
            Series*|S4*)
-               UNAME_RELEASE=$(uname -v)
+               UNAME_RELEASE=`uname -v`
                ;;
        esac
        # Japanese Language versions have a version number like `4.1.3-JL'.
-       echo sparc-sun-sunos"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+       GUESS=sparc-sun-sunos$SUN_REL
+       ;;
     sun3*:SunOS:*:*)
-       echo m68k-sun-sunos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-sun-sunos$UNAME_RELEASE
+       ;;
     sun*:*:4.2BSD:*)
-       UNAME_RELEASE=$( (sed 1q /etc/motd | awk '{print substr($5,1,3)}') 
2>/dev/null)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 
2>/dev/null`
        test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
-       case "$(/bin/arch)" in
+       case `/bin/arch` in
            sun3)
-               echo m68k-sun-sunos"$UNAME_RELEASE"
+               GUESS=m68k-sun-sunos$UNAME_RELEASE
                ;;
            sun4)
-               echo sparc-sun-sunos"$UNAME_RELEASE"
+               GUESS=sparc-sun-sunos$UNAME_RELEASE
                ;;
        esac
-       exit ;;
+       ;;
     aushp:SunOS:*:*)
-       echo sparc-auspex-sunos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-auspex-sunos$UNAME_RELEASE
+       ;;
     # The situation for MiNT is a little confusing.  The machine name
     # can be virtually everything (everything which is not
     # "atarist" or "atariste" at least should have a processor
@@ -467,41 +490,41 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # be no problem.
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-       echo m68k-atari-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-atari-mint$UNAME_RELEASE
+       ;;
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-       echo m68k-milan-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-milan-mint$UNAME_RELEASE
+       ;;
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-       echo m68k-hades-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-hades-mint$UNAME_RELEASE
+       ;;
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-       echo m68k-unknown-mint"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-unknown-mint$UNAME_RELEASE
+       ;;
     m68k:machten:*:*)
-       echo m68k-apple-machten"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-apple-machten$UNAME_RELEASE
+       ;;
     powerpc:machten:*:*)
-       echo powerpc-apple-machten"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-apple-machten$UNAME_RELEASE
+       ;;
     RISC*:Mach:*:*)
-       echo mips-dec-mach_bsd4.3
-       exit ;;
+       GUESS=mips-dec-mach_bsd4.3
+       ;;
     RISC*:ULTRIX:*:*)
-       echo mips-dec-ultrix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-dec-ultrix$UNAME_RELEASE
+       ;;
     VAX*:ULTRIX*:*:*)
-       echo vax-dec-ultrix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=vax-dec-ultrix$UNAME_RELEASE
+       ;;
     2020:CLIX:*:* | 2430:CLIX:*:*)
-       echo clipper-intergraph-clix"$UNAME_RELEASE"
-       exit ;;
+       GUESS=clipper-intergraph-clix$UNAME_RELEASE
+       ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
        set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
@@ -526,78 +549,79 @@ case 
"$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
        }
 EOF
        $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
-         dummyarg=$(echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p') &&
-         SYSTEM_NAME=$("$dummy" "$dummyarg") &&
+         dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
            { echo "$SYSTEM_NAME"; exit; }
-       echo mips-mips-riscos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-mips-riscos$UNAME_RELEASE
+       ;;
     Motorola:PowerMAX_OS:*:*)
-       echo powerpc-motorola-powermax
-       exit ;;
+       GUESS=powerpc-motorola-powermax
+       ;;
     Motorola:*:4.3:PL8-*)
-       echo powerpc-harris-powermax
-       exit ;;
+       GUESS=powerpc-harris-powermax
+       ;;
     Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
-       echo powerpc-harris-powermax
-       exit ;;
+       GUESS=powerpc-harris-powermax
+       ;;
     Night_Hawk:Power_UNIX:*:*)
-       echo powerpc-harris-powerunix
-       exit ;;
+       GUESS=powerpc-harris-powerunix
+       ;;
     m88k:CX/UX:7*:*)
-       echo m88k-harris-cxux7
-       exit ;;
+       GUESS=m88k-harris-cxux7
+       ;;
     m88k:*:4*:R4*)
-       echo m88k-motorola-sysv4
-       exit ;;
+       GUESS=m88k-motorola-sysv4
+       ;;
     m88k:*:3*:R3*)
-       echo m88k-motorola-sysv3
-       exit ;;
+       GUESS=m88k-motorola-sysv3
+       ;;
     AViiON:dgux:*:*)
        # DG/UX returns AViiON for all architectures
-       UNAME_PROCESSOR=$(/usr/bin/uname -p)
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
        if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = 
mc88110
        then
            if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
               test "$TARGET_BINARY_INTERFACE"x = x
            then
-               echo m88k-dg-dgux"$UNAME_RELEASE"
+               GUESS=m88k-dg-dgux$UNAME_RELEASE
            else
-               echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+               GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
            fi
        else
-           echo i586-dg-dgux"$UNAME_RELEASE"
+           GUESS=i586-dg-dgux$UNAME_RELEASE
        fi
-       exit ;;
+       ;;
     M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
-       echo m88k-dolphin-sysv3
-       exit ;;
+       GUESS=m88k-dolphin-sysv3
+       ;;
     M88*:*:R3*:*)
        # Delta 88k system running SVR3
-       echo m88k-motorola-sysv3
-       exit ;;
+       GUESS=m88k-motorola-sysv3
+       ;;
     XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-       echo m88k-tektronix-sysv3
-       exit ;;
+       GUESS=m88k-tektronix-sysv3
+       ;;
     Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-       echo m68k-tektronix-bsd
-       exit ;;
+       GUESS=m68k-tektronix-bsd
+       ;;
     *:IRIX*:*:*)
-       echo mips-sgi-irix"$(echo "$UNAME_RELEASE"|sed -e 's/-/_/g')"
-       exit ;;
+       IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+       GUESS=mips-sgi-irix$IRIX_REL
+       ;;
     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
-       exit ;;               # Note that: echo "'$(uname -s)'" gives 'AIX '
+       GUESS=romp-ibm-aix    # uname -m gives an 8 hex-code CPU id
+       ;;                    # Note that: echo "'`uname -s`'" gives 'AIX '
     i*86:AIX:*:*)
-       echo i386-ibm-aix
-       exit ;;
+       GUESS=i386-ibm-aix
+       ;;
     ia64:AIX:*:*)
        if test -x /usr/bin/oslevel ; then
-               IBM_REV=$(/usr/bin/oslevel)
+               IBM_REV=`/usr/bin/oslevel`
        else
-               IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+               IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
        fi
-       echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
-       exit ;;
+       GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+       ;;
     *:AIX:2:3)
        if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
                set_cc_for_build
@@ -612,68 +636,68 @@ EOF
                        exit(0);
                        }
 EOF
-               if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && 
SYSTEM_NAME=$("$dummy")
+               if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && 
SYSTEM_NAME=`"$dummy"`
                then
-                       echo "$SYSTEM_NAME"
+                       GUESS=$SYSTEM_NAME
                else
-                       echo rs6000-ibm-aix3.2.5
+                       GUESS=rs6000-ibm-aix3.2.5
                fi
        elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-               echo rs6000-ibm-aix3.2.4
+               GUESS=rs6000-ibm-aix3.2.4
        else
-               echo rs6000-ibm-aix3.2
+               GUESS=rs6000-ibm-aix3.2
        fi
-       exit ;;
+       ;;
     *:AIX:*:[4567])
-       IBM_CPU_ID=$(/usr/sbin/lsdev -C -c processor -S available | sed 1q | 
awk '{ print $1 }')
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk 
'{ print $1 }'`
        if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; 
then
                IBM_ARCH=rs6000
        else
                IBM_ARCH=powerpc
        fi
        if test -x /usr/bin/lslpp ; then
-               IBM_REV=$(/usr/bin/lslpp -Lqc bos.rte.libc |
-                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/)
+               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
+                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
        else
-               IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+               IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
        fi
-       echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
-       exit ;;
+       GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+       ;;
     *:AIX:*:*)
-       echo rs6000-ibm-aix
-       exit ;;
+       GUESS=rs6000-ibm-aix
+       ;;
     ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
-       echo romp-ibm-bsd4.4
-       exit ;;
+       GUESS=romp-ibm-bsd4.4
+       ;;
     ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-       echo romp-ibm-bsd"$UNAME_RELEASE"   # 4.3 with uname added to
-       exit ;;                             # report: romp-ibm BSD 4.3
+       GUESS=romp-ibm-bsd$UNAME_RELEASE    # 4.3 with uname added to
+       ;;                                  # report: romp-ibm BSD 4.3
     *:BOSX:*:*)
-       echo rs6000-bull-bosx
-       exit ;;
+       GUESS=rs6000-bull-bosx
+       ;;
     DPX/2?00:B.O.S.:*:*)
-       echo m68k-bull-sysv3
-       exit ;;
+       GUESS=m68k-bull-sysv3
+       ;;
     9000/[34]??:4.3bsd:1.*:*)
-       echo m68k-hp-bsd
-       exit ;;
+       GUESS=m68k-hp-bsd
+       ;;
     hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-       echo m68k-hp-bsd4.4
-       exit ;;
+       GUESS=m68k-hp-bsd4.4
+       ;;
     9000/[34678]??:HP-UX:*:*)
-       HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
-       case "$UNAME_MACHINE" in
+       HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+       case $UNAME_MACHINE in
            9000/31?)            HP_ARCH=m68000 ;;
            9000/[34]??)         HP_ARCH=m68k ;;
            9000/[678][0-9][0-9])
                if test -x /usr/bin/getconf; then
-                   sc_cpu_version=$(/usr/bin/getconf SC_CPU_VERSION 
2>/dev/null)
-                   sc_kernel_bits=$(/usr/bin/getconf SC_KERNEL_BITS 
2>/dev/null)
-                   case "$sc_cpu_version" in
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                   case $sc_cpu_version in
                      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
                      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
                      532)                      # CPU_PA_RISC2_0
-                       case "$sc_kernel_bits" in
+                       case $sc_kernel_bits in
                          32) HP_ARCH=hppa2.0n ;;
                          64) HP_ARCH=hppa2.0w ;;
                          '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
@@ -715,7 +739,7 @@ EOF
                    exit (0);
                }
 EOF
-                   (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 
2>/dev/null) && HP_ARCH=$("$dummy")
+                   (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 
2>/dev/null) && HP_ARCH=`"$dummy"`
                    test -z "$HP_ARCH" && HP_ARCH=hppa
                fi ;;
        esac
@@ -740,12 +764,12 @@ EOF
                HP_ARCH=hppa64
            fi
        fi
-       echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
-       exit ;;
+       GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+       ;;
     ia64:HP-UX:*:*)
-       HPUX_REV=$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//')
-       echo ia64-hp-hpux"$HPUX_REV"
-       exit ;;
+       HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+       GUESS=ia64-hp-hpux$HPUX_REV
+       ;;
     3050*:HI-UX:*:*)
        set_cc_for_build
        sed 's/^        //' << EOF > "$dummy.c"
@@ -773,38 +797,38 @@ EOF
          exit (0);
        }
 EOF
-       $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=$("$dummy") &&
+       $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
                { echo "$SYSTEM_NAME"; exit; }
-       echo unknown-hitachi-hiuxwe2
-       exit ;;
+       GUESS=unknown-hitachi-hiuxwe2
+       ;;
     9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
-       echo hppa1.1-hp-bsd
-       exit ;;
+       GUESS=hppa1.1-hp-bsd
+       ;;
     9000/8??:4.3bsd:*:*)
-       echo hppa1.0-hp-bsd
-       exit ;;
+       GUESS=hppa1.0-hp-bsd
+       ;;
     *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
-       echo hppa1.0-hp-mpeix
-       exit ;;
+       GUESS=hppa1.0-hp-mpeix
+       ;;
     hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
-       echo hppa1.1-hp-osf
-       exit ;;
+       GUESS=hppa1.1-hp-osf
+       ;;
     hp8??:OSF1:*:*)
-       echo hppa1.0-hp-osf
-       exit ;;
+       GUESS=hppa1.0-hp-osf
+       ;;
     i*86:OSF1:*:*)
        if test -x /usr/sbin/sysversion ; then
-           echo "$UNAME_MACHINE"-unknown-osf1mk
+           GUESS=$UNAME_MACHINE-unknown-osf1mk
        else
-           echo "$UNAME_MACHINE"-unknown-osf1
+           GUESS=$UNAME_MACHINE-unknown-osf1
        fi
-       exit ;;
+       ;;
     parisc*:Lites*:*:*)
-       echo hppa1.1-hp-lites
-       exit ;;
+       GUESS=hppa1.1-hp-lites
+       ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-       echo c1-convex-bsd
-       exit ;;
+       GUESS=c1-convex-bsd
+       ;;
     C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
        if getsysinfo -f scalar_acc
        then echo c32-convex-bsd
@@ -812,17 +836,18 @@ EOF
        fi
        exit ;;
     C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-       echo c34-convex-bsd
-       exit ;;
+       GUESS=c34-convex-bsd
+       ;;
     C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-       echo c38-convex-bsd
-       exit ;;
+       GUESS=c38-convex-bsd
+       ;;
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-       echo c4-convex-bsd
-       exit ;;
+       GUESS=c4-convex-bsd
+       ;;
     CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=ymp-cray-unicos$CRAY_REL
+       ;;
     CRAY*[A-Z]90:*:*:*)
        echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
        | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -830,114 +855,126 @@ EOF
              -e 's/\.[^.]*$/.X/'
        exit ;;
     CRAY*TS:*:*:*)
-       echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=t90-cray-unicos$CRAY_REL
+       ;;
     CRAY*T3E:*:*:*)
-       echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=alphaev5-cray-unicosmk$CRAY_REL
+       ;;
     CRAY*SV1:*:*:*)
-       echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=sv1-cray-unicos$CRAY_REL
+       ;;
     *:UNICOS/mp:*:*)
-       echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
+       CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+       GUESS=craynv-cray-unicosmp$CRAY_REL
+       ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-       FUJITSU_PROC=$(uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz)
-       FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
-       FUJITSU_REL=$(echo "$UNAME_RELEASE" | sed -e 's/ /_/')
-       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
+       FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz`
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+       FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+       GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+       ;;
     5000:UNIX_System_V:4.*:*)
-       FUJITSU_SYS=$(uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/\///')
-       FUJITSU_REL=$(echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/')
-       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+       FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ 
abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+       GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+       ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-       echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+       ;;
     sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+       ;;
     *:BSD/OS:*:*)
-       echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+       ;;
     arm:FreeBSD:*:*)
-       UNAME_PROCESSOR=$(uname -p)
+       UNAME_PROCESSOR=`uname -p`
        set_cc_for_build
        if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
            | grep -q __ARM_PCS_VFP
        then
-           echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo 
${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabi
+           FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+           GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
        else
-           echo "${UNAME_PROCESSOR}"-unknown-freebsd"$(echo 
${UNAME_RELEASE}|sed -e 's/[-(].*//')"-gnueabihf
+           FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+           GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
        fi
-       exit ;;
+       ;;
     *:FreeBSD:*:*)
-       UNAME_PROCESSOR=$(/usr/bin/uname -p)
-       case "$UNAME_PROCESSOR" in
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       case $UNAME_PROCESSOR in
            amd64)
                UNAME_PROCESSOR=x86_64 ;;
            i386)
                UNAME_PROCESSOR=i586 ;;
        esac
-       echo "$UNAME_PROCESSOR"-unknown-freebsd"$(echo "$UNAME_RELEASE"|sed -e 
's/[-(].*//')"
-       exit ;;
+       FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+       ;;
     i*:CYGWIN*:*)
-       echo "$UNAME_MACHINE"-pc-cygwin
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-cygwin
+       ;;
     *:MINGW64*:*)
-       echo "$UNAME_MACHINE"-pc-mingw64
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-mingw64
+       ;;
     *:MINGW*:*)
-       echo "$UNAME_MACHINE"-pc-mingw32
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-mingw32
+       ;;
     *:MSYS*:*)
-       echo "$UNAME_MACHINE"-pc-msys
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-msys
+       ;;
     i*:PW*:*)
-       echo "$UNAME_MACHINE"-pc-pw32
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-pw32
+       ;;
     *:Interix*:*)
-       case "$UNAME_MACHINE" in
+       case $UNAME_MACHINE in
            x86)
-               echo i586-pc-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=i586-pc-interix$UNAME_RELEASE
+               ;;
            authenticamd | genuineintel | EM64T)
-               echo x86_64-unknown-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=x86_64-unknown-interix$UNAME_RELEASE
+               ;;
            IA64)
-               echo ia64-unknown-interix"$UNAME_RELEASE"
-               exit ;;
+               GUESS=ia64-unknown-interix$UNAME_RELEASE
+               ;;
        esac ;;
     i*:UWIN*:*)
-       echo "$UNAME_MACHINE"-pc-uwin
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-uwin
+       ;;
     amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-       echo x86_64-pc-cygwin
-       exit ;;
+       GUESS=x86_64-pc-cygwin
+       ;;
     prep*:SunOS:5.*:*)
-       echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 
's/[^.]*//')"
-       exit ;;
+       SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+       GUESS=powerpcle-unknown-solaris2$SUN_REL
+       ;;
     *:GNU:*:*)
        # the GNU system
-       echo "$(echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,')-unknown-$LIBC$(echo 
"$UNAME_RELEASE"|sed -e 's,/.*$,,')"
-       exit ;;
+       GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+       GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+       GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+       ;;
     *:GNU/*:*:*)
        # other systems with GNU libc and userland
-       echo "$UNAME_MACHINE-unknown-$(echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' 
| tr "[:upper:]" "[:lower:]")$(echo "$UNAME_RELEASE"|sed -e 's/[-(].*//')-$LIBC"
-       exit ;;
+       GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" 
"[:lower:]"`
+       GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+       ;;
     *:Minix:*:*)
-       echo "$UNAME_MACHINE"-unknown-minix
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-minix
+       ;;
     aarch64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     aarch64_be:Linux:*:*)
        UNAME_MACHINE=aarch64_be
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     alpha:Linux:*:*)
-       case $(sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 
2>/dev/null) in
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 
2>/dev/null` in
          EV5)   UNAME_MACHINE=alphaev5 ;;
          EV56)  UNAME_MACHINE=alphaev56 ;;
          PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -948,63 +985,63 @@ EOF
        esac
        objdump --private-headers /bin/sh | grep -q ld.so.1
        if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
-    arc:Linux:*:* | arceb:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
+    arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     arm*:Linux:*:*)
        set_cc_for_build
        if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
            | grep -q __ARM_EABI__
        then
-           echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+           GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
        else
            if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
                | grep -q __ARM_PCS_VFP
            then
-               echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+               GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
            else
-               echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+               GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
            fi
        fi
-       exit ;;
+       ;;
     avr32*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     cris:Linux:*:*)
-       echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+       ;;
     crisv32:Linux:*:*)
-       echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+       ;;
     e2k:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     frv:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     hexagon:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     i*86:Linux:*:*)
-       echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+       ;;
     ia64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     k1om:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     m32r*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     m68*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     mips:Linux:*:* | mips64:Linux:*:*)
        set_cc_for_build
        IS_GLIBC=0
@@ -1049,65 +1086,66 @@ EOF
        #endif
        #endif
 EOF
-       eval "$($CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep 
'^CPU\|^MIPS_ENDIAN\|^LIBCABI')"
+       cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep 
'^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+       eval "$cc_set_vars"
        test "x$CPU" != x && { echo 
"$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
        ;;
     mips64el:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     openrisc*:Linux:*:*)
-       echo or1k-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=or1k-unknown-linux-$LIBC
+       ;;
     or32:Linux:*:* | or1k*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     padre:Linux:*:*)
-       echo sparc-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=sparc-unknown-linux-$LIBC
+       ;;
     parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=hppa64-unknown-linux-$LIBC
+       ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
        # Look for CPU level
-       case $(grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2) in
-         PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
-         PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
-         *)    echo hppa-unknown-linux-"$LIBC" ;;
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+         PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+         *)    GUESS=hppa-unknown-linux-$LIBC ;;
        esac
-       exit ;;
+       ;;
     ppc64:Linux:*:*)
-       echo powerpc64-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc64-unknown-linux-$LIBC
+       ;;
     ppc:Linux:*:*)
-       echo powerpc-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc-unknown-linux-$LIBC
+       ;;
     ppc64le:Linux:*:*)
-       echo powerpc64le-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpc64le-unknown-linux-$LIBC
+       ;;
     ppcle:Linux:*:*)
-       echo powerpcle-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=powerpcle-unknown-linux-$LIBC
+       ;;
     riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | 
riscv64be:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     s390:Linux:*:* | s390x:Linux:*:*)
-       echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+       ;;
     sh64*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     sh*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     sparc:Linux:*:* | sparc64:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     tile*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     vax:Linux:*:*)
-       echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+       ;;
     x86_64:Linux:*:*)
        set_cc_for_build
        LIBCABI=$LIBC
@@ -1116,71 +1154,71 @@ EOF
                (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
                grep IS_X32 >/dev/null
            then
-               LIBCABI="$LIBC"x32
+               LIBCABI=${LIBC}x32
            fi
        fi
-       echo "$UNAME_MACHINE"-pc-linux-"$LIBCABI"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+       ;;
     xtensa*:Linux:*:*)
-       echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+       ;;
     i*86:DYNIX/ptx:4*:*)
        # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
        # earlier versions are messed up and put the nodename in both
        # sysname and nodename.
-       echo i386-sequent-sysv4
-       exit ;;
+       GUESS=i386-sequent-sysv4
+       ;;
     i*86:UNIX_SV:4.2MP:2.*)
        # Unixware is an offshoot of SVR4, but it has its own version
        # number series starting with 2...
        # I am not positive that other SVR4 systems won't match this,
        # I just have to hope.  -- rms.
        # Use sysv4.2uw... so that sysv4* matches it.
-       echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+       ;;
     i*86:OS/2:*:*)
        # If we were able to find `uname', then EMX Unix compatibility
        # is probably installed.
-       echo "$UNAME_MACHINE"-pc-os2-emx
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-os2-emx
+       ;;
     i*86:XTS-300:*:STOP)
-       echo "$UNAME_MACHINE"-unknown-stop
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-stop
+       ;;
     i*86:atheos:*:*)
-       echo "$UNAME_MACHINE"-unknown-atheos
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-atheos
+       ;;
     i*86:syllable:*:*)
-       echo "$UNAME_MACHINE"-pc-syllable
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-syllable
+       ;;
     i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
-       echo i386-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=i386-unknown-lynxos$UNAME_RELEASE
+       ;;
     i*86:*DOS:*:*)
-       echo "$UNAME_MACHINE"-pc-msdosdjgpp
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+       ;;
     i*86:*:4.*:*)
-       UNAME_REL=$(echo "$UNAME_RELEASE" | sed 's/\/MP$//')
+       UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
        if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
        else
-               echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
        fi
-       exit ;;
+       ;;
     i*86:*:5:[678]*)
        # UnixWare 7.x, OpenUNIX and OpenServer 6.
-       case $(/bin/uname -X | grep "^Machine") in
+       case `/bin/uname -X | grep "^Machine"` in
            *486*)           UNAME_MACHINE=i486 ;;
            *Pentium)        UNAME_MACHINE=i586 ;;
            *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
        esac
-       echo 
"$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
-       exit ;;
+       
GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       ;;
     i*86:*:3.2:*)
        if test -f /usr/options/cb.name; then
-               UNAME_REL=$(sed -n 's/.*Version //p' </usr/options/cb.name)
-               echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
        elif /bin/uname -X 2>/dev/null >/dev/null ; then
-               UNAME_REL=$( (/bin/uname -X|grep Release|sed -e 's/.*= //'))
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
                (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
                (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
                        && UNAME_MACHINE=i586
@@ -1188,11 +1226,11 @@ EOF
                        && UNAME_MACHINE=i686
                (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
                        && UNAME_MACHINE=i686
-               echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+               GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
        else
-               echo "$UNAME_MACHINE"-pc-sysv32
+               GUESS=$UNAME_MACHINE-pc-sysv32
        fi
-       exit ;;
+       ;;
     pc:*:*:*)
        # Left here for compatibility:
        # uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1200,37 +1238,37 @@ EOF
        # Note: whatever this is, it MUST be the same as what config.sub
        # prints for the "djgpp" host, or else GDB configure will decide that
        # this is a cross-build.
-       echo i586-pc-msdosdjgpp
-       exit ;;
+       GUESS=i586-pc-msdosdjgpp
+       ;;
     Intel:Mach:3*:*)
-       echo i386-pc-mach3
-       exit ;;
+       GUESS=i386-pc-mach3
+       ;;
     paragon:*:*:*)
-       echo i860-intel-osf1
-       exit ;;
+       GUESS=i860-intel-osf1
+       ;;
     i860:*:4.*:*) # i860-SVR4
        if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-         echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+         GUESS=i860-stardent-sysv$UNAME_RELEASE    # Stardent Vistra i860-SVR4
        else # Add other i860-SVR4 vendors below as they are discovered.
-         echo i860-unknown-sysv"$UNAME_RELEASE"  # Unknown i860-SVR4
+         GUESS=i860-unknown-sysv$UNAME_RELEASE     # Unknown i860-SVR4
        fi
-       exit ;;
+       ;;
     mini*:CTIX:SYS*5:*)
        # "miniframe"
-       echo m68010-convergent-sysv
-       exit ;;
+       GUESS=m68010-convergent-sysv
+       ;;
     mc68k:UNIX:SYSTEM5:3.51m)
-       echo m68k-convergent-sysv
-       exit ;;
+       GUESS=m68k-convergent-sysv
+       ;;
     M680?0:D-NIX:5.3:*)
-       echo m68k-diab-dnix
-       exit ;;
+       GUESS=m68k-diab-dnix
+       ;;
     M68*:*:R3V[5678]*:*)
        test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
     3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 
3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | 
SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
        OS_REL=''
        test -r /etc/.relid \
-       && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid)
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
          && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
        /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1241,7 +1279,7 @@ EOF
     NCR*:*:4.2:* | MPRAS*:*:4.2:*)
        OS_REL='.3'
        test -r /etc/.relid \
-           && OS_REL=.$(sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < 
/etc/.relid)
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < 
/etc/.relid`
        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
            && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
        /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
@@ -1249,118 +1287,118 @@ EOF
        /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
            && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
     m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-       echo m68k-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+       ;;
     mc68030:UNIX_System_V:4.*:*)
-       echo m68k-atari-sysv4
-       exit ;;
+       GUESS=m68k-atari-sysv4
+       ;;
     TSUNAMI:LynxOS:2.*:*)
-       echo sparc-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+       ;;
     rs6000:LynxOS:2.*:*)
-       echo rs6000-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+       ;;
     PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
-       echo powerpc-unknown-lynxos"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+       ;;
     SM[BE]S:UNIX_SV:*:*)
-       echo mips-dde-sysv"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-dde-sysv$UNAME_RELEASE
+       ;;
     RM*:ReliantUNIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
+       GUESS=mips-sni-sysv4
+       ;;
     RM*:SINIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
+       GUESS=mips-sni-sysv4
+       ;;
     *:SINIX-*:*:*)
        if uname -p 2>/dev/null >/dev/null ; then
-               UNAME_MACHINE=$( (uname -p) 2>/dev/null)
-               echo "$UNAME_MACHINE"-sni-sysv4
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               GUESS=$UNAME_MACHINE-sni-sysv4
        else
-               echo ns32k-sni-sysv
+               GUESS=ns32k-sni-sysv
        fi
-       exit ;;
+       ;;
     PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
                        # says <Richard.M.Bartel@ccMail.Census.GOV>
-       echo i586-unisys-sysv4
-       exit ;;
+       GUESS=i586-unisys-sysv4
+       ;;
     *:UNIX_System_V:4*:FTX*)
        # From Gerald Hewes <hewes@openmarket.com>.
        # How about differentiating between stratus architectures? -djm
-       echo hppa1.1-stratus-sysv4
-       exit ;;
+       GUESS=hppa1.1-stratus-sysv4
+       ;;
     *:*:*:FTX*)
        # From seanf@swdc.stratus.com.
-       echo i860-stratus-sysv4
-       exit ;;
+       GUESS=i860-stratus-sysv4
+       ;;
     i*86:VOS:*:*)
        # From Paul.Green@stratus.com.
-       echo "$UNAME_MACHINE"-stratus-vos
-       exit ;;
+       GUESS=$UNAME_MACHINE-stratus-vos
+       ;;
     *:VOS:*:*)
        # From Paul.Green@stratus.com.
-       echo hppa1.1-stratus-vos
-       exit ;;
+       GUESS=hppa1.1-stratus-vos
+       ;;
     mc68*:A/UX:*:*)
-       echo m68k-apple-aux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=m68k-apple-aux$UNAME_RELEASE
+       ;;
     news*:NEWS-OS:6*:*)
-       echo mips-sony-newsos6
-       exit ;;
+       GUESS=mips-sony-newsos6
+       ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
        if test -d /usr/nec; then
-               echo mips-nec-sysv"$UNAME_RELEASE"
+               GUESS=mips-nec-sysv$UNAME_RELEASE
        else
-               echo mips-unknown-sysv"$UNAME_RELEASE"
+               GUESS=mips-unknown-sysv$UNAME_RELEASE
        fi
-       exit ;;
+       ;;
     BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
-       echo powerpc-be-beos
-       exit ;;
+       GUESS=powerpc-be-beos
+       ;;
     BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
-       echo powerpc-apple-beos
-       exit ;;
+       GUESS=powerpc-apple-beos
+       ;;
     BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
-       echo i586-pc-beos
-       exit ;;
+       GUESS=i586-pc-beos
+       ;;
     BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
-       echo i586-pc-haiku
-       exit ;;
+       GUESS=i586-pc-haiku
+       ;;
     x86_64:Haiku:*:*)
-       echo x86_64-unknown-haiku
-       exit ;;
+       GUESS=x86_64-unknown-haiku
+       ;;
     SX-4:SUPER-UX:*:*)
-       echo sx4-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx4-nec-superux$UNAME_RELEASE
+       ;;
     SX-5:SUPER-UX:*:*)
-       echo sx5-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx5-nec-superux$UNAME_RELEASE
+       ;;
     SX-6:SUPER-UX:*:*)
-       echo sx6-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx6-nec-superux$UNAME_RELEASE
+       ;;
     SX-7:SUPER-UX:*:*)
-       echo sx7-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx7-nec-superux$UNAME_RELEASE
+       ;;
     SX-8:SUPER-UX:*:*)
-       echo sx8-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx8-nec-superux$UNAME_RELEASE
+       ;;
     SX-8R:SUPER-UX:*:*)
-       echo sx8r-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sx8r-nec-superux$UNAME_RELEASE
+       ;;
     SX-ACE:SUPER-UX:*:*)
-       echo sxace-nec-superux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=sxace-nec-superux$UNAME_RELEASE
+       ;;
     Power*:Rhapsody:*:*)
-       echo powerpc-apple-rhapsody"$UNAME_RELEASE"
-       exit ;;
+       GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+       ;;
     *:Rhapsody:*:*)
-       echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+       ;;
     arm64:Darwin:*:*)
-       echo aarch64-apple-darwin"$UNAME_RELEASE"
-       exit ;;
+       GUESS=aarch64-apple-darwin$UNAME_RELEASE
+       ;;
     *:Darwin:*:*)
-       UNAME_PROCESSOR=$(uname -p)
+       UNAME_PROCESSOR=`uname -p`
        case $UNAME_PROCESSOR in
            unknown) UNAME_PROCESSOR=powerpc ;;
        esac
@@ -1394,109 +1432,116 @@ EOF
            # uname -m returns i386 or x86_64
            UNAME_PROCESSOR=$UNAME_MACHINE
        fi
-       echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+       ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
-       UNAME_PROCESSOR=$(uname -p)
+       UNAME_PROCESSOR=`uname -p`
        if test "$UNAME_PROCESSOR" = x86; then
                UNAME_PROCESSOR=i386
                UNAME_MACHINE=pc
        fi
-       echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+       ;;
     *:QNX:*:4*)
-       echo i386-pc-qnx
-       exit ;;
+       GUESS=i386-pc-qnx
+       ;;
     NEO-*:NONSTOP_KERNEL:*:*)
-       echo neo-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=neo-tandem-nsk$UNAME_RELEASE
+       ;;
     NSE-*:NONSTOP_KERNEL:*:*)
-       echo nse-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nse-tandem-nsk$UNAME_RELEASE
+       ;;
     NSR-*:NONSTOP_KERNEL:*:*)
-       echo nsr-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsr-tandem-nsk$UNAME_RELEASE
+       ;;
     NSV-*:NONSTOP_KERNEL:*:*)
-       echo nsv-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsv-tandem-nsk$UNAME_RELEASE
+       ;;
     NSX-*:NONSTOP_KERNEL:*:*)
-       echo nsx-tandem-nsk"$UNAME_RELEASE"
-       exit ;;
+       GUESS=nsx-tandem-nsk$UNAME_RELEASE
+       ;;
     *:NonStop-UX:*:*)
-       echo mips-compaq-nonstopux
-       exit ;;
+       GUESS=mips-compaq-nonstopux
+       ;;
     BS2000:POSIX*:*:*)
-       echo bs2000-siemens-sysv
-       exit ;;
+       GUESS=bs2000-siemens-sysv
+       ;;
     DS/*:UNIX_System_V:*:*)
-       echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+       ;;
     *:Plan9:*:*)
        # "uname -m" is not consistent, so use $cputype instead. 386
        # is converted to i386 for consistency with other x86
        # operating systems.
-       # shellcheck disable=SC2154
-       if test "$cputype" = 386; then
+       if test "${cputype-}" = 386; then
            UNAME_MACHINE=i386
-       else
-           UNAME_MACHINE="$cputype"
+       elif test "x${cputype-}" != x; then
+           UNAME_MACHINE=$cputype
        fi
-       echo "$UNAME_MACHINE"-unknown-plan9
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-plan9
+       ;;
     *:TOPS-10:*:*)
-       echo pdp10-unknown-tops10
-       exit ;;
+       GUESS=pdp10-unknown-tops10
+       ;;
     *:TENEX:*:*)
-       echo pdp10-unknown-tenex
-       exit ;;
+       GUESS=pdp10-unknown-tenex
+       ;;
     KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
-       echo pdp10-dec-tops20
-       exit ;;
+       GUESS=pdp10-dec-tops20
+       ;;
     XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
-       echo pdp10-xkl-tops20
-       exit ;;
+       GUESS=pdp10-xkl-tops20
+       ;;
     *:TOPS-20:*:*)
-       echo pdp10-unknown-tops20
-       exit ;;
+       GUESS=pdp10-unknown-tops20
+       ;;
     *:ITS:*:*)
-       echo pdp10-unknown-its
-       exit ;;
+       GUESS=pdp10-unknown-its
+       ;;
     SEI:*:*:SEIUX)
-       echo mips-sei-seiux"$UNAME_RELEASE"
-       exit ;;
+       GUESS=mips-sei-seiux$UNAME_RELEASE
+       ;;
     *:DragonFly:*:*)
-       echo "$UNAME_MACHINE"-unknown-dragonfly"$(echo "$UNAME_RELEASE"|sed -e 
's/[-(].*//')"
-       exit ;;
+       DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+       GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+       ;;
     *:*VMS:*:*)
-       UNAME_MACHINE=$( (uname -p) 2>/dev/null)
-       case "$UNAME_MACHINE" in
-           A*) echo alpha-dec-vms ; exit ;;
-           I*) echo ia64-dec-vms ; exit ;;
-           V*) echo vax-dec-vms ; exit ;;
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case $UNAME_MACHINE in
+           A*) GUESS=alpha-dec-vms ;;
+           I*) GUESS=ia64-dec-vms ;;
+           V*) GUESS=vax-dec-vms ;;
        esac ;;
     *:XENIX:*:SysV)
-       echo i386-pc-xenix
-       exit ;;
+       GUESS=i386-pc-xenix
+       ;;
     i*86:skyos:*:*)
-       echo "$UNAME_MACHINE"-pc-skyos"$(echo "$UNAME_RELEASE" | sed -e 's/ 
.*$//')"
-       exit ;;
+       SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+       GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+       ;;
     i*86:rdos:*:*)
-       echo "$UNAME_MACHINE"-pc-rdos
-       exit ;;
-    i*86:AROS:*:*)
-       echo "$UNAME_MACHINE"-pc-aros
-       exit ;;
+       GUESS=$UNAME_MACHINE-pc-rdos
+       ;;
+    *:AROS:*:*)
+       GUESS=$UNAME_MACHINE-unknown-aros
+       ;;
     x86_64:VMkernel:*:*)
-       echo "$UNAME_MACHINE"-unknown-esx
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-esx
+       ;;
     amd64:Isilon\ OneFS:*:*)
-       echo x86_64-unknown-onefs
-       exit ;;
+       GUESS=x86_64-unknown-onefs
+       ;;
     *:Unleashed:*:*)
-       echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
-       exit ;;
+       GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+       ;;
 esac
 
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+    echo "$GUESS"
+    exit
+fi
+
 # No uname command or uname output not recognized.
 set_cc_for_build
 cat > "$dummy.c" <<EOF
@@ -1536,7 +1581,7 @@ main ()
 #define __ARCHITECTURE__ "m68k"
 #endif
   int version;
-  version=$( (hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 
2>/dev/null);
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
   if (version < 4)
     printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
   else
@@ -1628,7 +1673,7 @@ main ()
 }
 EOF
 
-$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=$($dummy) &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
        { echo "$SYSTEM_NAME"; exit; }
 
 # Apollos put the system type in the environment.
@@ -1636,7 +1681,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; 
exit; }
 
 echo "$0: unable to guess system type" >&2
 
-case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+case $UNAME_MACHINE:$UNAME_SYSTEM in
     mips:Linux | mips64:Linux)
        # If we got here on MIPS GNU/Linux, output extra information.
        cat >&2 <<EOF
@@ -1658,9 +1703,11 @@ and
   https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
 EOF
 
-year=$(echo $timestamp | sed 's,-.*,,')
+our_year=`echo $timestamp | sed 's,-.*,,'`
+thisyear=`date +%Y`
 # shellcheck disable=SC2003
-if test "$(expr "$(date +%Y)" - "$year")" -lt 3 ; then
+script_age=`expr "$thisyear" - "$our_year"`
+if test "$script_age" -lt 3 ; then
    cat >&2 <<EOF
 
 If $0 has already been updated, send the following data and any
@@ -1669,20 +1716,20 @@ provide the necessary information to handle your system.
 
 config.guess timestamp = $timestamp
 
-uname -m = $( (uname -m) 2>/dev/null || echo unknown)
-uname -r = $( (uname -r) 2>/dev/null || echo unknown)
-uname -s = $( (uname -s) 2>/dev/null || echo unknown)
-uname -v = $( (uname -v) 2>/dev/null || echo unknown)
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
 
-/usr/bin/uname -p = $( (/usr/bin/uname -p) 2>/dev/null)
-/bin/uname -X     = $( (/bin/uname -X) 2>/dev/null)
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
 
-hostinfo               = $( (hostinfo) 2>/dev/null)
-/bin/universe          = $( (/bin/universe) 2>/dev/null)
-/usr/bin/arch -k       = $( (/usr/bin/arch -k) 2>/dev/null)
-/bin/arch              = $( (/bin/arch) 2>/dev/null)
-/usr/bin/oslevel       = $( (/usr/bin/oslevel) 2>/dev/null)
-/usr/convex/getsysinfo = $( (/usr/convex/getsysinfo) 2>/dev/null)
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
 
 UNAME_MACHINE = "$UNAME_MACHINE"
 UNAME_RELEASE = "$UNAME_RELEASE"
diff --git a/build-aux/config.sub b/build-aux/config.sub
index b0f8492348..d74fb6deac 100755
--- a/build-aux/config.sub
+++ b/build-aux/config.sub
@@ -2,7 +2,9 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2021 Free Software Foundation, Inc.
 
-timestamp='2021-01-07'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2021-08-14'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -50,7 +52,14 @@ timestamp='2021-01-07'
 #      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
 # It is wrong to echo any other type of specification.
 
-me=$(echo "$0" | sed -e 's,.*/,,')
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX.  However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
 Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
@@ -112,9 +121,11 @@ esac
 
 # Split fields of configuration type
 # shellcheck disable=SC2162
+saved_IFS=$IFS
 IFS="-" read field1 field2 field3 field4 <<EOF
 $1
 EOF
+IFS=$saved_IFS
 
 # Separate into logical components for further validation
 case $1 in
@@ -163,6 +174,10 @@ case $1 in
                                                basic_machine=$field1
                                                basic_os=$field2
                                                ;;
+                                       zephyr*)
+                                               basic_machine=$field1-unknown
+                                               basic_os=$field2
+                                               ;;
                                        # Manufacturers
                                        dec* | mips* | sequent* | encore* | 
pc533* | sgi* | sony* \
                                        | att* | 7300* | 3300* | delta* | 
motorola* | sun[234]* \
@@ -769,22 +784,22 @@ case $basic_machine in
                vendor=hp
                ;;
        i*86v32)
-               cpu=$(echo "$1" | sed -e 's/86.*/86/')
+               cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
                basic_os=sysv32
                ;;
        i*86v4*)
-               cpu=$(echo "$1" | sed -e 's/86.*/86/')
+               cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
                basic_os=sysv4
                ;;
        i*86v)
-               cpu=$(echo "$1" | sed -e 's/86.*/86/')
+               cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
                basic_os=sysv
                ;;
        i*86sol2)
-               cpu=$(echo "$1" | sed -e 's/86.*/86/')
+               cpu=`echo "$1" | sed -e 's/86.*/86/'`
                vendor=pc
                basic_os=solaris2
                ;;
@@ -917,14 +932,16 @@ case $basic_machine in
                ;;
        leon-*|leon[3-9]-*)
                cpu=sparc
-               vendor=$(echo "$basic_machine" | sed 's/-.*//')
+               vendor=`echo "$basic_machine" | sed 's/-.*//'`
                ;;
 
        *-*)
                # shellcheck disable=SC2162
+               saved_IFS=$IFS
                IFS="-" read cpu vendor <<EOF
 $basic_machine
 EOF
+               IFS=$saved_IFS
                ;;
        # We use `pc' rather than `unknown'
        # because (1) that's what they normally are, and
@@ -1084,7 +1101,7 @@ case $cpu-$vendor in
                cpu=mipsisa64sb1el
                ;;
        sh5e[lb]-*)
-               cpu=$(echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/')
+               cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
                ;;
        spur-*)
                cpu=spur
@@ -1102,7 +1119,7 @@ case $cpu-$vendor in
                cpu=x86_64
                ;;
        xscale-* | xscalee[bl]-*)
-               cpu=$(echo "$cpu" | sed 's/^xscale/arm/')
+               cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
                ;;
        arm64-*)
                cpu=aarch64
@@ -1165,7 +1182,7 @@ case $cpu-$vendor in
                        | alphapca5[67] | alpha64pca5[67] \
                        | am33_2.0 \
                        | amdgcn \
-                       | arc | arceb \
+                       | arc | arceb | arc32 | arc64 \
                        | arm | arm[lb]e | arme[lb] | armv* \
                        | avr | avr32 \
                        | asmjs \
@@ -1204,9 +1221,13 @@ case $cpu-$vendor in
                        | mips64vr5900 | mips64vr5900el \
                        | mipsisa32 | mipsisa32el \
                        | mipsisa32r2 | mipsisa32r2el \
+                       | mipsisa32r3 | mipsisa32r3el \
+                       | mipsisa32r5 | mipsisa32r5el \
                        | mipsisa32r6 | mipsisa32r6el \
                        | mipsisa64 | mipsisa64el \
                        | mipsisa64r2 | mipsisa64r2el \
+                       | mipsisa64r3 | mipsisa64r3el \
+                       | mipsisa64r5 | mipsisa64r5el \
                        | mipsisa64r6 | mipsisa64r6el \
                        | mipsisa64sb1 | mipsisa64sb1el \
                        | mipsisa64sr71k | mipsisa64sr71kel \
@@ -1288,30 +1309,32 @@ then
 case $basic_os in
        gnu/linux*)
                kernel=linux
-               os=$(echo $basic_os | sed -e 's|gnu/linux|gnu|')
+               os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
                ;;
        os2-emx)
                kernel=os2
-               os=$(echo $basic_os | sed -e 's|os2-emx|emx|')
+               os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
                ;;
        nto-qnx*)
                kernel=nto
-               os=$(echo $basic_os | sed -e 's|nto-qnx|qnx|')
+               os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
                ;;
        *-*)
                # shellcheck disable=SC2162
+               saved_IFS=$IFS
                IFS="-" read kernel os <<EOF
 $basic_os
 EOF
+               IFS=$saved_IFS
                ;;
        # Default OS when just kernel was specified
        nto*)
                kernel=nto
-               os=$(echo $basic_os | sed -e 's|nto|qnx|')
+               os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
                ;;
        linux*)
                kernel=linux
-               os=$(echo $basic_os | sed -e 's|linux|gnu|')
+               os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
                ;;
        *)
                kernel=
@@ -1332,7 +1355,7 @@ case $os in
                os=cnk
                ;;
        solaris1 | solaris1.*)
-               os=$(echo $os | sed -e 's|solaris1|sunos4|')
+               os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
                ;;
        solaris)
                os=solaris2
@@ -1361,7 +1384,7 @@ case $os in
                os=sco3.2v4
                ;;
        sco3.2.[4-9]*)
-               os=$(echo $os | sed -e 's/sco3.2./sco3.2v/')
+               os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
                ;;
        sco*v* | scout)
                # Don't match below
@@ -1391,7 +1414,7 @@ case $os in
                os=lynxos
                ;;
        mac[0-9]*)
-               os=$(echo "$os" | sed -e 's|mac|macos|')
+               os=`echo "$os" | sed -e 's|mac|macos|'`
                ;;
        opened*)
                os=openedition
@@ -1400,10 +1423,10 @@ case $os in
                os=os400
                ;;
        sunos5*)
-               os=$(echo "$os" | sed -e 's|sunos5|solaris2|')
+               os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
                ;;
        sunos6*)
-               os=$(echo "$os" | sed -e 's|sunos6|solaris3|')
+               os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
                ;;
        wince*)
                os=wince
@@ -1437,7 +1460,7 @@ case $os in
                ;;
        # Preserve the version number of sinix5.
        sinix5.*)
-               os=$(echo $os | sed -e 's|sinix|sysv|')
+               os=`echo "$os" | sed -e 's|sinix|sysv|'`
                ;;
        sinix*)
                os=sysv4
@@ -1683,12 +1706,15 @@ fi
 
 # Now, validate our (potentially fixed-up) OS.
 case $os in
-       # Sometimes we do "kernel-abi", so those need to count as OSes.
-       musl* | newlib* | uclibc*)
+       # Sometimes we do "kernel-libc", so those need to count as OSes.
+       musl* | newlib* | relibc* | uclibc*)
                ;;
-       # Likewise for "kernel-libc"
+       # Likewise for "kernel-abi"
        eabi* | gnueabi*)
                ;;
+       # VxWorks passes extra cpu info in the 4th filed.
+       simlinux | simwindows | spe)
+               ;;
        # Now accept the basic system types.
        # The portable systems comes first.
        # Each alternative MUST end in a * to match a version number.
@@ -1704,12 +1730,12 @@ case $os in
             | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
             | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
             | mirbsd* | netbsd* | dicos* | openedition* | ose* \
-            | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+            | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
             | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
             | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
             | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
             | udi* | lites* | ieee* | go32* | aux* | hcos* \
-            | chorusrdb* | cegcc* | glidix* \
+            | chorusrdb* | cegcc* | glidix* | serenity* \
             | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
             | midipix* | mingw32* | mingw64* | mint* \
             | uxpv* | beos* | mpeix* | udk* | moxiebox* \
@@ -1722,7 +1748,7 @@ case $os in
             | skyos* | haiku* | rdos* | toppers* | drops* | es* \
             | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
             | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
-            | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+            | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*)
                ;;
        # This one is extra strict with allowed versions
        sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
@@ -1739,11 +1765,12 @@ esac
 # As a final step for OS-related things, validate the OS-kernel combination
 # (given a valid OS), if there is a kernel.
 case $kernel-$os in
-       linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | 
linux-musl* | linux-uclibc* )
+       linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+                  | linux-musl* | linux-relibc* | linux-uclibc* )
                ;;
        uclinux-uclibc* )
                ;;
-       -dietlibc* | -newlib* | -musl* | -uclibc* )
+       -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
                # These are just libc implementations, not actual OSes, and thus
                # require a kernel.
                echo "Invalid configuration \`$1': libc \`$os' needs explicit 
kernel." 1>&2
@@ -1751,6 +1778,8 @@ case $kernel-$os in
                ;;
        kfreebsd*-gnu* | kopensolaris*-gnu*)
                ;;
+       vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+               ;;
        nto-qnx*)
                ;;
        os2-emx)
diff --git a/build-aux/gitlog-to-changelog b/build-aux/gitlog-to-changelog
index de76f658d4..9ff15f6019 100755
--- a/build-aux/gitlog-to-changelog
+++ b/build-aux/gitlog-to-changelog
@@ -35,7 +35,7 @@
 eval 'exec perl -wSx "$0" "$@"'
      if 0;
 
-my $VERSION = '2020-04-04 15:07'; # UTC
+my $VERSION = '2021-02-24 23:42'; # UTC
 # The definition above must lie within the first 8 lines in order
 # for the Emacs time-stamp write hook (at end) to update it.
 # If you change this file with Emacs, please let the write hook
@@ -455,7 +455,8 @@ sub git_dir_option($)
           # If there were any lines
           if (@line == 0)
             {
-              warn "$ME: warning: empty commit message:\n  $date_line\n";
+              warn "$ME: warning: empty commit message:\n"
+                   . "  commit $sha\n  $date_line\n";
             }
           else
             {
diff --git a/configure.ac b/configure.ac
index f151dd551d..33e7037afe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@ dnl  along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.
 
 AC_PREREQ(2.65)
 dnl Note this is parsed by (at least) make-dist and lisp/cedet/ede/emacs.el.
-AC_INIT(GNU Emacs, 28.0.50, bug-gnu-emacs@gnu.org, , 
https://www.gnu.org/software/emacs/)
+AC_INIT(GNU Emacs, 29.0.50, bug-gnu-emacs@gnu.org, , 
https://www.gnu.org/software/emacs/)
 
 dnl Set emacs_config_options to the options of 'configure', quoted for the 
shell,
 dnl and then quoted again for a C string.  Separate options with spaces.
@@ -447,6 +447,7 @@ OPTION_DEFAULT_ON([tiff],[don't compile with TIFF image 
support])
 OPTION_DEFAULT_ON([gif],[don't compile with GIF image support])
 OPTION_DEFAULT_ON([png],[don't compile with PNG image support])
 OPTION_DEFAULT_ON([rsvg],[don't compile with SVG image support])
+OPTION_DEFAULT_ON([webp],[don't compile with WebP image support])
 OPTION_DEFAULT_ON([lcms2],[don't compile with Little CMS support])
 OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support])
 OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing])
@@ -485,6 +486,7 @@ OPTION_DEFAULT_ON([zlib],[don't compile with zlib 
decompression support])
 OPTION_DEFAULT_ON([modules],[don't compile with dynamic modules support])
 OPTION_DEFAULT_ON([threads],[don't compile with elisp threading support])
 OPTION_DEFAULT_OFF([native-compilation],[compile with Emacs Lisp native 
compiler support])
+OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 
32-bit Cygwin])
 
 AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB],
  [use a file notification library (LIB one of: yes, inotify, kqueue, gfile, 
w32, no)])],
@@ -875,8 +877,8 @@ done
 ac_func_list=$funcs
 # Emacs does not use the wchar or wctype-h modules.
 AC_DEFUN([gt_TYPE_WINT_T],
-  [GNULIB_OVERRIDES_WINT_T=0
-   AC_SUBST([GNULIB_OVERRIDES_WINT_T])])
+  [GNULIBHEADERS_OVERRIDE_WINT_T=0
+   AC_SUBST([GNULIBHEADERS_OVERRIDE_WINT_T])])
 
 # Initialize gnulib right after choosing the compiler.
 dnl Amongst other things, this sets AR and ARFLAGS.
@@ -2588,6 +2590,28 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = 
"yes" || test "${opsys}" =
   fi
 fi
 
+### Use -lwebp if available, unless '--with-webp=no'
+HAVE_WEBP=no
+if test "${with_webp}" != "no"; then
+   if test "${HAVE_X11}" = "yes" || test "${opsys}" = "mingw32" \
+   || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes"; then
+      WEBP_REQUIRED=0.6.0
+      WEBP_MODULE="libwebp >= $WEBP_REQUIRED"
+
+      EMACS_CHECK_MODULES([WEBP], [$WEBP_MODULE])
+      AC_SUBST(WEBP_CFLAGS)
+      AC_SUBST(WEBP_LIBS)
+   fi
+   if test $HAVE_WEBP = yes; then
+      AC_DEFINE(HAVE_WEBP, 1, [Define to 1 if using libwebp.])
+      CFLAGS="$CFLAGS $WEBP_CFLAGS"
+      # Windows loads libwebp dynamically
+      if test "${opsys}" = "mingw32"; then
+       WEBP_LIBS=
+      fi
+   fi
+fi
+
 HAVE_IMAGEMAGICK=no
 if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test 
"${HAVE_W32}" = "yes"; then
   if test "${with_imagemagick}" != "no"; then
@@ -3738,10 +3762,12 @@ AC_SUBST_FILE([module_env_snippet_25])
 AC_SUBST_FILE([module_env_snippet_26])
 AC_SUBST_FILE([module_env_snippet_27])
 AC_SUBST_FILE([module_env_snippet_28])
+AC_SUBST_FILE([module_env_snippet_29])
 module_env_snippet_25="$srcdir/src/module-env-25.h"
 module_env_snippet_26="$srcdir/src/module-env-26.h"
 module_env_snippet_27="$srcdir/src/module-env-27.h"
 module_env_snippet_28="$srcdir/src/module-env-28.h"
+module_env_snippet_29="$srcdir/src/module-env-29.h"
 emacs_major_version="${PACKAGE_VERSION%%.*}"
 AC_SUBST(emacs_major_version)
 
@@ -3814,6 +3840,16 @@ source on this site:
 HAVE_NATIVE_COMP=no
 LIBGCCJIT_LIBS=
 LIBGCCJIT_CFLAGS=
+if test "$canonical" = i686-pc-cygwin; then
+  if test "${with_cygwin32_native_compilation}" = yes; then
+    with_native_compilation=yes
+  elif test "${with_native_compilation}" != no; then
+    AC_MSG_ERROR([Native compilation is not supported on 32-bit Cygwin.
+If you really want to try it anyway, use the configure option
+'--with-cygwin32-native-compilation'.])
+  fi
+fi
+
 if test "${with_native_compilation}" != "no"; then
     if test "${HAVE_PDUMPER}" = no; then
        AC_MSG_ERROR(['--with-native-compilation' requires 
'--with-dumping=pdumper'])
@@ -5671,6 +5707,7 @@ CFLAGS=$pre_PKG_CONFIG_CFLAGS
 LIBS="$LIB_PTHREAD $pre_PKG_CONFIG_LIBS"
 gl_ASSERT_NO_GNULIB_POSIXCHECK
 gl_ASSERT_NO_GNULIB_TESTS
+gl_EEMALLOC
 gl_INIT
 CFLAGS=$SAVE_CFLAGS
 LIBS=$SAVE_LIBS
@@ -5879,8 +5916,8 @@ emacs_config_features=
 for opt in ACL CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \
  HARFBUZZ IMAGEMAGICK JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 \
  M17N_FLT MODULES NATIVE_COMP NOTIFY NS OLDXMENU PDUMPER PNG RSVG SECCOMP \
- SOUND THREADS TIFF \
- TOOLKIT_SCROLL_BARS UNEXEC X11 XAW3D XDBE XFT XIM XPM XWIDGETS X_TOOLKIT \
+ SOUND THREADS TIFF TOOLKIT_SCROLL_BARS \
+ UNEXEC WEBP X11 XAW3D XDBE XFT XIM XPM XWIDGETS X_TOOLKIT \
  ZLIB; do
 
     case $opt in
@@ -5925,6 +5962,7 @@ AS_ECHO(["  Does Emacs use -lXaw3d?                       
          ${HAVE_XAW3D
   Does Emacs use a gif library?                           ${HAVE_GIF} $LIBGIF
   Does Emacs use a png library?                           ${HAVE_PNG} $LIBPNG
   Does Emacs use -lrsvg-2?                                ${HAVE_RSVG}
+  Does Emacs use -lwebp?                                  ${HAVE_WEBP}
   Does Emacs use cairo?                                   ${HAVE_CAIRO}
   Does Emacs use -llcms2?                                 ${HAVE_LCMS2}
   Does Emacs use imagemagick?                             ${HAVE_IMAGEMAGICK}
diff --git a/doc/emacs/anti.texi b/doc/emacs/anti.texi
index 49da473fa5..3b02187b5c 100644
--- a/doc/emacs/anti.texi
+++ b/doc/emacs/anti.texi
@@ -4,156 +4,138 @@
 @c See file emacs.texi for copying conditions.
 
 @node Antinews
-@appendix Emacs 26 Antinews
+@appendix Emacs 27 Antinews
 @c Update the emacs.texi Antinews menu entry with the above version number.
 
   For those users who live backwards in time, here is information
-about downgrading to Emacs version 26.3.  We hope you will enjoy the
+about downgrading to Emacs version 27.2.  We hope you will enjoy the
 greater simplicity that results from the absence of many @w{Emacs
 @value{EMACSVER}} features.
 
 @itemize @bullet
 @item
-Emacs no longer uses @acronym{GMP}, the GNU Multiple Precision
-library, and doesn't support Lisp integers greater than
-@code{most-positive-fixnum} or smaller than
-@code{most-negative-fixnum}.  We now have only one kind of a Lisp
-integer.  This simplifies many Lisp programs that use integers, and
-makes integer calculations always fast.  If you want larger values,
-use Lisp floats, as Emacs has done since day one.
+Emacs can no longer be built with support of native compilation of
+Lisp programs.  This means Emacs builds much faster, and the problems
+that came with native compilation: the need to have GCC and Binutils
+installed, the complications of managing your @file{eln-cache}
+directories---all of that is now future history.  The simplicity and
+elegance of the Emacs byte-compiled code is now restored in all of its
+pristine beauty.
 
 @item
-Emacs no longer supports HarfBuzz as the engine for shaping complex
-text.  As you move back in time, we will gradually shed off all traces
-of support for complex text shaping, and this is one step in that
-direction.
+Emacs no longer builds by default with Cairo, even if it's present.
+The warnings about not using HarfBuzz are also gone, in preparation
+for complete removal of HarfBuzz support in previous Emacs versions.
+Fancy text shaping and display is becoming less important as you move
+back in time.  The @code{ftx} font backend is again part of Emacs, for
+the same reasons.
 
 @item
-We have removed support for building with the Jansson library, and
-consequently the native support for JSON parsing is gone.  The
-importance of JSON decreases as we go back in time, so for now using
-the Lisp code for handling it should be good enough; in one of the
-past Emacs versions, we intend to remove even that, as useless bloat.
-
-The library for supporting JSONRPC applications was removed for the
-same reason.
+As Motif becomes more and more important with moving farther into the
+past, we've reinstated the code which supports Motif in Emacs.
 
 @item
-The ``portable dumper'' feature is gone.  We are once again using the
-field-proven ``unexec'' way of dumping Emacs.  With that, the hope for
-being able to re-dump your customized Emacs session is also gone: why
-would anyone want to record their random customization experiments on
-disk, and restore them the next time they start Emacs?  And true
-Emacsers don't restart their Emacs sessions anyway.
+Emacs once again supports versions 5.3 and older OpenBSD systems,
+which will be needed as you move back in time.
 
 @item
-We dropped the support for @acronym{XDG}-style configuration
-directories and the @env{XDG_CONFIG_HOME} environment variable.
-There's once again only one place where Emacs looks for its init
-files: the @file{~/.emacs.d} directory, with the @file{~/.emacs} file
-as fallback.  We think this will go a long way towards preventing
-confusion among users who for some reason have @env{XDG_CONFIG_HOME}
-set, thus risking to have their init files randomly spread between two
-places.  In one of the past Emacs versions, we intend to further
-simplify this, removing the @file{~/.emacs.d} place and leaving only
-@file{~/.emacs}; stay tuned.
-
-For similar reasons, we've removed the ``early init'' file.  You can
-now again use all the tricks you want to initialize variables like
-@code{package-user-dir} and @code{package-load-list} just in time for
-the packages to load.
+We've dropped support for Secure Computing filter on GNU/Linux.  The
+past world is much more secure than the present, so the complexities
+related with this stuff, which can only be explained by severe
+paranoia, are no longer justified.
 
-@command{emacsclient} no longer supports @acronym{XDG}-style directory
-trees, either.
+@item
+Emacs reverted back to supporting Unicode 13.x, since the following
+versions of the standards are not yet published where you are going.
+The @samp{emoji} script and the support for displaying Emoji sequences
+were removed for the same reasons: no one will produce them in the
+past.
 
 @item
-TLS connections are back to their lenient security settings.  We
-decided that too tight security settings are an annoyance for users,
-and make little sense considering the world-wide tendency to have
-fewer and fewer network security problems as we move back in time
-(those issues will be completely gone when networks disappear in some
-distant past).
+Mode-specific commands and the @kbd{M-S-x} command that invokes them
+were removed.  As you move back in time, the command set in Emacs
+becomes smaller, so any such filtering of applicable commands just
+gets in the way.
 
 @item
-The @code{server-after-make-frame-hook} hook was deleted, in
-preparation for removing the entire daemon business in some past Emacs
-version.  You will be glad to learn that setting up the GUI
-customizations of your sessions is now once again as easy as it ever
-was, with just the @code{after-make-frame-functions} to use.
+We have removed the system for displaying documentation of groups of
+related functions, the @kbd{shortdoc-display-group} command to go with
+it, and the corresponding ``See also'' button in the @file{*Help*}
+buffer.  That should make searching for certain functions simpler:
+just use the venerable @samp{apropos} commands.
 
 @item
-The @code{flex} completion style was removed.  We feel that it
-unnecessarily complicates the Emacs user experience, and therefore
-will continue to remove other tricky completion styles, until in some
-past Emacs version we get to a single original style Emacs pioneered
-decades ago.  Long live simplicity; down with complications!
+The @code{context-menu-mode} was removed, and with it the context
+menus popped by pressing the right mouse button.  This is one small
+step towards freeing Emacs (and eventually, the whole world of
+computing) from the tyranny of the GUI pointing devices in general,
+and moving back to the simplicity of text-mode user interfaces.
+Down with mice and other rodents!
 
 @item
-The optional display of the fill-column indicator is no longer
-supported.  With the display sizes becoming smaller and smaller as you
-move back in time, we feel that the display itself will always show
-you where to fill or wrap your text, and do this much more easily and
-reliably than any such display indicator.
+The commands @kbd{C-x 4 4} and @kbd{C-x 5 5} for displaying the
+results in a new window/frame re gone.  We are quite certain that
+creating a new window/frame before running a command is much simpler,
+and doesn't require a complication of a new prefix.
 
 @item
-We removed the features that made visiting large files easier.  Thus,
-Emacs will no longer suggest visiting a large file literally, nor
-offer the @code{so-long} mode to deal with overly-long lines.  We
-decided that this simplification is worthwhile, given that the general
-tendency of having very large files is becoming a rarity as we move
-back in time.
+The behavior of active minibuffers when switching frames is now the
+perfect mess it should be: sometimes the minibuffer moves to the new
+selected frame, sometimes it doesn't, and sometimes you get an error.
+This makes Emacs usage much more fun, as you get to guess the result,
+instead of having it boringly consistent.
 
 @item
-We have removed the feature that displayed echo-area messages without
-hiding content of the active minibuffer.  This should prevent user
-confusion from having two unrelated pieces of text staring at them,
-with no clear separation between them.  Users with good memories (and
-Emacs users are all expected to be of that kind) will have no trouble
-keeping the minibuffer text in their minds, and typing the responses
-without actually seeing the prompts.
+Compact mode-line display mode has been removed.  The items displayed
+on the mode line are now always in the same place, and if there's not
+enough space for them, they are not displayed at all, instead of being
+confusingly displayed in a different position.  You no longer need to
+think twice where to find a particular mode-line element on display.
 
 @item
-Horizontal scrolling using the mouse or touchpad has been removed.  In
-the past, wide monitors will become less popular, so horizontal
-scrolling will no longer be needed.  Removal of the mouse support for
-horizontal scrolling is the first step towards its complete removal in
-prior Emacs versions.
+Many commands and options related to tab bars were removed, including
+(but not limited to) frame-specific appearance of tab bars, the
+@code{tab-bar-format} option, the @kbd{C-x t n}, @kbd{C-x t N},
+@kbd{C-x t M}, and @kbd{C-x t G} commands, and many mouse gestures on
+the tab bar.  We are going to delete the tab bar support from Emacs in
+one of the past versions, and this is a step in that direction.
 
 @item
-The @code{main-thread} variable and @code{list-threads} were removed,
-and @code{thread-join} no longer returns the result of the finished
-thread.  We intend to remove the support for Lisp threads in some past
-Emacs version, so we continue removing the associated complexities and
-features as we go back in time.
+The ``transient'' input methods have been removed; use @kbd{C-\} to
+turn input methods on and off instead.  This is in preparation for
+complete removal of input methods from Emacs in version 19, and
+consistent with the fact that the number of input methods we support
+becomes smaller as you move back in time.
 
 @item
-Tab bar and window tab-lines were removed.  This should make the Emacs
-display simpler and less cluttered, and help those users who disable
-menu bar and tool bar in their GUI sessions.  The fashion to provide
-tabs in every GUI application out there is gaining less and less
-popularity as we move back in time, and will completely disappear at
-some past point; removing the tabs from Emacs is the step in that
-direction.
+We disabled @code{show-paren-mode} by default, since we think the
+venerable @code{blink-matching-paren} feature is more than enough, and
+better fits the simplicity of past Emacs versions.  It will definitely
+be better when colors are removed from Emacs in the distant past.
+
+For the same reason, sub-groups in interactive regexp searches are no
+longer highlighted in distinct colors.
 
 @item
-Displaying line numbers for a buffer is only possibly using add-on
-features, such as @code{linum-mode}, which can only display the
-numbers in the display margins.  Line-number display using these
-features is also slow, as we firmly believe such a feature is
-un-Emacsy and should not have been included in Emacs to begin with.
-Consequently, @code{display-line-numbers-mode} was removed.
+On our permanent quest for simplifying Emacs, we've removed the Ispell
+command @code{ispell-comment-or-string-at-point}; the old-time friend
+@code{ispell-comments-and-strings} should suffice.
 
 @item
-On our permanent quest for simplifying Emacs, we've removed the
-support for changing the font size by turning the mouse wheel.
+Many Gnus commands and options were deemed to unnecessarily complicate
+the use of Gnus (which is too complex to begin with), and thus were
+removed.  This includes @code{gnus-topic-display-predicate},
+@code{gnus-process-mark-toggle}, @code{gnus-registry-register-all},
+@code{gnus-paging-select-next}, and many others.  The @code{nnselect}
+backend was deleted for the same reason.
 
 @item
-Several commands, deemed to be unnecessary complications, have been
-removed.  Examples include @code{make-empty-file},
-@code{font-lock-refontify}, @code{xref-find-definitions-at-mouse},
-@code{make-frame-on-monitor}, and @code{diff-buffers}.
+The @file{project.el} package have been redesigned to remove many
+unnecessary features, so that just the bare essentials remain.  We
+plan on removing this package from Emacs in a previous version, but
+decided to begin with removing some extra features first.
 
 @item
 To keep up with decreasing computer memory capacity and disk space, many
-other functions and files have been eliminated in Emacs 26.3.
+other functions and files have been eliminated in Emacs 27.2.
 @end itemize
diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi
index 8de93867ba..2c694a5e39 100644
--- a/doc/emacs/building.texi
+++ b/doc/emacs/building.texi
@@ -213,7 +213,6 @@ Select a buffer to be used by next invocation of 
@code{next-error} and
 @kindex M-g n
 @kindex C-x `
 @findex next-error
-@findex next-error-message
 @vindex next-error-message-highlight
 @vindex next-error-highlight
 @vindex next-error-highlight-no-select
@@ -263,7 +262,9 @@ to skip any messages.
 highlights the relevant source line.  The duration of this highlight
 is determined by the variable @code{next-error-highlight} for the locus
 in the selected buffer, and @code{next-error-highlight-no-select} for
-the locus in non-selected buffers.
+the locus in non-selected buffers.  Also you can customize the variable
+@code{next-error-message-highlight} that defines how to highlight the
+current error message in the buffer that contains messages.
 
 @vindex compilation-context-lines
   If the @file{*compilation*} buffer is shown in a window with a left
diff --git a/doc/emacs/cmdargs.texi b/doc/emacs/cmdargs.texi
index d5177faea9..86c04c84a2 100644
--- a/doc/emacs/cmdargs.texi
+++ b/doc/emacs/cmdargs.texi
@@ -185,6 +185,11 @@ successfully.
 @item --version
 @opindex --version
 Print Emacs version, then exit successfully.
+
+@item --fingerprint
+@opindex --fingerprint
+Print the Emacs ``fingerprint'', which is used to uniquely identify
+the compiled version of Emacs.
 @end table
 
 @node Initial Options
@@ -268,7 +273,7 @@ system call unless otherwise requested.
 
 @vindex backtrace-on-error-noninteractive
 Errors that occur when running a @samp{--batch} Emacs will result in
-an Emacs Lisp backtrace being printed.  To disable this behaviour, set
+an Emacs Lisp backtrace being printed.  To disable this behavior, set
 @code{backtrace-on-error-noninteractive} to @code{nil}.
 
 @item --script @var{file}
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index d12033f841..d9d6a68005 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -195,7 +195,7 @@ the customization buffer:
 
   The first line shows that the variable is named
 @code{kill-ring-max}, formatted as @samp{Kill Ring Max} for easier
-viewing.  Its value is @samp{60}.  The button labeled @samp{[Hide]},
+viewing.  Its value is @samp{120}.  The button labeled @samp{[Hide]},
 if activated, hides the variable's value and state; this is useful to
 avoid cluttering up the customization buffer with very long values
 (for this reason, variables that have very long values may start out
@@ -1084,8 +1084,9 @@ first line:
 @noindent
 You can specify any number of variable/value pairs in this way, each
 pair with a colon and semicolon.  The special variable/value pair
-@code{mode: @var{modename};}, if present, specifies a major mode.  The
-@var{value}s are used literally, and not evaluated.
+@code{mode: @var{modename};}, if present, specifies a major mode
+(without the ``-mode'' suffix).  The @var{value}s are used literally,
+and not evaluated.
 
 @findex add-file-local-variable-prop-line
 @findex delete-file-local-variable-prop-line
@@ -1473,9 +1474,10 @@ as Dired buffers (@pxref{Dired}).
 
   Most of the variables reflect the situation on the local machine.
 Often, they must use a different value when you operate in buffers
-with a remote default directory.  Think about the shell to be applied
-when calling @code{shell} -- it might be @file{/bin/bash} on your
-local machine, and @file{/bin/ksh} on a remote machine.
+with a remote default directory.  Think about the behavior when
+calling @code{shell} -- on your local machine, you might use
+@file{/bin/bash} and rely on termcap, but on a remote machine, it may
+be @file{/bin/ksh} and terminfo.
 
   This can be accomplished with @dfn{connection-local variables}.
 Directory and file local variables override connection-local
@@ -1491,6 +1493,10 @@ variables/value pairs in a @dfn{profile}, using the
 criteria, identifying a remote machine:
 
 @example
+(connection-local-set-profile-variables 'remote-terminfo
+   '((system-uses-terminfo . t)
+     (comint-terminfo-terminal . "dumb-emacs-ansi")))
+
 (connection-local-set-profile-variables 'remote-ksh
    '((shell-file-name . "/bin/ksh")
      (shell-command-switch . "-c")))
@@ -1500,13 +1506,15 @@ criteria, identifying a remote machine:
      (shell-command-switch . "-c")))
 
 (connection-local-set-profiles
-   '(:application tramp :machine "remotemachine") 'remote-ksh)
+   '(:application tramp :machine "remotemachine")
+   'remote-terminfo 'remote-ksh)
 @end example
 
-  This code declares two different profiles, @code{remote-ksh} and
-@code{remote-bash}. The profile @code{remote-ksh} is applied to all
+  This code declares three different profiles, @code{remote-terminfo},
+@code{remote-ksh}, and @code{remote-bash}.  The profiles
+@code{remote-terminfo} and @code{remote-ksh} are applied to all
 buffers which have a remote default directory matching the regexp
-@code{"remotemachine} as host name.  Such a criteria can also
+@code{"remotemachine"} as host name.  Such a criteria can also
 discriminate for the properties @code{:protocol} (this is the Tramp
 method) or @code{:user} (a remote user name).  The @code{nil} criteria
 matches all buffers with a remote default directory.
diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 540abc3f3b..704850e584 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -1507,16 +1507,14 @@ buffer containing image-dired, corresponding to the 
marked files.
   You can also enter Image-Dired directly by typing @kbd{M-x
 image-dired}.  This prompts for a directory; specify one that has
 image files.  This creates thumbnails for all the images in that
-directory, and displays them all in the thumbnail buffer.  This
-takes a long time if the directory contains many image files, and it
-asks for confirmation if the number of image files exceeds
-@code{image-dired-show-all-from-dir-max-files}.
+directory, and displays them all in the thumbnail buffer.  The
+thumbnails are generated in the background and are loaded as they
+become available.
 
   With point in the thumbnail buffer, you can type @key{RET}
-(@code{image-dired-display-thumbnail-original-image}) to display a
-sized version of it in another window.  This sizes the image to fit
-the window.  Use the arrow keys to move around in the buffer.  For
-easy browsing, use @key{SPC}
+(@code{image-dired-display-thumbnail-original-image}) to display the
+image in another window.  Use the arrow keys to move around in the
+thumbnail buffer.  For easy browsing, use @key{SPC}
 (@code{image-dired-display-next-thumbnail-original}) to advance and
 display the next image.  Typing @key{DEL}
 (@code{image-dired-display-previous-thumbnail-original}) backs up to
diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi
index 996c5a6654..7ea754612e 100644
--- a/doc/emacs/display.texi
+++ b/doc/emacs/display.texi
@@ -150,6 +150,14 @@ gives you less jerky scrolling when you hold down 
@kbd{C-v}, but the
 window contents after any action which scrolls into a fresh portion of
 the buffer will be momentarily unfontified.
 
+@vindex redisplay-skip-fontification-on-input
+Finally, a third alternative to these variables is
+@code{redisplay-skip-fontification-on-input}.  If this variable is
+non-@code{nil}, skip some fontifications is there's input pending.
+This usually does not affect the display because redisplay is
+completely skipped anyway if input was pending, but it can make
+scrolling smoother by avoiding unnecessary fontification.
+
 @vindex scroll-up
 @vindex scroll-down
 @findex scroll-up-line
diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi
index 2fafb43e9f..83847fb8f1 100644
--- a/doc/emacs/emacs.texi
+++ b/doc/emacs/emacs.texi
@@ -219,7 +219,7 @@ Appendices
 * GNU Free Documentation License:: The license for this documentation.
 * Emacs Invocation::    Hairy startup options.
 * X Resources::         X resources for customizing Emacs.
-* Antinews::            Information about Emacs version 26.
+* Antinews::            Information about Emacs version 27.
 * Mac OS / GNUstep::     Using Emacs under macOS and GNUstep.
 * Microsoft Windows::   Using Emacs on Microsoft Windows and MS-DOS.
 * Manifesto::           What's GNU?  Gnu's Not Unix!
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 65a57ccd31..3e0788307a 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -2205,11 +2205,11 @@ window, so this is only necessary if you customize the 
default
 behavior by using the options @code{image-auto-resize} and
 @code{image-auto-resize-on-window-resize}.
 
-@findex image-transform-fit-both
+@findex image-transform-fit-to-window
 @findex image-transform-set-scale
 @findex image-transform-reset
 To resize the image manually you can use the command
-@code{image-transform-fit-both} bound to @kbd{s b}
+@code{image-transform-fit-to-window} bound to @kbd{s w}
 that fits the image to both the window height and width.
 To scale the image specifying a scale factor, use the command
 @code{image-transform-set-scale} bound to @kbd{s s}.
diff --git a/doc/emacs/fixit.texi b/doc/emacs/fixit.texi
index 85cdbff5fa..7feebddee8 100644
--- a/doc/emacs/fixit.texi
+++ b/doc/emacs/fixit.texi
@@ -463,7 +463,7 @@ use @code{flyspell-region} or @code{flyspell-buffer} for 
that.
 it with @kbd{mouse-2} (@code{flyspell-correct-word}) to display a menu
 of possible corrections and actions.  If you want this menu on
 @kbd{mouse-3} instead, enable @code{context-menu-mode}.  In addition,
-@kbd{C-.} or @kbd{@key{ESC}-@key{TAB}} (@code{flyspell-auto-correct-word})
+@kbd{C-.} or @kbd{@key{ESC} @key{TAB}} (@code{flyspell-auto-correct-word})
 will propose various successive corrections for the word at point, and
 @w{@kbd{C-c $}} (@code{flyspell-correct-word-before-point}) will pop
 up a menu of possible corrections.  Of course, you can always correct
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 06e2642638..c14ada2957 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -458,8 +458,8 @@ Create a new frame using the default frame parameters
 @item C-x 5 c
 @kindex C-x 5 c
 @findex clone-frame
-Create a new frame using the parameters of the current frame
-(@code{clone-frame}).
+Create a new frame using the window configuration and frame parameters
+of the current frame (@code{clone-frame}).
 
 @item C-x 5 b @var{bufname} @key{RET}
 Select buffer @var{bufname} in another frame.  This runs
@@ -1316,11 +1316,6 @@ command applies to all frames, including frames yet to 
be created.  To
 control the use of tab bars at startup, customize the variable
 @code{tab-bar-mode} and save your customization.
 
-@findex toggle-frame-tab-bar
-  To toggle the use of the Tab Bar only on the selected frame, type
-@kbd{M-x toggle-frame-tab-bar}.  This command allows to enable the
-display of the Tab Bar on some frames and disable it on others.
-
 @vindex tab-bar-show
   The variable @code{tab-bar-show} controls whether the Tab Bar mode
 is turned on automatically.  If the value is @code{t}, then
@@ -1338,7 +1333,13 @@ Bar by using commands @kbd{M-x tab-new}, @kbd{M-x 
tab-close}, etc.
 
   Note that a numerical value of @code{tab-bar-show} can cause the Tab
 Bar to be displayed on some frames, but not on others, depending on
-the number of tabs defined on each frame.
+the number of tabs created on each frame.
+
+@findex toggle-frame-tab-bar
+  To toggle the use of the Tab Bar only on the selected frame, type
+@kbd{M-x toggle-frame-tab-bar}.  This command allows to enable the
+display of the Tab Bar on some frames and disable it on others,
+regardless of the values of @code{tab-bar-mode} and @code{tab-bar-show}.
 
 @kindex C-x t
   The prefix key @kbd{C-x t} is analogous to @kbd{C-x 5}.
@@ -1455,9 +1456,7 @@ names is sorted by recency, so you can use @kbd{M-n}
 the second last, and so on.
 
 @kindex C-1, tab bar
-@kindex C-9, tab bar
 @kindex M-1, tab bar
-@kindex M-9, tab bar
 @findex tab-select
 @vindex tab-bar-select-tab-modifiers
 @vindex tab-bar-tab-hints
@@ -1473,6 +1472,15 @@ name, you can customize another variable 
@code{tab-bar-tab-hints}.
 This will help you decide which numerical key to press to select the
 tab by its number.
 
+@kindex C-9, tab bar
+@kindex M-9, tab bar
+@findex tab-last
+@item @var{modifier}-@kbd{9}
+Switch to the last tab (@code{tab-last}).  The key combination is
+the modifier key defined by @code{tab-bar-select-tab-modifiers} and
+the key @kbd{9}.  With a numeric argument @var{n}, switch to the
+@var{n}th last tab.
+
 @kindex C-0, tab bar
 @kindex M-0, tab bar
 @findex tab-recent
@@ -1500,6 +1508,13 @@ to the right; with a negative argument @minus{}@var{n}, 
move it
 @var{n} positions to the left.
 @end table
 
+  You can use the mouse to operate on tabs.  Clicking @kbd{mouse-2}
+closes the tab.  Clicking @kbd{mouse-3} pops up the context menu with
+the items that operate on the clicked tab.  Dragging the tab with
+@kbd{mouse-1} moves it to another position on the tab bar.  Mouse
+wheel scrolling switches to the next or previous tab.  Holding down
+the @key{SHIFT} key during scrolling moves the tab to the left or right.
+
 @findex tab-bar-history-mode
   You can enable @code{tab-bar-history-mode} to remember window
 configurations used in every tab, and later restore them.
@@ -1516,6 +1531,9 @@ Cancel restoration of the previous window configuration.
 This moves forward in the history of window configurations.
 @end table
 
+  It's possible to customize the items displayed on the tab bar
+by the user option @code{tab-bar-format}.
+
 @node Dialog Boxes
 @section Using Dialog Boxes
 @cindex dialog boxes
diff --git a/doc/emacs/glossary.texi b/doc/emacs/glossary.texi
index 4f971eb1e0..9c06bcc4af 100644
--- a/doc/emacs/glossary.texi
+++ b/doc/emacs/glossary.texi
@@ -86,8 +86,8 @@ delimiter for you (@pxref{Matching,,Matching Parens}).
 @anchor{Glossary---Balanced Expression}
 @item Balanced Expressions
 A balanced expression is a syntactically recognizable expression, such
-as a symbol, number, string constant, block, or parenthesized expression
-in C@.  @xref{Expressions,Balanced Expressions}.
+as a symbol (q.v.@:), number, string constant, block, or parenthesized
+expression in C@.  @xref{Expressions,Balanced Expressions}.
 
 @item Balloon Help
 @xref{Glossary---Tooltips}.
@@ -238,7 +238,7 @@ a key binding in Emacs or to be invoked by its name
 
 @anchor{Glossary---Command Name}
 @item Command Name
-A command name is the name of a Lisp symbol that is a command
+A command name is the name of a Lisp symbol (q.v.@:) that is a command
 (@pxref{Commands}).  You can invoke any command by its name using
 @kbd{M-x} (@pxref{M-x,M-x,Running Commands by Name}).
 
@@ -1113,7 +1113,7 @@ Emacs.  @xref{Query Replace}.
 @anchor{Glossary---Quitting}
 @item Quitting
 Quitting means canceling a partially typed command or a running
-command, using @kbd{C-g} (or @kbd{C-@key{BREAK}} on MS-DOS).  @xref{Quitting}.
+command, using @kbd{C-g} (or @kbd{C-@key{Break}} on MS-DOS).  @xref{Quitting}.
 
 @item Quoting
 Quoting means depriving a character of its usual special significance.
@@ -1334,6 +1334,13 @@ allowed as well.
 @item String Substitution
 @xref{Glossary---Global Substitution}.
 
+@item Symbol
+A symbol in Emacs Lisp is an object with a name.  The object can be a
+variable (q.v.@:), a function or command (q.v.@:), or a face (q.v.@:).
+The symbol's name serves as the printed representation of the symbol.
+@xref{Symbol Type,, Symbol Type, elisp, The Emacs Lisp Reference
+Manual}.
+
 @item Syntax Highlighting
 @xref{Glossary---Font Lock}.
 
diff --git a/doc/emacs/help.texi b/doc/emacs/help.texi
index 4ee302fbf7..20a9d8be13 100644
--- a/doc/emacs/help.texi
+++ b/doc/emacs/help.texi
@@ -443,11 +443,13 @@ alphabetical order, change the variable
 
 @node Help Mode
 @section Help Mode Commands
+@findex help-mode
+@cindex help mode
 
-  Help buffers provide the same commands as View mode (@pxref{View
-Mode}); for instance, @key{SPC} scrolls forward, and @key{DEL} or
-@kbd{S-@key{SPC}} scrolls backward.  A few special commands are also
-provided:
+  Help buffers have Help mode as their major mode.  Help mode provides
+the same commands as View mode (@pxref{View Mode}); for instance,
+@key{SPC} scrolls forward, and @key{DEL} or @kbd{S-@key{SPC}} scrolls
+backward.  It also provides a few special commands:
 
 @table @kbd
 @item @key{RET}
@@ -459,15 +461,18 @@ Move point back to the previous hyperlink 
(@code{backward-button}).
 @item mouse-1
 @itemx mouse-2
 Follow a hyperlink that you click on.
+@item n
+@itemx p
+Move forward and back between pages in the Help buffer.
 @item C-c C-c
 Show all documentation about the symbol at point
 (@code{help-follow-symbol}).
 @item C-c C-f
 @itemx r
-Go forward to the next help topic (@code{help-go-forward}).
+Go forward in history of help commands (@code{help-go-forward}).
 @item C-c C-b
 @itemx l
-Go back to the previous help topic (@code{help-go-back}).
+Go back in history of help commands (@code{help-go-back}).
 @item s
 View the source of the current help topic (if any)
 (@code{help-view-source}).
@@ -496,6 +501,30 @@ C-b} or @kbd{l} (@code{help-go-back}).  While retracing 
your steps,
 you can go forward by using @kbd{C-c C-f} or @kbd{r}
 (@code{help-go-forward}).
 
+@kindex TAB @r{(Help mode)}
+@findex forward-button
+@kindex S-TAB @r{(Help mode)}
+@findex backward-button
+  To move between hyperlinks in a help buffer, use @key{TAB}
+(@code{forward-button}) to move forward to the next hyperlink and
+@kbd{S-@key{TAB}} (@code{backward-button}) to move back to the
+previous hyperlink.  These commands act cyclically; for instance,
+typing @key{TAB} at the last hyperlink moves back to the first
+hyperlink.
+
+@kindex n @r{(Help mode)}
+@kindex p @r{(Help mode)}
+@findex help-goto-next-page
+@findex help-goto-previous-page
+  Help buffers produced by some Help commands (like @kbd{C-h b}, which
+shows a long list of key bindings) are divided into pages by the
+@samp{^L} character.  In such buffers, the @kbd{n}
+(@code{help-goto-next-page}) command will take you to the next start
+of page, and the @kbd{p} (@code{help-goto-previous-page}) command will
+take you to the previous start of page.  This way you can quickly
+navigate between the different kinds of documentation in a help
+buffer.
+
 @cindex URL, viewing in help
 @cindex help, viewing web pages
 @cindex viewing web pages in help
@@ -505,16 +534,6 @@ code definitions, and URLs (web pages).  The first two are 
opened in
 Emacs, and the third using a web browser via the @code{browse-url}
 command (@pxref{Browse-URL}).
 
-@kindex TAB @r{(Help mode)}
-@findex forward-button
-@kindex S-TAB @r{(Help mode)}
-@findex backward-button
-  In a help buffer, @key{TAB} (@code{forward-button}) moves point
-forward to the next hyperlink, while @kbd{S-@key{TAB}}
-(@code{backward-button}) moves point back to the previous hyperlink.
-These commands act cyclically; for instance, typing @key{TAB} at the
-last hyperlink moves back to the first hyperlink.
-
   To view all documentation about any symbol in the text, move point
 to the symbol and type @kbd{C-c C-c} (@code{help-follow-symbol}).
 This shows the documentation for all the meanings of the symbol---as a
@@ -646,14 +665,14 @@ Emacs Lisp Reference Manual}).
 
 @findex describe-prefix-bindings
   You can get a list of subcommands for a particular prefix key by
-typing @kbd{C-h}, @kbd{?}, or @key{f1}
+typing @kbd{C-h}, @kbd{?}, or @key{F1}
 (@code{describe-prefix-bindings}) after the prefix key.  (There are a
 few prefix keys for which not all of these keys work---those that
 provide their own bindings for that key.  One of these prefix keys
 is @key{ESC}, because @kbd{@key{ESC} C-h} and @kbd{@key{ESC} ?} are
 actually @kbd{C-M-h} (@code{mark-defun}) and @kbd{M-?}
 (@code{xref-find-references}), respectively.  However,
-@w{@kbd{@key{ESC} @key{f1}}} works fine.)
+@w{@kbd{@key{ESC} @key{F1}}} works fine.)
 
 @findex describe-keymap
 Finally, @kbd{M-x describe-keymap} prompts for the name of a keymap,
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 6e4fd77e8b..375ac970d7 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -353,7 +353,7 @@ other ways to move text around.)
 
 @vindex kill-ring-max
   The maximum number of entries in the kill ring is controlled by the
-variable @code{kill-ring-max}.  The default is 60.  If you make a new
+variable @code{kill-ring-max}.  The default is 120.  If you make a new
 kill when this limit has been reached, Emacs makes room by deleting
 the oldest entry in the kill ring.
 
@@ -562,6 +562,14 @@ new yank to the clipboard.
   To prevent kill and yank commands from accessing the clipboard,
 change the variable @code{select-enable-clipboard} to @code{nil}.
 
+@findex yank-media
+  Programs can put other things than plain text on the clipboard.  For
+instance, a web browser will usually let you choose ``Copy Image'' on
+images, and this image will be put on the clipboard.  On capable
+platforms, Emacs can yank these objects with the @code{yank-media}
+command---but only in modes that have support for it (@pxref{Yanking
+Media,,, elisp, The Emacs Lisp Reference Manual}).
+
 @cindex clipboard manager
 @vindex x-select-enable-clipboard-manager
   Many X desktop environments support a feature called the
diff --git a/doc/emacs/kmacro.texi b/doc/emacs/kmacro.texi
index 16a97db54c..78964bb903 100644
--- a/doc/emacs/kmacro.texi
+++ b/doc/emacs/kmacro.texi
@@ -102,7 +102,7 @@ are in the process of defining one, or calls the last macro
 otherwise.)  You can also supply @key{F4} with a numeric prefix
 argument @samp{n}, which means to invoke the macro @samp{n} times.  An
 argument of zero repeats the macro indefinitely, until it gets an
-error or you type @kbd{C-g} (or, on MS-DOS, @kbd{C-@key{BREAK}}).
+error or you type @kbd{C-g} (or, on MS-DOS, @kbd{C-@key{Break}}).
 
   The above example demonstrates a handy trick that you can employ
 with keyboard macros: if you wish to repeat an operation at regularly
diff --git a/doc/emacs/m-x.texi b/doc/emacs/m-x.texi
index d35a835154..7b9b40388c 100644
--- a/doc/emacs/m-x.texi
+++ b/doc/emacs/m-x.texi
@@ -45,10 +45,11 @@ from running the command by name.
 
 @cindex obsolete command
   When @kbd{M-x} completes on commands, it ignores the commands that
-are declared @dfn{obsolete}; for these, you will have to type their
-full name.  (Obsolete commands are those for which newer, better
-alternatives exist, and which are slated for removal in some future
-Emacs release.)
+were declared @dfn{obsolete} in any previous major version of Emacs;
+for these, you will have to type their full name.  Commands that were
+marked obsolete in the current version of Emacs are listed.  (Obsolete
+commands are those for which newer, better alternatives exist, and
+which are slated for removal in some future Emacs release.)
 
 @vindex read-extended-command-predicate
   In addition, @kbd{M-x} completion can exclude commands that are not
diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi
index cd1db1a7ba..99c67ed09e 100644
--- a/doc/emacs/macos.texi
+++ b/doc/emacs/macos.texi
@@ -290,7 +290,7 @@ The default behavior is to save all file-visiting buffers.
 @cindex using Nextstep services (macOS)
   Emacs also allows users to make use of Nextstep services, via a set
 of commands whose names begin with @samp{ns-service-} and end with the
-name of the service.  Type @kbd{M-x ns-service-@key{TAB}} to
+name of the service.  Type @kbd{M-x ns-service- @key{TAB}} to
 see a list of these commands.  These functions either operate on
 marked text (replacing it with the result) or take a string argument
 and return the result as a string.  You can also use the Lisp function
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 7e8b0e5914..9a90a0054d 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -945,7 +945,7 @@ the author's description of the changes in the revision on 
the current
 line.
 
 @item w
-Annotate the working revision--the one you are editing.  If you used
+Annotate the working revision---the one you are editing.  If you used
 @kbd{p} and @kbd{n} to browse to other revisions, use this key to
 return to your working revision.
 
@@ -2139,7 +2139,10 @@ Find definition of identifier, and display it in a new 
frame
 Find definition of identifier at mouse click.
 @item M-,
 Go back to where you previously invoked @kbd{M-.} and friends
-(@code{xref-pop-marker-stack}).
+(@code{xref-go-back}).
+@item C-M-,
+Go forward to where you previously invoked @kbd{M-,}
+(@code{xref-go-forward}).
 @item M-x xref-etags-mode
 Switch @code{xref} to use the @code{etags} backend.
 @end table
@@ -2204,15 +2207,17 @@ selects the window showing the first candidate.  The 
default value is
 buffer, but doesn't select any of them.
 
 @kindex M-,
-@findex xref-pop-marker-stack
-@vindex xref-marker-ring-length
+@findex xref-go-back
   To go back to places @emph{from where} you've displayed the definition,
-use @kbd{M-,} (@code{xref-pop-marker-stack}).  It jumps back to the
+use @kbd{M-,} (@code{xref-go-back}).  It jumps back to the
 point of the last invocation of @kbd{M-.}.  Thus you can find and
 examine the definition of something with @kbd{M-.} and then return to
-where you were with @kbd{M-,}.  @kbd{M-,} allows you to retrace your
-steps to a depth determined by the variable
-@code{xref-marker-ring-length}, which defaults to 16.
+where you were with @kbd{M-,}.
+
+@kindex C-M-,
+@findex xref-go-forward
+  Go forward to a place from where you previously went back using @kbd{M-,}.
+This is useful if you find that you went back too far.
 
 @findex xref-etags-mode
   Some major modes install @code{xref} support facilities that might
@@ -2283,12 +2288,12 @@ the match with @var{replacement}.  @xref{Identifier 
Search}.
 @item g
 @findex xref-revert-buffer
 Refresh the contents of the @file{*xref*} buffer
-(@code{xref-revert-buffer}.
+(@code{xref-revert-buffer}).
 
 @item M-,
 @findex xref-quit-and-pop-marker-stack
 Quit the window showing the @file{*xref*} buffer, and then jump to the
-previous Xref stack location (@code{xref-quit-and-pop-marker-stack}.
+previous Xref stack location (@code{xref-quit-and-pop-marker-stack}).
 
 @item q
 @findex xref-quit
diff --git a/doc/emacs/mark.texi b/doc/emacs/mark.texi
index 20cb8ee2c6..2461cb0f6a 100644
--- a/doc/emacs/mark.texi
+++ b/doc/emacs/mark.texi
@@ -409,9 +409,14 @@ region by dragging the mouse, you can continue to extend 
the region
 using shifted cursor motion commands.  In either case, any unshifted
 cursor motion command deactivates the mark.
 
+@vindex shift-select-mode
   To turn off shift-selection, set @code{shift-select-mode} to
 @code{nil}.  Doing so does not disable setting the mark via mouse
-commands.
+commands.  If you set @code{shift-select-mode} to the value
+@code{permanent}, cursor motion keys that were not shift-translated
+will not deactivate the mark, so, for example, the region set by prior
+commands can be extended by shift-selection, and unshifted cursor
+motion keys will extend the region set by shift-selection.
 
 @node Disabled Transient Mark
 @section Disabling Transient Mark Mode
diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi
index 6dcee3fa82..b0f6e424a7 100644
--- a/doc/emacs/mini.texi
+++ b/doc/emacs/mini.texi
@@ -41,11 +41,14 @@ Alternatively, you can type @kbd{C-g} to exit the 
minibuffer by
 canceling the command asking for the argument (@pxref{Quitting}).
 
 @cindex default argument
+@vindex minibuffer-default-prompt-format
   Sometimes, the prompt shows a @dfn{default argument}, inside
 parentheses before the colon.  This default will be used as the
 argument if you just type @key{RET}.  For example, commands that read
 buffer names usually show a buffer name as the default; you can type
-@key{RET} to operate on that default buffer.
+@key{RET} to operate on that default buffer.  You can customize how
+the default argument is shown with the user option
+@code{minibuffer-default-prompt-format}.
 
 @cindex Minibuffer Electric Default mode
 @cindex mode, Minibuffer Electric Default
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 47e3e11d33..4b3c2ea4bd 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -1497,14 +1497,20 @@ directory stack if they are not already on it
 underlying shell, of course.
 
 @vindex comint-terminfo-terminal
+@vindex system-uses-terminfo
 @vindex TERM@r{, environment variable, in sub-shell}
 Comint mode sets the @env{TERM} environment variable to a safe default
 value, but this value disables some useful features.  For example,
 color is disabled in applications that use @env{TERM} to determine if
 color is supported.  Therefore, Emacs provides an option
-@code{comint-terminfo-terminal}, which you can set to a terminal that
-is present in your system's terminfo database, in order to take
-advantage of advanced features of that terminal.
+@code{comint-terminfo-terminal} to let you choose a terminal with more
+advanced features, as defined in your system's terminfo database.
+Emacs will use this option as the value for @env{TERM} so long as
+@code{system-uses-terminfo} is non-nil.
+
+Both @code{comint-terminfo-terminal} and @code{system-uses-terminfo}
+can be declared as connection-local variables to adjust these options
+to match what a remote system expects (@pxref{Connection Variables}).
 
 @node Terminal emulator
 @subsection Emacs Terminal Emulator
@@ -1986,6 +1992,11 @@ the new frame displays the @file{*scratch*} buffer by 
default.  You
 can customize this behavior with the variable @code{initial-buffer-choice}
 (@pxref{Entering Emacs}).
 
+@item -r
+@itemx --reuse-frame
+Create a new graphical client frame if none exists, otherwise use an
+existing Emacs frame.
+
 @item -F @var{alist}
 @itemx --frame-parameters=@var{alist}
 Set the parameters for a newly-created graphical frame
@@ -2602,7 +2613,7 @@ invoked @code{hexl-mode}.
 @noindent
 Other Hexl commands let you insert strings (sequences) of binary
 bytes, move by @code{short}s or @code{int}s, etc.; type @kbd{C-h a
-hexl-@key{RET}} for details.
+hexl- @key{TAB}} for details.
 
   Hexl mode can also be used for editing text files.  This could come
 in handy if the text file includes unusual characters or uses unusual
@@ -2942,6 +2953,33 @@ one-key commands for scrolling the widget, changing its 
size, and
 reloading it.  Type @w{@kbd{C-h b}} in that buffer to see the key
 bindings.
 
+@findex xwidget-webkit-edit-mode
+@cindex xwidget-webkit-edit-mode
+  By default, typing a self-inserting character inside an xwidget
+webkit buffer will do nothing, or trigger some special action.  To
+make those characters and other common editing keys insert themselves
+when pressed, you can enable @code{xwidget-webkit-edit-mode}, which
+redefines them to be passed through to the WebKit xwidget.
+
+You can also enable @code{xwidget-webkit-edit-mode} by typing @kbd{e}
+inside the xwidget webkit buffer.
+
+@findex xwidget-webkit-isearch-mode
+@cindex searching in webkit buffers
+  @code{xwidget-webkit-isearch-mode} is a minor mode that behaves
+similarly to incremental search (@pxref{Incremental Search}), but
+operates on the contents of a WebKit widget instead of the current
+buffer.  It is bound to @kbd{C-s} and @kbd{C-r} inside xwidget-webkit
+buffers.  When it is invoked by @kbd{C-r}, the initial search will be
+performed in reverse direction.
+
+Typing any self-inserting character will cause the character to be
+inserted into the current search query.  Typing @kbd{C-s} will cause
+the WebKit widget to display the next search result, while typing
+@kbd{C-r} will cause it to display the previous one.
+
+To leave incremental search, you can type @kbd{C-g}.
+
 @node Browse-URL
 @subsection  Following URLs
 @cindex World Wide Web
diff --git a/doc/emacs/msdos.texi b/doc/emacs/msdos.texi
index 33d389acd5..20eaa0bcb6 100644
--- a/doc/emacs/msdos.texi
+++ b/doc/emacs/msdos.texi
@@ -543,7 +543,7 @@ keyboard input in Emacs.
 conventional uses in MS-Windows programs conflict with traditional
 Emacs key bindings.  (These Emacs key bindings were established years
 before Microsoft was founded.)  Examples of conflicts include
-@kbd{C-c}, @kbd{C-x}, @kbd{C-z}, @kbd{C-a}, and @kbd{W-@key{SPC}}.
+@kbd{C-c}, @kbd{C-x}, @kbd{C-z}, and @kbd{C-a}.
 You can redefine some of them with meanings more like the MS-Windows
 meanings by enabling CUA Mode (@pxref{CUA Bindings}).  Another
 optional feature which will make Emacs behave like other Windows
@@ -1181,6 +1181,14 @@ The default is @code{t}, which fits well with the 
Windows default
 click-to-focus policy.
 @end ifnottex
 
+  On Windows 10 (version 1809 and higher) and Windows 11, Emacs title
+bars and scroll bars will follow the system's Light or Dark mode,
+similar to other programs such as Explorer and Command Prompt.  To
+change the color mode, select @code{Personalization} from
+@w{@code{Windows Settings}}, then
+@w{@code{Colors->Choose your color}} (or @w{@code{Choose your default
+app mode}}); then restart Emacs.
+
 @ifnottex
 @include msdos-xtra.texi
 @end ifnottex
diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi
index 81aabfb57d..83c775df0e 100644
--- a/doc/emacs/mule.texi
+++ b/doc/emacs/mule.texi
@@ -473,6 +473,10 @@ First, letters are mapped into symbols for particular 
sounds or tone
 marks; then, sequences of these that make up a whole syllable are
 mapped into one syllable sign.
 
+@kindex C-f@r{, when using input methods}
+@kindex C-b@r{, when using input methods}
+@kindex C-n@r{, when using input methods}
+@kindex C-p@r{, when using input methods}
   Chinese and Japanese require more complex methods.  In Chinese input
 methods, first you enter the phonetic spelling of a Chinese word (in
 input method @code{chinese-py}, among others), or a sequence of
@@ -498,6 +502,7 @@ alternatives in the row are also numbered; the number 
appears before
 the alternative.  Typing a number selects the associated alternative
 of the current row and uses it as input.
 
+@kindex TAB@r{, when using Chinese input methods}
   @key{TAB} in these Chinese input methods displays a buffer showing
 all the possible characters at once; then clicking @kbd{mouse-2} on
 one of them selects that alternative.  The keys @kbd{C-f}, @kbd{C-b},
@@ -571,11 +576,37 @@ modes that make buffer text or parts of it read-only, 
such as
 @code{read-only-mode} and @code{image-mode}, even when an input method
 is active.
 
+@kindex C-x 8 @key{RET}
+@cindex insert character by name or code-point
   Another facility for typing characters not on your keyboard is by
 using @kbd{C-x 8 @key{RET}} (@code{insert-char}) to insert a single
 character based on its Unicode name or code-point; see @ref{Inserting
 Text}.
 
+@cindex emoji input
+@cindex inserting Emoji
+@kindex C-x 8 e
+@findex emoji-insert
+@findex emoji-list
+@findex emoji-search
+  There are specialized commands for inserting Emoji, and these can be
+found on the @kbd{C-x 8 e} keymap.  @kbd{C-x 8 e e}
+(@code{emoji-insert}) will let you navigate through different Emoji
+categories and then choose one.  @kbd{C-x 8 e l} (@code{emoji-list})
+will pop up a new buffer and list all the Emoji; clicking (or using
+@kbd{RET}) on an emoji character will insert it in the current buffer.
+Finally, @kbd{C-x 8 e s} (@code{emoji-search}) will allow you to
+search for Emoji based on their names.
+
+@findex emoji-describe
+  @code{describe-char} displays a lot of information about the
+character/glyphs under point (including emojis).  It's sometimes
+useful to get a quick description of the name, and you can use the
+@kbd{C-x 8 e d} (@code{emoji-describe}) command to do that.  It's
+meant primarily to help distinguish between different Emoji
+variants (which can look very similar), but it will also tell you
+the names of non-Emoji characters.
+
 @node Select Input Method
 @section Selecting an Input Method
 
diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index ec11b0c00f..0056906e1f 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -471,6 +471,23 @@ the function name.  This is normally done for macro 
definitions, using
 the @code{declare} construct.  @xref{Defining Macros,,, elisp, The
 Emacs Lisp Reference Manual}.
 
+  In Emacs Lisp, lists are usually indented as if they are
+function-like forms:
+
+@lisp
+(setq foo '(bar zot
+                gazonk))
+@end lisp
+
+  However, if you add a space after the opening parenthesis, this tells
+Emacs that it's a data list instead of a piece of code, and Emacs will
+then indent it like this:
+
+@lisp
+(setq foo '( bar zot
+             gazonk))
+@end lisp
+
 @node C Indent
 @subsection Commands for C Indentation
 
@@ -851,6 +868,15 @@ highlighting also when point is in whitespace at the 
beginning of a
 line and there is a paren at the first or last non-whitespace position
 on the line, or when point is at the end of a line and there is a
 paren at the last non-whitespace position on the line.
+
+@item
+@vindex show-paren-context-when-offscreen
+@code{show-paren-context-when-offscreen}, when non-@code{nil}, shows
+some context in the echo area when point is in a closing delimiter and
+the opening delimiter is offscreen.  The context is usually the line
+that contains the opening delimiter, except if the opening delimiter
+is on its own line, in which case the context includes the previous
+nonblank line.
 @end itemize
 
 @cindex Electric Pair mode
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index 8a101f1150..fbbb1f6e68 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -337,6 +337,16 @@ value of the variable @code{search-upper-case} (@pxref{Lax 
Search,
 search-upper-case}) is other than @code{not-yanks}, that disables this
 down-casing.
 
+@kindex M-s M-.
+@findex isearch-forward-thing-at-point
+  To begin a new incremental search with the text near point yanked
+into the initial search string, type @kbd{M-s M-.} that runs the
+command @code{isearch-forward-thing-at-point}.  If the region was
+active, then it yanks the text from the region into the search string.
+Otherwise, it tries to yank a URL, a symbol or an expression found
+near point.  What to yank is defined by the user option
+@code{isearch-forward-thing-at-point}.
+
 @node Error in Isearch
 @subsection Errors in Incremental Search
 
@@ -1331,10 +1341,9 @@ matches @w{@samp{foo bar}}, @w{@samp{foo@ @ bar}},
 precisely, Emacs matches each sequence of space characters in the
 search string to a regular expression specified by the variable
 @code{search-whitespace-regexp}.  For example, to make spaces match
-sequences of newlines as well as spaces, set it to
-@samp{"[[:space:]\n]+"}.  The default value of this variable depends
-on the buffer's major mode; most major modes classify spaces, tabs,
-and formfeed characters as whitespace.
+sequences of newlines as well as spaces, set it to the regular expression
+@samp{[[:space:]\n]+}.  The default value of this variable considers
+any sequence of spaces and tab characters as whitespace.
 
   If you want whitespace characters to match exactly, you can turn lax
 space matching off by typing @kbd{M-s @key{SPC}}
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index dc8ca903b7..53291332d3 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -996,6 +996,13 @@ specific file (@pxref{File Variables}).
 major mode's special commands.  (The variable
 @code{outline-minor-mode-prefix} controls the prefix used.)
 
+@vindex outline-minor-mode-use-buttons
+  If @code{outline-minor-mode-use-buttons} is non-@code{nil}, Outline
+minor mode will use buttons (at the start of the header lines) in
+addition to ellipsis to show that a section is hidden.  Using
+@kbd{RET} (or clicking on the button with a mouse) will toggle
+displaying the section.
+
 @vindex outline-minor-mode-cycle
   If the @code{outline-minor-mode-cycle} user option is
 non-@code{nil}, the @kbd{TAB} and @kbd{S-TAB} keys are enabled on the
diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index 9a638818c9..027086cab5 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -393,7 +393,7 @@ this---saving them---updates the files themselves.
 associated with any files, or if the autosave was not recent enough to
 have recorded important changes, you can use the
 @file{etc/emacs-buffer.gdb} script with GDB (the GNU Debugger) to
-retrieve them from a core dump--provided that a core dump was saved,
+retrieve them from a core dump---provided that a core dump was saved,
 and that the Emacs executable was not stripped of its debugging
 symbols.
 
@@ -1352,8 +1352,13 @@ downloaded the repository source, you should read the 
file
 from a normal build).
 
 If you would like to make more extensive contributions, see the
-@file{CONTRIBUTE} file in the Emacs distribution for information on
-how to be an Emacs developer.
+@file{CONTRIBUTE} file in the Emacs source tree for information on how
+to be an Emacs developer.  That file is distributed as part of the source
+tarball of every released Emacs version, and can also be found on-line
+in the @url{https://git.savannah.gnu.org/cgit/emacs.git/tree/CONTRIBUTE,
+Emacs on-line source repository}.  If you cloned the Emacs repository,
+per the instructions in @url{https://savannah.gnu.org/projects/emacs/},
+you will find this file in the top directory of the source Emacs tree.
 
 For documentation on Emacs (to understand how to implement your
 desired change), refer to:
diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi
index facbc7f3ed..8cb88a2095 100644
--- a/doc/emacs/windows.texi
+++ b/doc/emacs/windows.texi
@@ -444,7 +444,7 @@ selected window write:
 @group
 (customize-set-variable
  'display-buffer-alist
- '("\\*scratch\\*" (display-buffer-same-window)))
+ '(("\\*scratch\\*" (display-buffer-same-window))))
 @end group
 @end example
 
diff --git a/doc/lispintro/emacs-lisp-intro.texi 
b/doc/lispintro/emacs-lisp-intro.texi
index 7c7005b348..f5f79a543c 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -1162,6 +1162,10 @@ computer.  Often, people use the term @dfn{expression}
 indiscriminately.  (Also, in many texts, the word @dfn{form} is used
 as a synonym for expression.)
 
+@c This and the next paragraph say ``kinds of atom'', but that is not
+@c a typo, just slightly ``old-fashioned wording which adds a fillip
+@c of interest to it'', and ``is more elegant writing'', according to
+@c RMS.
 Incidentally, the atoms that make up our universe were named such when
 they were thought to be indivisible; but it has been found that physical
 atoms are not indivisible.  Parts can split off an atom or it can
@@ -4201,7 +4205,7 @@ times.
 
 The part of the buffer between point and mark is called @dfn{the
 region}.  Numerous commands work on the region, including
-@code{center-region}, @code{count-lines-region}, @code{kill-region}, and
+@code{center-region}, @code{count-words-region}, @code{kill-region}, and
 @code{print-region}.
 
 The @code{save-excursion} special form saves the location of point and
@@ -4214,7 +4218,7 @@ evaluated.
 
 In Emacs, a function frequently moves point as part of its internal
 workings even though a user would not expect this.  For example,
-@code{count-lines-region} moves point.  To prevent the user from being
+@code{count-words-region} moves point.  To prevent the user from being
 bothered by jumps that are both unexpected and (from the user's point of
 view) unnecessary, @code{save-excursion} is often used to keep point in
 the location expected by the user.  The use of
@@ -4893,6 +4897,23 @@ region.
 
 @c FIXME: the definition of append-to-buffer has been changed (in
 @c 2010-03-30).
+@c In Bug#8275, Stefan Monner <monnier@iro.umontreal.ca> writes:
+@c >> Do you want to fix this, or shall I try?  The problem is that
+@c >> append-to-buffer now uses let* and with-current-buffer, so this might
+@c >> break the flow of the text.  At this point in the book, let* and
+@c >> with-current-buffer are not yet introduced.
+@c >
+@c > Here are some thoughts:
+@c > - I don't think it's of any importance that the example code be
+@c >   identical to the currently used code.
+@c > - append-to-buffer might not be the best example since AFAICT copying
+@c >   text from one buffer to another is not a common operation and in most
+@c >   cases this is done via buffer-substring + insert (often with some
+@c >   processing on the string between the two) rather than with
+@c >   insert-buffer-substring which is a rarely used function.
+@c > - yes, I think the text would benefit from some rethink to try and present
+@c >   with-current-buffer in preference to set-buffer, but it's not
+@c >   a simple fix.
 @node append-to-buffer
 @section The Definition of @code{append-to-buffer}
 @findex append-to-buffer
@@ -8767,7 +8788,7 @@ keeps the kill ring from growing too long.  It looks like 
this:
 
 The code checks whether the length of the kill ring is greater than
 the maximum permitted length.  This is the value of
-@code{kill-ring-max} (which is 60, by default).  If the length of the
+@code{kill-ring-max} (which is 120, by default).  If the length of the
 kill ring is too long, then this code sets the last element of the
 kill ring to @code{nil}.  It does this by using two functions,
 @code{nthcdr} and @code{setcdr}.
@@ -13473,10 +13494,9 @@ The template for an interactive function definition 
is, as always:
 
 What we need to do is fill in the slots.
 
-The name of the function should be self-explanatory and similar to the
-existing @code{count-lines-region} name.  This makes the name easier
+The name of the function should be self-explanatory and easy
 to remember.  @code{count-words-region} is the obvious choice.  Since
-that name is now used for the standard Emacs command to count words, we
+that name is used for the standard Emacs command to count words, we
 will name our implementation @code{@value{COUNT-WORDS}}.
 
 The function counts words within a region.  This means that the
@@ -17457,9 +17477,9 @@ Manual}, for more information.
 @findex line-to-top-of-window
 @cindex Simple extension in @file{.emacs} file
 
-Here is a simple extension to Emacs that moves the line point is on to
-the top of the window.  I use this all the time, to make text easier
-to read.
+Here is a simple extension to Emacs that moves the line that point is
+on to the top of the window.  I use this all the time, to make text
+easier to read.
 
 You can put the following code into a separate file and then load it
 from your @file{.emacs} file, or you can include it within your
@@ -17840,7 +17860,7 @@ xmodmap -e "keysym Alt_L = Meta_L Alt_L"
 Finally, a feature I really like: a modified mode line.
 
 When I work over a network, I forget which machine I am using.  Also,
-I tend to I lose track of where I am, and which line point is on.
+I tend to lose track of where I am, and which line point is on.
 
 So I reset my mode line to look like this:
 
diff --git a/doc/lispref/anti.texi b/doc/lispref/anti.texi
index ced8082f6a..118df05c79 100644
--- a/doc/lispref/anti.texi
+++ b/doc/lispref/anti.texi
@@ -6,186 +6,179 @@
 @c This node must have no pointers.
 
 @node Antinews
-@appendix Emacs 26 Antinews
+@appendix Emacs 27 Antinews
 @c Update the elisp.texi Antinews menu entry with the above version number.
 
 For those users who live backwards in time, here is information about
-downgrading to Emacs version 26.3.  We hope you will enjoy the greater
+downgrading to Emacs version 27.2.  We hope you will enjoy the greater
 simplicity that results from the absence of many @w{Emacs
 @value{EMACSVER}} features.
 
 @itemize @bullet
 @item
-Lisp objects are again implemented on the C level as integer types,
-not as pointers.  This might be a small step for Emacs Lisp users, but
-it's a giant leap for the Emacs developers who work on the C level,
-since it is now again easy to print Lisp object in the debugger in the
-decimal format, which is so much easier for debugging.  It also makes
-calling Emacs functions from the debugger easier, and allows us to
-freely mix integers and Lisp objects in the C code.
+The annoying @code{lexical-binding} local variable now heeds the
+value of @code{enable-local-variables}: if it's @code{nil}, the
+@code{lexical-binding} cookie is ignored.  We are working hard on
+removing the lexical-binding support in some past Emacs version, and
+this small step advances us back to that change.
 
 @item
-The test suite was removed from the distribution tarball.  We believe
-that tests need seldom if ever be run, certainly not by the end
-users.  Removing the tests from the tarball makes it much smaller,
-which is important since disk space becomes more and more at premium
-as you move back in time.
+The @code{load-dangerous-libraries} variable is not obsolete, as it
+must be used to allow loading Lisp compiled by XEmacs, which will
+become more and more important as you move back in time.
 
 @item
-Dynamic module support is disabled by default.  This both makes Emacs
-smaller (a worthy goal by itself), and removes the complications and
-additional complexity related with installing module support files and
-letting random shared objects an opportunity to be loaded into Emacs
-and mess with it.
+The optional @var{modes} argument of @code{interactive} is not
+supported, and every command is deemed applicable to any major mode.
+We believe this makes the life of Lisp programmers much simpler, as
+there's now no need to tag commands with the modes where they make
+sense.
 
 @item
-You now must activate any installed packages only after loading your
-init files.  That requires an explicit call to
-@code{package-initialize} in your init file, which is a Good Thing, as
-it makes you think seriously where and indeed whether you'd like your
-packages to become available to your sessions.  Simplicity should
-tramp convenience!
+Shorthands for Lisp symbols have been removed, which makes loading
+Lisp files and handling Lisp symbols much simpler and more efficient.
+This is important for decent performance on slower CPUs as you move
+back in time.
 
 @item
 To reduce the amount of code in Emacs related to unimportant features,
-we've removed native rotation and resizing of images.  You will have
-to build Emacs with ImageMagick if you want to resize or rotate images
-inside Emacs.  We don't expect anyone to miss that.
+we've removed the variables @code{global-minor-modes} and
+@code{local-minor-modes}.  If your Lisp program needs to determine
+whether some minor mode is in effect, it will have to test explicitly
+for every mode.  We don't expect anyone to miss those fancy variables.
 
 @item
-We've re-enabled color fonts usage by the XFT font back-end.  We
-consider the availability of these fonts more important than a random
-crash here and there, especially since the use of these fonts for
-displaying Emoji will become less and less important as we travel back
-in time, and will completely disappear in some past Emacs version.
+The default preference for servicing sub-processes that produce output
+at a high rate, and the associated variable
+@code{process-prioritize-lower-fds}, have been removed.  Moving back
+in time means fewer and fewer programs can produce such high-rate
+output, so this features becomes just useless crud.
 
 @item
-The function @code{network-interface-list} can now return only IPv4
-addresses.  We consider the complexity introduced by IPv6 to be too
-much to be justified, and on the other hand its removal is the step in
-the right direction, given that IPv6 is expected to be completely
-removed as we move back in time.
+The encodings that are variants of EBCDIC were removed.  This includes
+@code{ibm256}, @code{ibm273}, and others---variants of the EBCDIC
+encoding tailored for some Japanese and European locales.  You won't
+need those where you are going.
 
 @item
-The limit on repetitions in regular expressions was reduced to
-@ifnottex
-2**15 @minus{} 1.
-@end ifnottex
-@tex
-@math{2^{15}-1}.
-@end tex
-We envision that regular expressions will become more and more simple
-as we move towards the distant past.
+The ``Bindat type expression'' description language has been removed,
+as the existing data layout specifications are perfectly suited for
+this job.
 
 @item
 To simplify code and reduce complexity, we removed the capability of
-searching programs on remote hosts in @code{executable-find}.  If you
-really need this feature (why would you?), you can always write your
-own shell script and run it on the remote.
+specifying the success handler in @code{condition-case} via the
+@code{:success} keyword.  If you really need this feature (why would
+you?), you can always write some simple Lisp that has the same effect.
 
 @item
-The @code{:extend} face attribute is no longer available; all faces
-have their background color extended by default past end of line.
-This should significantly simplify face management and remove
-unnecessary code bloat, as well as make faces significantly simpler to
-understand and use.
+Emacs modules can no longer provide interactive functions, or install
+finalizers, nor open channels to existing pipe sub-processes.  All
+this is extra ballast, especially since we plan on removing modules in
+some past Emacs version.  The @code{make_unibyte_string} module API
+was removed for the same reason.
 
 @item
-The predicates @code{display-blink-cursor-p} and
-@code{display-symbol-keys-p} were deleted.  They are rarely if ever
-needed, and can easily be substituted by appropriate calls to old and
-proven APIs like @code{display-graphic-p}.  As an additional bonus,
-writing Lisp programs that depend on this functionality will make sure
-the programmer understands better what exactly is the required
-features of the display terminal.
+To keep Emacs clean and elegant, we've removed the
+@code{print-integers-as-characters} option.  Recognizing characters by
+their decimal codes is a basic requirement for Emacs Lisp programmers,
+and with the expected decrease in use of Unicode characters, this will
+be soon limited to ASCII only: surely something you all can master!
 
 @item
-Relative directories in the value of the @env{HOME} environment
-variable are once again interpreted relative to the
-@code{default-directory} of the current buffer.  This is much simpler,
-and also allows @env{HOME} to resolve to a different place in
-different buffers, which allows some interesting applications.
+The optional @var{count} argument of the @code{directory-files}
+function has been removed.  Extracting the first @var{n} members from
+the full list is trivial, so this is a significant simplification for
+an insignificant cost.
 
-For the same reasons, @code{file-name-absolute-p} now again considers
-@file{~foo} an absolute file name, even if there's no known user
-@samp{foo}.  This means a Lisp program which uses such file names will
-always work the same on any system, regardless of its known users.
+@item
+Functions that create sub-processes and network connections no longer
+accept the @code{:coding} argument; use
+@code{set-process-coding-system} or bind
+@code{coding-system-for-read/write} instead: again, a significant
+reduction in Emacs complexity for little or no cost.
+
+@item
+We deleted from the macros @code{define-derived-mode} and
+@code{define-minor-mode} the code which allowed using the
+@code{:interactive} argument.  The possibility of marking a mode
+non-interactive makes very little sense,
+
+@item
+The possibility of having links to man pages in doc strings has been
+removed.  Use plain text instead, if you need such references.
+
+@item
+Temporary buffers are no longer exempt from running any buffer-related
+hooks.  Programs that don't want such hooks in some buffer can always
+disable it locally, whereas making that simpler complicates Emacs for
+no good reason.
 
 @item
-File-related primitives like @code{file-attributes},
-@code{file-modes}, @code{file-newer-than-file-p}, and some others once
-again return @code{nil} when the underlying low-level APIs fail,
-instead of signaling an error.  We decided that functions which signal
-errors require more complex code from Lisp programs which use them,
-and found this complexity unjustified when returning @code{nil} will
-do.
+Several features that complicated the byte compiler have been removed:
 
+@itemize @minus
 @item
-Similarly, old-style backquotes no longer signal errors; they generate
-warnings instead.  You can remove error handling from programs that
-use backquotes.
+The checks for missing declarations of dynamic variables.  This will
+continue making less and less sense as we move away of lexical-binding
+support.
 
 @item
-Formatting floating-point numbers has been sped up by letting the
-underlying implementation produce unpredictable values, instead of
-signaling errors when the number is too large to format correctly.  We
-believe the Emacs Lisp programmers should always know what they are
-doing when they deal with floating-point values.
+The ability of compiling symlinked @file{*.el} files, which is really
+gross: copy the files instead.
 
 @item
-The function @code{read-char-from-minibuffer} was deleted.  We decided
-that @code{read-char} should be enough for any Lisp program that needs
-to ask the user for a single-character input, in recognition of the
-fact that nothing makes Emacs Lisp hackers rejoice more than the need
-to sit down and write yet another interactive question-and-answer
-function, and make it optimal for each specific case.  Consequently,
-no history is provided for such responses (why would someone want
-history of single-key strokes, anyway?).
+The warnings about too-wide doc strings---that is just a nuisance, as
+the programmers should be trusted to know what they are doing.
+@end itemize
+
+
+@item
+We deleted several features of the @code{pcase} macro, in accordance
+with our general plane to remove @code{pcase} from Emacs:
 
+@itemize @minus
 @item
-The function @code{ngettext} was deleted.  Non-English languages will
-become less and less widespread, let alone useful, as you move back in
-time, so we took this small step in that direction, and simplified
-Emacs as a nice bonus.
+The @code{cl-type} pattern.
 
 @item
-Focus-change notifications on text-mode frames are no longer
-recognized or supported.  You can now safely disregard the possibility
-of receiving such notifications on TTY frames.  This is one small step
-on the long road of removing all non-character input events Emacs
-supports on TTY frames.
+the @code{pcase-setq} macro.
+
+@item
+The @code{pcase-compile-patterns} function.
+@end itemize
 
 @item
-Face specifications in @code{face-remapping-alist} now have to be
-buffer-specific, without any differences between windows showing the
-same buffers.  This allowed us to remove a lot of unneeded code bloat
-from Emacs, and make the face handling much simpler.
+Some of the keywords used in Edebug specification lists were deemed to
+be of little use, and were therefore removed: @code{&interpose},
+@code{&error}, and @code{&name}.  The long-term plane is for Emacs to
+drop Edebug entirely, leaving only the trusted Lisp debugger, and we
+continue working according to that plan.
 
 @item
-The @samp{%o} and @samp{%x} formats now always produce unsigned
-values, as you'd expect.  This allows you to reveal the underlying
-machine representation, which is different on each architecture,
-something we consider a valuable feature.
+The function @code{object-intervals} was dropped, as a Lisp program
+can easily collect the intervals of a buffer or a string by iterating
+through them one by one.
 
 @item
-We no longer highlight in @code{font-lock-warning-face} symbols with
-confusable quote characters, such as U+2018.  Detecting them
-needed  non-trivial amount of code, and we firmly believe that Lisp
-programmers always know what they are doing, and don't need to be
-annoyed with typefaces that stand out and distract.
+We decided that the @code{require-theme} function is an unnecessary
+complication, so we deleted it.  Lisp programs can easily search along
+@code{custom-theme-load-path} instead.
 
 @item
-The function @code{file-system-info} was dropped on Posix platforms,
-since you can always invoke @command{df} instead and parse its
-output.
+The convenience functions @code{length<}, @code{length>}, and
+@code{length=} were removed, as using @code{length} followed by a
+comparison should be good enough for everyone, especially considering
+that the typical length of a list keeps going down as you move back
+through time.
 
 @item
-The functions that implement the @samp{base64url} encoding were
-removed, as they can always be emulated by suitable tweaking of the
-normal base-64 encoding.  No need to bloat Emacs and force Lisp
-programmers learn more interfaces on this account.
+The variable @code{current-minibuffer-command} is no longer available,
+as we found little justification for keeping it.
 
 @item
 As part of the ongoing quest for simplicity, many other functions and
-variables have been eliminated.
+variables have been eliminated.  Other functions and variables, that
+were declared obsolete since Emacs 23, have been added back, in
+preparation for releasing Emacs 23 in some distant past.
 @end itemize
diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi
index 55e9d00d8b..6a0095dca9 100644
--- a/doc/lispref/buffers.texi
+++ b/doc/lispref/buffers.texi
@@ -89,11 +89,12 @@ in which most editing takes place.  Most of the primitives 
for
 examining or changing text operate implicitly on the current buffer
 (@pxref{Text}).
 
-  Normally, the buffer displayed in the selected window is the current
-buffer, but this is not always so: a Lisp program can temporarily
-designate any buffer as current in order to operate on its contents,
-without changing what is displayed on the screen.  The most basic
-function for designating a current buffer is @code{set-buffer}.
+  Normally, the buffer displayed in the selected window
+(@pxref{Selecting Windows}) is the current buffer, but this is not
+always so: a Lisp program can temporarily designate any buffer as
+current in order to operate on its contents, without changing what is
+displayed on the screen.  The most basic function for designating a
+current buffer is @code{set-buffer}.
 
 @defun current-buffer
 This function returns the current buffer.
@@ -118,12 +119,12 @@ on it.
 
   When an editing command returns to the editor command loop, Emacs
 automatically calls @code{set-buffer} on the buffer shown in the
-selected window.  This is to prevent confusion: it ensures that the
-buffer that the cursor is in, when Emacs reads a command, is the
-buffer to which that command applies (@pxref{Command Loop}).  Thus,
-you should not use @code{set-buffer} to switch visibly to a different
-buffer; for that, use the functions described in @ref{Switching
-Buffers}.
+selected window (@pxref{Selecting Windows}).  This is to prevent
+confusion: it ensures that the buffer that the cursor is in, when Emacs
+reads a command, is the buffer to which that command applies
+(@pxref{Command Loop}).  Thus, you should not use @code{set-buffer} to
+switch visibly to a different buffer; for that, use the functions
+described in @ref{Switching Buffers}.
 
   When writing a Lisp function, do @emph{not} rely on this behavior of
 the command loop to restore the current buffer after an operation.
@@ -912,16 +913,17 @@ History}) provided it is shown in that window.
 
 If @var{buffer-or-name} is @code{nil} or omitted, this means to bury the
 current buffer.  In addition, if the current buffer is displayed in the
-selected window, this makes sure that the window is either deleted or
-another buffer is shown in it.  More precisely, if the selected window
-is dedicated (@pxref{Dedicated Windows}) and there are other windows on
-its frame, the window is deleted.  If it is the only window on its frame
-and that frame is not the only frame on its terminal, the frame is
-dismissed by calling the function specified by
-@code{frame-auto-hide-function} (@pxref{Quitting Windows}).  Otherwise,
-it calls @code{switch-to-prev-buffer} (@pxref{Window History}) to show
-another buffer in that window.  If @var{buffer-or-name} is displayed in
-some other window, it remains displayed there.
+selected window (@pxref{Selecting Windows}), this makes sure that the
+window is either deleted or another buffer is shown in it.  More
+precisely, if the selected window is dedicated (@pxref{Dedicated
+Windows}) and there are other windows on its frame, the window is
+deleted.  If it is the only window on its frame and that frame is not
+the only frame on its terminal, the frame is dismissed by calling the
+function specified by @code{frame-auto-hide-function} (@pxref{Quitting
+Windows}).  Otherwise, it calls @code{switch-to-prev-buffer}
+(@pxref{Window History}) to show another buffer in that window.  If
+@var{buffer-or-name} is displayed in some other window, it remains
+displayed there.
 
 To replace a buffer in all the windows that display it, use
 @code{replace-buffer-in-windows}, @xref{Buffers and Windows}.
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 3425880fec..6ed46fa6a2 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1176,6 +1176,7 @@ intended by Lisp code to be used as an event.
 * Repeat Events::               Double and triple click (or drag, or down).
 * Motion Events::               Just moving the mouse, not pushing a button.
 * Focus Events::                Moving the mouse between frames.
+* Xwidget Events::              Events generated by xwidgets.
 * Misc Events::                 Other events the system can generate.
 * Event Examples::              Examples of the lists for mouse events.
 * Classifying Events::          Finding the modifier keys in an event symbol.
@@ -1871,6 +1872,85 @@ sequence---that is, after a prefix key---then Emacs 
reorders the events
 so that the focus event comes either before or after the multi-event key
 sequence, and not within it.
 
+@node Xwidget Events
+@subsection Xwidget events
+
+Xwidgets (@pxref{Xwidgets}) can send events to update Lisp programs on
+their status.  These events are dubbed @code{xwidget-events}, and
+contain various data describing the nature of the change.
+
+@table @code
+@cindex @code{xwidget-event} event
+@item (xwidget-event @var{kind} @var{xwidget} @var{arg})
+This event is sent whenever some kind of update occurs in
+@var{xwidget}.  There are several types of updates, identified by
+their @var{kind}.
+
+@table @code
+@cindex @code{load-changed} xwidget event
+@item load-changed
+This xwidget event indicates that the @var{xwidget} has reached a
+particular point of the page-loading process.  When these events are
+sent, @var{arg} will contain a string that futher describes the status
+of the widget:
+
+@table @samp
+@cindex @samp{load-started} in xwidgets
+@item load-started
+This means the widget has begun a page-loading operation.
+
+@cindex @samp{load-finished} in xwidgets
+@item load-finished
+This means the @var{xwidget} has finished processing whatever
+page-loading operation that it was previously performing.
+
+@cindex @samp{load-redirected} in xwidgets
+@item load-redirected
+This means the @var{xwidget} has encountered and followed a redirect
+during the page-loading operation.
+
+@cindex @samp{load-committed} in xwidgets
+@item load-committed
+This means the @var{xwidget} has committed to a given URL during the
+page-loading operation, i.e.@: the URL is the final URL that will be
+rendered by @var{xwidget} during the current page-loading operation.
+@end table
+
+@cindex @code{download-callback} xwidget events
+@item download-callback
+This event indicates that a download of some kind has been completed.
+@end table
+
+In the above events, there can be arguments after @var{arg}, which
+itself indicates the URL from which the download file was retrieved:
+the first argument after @var{arg} indicates the MIME type of the
+download, as a string, while the second argument contains the full
+file name of the downloaded file.
+
+@table @code
+@cindex @code{download-started} xwidget events
+@item download-started
+This event indicates that a download has been started.  In these
+events, @var{arg} contains the URL of the file that is currently being
+downloaded.
+
+@cindex @code{javascript-callback} xwidget events
+@item javascript-callback
+This event contains JavaScript callback data.  These events are used
+internally by @code{xwidget-webkit-execute-script}.
+@end table
+
+@cindex @code{xwidget-display-event} event
+@item (xwidget-display-event @var{xwidget})
+This event is sent whenever an xwidget requests that another xwidget
+be displayed.  @var{xwidget} is the xwidget that should be displayed.
+
+@var{xwidget}'s buffer will be set to a temporary buffer.  When
+displaying the widget, care should be taken to replace the buffer with
+the buffer in which the xwidget will be displayed, using
+@code{set-xwidget-buffer}  (@pxref{Xwidgets}).
+@end table
+
 @node Misc Events
 @subsection Miscellaneous System Events
 
@@ -2354,10 +2434,9 @@ This function returns position information corresponding 
to pixel
 coordinates @var{x} and @var{y} in a specified frame or window,
 @var{frame-or-window}, which defaults to the selected window.
 The coordinates @var{x} and @var{y} are relative to the
-frame or window used.
-If @var{whole} is @code{nil}, the coordinates are relative
-to the window text area, otherwise they are relative to
-the entire window area including scroll bars, margins and fringes.
+text area of the selected window.
+If @var{whole} is @code{non-nil}, the @var{x} coordinate is relative
+to the entire window area including scroll bars, margins and fringes.
 @end defun
 
 @node Accessing Scroll
@@ -2617,10 +2696,14 @@ returns the key sequence as a vector, never as a string.
 @cindex upper case key sequence
 @cindex downcasing in @code{lookup-key}
 @cindex shift-translation
+@vindex translate-upper-case-key-bindings
 If an input character is upper-case (or has the shift modifier) and
 has no key binding, but its lower-case equivalent has one, then
-@code{read-key-sequence} converts the character to lower case.  Note
-that @code{lookup-key} does not perform case conversion in this way.
+@code{read-key-sequence} converts the character to lower case.  (This
+behaviour can be disabled by setting the
+@code{translate-upper-case-key-bindings} user option to @code{nil}.)
+Note that @code{lookup-key} does not perform case conversion in this
+way.
 
 @vindex this-command-keys-shift-translated
 When reading input results in such a @dfn{shift-translation}, Emacs
diff --git a/doc/lispref/compile.texi b/doc/lispref/compile.texi
index f48f4f47e8..523758c10f 100644
--- a/doc/lispref/compile.texi
+++ b/doc/lispref/compile.texi
@@ -811,8 +811,7 @@ for you to be able to native-compile Lisp code.
 
 @vindex native-compile@r{, a Lisp feature}
   To determine whether the current Emacs process can produce and load
-natively-compiled Lisp code, test whether the @code{native-compile}
-feature is available (@pxref{Named Features}).  Alternatively, call
+natively-compiled Lisp code, call
 @code{native-comp-available-p} (@pxref{Native-Compilation Functions}).
 
   Unlike byte-compiled code, natively-compiled Lisp code is executed
@@ -904,13 +903,20 @@ invokes the same Emacs executable as the process that 
called this
 function.
 @end defun
 
-@defun batch-native-compile
+@defun batch-native-compile &optional for-tarball
 This function runs native-compilation on files specified on the Emacs
 command line in batch mode.  It must be used only in a batch execution
 of Emacs, as it kills Emacs upon completion of the compilation.  If
 one or more of the files fail to compile, the Emacs process will
 attempt to compile all the other files, and will terminate with a
-non-zero status code.
+non-zero status code.  The optional argument @var{for-tarball}, if
+non-@code{nil}, tells the function to place the resulting @file{.eln}
+files in the last directory mentioned in
+@code{native-comp-eln-load-path} (@pxref{Library Search}); this is
+meant to be used as part of building an Emacs source tarball for the
+first time, when the natively-compiled files, which are absent from
+the source tarball, should be generated in the build tree instead of
+the user's cache directory.
 @end defun
 
 Native compilation can be run entirely asynchronously, in a subprocess
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index aacf66c5cf..06da102518 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -557,7 +557,7 @@ Likewise, it makes no sense to bind keyword symbols
 
 @item (cl-type @var{type})
 Matches if @var{expval} is of type @var{type}, which is a type
-descriptor as accepted by @code{cl-typep} (@pxref{cl-typep,,,cl,Common
+descriptor as accepted by @code{cl-typep} (@pxref{Type Predicates,,,cl,Common
 Lisp Extensions}).  Examples:
 
 @lisp
@@ -1283,6 +1283,15 @@ bindings that can then be used inside @var{body}.  The 
variable
 bindings are produced by destructuring binding of elements of
 @var{pattern} to the values of the corresponding elements of the
 evaluated @var{exp}.
+
+Here's a trivial example:
+
+@example
+(pcase-let ((`(,major ,minor)
+            (split-string "image/png" "/")))
+  minor)
+     @result{} "png"
+@end example
 @end defmac
 
 @defmac pcase-let* bindings body@dots{}
diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
index bc35982c17..b93b8bc015 100644
--- a/doc/lispref/customize.texi
+++ b/doc/lispref/customize.texi
@@ -594,6 +594,9 @@ want to take the time to work out a more specific type to 
use.
 @item integer
 The value must be an integer.
 
+@item natnum
+The value must be a nonnegative integer.
+
 @item number
 The value must be a number (floating point or integer).
 
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 510efaf271..b6bd14f887 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -561,6 +561,26 @@ You can rewrite the previous example with this macro as 
follows:
 @end example
 @end defmac
 
+@defmac with-delayed-message (timeout message) body@dots{}
+Sometimes it's unclear whether an operation will take a long time to
+execute or not, or it can be inconvenient to implement a progress
+reporter.  This macro can be used in those situations.
+
+@lisp
+(with-delayed-message (2 (format "Gathering data for %s" entry))
+  (setq data (gather-data entry)))
+@end lisp
+
+In this example, if the body takes more than two seconds to execute,
+the message will be displayed.  If it takes a shorter time than that,
+the message won't be displayed.  In either case, the body is evaluated
+as normally, and the return value of the final element in the body is
+the return value of the macro.
+
+The @var{message} element is evaluated before @var{body}, and is
+always evaluated, whether the message is displayed or not.
+@end defmac
+
 @node Logging Messages
 @subsection Logging Messages in @file{*Messages*}
 @cindex logging echo-area messages
@@ -1334,6 +1354,11 @@ are not resized.  By default, this mode uses 
@code{fit-window-to-buffer}
 (@pxref{Resizing Windows}) for resizing.  You can specify a different
 function by customizing the options @code{temp-buffer-max-height} and
 @code{temp-buffer-max-width} below.
+
+The effect of this option can be overridden by providing a suitable
+@code{window-height}, @code{window-width} or @code{window-size} action
+alist entry for @code{display-buffer} (@pxref{Buffer Display Action
+Alists}).
 @end defopt
 
 @defopt temp-buffer-max-height
@@ -1983,7 +2008,8 @@ The return value is an approximation: it only considers 
the values
 returned by @code{char-width} for the constituent characters, always
 takes a tab character as taking @code{tab-width} columns, ignores
 display properties and fonts, etc.  For these reasons, we recommend
-using @code{window-text-pixel-size}, described below, instead.
+using @code{window-text-pixel-size} or @code{string-pixel-width},
+described below, instead.
 @end defun
 
 @defun truncate-string-to-width string width &optional start-column padding 
ellipsis ellipsis-text-property
@@ -1997,11 +2023,11 @@ If a multi-column character in @var{string} exceeds the 
goal
 result can sometimes fall short of @var{width}, but cannot go beyond
 it.
 
-The optional argument @var{start-column} specifies the starting column.
-If this is non-@code{nil}, then the first @var{start-column} columns of
-the string are omitted from the result.  If one multi-column character in
-@var{string} extends across the column @var{start-column}, that
-character is omitted.
+The optional argument @var{start-column} specifies the starting
+column; it defaults to zero.  If this is non-@code{nil}, then the
+first @var{start-column} columns of the string are omitted from the
+result.  If one multi-column character in @var{string} extends across
+the column @var{start-column}, that character is omitted.
 
 The optional argument @var{padding}, if non-@code{nil}, is a padding
 character added at the beginning and end of the result string, to
@@ -2026,12 +2052,22 @@ means hide the excess parts of @var{string} with a 
@code{display} text
 property (@pxref{Display Property}) showing the ellipsis, instead of
 actually truncating the string.
 
+@group
 @example
 (truncate-string-to-width "\tab\t" 12 4)
      @result{} "ab"
 (truncate-string-to-width "\tab\t" 12 4 ?\s)
      @result{} "    ab  "
 @end example
+@end group
+
+This function uses @code{string-width} and @code{char-width} to find
+the suitable truncation point when @var{string} is too wide, so it
+suffers from the same basic issues as @code{string-width} does.  In
+particular, when character composition happens within @var{string},
+the display width of a string could be smaller than the sum of widths
+of the constituent characters, and this function might return
+inaccurate results.
 @end defun
 
 @defun truncate-string-ellipsis
@@ -2050,7 +2086,7 @@ displayed in a given window.  This function is used by
 (@pxref{Resizing Windows}) to make a window exactly as large as the text
 it contains.
 
-@defun window-text-pixel-size &optional window from to x-limit y-limit 
mode-and-header-line
+@defun window-text-pixel-size &optional window from to x-limit y-limit 
mode-lines
 This function returns the size of the text of @var{window}'s buffer in
 pixels.  @var{window} must be a live window and defaults to the
 selected one.  The return value is a cons of the maximum pixel-width
@@ -2092,12 +2128,12 @@ calculating the pixel-height of a large buffer can take 
some time, it
 makes sense to specify this argument; in particular, if the caller
 does not know the size of the buffer.
 
-The optional argument @var{mode-and-header-line} @code{nil} or omitted
-means to not include the height of the mode- or header-line of
-@var{window} in the return value.  If it is either the symbol
-@code{mode-line} or @code{header-line}, include only the height of that
+The optional argument @var{mode-lines} @code{nil} or omitted means to
+not include the height of the mode-, tab- or header-line of @var{window}
+in the return value.  If it is either the symbol @code{mode-line},
+@code{tab-line} or @code{header-line}, include only the height of that
 line, if present, in the return value.  If it is @code{t}, include the
-height of both, if present, in the return value.
+height of all of these lines, if present, in the return value.
 @end defun
 
 @code{window-text-pixel-size} treats the text displayed in a window as a
@@ -2165,12 +2201,42 @@ though when this function is run from an idle timer 
with a delay of zero
 seconds.
 @end defun
 
+@defun string-pixel-width string
+This is a convenience function that uses @code{window-text-pixel-size}
+to compute the width of @var{string} (in pixels).
+@end defun
+
 @defun line-pixel-height
 This function returns the height in pixels of the line at point in the
 selected window.  The value includes the line spacing of the line
 (@pxref{Line Height}).
 @end defun
 
+@cindex grapheme cluster
+@defun string-glyph-split string
+When character compositions are in effect, sequence of characters can
+be composed for display to form @dfn{grapheme clusters}, for example
+to display accented characters, or ligatures, or Emoji, or when
+complex text shaping requires that for some scripts.  When that
+happens, characters no longer map in a simple way to display columns,
+and display layout decisions with such strings, such as truncating too
+wide strings, can be a complex job.  This function helps in performing
+suvh jobs: it splits up its argument @var{string} into a list of
+substrings, where each substring produces a single grapheme cluster
+that should be displayed as a unit.  Lisp programs can then use this
+list to construct visually-valid substrings of @var{string} which will
+look correctly on display, or compute the width of any substring of
+@var{string} by adding the width of its constituents in the returned
+list, etc.
+
+For instance, if you want to display a string without the first glyph,
+you can say:
+
+@example
+(apply #'insert (cdr (string-glyph-split string))))
+@end example
+@end defun
+
 When a buffer is displayed with line numbers (@pxref{Display Custom,,,
 emacs, The GNU Emacs Manual}), it is sometimes useful to know the
 width taken for displaying the line numbers.  The following function
@@ -2362,8 +2428,10 @@ value @code{unspecified}.  This special value means that 
the face
 doesn't specify that attribute directly.  An @code{unspecified}
 attribute tells Emacs to refer instead to a parent face (see the
 description @code{:inherit} attribute below); or, failing that, to an
-underlying face (@pxref{Displaying Faces}).  The @code{default} face
-must specify all attributes.
+underlying face (@pxref{Displaying Faces}).  (However,
+@code{unspecified} is not a valid value in @code{defface}.)
+
+  The @code{default} face must specify all attributes.
 
   Some of these attributes are meaningful only on certain kinds of
 displays.  If your display cannot handle a certain attribute, the
@@ -2750,6 +2818,11 @@ terminal must match one of the @var{value}s specified 
for it in
   :group 'basic-faces)
 @end example
 
+@kindex face-defface-spec @r{(face symbol property)}
+@kindex saved-face @r{(face symbol property)}
+@kindex customized-face @r{(face symbol property)}
+@kindex theme-face @r{(face symbol property)}
+@kindex face-documentation @r{(face symbol property)}
   Internally, Emacs stores each face's default spec in its
 @code{face-defface-spec} symbol property (@pxref{Symbol Properties}).
 The @code{saved-face} property stores any face spec saved by the user
@@ -2806,9 +2879,12 @@ This function returns the value of the @var{attribute} 
attribute for
 
 If @var{frame} is omitted or @code{nil}, that means the selected frame
 (@pxref{Input Focus}).  If @var{frame} is @code{t}, this function
-returns the value of the specified attribute for newly-created frames
-(this is normally @code{unspecified}, unless you have specified some
-value using @code{set-face-attribute}; see below).
+returns the value of the specified attribute for newly-created frames,
+i.e.@: the value of the attribute before applying the face spec in the
+face's @code{defface} definition (@pxref{Defining Faces}) or the spec
+set by @code{face-spec-set}.  This default value of @var{attribute} is
+normally @code{unspecified}, unless you have specified some other
+value using @code{set-face-attribute}; see below.
 
 If @var{inherit} is @code{nil}, only attributes directly defined by
 @var{face} are considered, so the return value may be
@@ -2858,7 +2934,12 @@ elements of the result are name-value pairs of the form
 @w{@code{(@var{attr-name} . @var{attr-value})}}.  Optional argument
 @var{frame} specifies the frame whose definition of @var{face} to
 return; if omitted or @code{nil}, the returned value describes the
-default attributes of @var{face} for newly created frames.
+default attributes of @var{face} for newly created frames, i.e.@: the
+values these attributes have before applying the face spec in the
+face's @code{defface} definition or the spec set by
+@code{face-spec-set}.  These default values of the attributes are
+normally @code{unspecified}, unless you have specified some other
+value using @code{set-face-attribute}; see below.
 @end defun
 
 @defun merge-face-attribute attribute value1 value2
@@ -2876,7 +2957,7 @@ for all frames.  This function is mostly intended for 
internal usage.
 
 @defun set-face-attribute face frame &rest arguments
 This function sets one or more attributes of @var{face} for
-@var{frame}.  The attributes specifies in this way override the face
+@var{frame}.  The attributes specified in this way override the face
 spec(s) belonging to @var{face}.
 
 The extra arguments @var{arguments} specify the attributes to set, and
@@ -2893,9 +2974,10 @@ sets the attribute @code{:weight} to @code{bold} and the 
attribute
 
 
 If @var{frame} is @code{t}, this function sets the default attributes
-for newly created frames.  If @var{frame} is @code{nil}, this function
-sets the attributes for all existing frames, as well as for newly
-created frames.
+for newly created frames; they will effectively override the attribute
+values specified by @code{defface}.  If @var{frame} is @code{nil},
+this function sets the attributes for all existing frames, as well as
+for newly created frames.
 @end defun
 
   The following commands and functions mostly provide compatibility
@@ -5259,13 +5341,13 @@ to modify the set of known names for these dynamic 
libraries.
   Supported image formats (and the required support libraries) include
 PBM and XBM (which do not depend on support libraries and are always
 available), XPM (@code{libXpm}), GIF (@code{libgif} or
-@code{libungif}), JPEG (@code{libjpeg}), TIFF
-(@code{libtiff}), PNG (@code{libpng}), and SVG (@code{librsvg}).
+@code{libungif}), JPEG (@code{libjpeg}), TIFF (@code{libtiff}), PNG
+(@code{libpng}), SVG (@code{librsvg}), and WebP (@code{libwebp}).
 
   Each of these image formats is associated with an @dfn{image type
 symbol}.  The symbols for the above formats are, respectively,
-@code{pbm}, @code{xbm}, @code{xpm}, @code{gif},
-@code{jpeg}, @code{tiff}, @code{png}, and @code{svg}.
+@code{pbm}, @code{xbm}, @code{xpm}, @code{gif}, @code{jpeg},
+@code{tiff}, @code{png}, @code{svg}, and @code{webp}.
 
   Furthermore, if you build Emacs with ImageMagick
 (@code{libMagickWand}) support, Emacs can display any image format
@@ -6269,6 +6351,9 @@ Image type @code{png}.
 @item TIFF
 Image type @code{tiff}.
 Supports the @code{:index} property.  @xref{Multi-Frame Images}.
+
+@item WebP
+Image type @code{webp}.
 @end table
 
 @node Defining Images
@@ -6420,7 +6505,7 @@ will compute a scaling factor based on the font pixel 
size.
 property yourself, but it is easier to use the functions in this
 section.
 
-@defun insert-image image &optional string area slice
+@defun insert-image image &optional string area slice inhibit-isearch
 This function inserts @var{image} in the current buffer at point.  The
 value @var{image} should be an image descriptor; it could be a value
 returned by @code{create-image}, or the value of a symbol defined with
@@ -6445,7 +6530,9 @@ image.
 
 Internally, this function inserts @var{string} in the buffer, and gives
 it a @code{display} property which specifies @var{image}.  @xref{Display
-Property}.
+Property}.  By default, doing interactive searches in the buffer will
+consider @var{string} when searching.  If @var{inhibit-isearch} is
+non-@code{nil}, this is inhibited.
 @end defun
 
 @cindex slice, image
@@ -6521,6 +6608,11 @@ cache, it can always be displayed, even if the value of
 @code{max-image-size} is subsequently changed (@pxref{Image Cache}).
 @end defvar
 
+@defun image-at-point-p
+This function returns @code{t} if point is on an image, and @code{nil}
+otherwise.
+@end defun
+
 Images inserted with the insertion functions above also get a local
 keymap installed in the text properties (or overlays) that span the
 displayed image.  This keymap defines the following commands:
@@ -6692,7 +6784,10 @@ xwidget object, and then use that object as the display 
specifier
 in a @code{display} text or overlay property (@pxref{Display
 Property}).
 
-@defun make-xwidget type title width height arguments &optional buffer
+  Embedded widgets can send events notifying Lisp code about changes
+occurring within them.  (@pxref{Xwidget Events}).
+
+@defun make-xwidget type title width height arguments &optional buffer related
 This creates and returns an xwidget object.  If
 @var{buffer} is omitted or @code{nil}, it defaults to the current
 buffer.  If @var{buffer} names a buffer that doesn't exist, it will be
@@ -6705,7 +6800,10 @@ The WebKit component.
 @end table
 
 The @var{width} and @var{height} arguments specify the widget size in
-pixels, and @var{title}, a string, specifies its title.
+pixels, and @var{title}, a string, specifies its title.  @var{related}
+is used internally by the WebKit widget, and specifies another WebKit
+widget that the newly created widget should share settings and
+subprocesses with.
 @end defun
 
 @defun xwidgetp object
@@ -6726,6 +6824,10 @@ property list given by @var{plist}.
 This function returns the buffer of @var{xwidget}.
 @end defun
 
+@defun set-xwidget-buffer xwidget buffer
+This function sets the buffer of @var{xwidget} to @var{buffer}.
+@end defun
+
 @defun get-buffer-xwidgets buffer
 This function returns a list of xwidget objects associated with the
 @var{buffer}, which can be specified as a buffer object or a name of
@@ -6786,6 +6888,61 @@ This function returns the current setting of 
@var{xwidget}s
 query-on-exit flag, either @code{t} or @code{nil}.
 @end defun
 
+@defun xwidget-perform-lispy-event xwidget event frame
+Send an input event @var{event} to @var{xwidget}.  The precise action
+performed is platform-specific.  @xref{Input Events}.
+
+You can optionally pass the frame on which the event was generated via
+@var{frame}.  On X11, modifier keys in key events will not be
+considered if @var{frame} is @code{nil}, and the selected frame is not
+an X-Windows frame.
+
+On GTK, only keyboard and function key events are supported.  Mouse,
+motion, and click events are dispatched to the xwidget without going
+through Lisp code, and as such shouldn't require this function to be
+called.
+@end defun
+
+@defun xwidget-webkit-search query xwidget &optional case-insensitive 
backwards wrap-around
+Start an incremental search on the WebKit widget @var{xwidget} with
+the string @var{query} as the query.  @var{case-insensitive} denotes
+whether or not the search is case-insensitive, @var{backwards}
+determines if the search is performed backwards towards the start of
+the document, and @var{wrap-around} determines whether or not the
+search terminates at the end of the document.
+
+If the function is called while a search query is already present,
+then the query specified here will replace the existing query.
+
+To stop a search query, use @code{xwidget-webkit-finish-search}.
+@end defun
+
+@defun xwidget-webkit-next-result xwidget
+Display the next search result in @var{xwidget}.  This function will
+signal an error if a search query has not been already started in
+@var{xwidget} through @code{xwidget-webkit-search}.
+
+If @code{wrap-around} was non-nil when @code{xwidget-webkit-search}
+was called, then the search will restart from the beginning of the
+document when its end is reached.
+@end defun
+
+@defun xwidget-webkit-previous-result xwidget
+Display the previous search result in @var{xwidget}.  This function
+signals an error if a search query has not been already started in
+@var{xwidget} through @code{xwidget-webkit-search}.
+
+If @code{wrap-around} was non-nil when @code{xwidget-webkit-search}
+was called, then the search will restart from the end of the
+document when its beginning is reached.
+@end defun
+
+@defun xwidget-webkit-finish-search xwidget
+Finish a search operation started with @code{xwidget-webkit-search} in
+@var{xwidget}.  If there is no query currently ongoing, this function
+signals an error.
+@end defun
+
 @node Buttons
 @section Buttons
 @cindex buttons in buffers
@@ -6979,7 +7136,7 @@ This inserts a button with the label @var{label} at 
point, using text
 properties.
 @end defun
 
-@defun button-buttonize string callback &optional data
+@defun buttonize string callback &optional data
 Sometimes it's more convenient to make a string into a button without
 inserting it into a buffer immediately, for instance when creating
 data structures that may then, later, be inserted into a buffer.  This
@@ -7952,6 +8109,11 @@ Characters of Unicode General Category [Cf], such as 
U+200E
 @sc{left-to-right mark}, but excluding characters that have graphic
 images, such as U+00AD @sc{soft hyphen}.
 
+@item variation-selectors
+Unicode VS-1 through VS-16 (U+FE00 through U+FE0F), which are used to
+select between different glyphs for the same codepoints (typically
+emojis).
+
 @item no-font
 Characters for which there is no suitable font, or which cannot be
 encoded by the terminal's coding system.
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 323130f237..7d67cc3af1 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1216,9 +1216,7 @@ directs processing of arguments.
 @table @asis
 @item @code{t}
 All arguments are instrumented for evaluation.
-
-@item @code{0}
-None of the arguments is instrumented.
+This is short for @code{(body)}.
 
 @item a symbol
 The symbol must have an Edebug specification, which is used instead.
@@ -1528,6 +1526,16 @@ example of the @code{let} specification.
 It may be easier to understand Edebug specifications by studying
 the examples provided here.
 
+Consider a hypothetical macro @code{my-test-generator} that runs
+tests on supplied lists of data.  Although it is Edebug's default
+behavior to not instrument arguments as code, as controlled by
+@code{edebug-eval-macro-args} (@pxref{Instrumenting Macro Calls}),
+it can be useful to explicitly document that the arguments are data:
+
+@example
+(def-edebug-spec my-test-generator (&rest sexp))
+@end example
+
 A @code{let} special form has a sequence of bindings and a body.  Each
 of the bindings is either a symbol or a sublist with a symbol and
 optional expression.  In the specification below, notice the @code{gate}
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index e9e306fa0d..1c0b0fa1b5 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -234,7 +234,7 @@ To view this manual in other formats, click
 
 Appendices
 
-* Antinews::                Info for users downgrading to Emacs 26.
+* Antinews::                Info for users downgrading to Emacs 27.
 * GNU Free Documentation License:: The license for this documentation.
 * GPL::                     Conditions for copying and changing GNU Emacs.
 * Tips::                    Advice and coding conventions for Emacs Lisp.
@@ -365,6 +365,7 @@ Editing Types
 * Keymap Type::             What function a keystroke invokes.
 * Overlay Type::            How an overlay is represented.
 * Font Type::               Fonts for displaying text.
+* Xwidget Type::            Embeddable widgets.
 
 Numbers
 
@@ -1048,6 +1049,7 @@ Windows
 
 * Basic Windows::           Basic information on using windows.
 * Windows and Frames::      Relating windows to the frame they appear on.
+* Selecting Windows::       The selected window is the one that you edit in.
 * Window Sizes::            Accessing a window's size.
 * Resizing Windows::        Changing the sizes of windows.
 * Preserving Window Sizes:: Preserving the size of windows.
@@ -1055,7 +1057,6 @@ Windows
 * Deleting Windows::        Deleting a window gives its space to other windows.
 * Recombining Windows::     Preserving the frame layout when splitting and
                               deleting windows.
-* Selecting Windows::       The selected window is the one that you edit in.
 * Cyclic Window Ordering::  Moving around the existing windows.
 * Buffers and Windows::     Each window displays the contents of a buffer.
 * Switching Buffers::       Higher-level functions for switching to a buffer.
@@ -1123,6 +1124,7 @@ Frames
 * Dialog Boxes::            Displaying a box to ask yes or no.
 * Pointer Shape::           Specifying the shape of the mouse pointer.
 * Window System Selections::Transferring text to and from other X clients.
+* Yanking Media::           Yanking things that aren't plain text.
 * Drag and Drop::           Internals of Drag-and-Drop implementation.
 * Color Names::             Getting the definitions of color names.
 * Text Terminal Colors::    Defining colors for text terminals.
@@ -1316,6 +1318,7 @@ Regular Expressions
 * Rx Notation::             An alternative, structured regexp notation.
 @end ifnottex
 * Regexp Functions::        Functions for operating on regular expressions.
+* Regexp Problems::         Some problems and how they may be avoided.
 
 Syntax of Regular Expressions
 
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index 2dc808e694..dd058b1215 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -563,7 +563,17 @@ In this case, @var{visit} must be @code{nil}.  For example,
 @end example
 
 @noindent
-inserts the first 500 characters of a file.
+inserts the characters coded by the first 500 bytes of a file.
+
+If @var{beg} or @var{end} happens to be in the middle of a character's
+multibyte sequence, Emacs's character code conversion will insert one
+or more eight-bit characters (a.k.a.@: ``raw bytes'')
+(@pxref{Character Sets}) into the buffer.  If you want to read part of
+a file this way, we recommend to bind @code{coding-system-for-read} to
+a suitable value around the call to this function (@pxref{Specifying
+Coding Systems}), and to write Lisp code which will check for raw
+bytes at the boundaries, read the entire sequence of these bytes, and
+convert them back to valid characters.
 
 If the argument @var{replace} is non-@code{nil}, it means to replace the
 contents of the buffer (actually, just the accessible portion) with the
@@ -577,10 +587,11 @@ with @code{insert-file-contents}, as long as 
@var{replace} and
 @end defun
 
 @defun insert-file-contents-literally filename &optional visit beg end replace
-This function works like @code{insert-file-contents} except that it
-does not run @code{after-insert-file-functions}, and does not do
-format decoding, character code conversion, automatic uncompression,
-and so on.
+This function works like @code{insert-file-contents} except that each
+byte in the file is handled separately, being converted into an
+eight-bit character if needed.  It does not run
+@code{after-insert-file-functions}, and does not do format decoding,
+character code conversion, automatic uncompression, and so on.
 @end defun
 
 If you want to pass a file name to another process so that another
@@ -1303,6 +1314,20 @@ on the 19th, @file{aug-20} was written on the 20th, and 
the file
 @end example
 @end defun
 
+@defun file-has-changed-p filename tag
+This function returns non-@code{nil} if the time stamp of
+@var{filename} has changed since the last call.  When called for the
+first time for some @var{filename}, it records the last modification
+time and size of the file, and returns non-@code{nil} when
+@var{filename} exists.  Thereafter, when called for the same
+@var{filename}, it compares the current time stamp and size with the
+recorded ones, and returns non-@code{nil} only if either the time
+stamp or the size (or both) are different.  This is useful when a Lisp
+program wants to re-read a file whenever it changes.  With an optional
+argument @var{tag}, which must be a symbol, the size and modification
+time comparisons are limited to calls with the same tag.
+@end defun
+
 @defun file-attributes filename &optional id-format
 @anchor{Definition of file-attributes}
 This function returns a list of attributes of file @var{filename}.  If
@@ -2072,6 +2097,9 @@ directory.  Therefore, Emacs considers a file name as 
having two main
 parts: the @dfn{directory name} part, and the @dfn{nondirectory} part
 (or @dfn{file name within the directory}).  Either part may be empty.
 Concatenating these two parts reproduces the original file name.
+@footnote{Emacs follows the GNU convention to use the term @emph{file name}
+instead of the term @emph{pathname}.  We use the term @emph{path} only for
+search paths, which are lists of directory names.}
 
   On most systems, the directory part is everything up to and including
 the last slash (backslash is also allowed in input on MS-DOS or
@@ -2216,6 +2244,19 @@ and @code{file-name-nondirectory}.  For example,
 @end example
 @end defun
 
+@defun file-name-split filename
+This function splits a file name into its components, and can be
+thought of as the inverse of @code{string-joing} with the appropriate
+directory separator.  For example,
+
+@example
+(file-name-split "/tmp/foo.txt")
+    @result{} ("" "tmp" "foo.txt")
+(string-join (file-name-split "/tmp/foo.txt") "/")
+    @result{} "/tmp/foo.txt"
+@end example
+@end defun
+
 @node Relative File Names
 @subsection Absolute and Relative File Names
 @cindex absolute file name
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 477c105a95..31ad82b7ad 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -105,6 +105,7 @@ window of another Emacs frame.  @xref{Child Frames}.
 * Dialog Boxes::                Displaying a box to ask yes or no.
 * Pointer Shape::               Specifying the shape of the mouse pointer.
 * Window System Selections::    Transferring text to and from other X clients.
+* Yanking Media::               Yanking things that aren't plain text.
 * Drag and Drop::               Internals of Drag-and-Drop implementation.
 * Color Names::                 Getting the definitions of color names.
 * Text Terminal Colors::        Defining colors for text terminals.
@@ -151,7 +152,7 @@ the window (a.k.a.@: the @dfn{dominating} monitor).
 
 This function itself does not make the new frame the selected frame.
 @xref{Input Focus}.  The previously selected frame remains selected.
-On graphical terminals, however, the windowing system may select the
+On graphical terminals, however, the window system may select the
 new frame for its own reasons.
 @end deffn
 
@@ -494,7 +495,8 @@ a graphical terminal:
      | |  |_____________ Title Bar ______________|  |
      | | (1)_____________ Menu Bar ______________|  | ^
      | | (2)_____________ Tool Bar ______________|  | ^
-     | | (3) _________ Internal Border ________  |  | ^
+     | | (3)_____________ Tab Bar _______________|  | ^
+     | |  |  _________ Internal Border ________  |  | ^
      | |  | |   ^                              | |  | |
      | |  | |   |                              | |  | |
 Outer  |  | | Inner                            | |  | Native
@@ -640,6 +642,15 @@ GTK+, on the other hand, never wraps the tool bar but may
 automatically increase the outer width of a frame in order to
 accommodate an overlong tool bar.
 
+@item Tab Bar
+@cindex tab bar
+The tab bar (@pxref{Tab Bars,,,emacs, The GNU Emacs Manual}) is always
+drawn by Emacs itself.  The tab bar appears above the tool bar in
+Emacs built with an internal tool bar, and below the tool bar in
+builds with an external tool bar.
+Display of the tab bar can be suppressed by setting the
+@code{tab-bar-lines} parameter (@pxref{Layout Parameters}) to zero.
+
 @item Native Frame
 @cindex native frame
 @cindex native edges
@@ -740,8 +751,8 @@ the internal border, one vertical scroll bar, and one left 
and one right
 fringe if they are specified for this frame, see @ref{Layout
 Parameters}.  Its height can be obtained by removing from that of the
 native height the widths of the internal border and the heights of the
-frame's internal menu and tool bars and one horizontal scroll bar if
-specified for this frame.
+frame's internal menu and tool bars, the tab bar and one horizontal
+scroll bar if specified for this frame.
 @end table
 
 @cindex absolute position
@@ -1208,10 +1219,10 @@ width of one scroll bar provided this option is 
@code{nil} and keep it
 unchanged if this option is @code{t} or a list containing
 @code{vertical-scroll-bars}.
 
-The default value is @code{'(tab-bar-lines tool-bar-lines)} for Lucid,
+The default value is @code{(tab-bar-lines tool-bar-lines)} for Lucid,
 Motif and MS-Windows (which means that adding/removing a tool or tab
 bar there does not change the outer frame height),
-@code{'(tab-bar-lines)} on all other window systems including GTK+
+@code{(tab-bar-lines)} on all other window systems including GTK+
 (which means that changing any of the parameters listed above with the
 exception of @code{tab-bar-lines} may change the size of the outer
 frame), and @code{t} otherwise (which means the outer frame size never
@@ -1875,6 +1886,13 @@ The position of the tool bar when Emacs was built with 
GTK+.  Its value
 can be one of @code{top}, @code{bottom} @code{left}, @code{right}.  The
 default is @code{top}.
 
+@vindex tab-bar-lines@r{, a frame parameter}
+@item tab-bar-lines
+The number of lines to use for the tab bar (@pxref{Tab Bars,,,emacs, The
+GNU Emacs Manual}).  The default is one if Tab Bar mode is enabled and
+zero otherwise.  This value may change whenever the tab bar wraps
+(@pxref{Frame Layout}).
+
 @vindex line-spacing@r{, a frame parameter}
 @item line-spacing
 Additional space to leave below each text line, in pixels (a positive
@@ -2758,7 +2776,8 @@ Terminals}.
 @cindex selected frame
 
 At any time, one frame in Emacs is the @dfn{selected frame}.  The
-selected window always resides on the selected frame.
+selected window (@pxref{Selecting Windows}) always resides on the
+selected frame.
 
 When Emacs displays its frames on several terminals (@pxref{Multiple
 Terminals}), each terminal has its own selected frame.  But only one
@@ -2992,12 +3011,11 @@ Auto-selection}).
 
 Note that this option does not distinguish ``sloppy'' focus (where the
 frame that previously had focus retains focus as long as the mouse
-pointer does not move into another window manager window) from
-``strict'' focus (where a frame immediately loses focus when it's left
-by the mouse pointer).  Neither does it recognize whether your window
-manager supports delayed focusing or auto-raising where you can
-explicitly specify the time until a new frame gets focus or is
-auto-raised.
+pointer does not move into another window-system window) from ``strict''
+focus (where a frame immediately loses focus when it's left by the mouse
+pointer).  Neither does it recognize whether your window manager
+supports delayed focusing or auto-raising where you can explicitly
+specify the time until a new frame gets focus or is auto-raised.
 
 You can supply a ``focus follows mouse'' policy for individual Emacs
 windows by customizing the variable @code{mouse-autoselect-window}
@@ -3906,6 +3924,47 @@ For backward compatibility, there are obsolete aliases
 names of @code{gui-get-selection} and @code{gui-set-selection} before
 Emacs 25.1.
 
+@node Yanking Media
+@section Yanking Media
+
+  If you choose, for instance, ``Copy Image'' in a web browser, that
+image is put onto the clipboard, and Emacs can access it via
+@code{gui-get-selection}.  But in general, inserting image data into
+an arbitrary buffer isn't very useful---you can't really do much with
+it by default.
+
+  So Emacs has a system to let modes register handlers for these
+``complicated'' selections.
+
+@defun yank-media-handler types handler
+@var{types} can be a @acronym{MIME} media type symbol, a regexp to
+match these, or a list of these symbols and regexps.  For instance:
+
+@example
+(yank-media-handler 'text/html #'my-html-handler)
+(yank-media-handler "image/.*" #'my-image-handler)
+@end example
+
+A mode can register as many handlers as required.
+
+  The @var{handler} function is called with two parameters: The
+@acronym{MIME} media type symbol and the data (as a string).  The
+handler should then insert the object into the buffer, or save it, or
+do whatever is appropriate for the mode.
+@end defun
+
+  The @code{yank-media} command will consult the registered handlers in
+the current buffer, compare that with the available media types on the
+clipboard, and then pass on the matching selection to the handler (if
+any).  If there's more than one matching selection, the user is
+queried first.
+
+  The @code{yank-media-types} command can be used to explore the
+clipboard/primary selection.  It lists all the media types that are
+currently available, and can be handy when creating handlers---to see
+what data is actually available.  Some applications put a surprising
+amount of different data types on the clipboard.
+
 @node Drag and Drop
 @section Drag and Drop
 @cindex drag and drop
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 77d1465c87..8f98ac935c 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -378,7 +378,7 @@ keyword @code{&rest} before one final argument.
 @group
 (@var{required-vars}@dots{}
  @r{[}&optional @r{[}@var{optional-vars}@dots{}@r{]}@r{]}
- @r{[}&rest @r{[}@var{rest-var}@r{]}@r{]})
+ @r{[}&rest @var{rest-var}@r{]})
 @end group
 @end example
 
@@ -826,12 +826,20 @@ This function returns a new function which, when called, 
will call
 @var{func} with the list of arguments composed from @var{args} and
 additional arguments specified at the time of the call.  If @var{func}
 accepts @var{n} arguments, then a call to @code{apply-partially} with
-@w{@code{@var{m} < @var{n}}} arguments will produce a new function of
-@w{@code{@var{n} - @var{m}}} arguments.
+@w{@code{@var{m} <= @var{n}}} arguments will produce a new function of
+@w{@code{@var{n} - @var{m}}} arguments@footnote{
+If the number of arguments that @var{func} can accept is unlimited,
+then the new function will also accept an unlimited number of
+arguments, so in that case @code{apply-partially} doesn't reduce the
+number of arguments that the new function could accept.
+}.
 
 Here's how we could define the built-in function @code{1+}, if it
 didn't exist, using @code{apply-partially} and @code{+}, another
-built-in function:
+built-in function@footnote{
+Note that unlike the built-in function, this version accepts any
+number of arguments.
+}:
 
 @example
 @group
@@ -902,11 +910,11 @@ length of @var{sequence}.  For example:
 
 @example
 @group
-(mapcar 'car '((a b) (c d) (e f)))
+(mapcar #'car '((a b) (c d) (e f)))
      @result{} (a c e)
-(mapcar '1+ [1 2 3])
+(mapcar #'1+ [1 2 3])
      @result{} (2 3 4)
-(mapcar 'string "abc")
+(mapcar #'string "abc")
      @result{} ("a" "b" "c")
 @end group
 
@@ -922,14 +930,14 @@ Return the list of results."
   ;; @r{If no list is exhausted,}
   (if (not (memq nil args))
       ;; @r{apply function to @sc{car}s.}
-      (cons (apply function (mapcar 'car args))
-            (apply 'mapcar* function
+      (cons (apply function (mapcar #'car args))
+            (apply #'mapcar* function
                    ;; @r{Recurse for rest of elements.}
-                   (mapcar 'cdr args)))))
+                   (mapcar #'cdr args)))))
 @end group
 
 @group
-(mapcar* 'cons '(a b c) '(1 2 3 4))
+(mapcar* #'cons '(a b c) '(1 2 3 4))
      @result{} ((a . 1) (b . 2) (c . 3))
 @end group
 @end example
@@ -946,10 +954,10 @@ the results (which must be lists), by altering the 
results (using
 @example
 @group
 ;; @r{Contrast this:}
-(mapcar 'list '(a b c d))
+(mapcar #'list '(a b c d))
      @result{} ((a) (b) (c) (d))
 ;; @r{with this:}
-(mapcan 'list '(a b c d))
+(mapcan #'list '(a b c d))
      @result{} (a b c d)
 @end group
 @end example
@@ -961,14 +969,14 @@ side-effects only---the values it returns are ignored, 
not collected
 into a list.  @code{mapc} always returns @var{sequence}.
 @end defun
 
-@defun mapconcat function sequence separator
+@defun mapconcat function sequence &optional separator
 @code{mapconcat} applies @var{function} to each element of
 @var{sequence}; the results, which must be sequences of characters
 (strings, vectors, or lists), are concatenated into a single string
 return value.  Between each pair of result sequences, @code{mapconcat}
 inserts the characters from @var{separator}, which also must be a
-string, or a vector or list of characters.  @xref{Sequences Arrays
-Vectors}.
+string, or a vector or list of characters; a @code{nil} value is
+treated as the empty string.  @xref{Sequences Arrays Vectors}.
 
 The argument @var{function} must be a function that can take one
 argument and returns a sequence of characters: a string, a vector, or
@@ -978,7 +986,7 @@ string.
 
 @example
 @group
-(mapconcat 'symbol-name
+(mapconcat #'symbol-name
            '(The cat in the hat)
            " ")
      @result{} "The cat in the hat"
@@ -986,8 +994,7 @@ string.
 
 @group
 (mapconcat (lambda (x) (format "%c" (1+ x)))
-           "HAL-8000"
-           "")
+           "HAL-8000")
      @result{} "IBM.9111"
 @end group
 @end example
diff --git a/doc/lispref/hooks.texi b/doc/lispref/hooks.texi
index 394928454b..e9d1e270d8 100644
--- a/doc/lispref/hooks.texi
+++ b/doc/lispref/hooks.texi
@@ -18,11 +18,13 @@ arguments and their values are completely ignored.  The 
recommended way
 to put a new function on such a hook is to call @code{add-hook}.
 @xref{Hooks}, for more information about using hooks.
 
-The variables whose names end in @samp{-functions} are usually @dfn{abnormal
-hooks} (some old code may also use the deprecated @samp{-hooks} suffix); their
-values are lists of functions, but these functions are called in a special way
-(they are passed arguments, or their return values are used).  The variables
-whose names end in @samp{-function} have single functions as their values.
+The variables whose names end in @samp{-functions} are usually
+@dfn{abnormal hooks} (some old code may also use the deprecated
+@samp{-hooks} suffix).  Their values are lists of functions, but these
+functions are called in a special way: they are either passed
+arguments, or their return values are used in some way.  The variables
+whose names end in @samp{-function} have single functions as their
+values.
 
 This is not an exhaustive list, it only covers the more general hooks.
 For example, every major mode defines a hook named
@@ -262,7 +264,6 @@ after-set-visited-file-name-hook
 auto-coding-functions
 choose-completion-string-functions
 completing-read-function
-completion-annotate-function
 completion-at-point-functions
 completion-list-insert-choice-function
 deactivate-current-input-method-function
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index d3edd63317..7718712b9b 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -218,6 +218,14 @@ the Emacs executable that dumped them.
 
 If you want to use this function in an Emacs that was already dumped,
 you must run Emacs with the @samp{-batch} option.
+
+@vindex after-pdump-load-hook
+If you're including @samp{.el} files in the dumped Emacs and that
+@samp{.el} file has code that is normally run at load time, that code
+won't be run when Emacs starts after dumping.  To help work around
+that problem, you can put functions on the
+@code{after-pdump-load-hook} hook.  This hook is run when starting
+Emacs.
 @end defun
 
 @defun dump-emacs to-file from-file
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index 4097c86f07..899499ed46 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -94,8 +94,25 @@ Manual}.
 (kbd "<f1> SPC") @result{} [f1 32]
 (kbd "C-M-<down>") @result{} [C-M-down]
 @end example
+
+@findex kbd-valid-p
+The @code{kbd} function is very permissive, and will try to return
+something sensible even if the syntax used isn't completely
+conforming.  To check whether the syntax is actually valid, use the
+@code{kbd-valid-p} function.
+
+@code{define-key} also supports using the shorthand syntax
+@samp{["..."]} syntax to define a key.  The string has to be a
+strictly valid @code{kbd} sequence, and if it's not valid, an error
+will be signalled.  For instance, to bind @key{C-c f}, you can say:
+
+@lisp
+(define-key global-map ["C-c f"] #'find-file-literally)
+@end lisp
+
 @end defun
 
+
 @node Keymap Basics
 @section Keymap Basics
 @cindex key binding
@@ -1278,24 +1295,46 @@ Binding Conventions}).
 
 @cindex meta character key constants
 @cindex control character key constants
-  In writing the key sequence to rebind, it is good to use the special
-escape sequences for control and meta characters (@pxref{String Type}).
-The syntax @samp{\C-} means that the following character is a control
-character and @samp{\M-} means that the following character is a meta
-character.  Thus, the string @code{"\M-x"} is read as containing a
-single @kbd{M-x}, @code{"\C-f"} is read as containing a single
-@kbd{C-f}, and @code{"\M-\C-x"} and @code{"\C-\M-x"} are both read as
-containing a single @kbd{C-M-x}.  You can also use this escape syntax in
-vectors, as well as others that aren't allowed in strings; one example
-is @samp{[?\C-\H-x home]}.  @xref{Character Type}.
-
-  The key definition and lookup functions accept an alternate syntax for
-event types in a key sequence that is a vector: you can use a list
-containing modifier names plus one base event (a character or function
-key name).  For example, @code{(control ?a)} is equivalent to
-@code{?\C-a} and @code{(hyper control left)} is equivalent to
-@code{C-H-left}.  One advantage of such lists is that the precise
-numeric codes for the modifier bits don't appear in compiled files.
+  @code{define-key} (and other functions that are used to rebind keys)
+understand a number of different syntaxes for the keys.
+
+@table @asis
+@item A vector containing a single string.
+This is the preferred way to represent a key sequence.  Here's a
+couple of examples:
+
+@example
+["C-c M-f"]
+["S-<home>"]
+@end example
+
+The syntax is the same as the one used by Emacs when displaying key
+bindings, for instance in @samp{*Help*} buffers and help texts.
+
+If the syntax isn't valid, an error will be raised when running
+@code{define-key}, or when byte-compiling code that has these calls.
+
+@item A vector containing lists of keys.
+You can use a list containing modifier names plus one base event (a
+character or function key name).  For example, @code{[(control ?a)
+(meta b)]} is equivalent to @kbd{C-a M-b} and @code{[(hyper control
+left)]} is equivalent to @kbd{C-H-left}.
+
+@item A string with control and meta characters.
+Internally, key sequences are often represented as strings using the
+special escape sequences for control and meta characters
+(@pxref{String Type}), but this representation can also be used by
+users when rebinding keys.  A string like @code{"\M-x"} is read as
+containing a single @kbd{M-x}, @code{"\C-f"} is read as containing a
+single @kbd{C-f}, and @code{"\M-\C-x"} and @code{"\C-\M-x"} are both
+read as containing a single @kbd{C-M-x}.
+
+@item a vector of characters.
+This is the other internal representation of key sequences, and
+supports a fuller range of modifiers than the string representation.
+One example is @samp{[?\C-\H-x home]}, which represents the @kbd{C-H-x
+home} key sequence.  @xref{Character Type}.
+@end table
 
   The functions below signal an error if @var{keymap} is not a keymap,
 or if @var{key} is not a string or vector representing a key sequence.
@@ -1337,7 +1376,7 @@ bindings in it:
     @result{} (keymap)
 @end group
 @group
-(define-key map "\C-f" 'forward-char)
+(define-key map ["C-f"] 'forward-char)
     @result{} forward-char
 @end group
 @group
@@ -1347,7 +1386,7 @@ map
 
 @group
 ;; @r{Build sparse submap for @kbd{C-x} and bind @kbd{f} in that.}
-(define-key map (kbd "C-x f") 'forward-word)
+(define-key map ["C-x f"] 'forward-word)
     @result{} forward-word
 @end group
 @group
@@ -1360,14 +1399,14 @@ map
 
 @group
 ;; @r{Bind @kbd{C-p} to the @code{ctl-x-map}.}
-(define-key map (kbd "C-p") ctl-x-map)
+(define-key map ["C-p"] ctl-x-map)
 ;; @code{ctl-x-map}
 @result{} [nil @dots{} find-file @dots{} backward-kill-sentence]
 @end group
 
 @group
 ;; @r{Bind @kbd{C-f} to @code{foo} in the @code{ctl-x-map}.}
-(define-key map (kbd "C-p C-f") 'foo)
+(define-key map ["C-p C-f"] 'foo)
 @result{} 'foo
 @end group
 @group
@@ -1386,6 +1425,99 @@ changing an entry in @code{ctl-x-map}, and this has the 
effect of
 changing the bindings of both @kbd{C-p C-f} and @kbd{C-x C-f} in the
 default global map.
 
+@defun define-keymap &key options... &rest pairs...
+@code{define-key} is the general work horse for defining a key in a
+keymap.  When writing modes, however, you frequently have to bind a
+large number of keys at once, and using @code{define-key} on them all
+can be tedious and error-prone.  Instead you can use
+@code{define-keymap}, which creates a keymaps and binds a number of
+keys.  Here's a very basic example:
+
+@lisp
+(define-keymap
+  "n" #'forward-line
+  "f" #'previous-line
+  ["C-c C-c"] #'quit-window)
+@end lisp
+
+This function creates a new sparse keymap, defines the two keystrokes
+in @var{pairs}, and returns the new keymap.
+
+@var{pairs} is a list of alternating key bindings and key definitions,
+as accepted by @code{define-key}.  In addition the key can be the
+special symbol @code{:menu}, in which case the definition should be a
+menu definition as accepted by @code{easy-menu-define} (@pxref{Easy
+Menu}).  Here's a brief example:
+
+@lisp
+(define-keymap :full t
+  "g" #'eww-reload
+  :menu '("Eww"
+          ["Exit" quit-window t]
+          ["Reload" eww-reload t]))
+@end lisp
+
+A number of keywords can be used before the key/definition pairs to
+changes features of the new keymap.  If the keyword is missing, the
+default value for the feature is @code{nil}.  Here's a list of the
+available keywords:
+
+@table @code
+@item :full
+If non-@code{nil}, create a chartable keymap (as from
+@code{make-keymap}) instead of a sparse keymap (as from
+@code{make-sparse-keymap} (@pxref{Creating Keymaps}).  A sparse keymap
+is the default.
+
+@item :parent
+If non-@code{nil}, this should be a keymap to use as the parent
+(@pxref{Inheritance and Keymaps}).
+
+@item :keymap
+If non-@code{nil}, this should be a keymap.  Instead of creating a new
+keymap, this keymap is modified instead.
+
+@item :suppress
+If non-@code{nil}, the keymap will be suppressed with
+@code{suppress-keymap} (@pxref{Changing Key Bindings}).  If
+@code{nodigits}, treat digits like other chars.
+
+@item :name
+If non-@code{nil}, this should be a string to use as the menu for the
+keymap if you use it as a menu with @code{x-popup-menu} (@pxref{Pop-Up
+Menus}).
+
+@item :prefix
+If non-@code{nil}, this should be a symbol to be used as a prefix
+command (@pxref{Prefix Keys}).  If this is the case, this symbol is
+returned by @code{define-keymap} instead of the map itself.
+@end table
+
+@end defun
+
+@defmac defvar-keymap name &key options... &rest pairs...
+By far, the most common thing to do with a keymap is to bind it to a
+variable.  This is what virtually all modes do---a mode called
+@code{foo} almost always has a variable called @code{foo-mode-map}.
+
+This macro defines @var{name} as a variable, and passes @var{options}
+and @var{pars} to @code{define-keymap}, and uses the result as the
+default value for the variable.
+
+@var{options} is like the keywords in @code{define-keymap}, but adds a
+@code{:doc} keyword that says what the doc string for the @var{name}
+variable should be.
+
+Here's an example:
+
+@lisp
+(defvar-keymap eww-textarea-map
+  :parent text-mode-map
+  "\r" #'forward-line
+  [?\t] #'shr-next-link)
+@end lisp
+@end defmac
+
   The function @code{substitute-key-definition} scans a keymap for
 keys that have a certain binding and rebinds them with a different
 binding.  Another feature which is cleaner and can often produce the
@@ -2227,6 +2359,12 @@ This property specifies that @var{string} is the string 
to display
 as the keyboard equivalent for this menu item.  You can use
 the @samp{\\[...]} documentation construct in @var{string}.
 
+This property can also be a function (which will be called with no
+arguments).  This function should return a string.  This function will
+be called every time the menu is computed, so using a function that
+takes a lot of time to compute is not a good idea, and it should
+expect to be called from any context.
+
 @item :filter @var{filter-fn}
 This property provides a way to compute the menu item dynamically.
 The property value @var{filter-fn} should be a function of one argument;
diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi
index 75641256b6..f98ae76da9 100644
--- a/doc/lispref/lists.texi
+++ b/doc/lispref/lists.texi
@@ -1227,13 +1227,13 @@ this is not guaranteed to happen):
 @cindex lists as sets
 @cindex sets
 
-  A list can represent an unordered mathematical set---simply consider a
-value an element of a set if it appears in the list, and ignore the
-order of the list.  To form the union of two sets, use @code{append} (as
-long as you don't mind having duplicate elements).  You can remove
-@code{equal} duplicates using @code{delete-dups}.  Other useful
-functions for sets include @code{memq} and @code{delq}, and their
-@code{equal} versions, @code{member} and @code{delete}.
+  A list can represent an unordered mathematical set---simply consider
+a value an element of a set if it appears in the list, and ignore the
+order of the list.  To form the union of two sets, use @code{append}
+(as long as you don't mind having duplicate elements).  You can remove
+@code{equal} duplicates using @code{delete-dups} or @code{seq-uniq}.
+Other useful functions for sets include @code{memq} and @code{delq},
+and their @code{equal} versions, @code{member} and @code{delete}.
 
 @cindex CL note---lack @code{union}, @code{intersection}
 @quotation
@@ -1489,7 +1489,8 @@ comparison.
 This function destructively removes all @code{equal} duplicates from
 @var{list}, stores the result in @var{list} and returns it.  Of
 several @code{equal} occurrences of an element in @var{list},
-@code{delete-dups} keeps the first one.
+@code{delete-dups} keeps the first one.  See @code{seq-uniq} for
+non-destructive operation (@pxref{Sequence Functions}).
 @end defun
 
   See also the function @code{add-to-list}, in @ref{List Variables},
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index ee55f982d0..bc5c08c687 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -59,12 +59,13 @@ runs just before Emacs suspends itself (@pxref{Suspending 
Emacs}).
 
 @cindex abnormal hook
   If the hook variable's name does not end with @samp{-hook}, that
-indicates it is probably an @dfn{abnormal hook}.  That means the hook
-functions are called with arguments, or their return values are used
-in some way.  The hook's documentation says how the functions are
-called.  Any functions added to an abnormal hook must follow the
-hook's calling convention.  By convention, abnormal hook names end in
-@samp{-functions}.
+indicates it is probably an @dfn{abnormal hook}.  These differ from
+normal hooks in two ways: they can be called with one or more
+arguments, and their return values can be used in some way.  The
+hook's documentation says how the functions are called and how their
+return values are used.  Any functions added to an abnormal hook must
+follow the hook's calling convention.  By convention, abnormal hook
+names end in @samp{-functions}.
 
 @cindex single-function hook
 If the name of the variable ends in @samp{-predicate} or
@@ -266,6 +267,18 @@ This function restores the major mode recorded by
 function calls @code{normal-mode} (@pxref{Auto Major Mode,
 normal-mode}), but tries to force it not to choose any modes in
 @var{avoided-modes}, if that argument is non-@code{nil}.
+@end defun
+
+@defun clean-mode
+Changing the major mode clears out most local variables, but it
+doesn't remove all artefacts in the buffer (like text properties and
+overlays).  It's rare to change a buffer from one major mode to
+another (except from @code{fundamental-mode} to everything else), so
+this is usually not a concern.  It can sometimes be convenient (mostly
+when debugging a problem in a buffer) to do a ``full reset'' of the
+buffer, and that's what the @code{clean-mode} major mode offers.  It
+will kill all local variables (even the permanently local ones), and
+also removes all overlays and text properties.
 @end defun
 
   The easiest way to write a major mode is to use the macro
@@ -1137,10 +1150,11 @@ re-sorting entries.  Comparison is done with 
@code{equal}.
 @item
 @var{contents} is a vector with the same number of elements as
 @code{tabulated-list-format}.  Each vector element is either a string,
-which is inserted into the buffer as-is, or a list @code{(@var{label}
-. @var{properties})}, which means to insert a text button by calling
-@code{insert-text-button} with @var{label} and @var{properties} as
-arguments (@pxref{Making Buttons}).
+which is inserted into the buffer as-is; an image descriptor, which is
+used to insert an image (@pxref{Image Descriptors}); or a list
+@w{@code{(@var{label} . @var{properties})}}, which means to insert a
+text button by calling @code{insert-text-button} with @var{label} and
+@var{properties} as arguments (@pxref{Making Buttons}).
 
 There should be no newlines in any of these strings.
 @end itemize
diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi
index 365d5ac8d6..bbd3973f61 100644
--- a/doc/lispref/objects.texi
+++ b/doc/lispref/objects.texi
@@ -516,9 +516,9 @@ codes for these non-@acronym{ASCII} control characters 
include the
 2**26
 @end ifnottex
 bit as well as the code for the corresponding non-control character.
-Ordinary text terminals have no way of generating non-@acronym{ASCII}
-control characters, but you can generate them straightforwardly using
-X and other window systems.
+Not all text terminals can generate non-@acronym{ASCII} control
+characters, but it is straightforward to generate them using X and
+other window systems.
 
   For historical reasons, Emacs treats the @key{DEL} character as
 the control equivalent of @kbd{?}:
@@ -588,8 +588,8 @@ character is upper case or lower case.  Emacs uses the
 2**25
 @end ifnottex
 bit to indicate that the shift key was used in typing a control
-character.  This distinction is possible only when you use X terminals
-or other special terminals; ordinary text terminals do not report the
+character.  This distinction is possible only on a graphical display
+such as a GUI display on X; text terminals do not report the
 distinction.  The Lisp syntax for the shift bit is @samp{\S-}; thus,
 @samp{?\C-\S-o} or @samp{?\C-\S-O} represents the shifted-control-o
 character.
@@ -1535,6 +1535,7 @@ editing.
 * Keymap Type::         What function a keystroke invokes.
 * Overlay Type::        How an overlay is represented.
 * Font Type::           Fonts for displaying text.
+* Xwidget Type::        Embeddable widgets.
 @end menu
 
 @node Buffer Type
@@ -1625,19 +1626,18 @@ markers.
 @node Window Type
 @subsection Window Type
 
-  A @dfn{window} describes the portion of the terminal screen that Emacs
-uses to display a buffer.  Every window has one associated buffer, whose
-contents appear in the window.  By contrast, a given buffer may appear
-in one window, no window, or several windows.
+  A @dfn{window} describes the portion of the screen that Emacs uses to
+display buffers.  Every live window (@pxref{Basic Windows}) has one
+associated buffer, whose contents appear in that window.  By contrast, a
+given buffer may appear in one window, no window, or several windows.
+Windows are grouped on the screen into frames; each window belongs to
+one and only one frame.  @xref{Frame Type}.
 
   Though many windows may exist simultaneously, at any time one window
-is designated the @dfn{selected window}.  This is the window where the
-cursor is (usually) displayed when Emacs is ready for a command.  The
-selected window usually displays the current buffer (@pxref{Current
-Buffer}), but this is not necessarily the case.
-
-  Windows are grouped on the screen into frames; each window belongs to
-one and only one frame.  @xref{Frame Type}.
+is designated the @dfn{selected window} (@pxref{Selecting Windows}).
+This is the window where the cursor is (usually) displayed when Emacs is
+ready for a command.  The selected window usually displays the current
+buffer (@pxref{Current Buffer}), but this is not necessarily the case.
 
   Windows have no read syntax.  They print in hash notation, giving the
 window number and the name of the buffer being displayed.  The window
@@ -1861,6 +1861,20 @@ syntax looks like @samp{#<font-object>}, 
@samp{#<font-spec>}, and
 @samp{#<font-entity>} respectively.  @xref{Low-Level Font}, for a
 description of these Lisp objects.
 
+@node Xwidget Type
+@subsection Xwidget Type
+@cindex xwidget type
+@cindex xwidget-view type
+
+  An @dfn{xwidget} is a special display element, such as a web
+browser, that can be embedded inside a buffer.  Each window that
+displays an xwidget will also have an @dfn{xwidget view}, which on
+X-Windows corresponds to a single X window used to display the widget.
+
+Neither of these objects are readable; their print syntaxes look like
+@samp{#<xwidget>} and @samp{#<xwidget-view>}, respectively.
+@xref{Xwidgets}, for a more detailed description of xwidgets.
+
 @node Circular Objects
 @section Read Syntax for Circular Objects
 @cindex circular structure, read syntax
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 658f742c41..1fbd66458a 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1042,6 +1042,21 @@ that variable with @code{let} is also reasonable 
practice.
 if it removed @var{variable} from the environment.
 @end deffn
 
+@defmac with-environment-variables variables body@dots{}
+This macro sets the environment variables according to @var{variables}
+temporarily when executing @var{body}.  The previous values are
+restored when the form finishes.  The argument @var{variables} should
+be a list of pairs of strings of the form
+@w{@code{(@var{var} @var{value})}}, where @var{var} is the name of the
+environment variable and @var{value} is that variable's value.
+
+@lisp
+(with-environment-variables (("LANG" "C")
+                             ("LANGUAGE" "en_US:en"))
+  (call-process "ls" nil t))
+@end lisp
+@end defmac
+
 @defvar process-environment
 This variable is a list of strings, each describing one environment
 variable.  The functions @code{getenv} and @code{setenv} work by means
@@ -3109,8 +3124,9 @@ watch for file attribute changes, like permissions or 
modification
 time
 @end table
 
-If @var{file} is a directory, changes for all files in that directory
-will be notified.  This does not work recursively.
+If @var{file} is a directory, @code{change} watches for file creation
+or deletion in that directory.  Some of the file notification backends
+report also file changes.  This does not work recursively.
 
 When any event happens, Emacs will call the @var{callback} function
 passing it a single argument @var{event}, which is of the form
@@ -3215,6 +3231,14 @@ Removes an existing file watch specified by its 
@var{descriptor}.
 @code{file-notify-add-watch}.
 @end defun
 
+@deffn Command file-notify-rm-all-watches
+Removes all existing file notification watches from Emacs.
+
+Use this command with caution, because it could have unexpected side
+effects on packages relying on file watches.  It is intended mainly
+for debugging purposes, or when Emacs has been stalled.
+@end deffn
+
 @defun file-notify-valid-p descriptor
 Checks a watch specified by its @var{descriptor} for validity.
 @var{descriptor} should be an object returned by
diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi
index 9c033fe3df..aeb455bb25 100644
--- a/doc/lispref/package.texi
+++ b/doc/lispref/package.texi
@@ -17,6 +17,11 @@ put it in a @dfn{package archive} for others to download.
 @xref{Packages,,, emacs, The GNU Emacs Manual}, for a description of
 user-level features of the packaging system.
 
+  These sections are mostly directed towards package archive
+maintainers---much of this information is not relevant for package
+authors (i.e., people who write code that will be distributed via
+these archives).
+
 @menu
 * Packaging Basics::        The basic concepts of Emacs Lisp packages.
 * Simple Packages::         How to package a single .el file.
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index 90c4215637..8a9cb2a8f8 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -1047,6 +1047,19 @@ This function returns a list of all processes that have 
not been deleted.
 @end smallexample
 @end defun
 
+@defun num-processors &optional query
+This function returns the number of processors, a positive integer.
+Each usable thread execution unit counts as a processor.
+By default, the count includes the number of available processors,
+which you can override by setting the
+@url{https://www.openmp.org/spec-html/5.1/openmpse59.html,
+@env{OMP_NUM_THREADS} environment variable of OpenMP}.
+If the optional argument @var{query} is @code{current},
+this function ignores @env{OMP_NUM_THREADS};
+if @var{query} is @code{all}, this function also counts processors
+that are on the system but are not available to the current process.
+@end defun
+
 @defun get-process name
 This function returns the process named @var{name} (a string), or
 @code{nil} if there is none.  The argument @var{name} can also be a
@@ -1766,9 +1779,12 @@ or more batches of output; one way to do this is to 
insert the
 received text into a temporary buffer, which can then be searched.
 
 @defun set-process-filter process filter
-This function gives @var{process} the filter function @var{filter}.  If
-@var{filter} is @code{nil}, it gives the process the default filter,
-which inserts the process output into the process buffer.
+This function gives @var{process} the filter function @var{filter}.
+If @var{filter} is @code{nil}, it gives the process the default
+filter, which inserts the process output into the process buffer.  If
+@var{filter} is @code{t}, Emacs stops accepting output from the
+process, unless it's a network server process that listens for
+incoming connections.
 @end defun
 
 @defun process-filter process
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index 0dcf3889a5..296ce20169 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -263,6 +263,7 @@ case-sensitive.
 * Rx Notation::             An alternative, structured regexp notation.
 @end ifnottex
 * Regexp Functions::        Functions for operating on regular expressions.
+* Regexp Problems::         Some problems and how they may be avoided.
 @end menu
 
 @node Syntax of Regexps
@@ -343,15 +344,6 @@ first tries to match all three @samp{a}s; but the rest of 
the pattern is
 The next alternative is for @samp{a*} to match only two @samp{a}s.  With
 this choice, the rest of the regexp matches successfully.
 
-@strong{Warning:} Nested repetition operators can run for a very
-long time, if they lead to ambiguous matching.  For
-example, trying to match the regular expression @samp{\(x+y*\)*a}
-against the string @samp{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz} could
-take hours before it ultimately fails.  Emacs may try each way of
-grouping the @samp{x}s before concluding that none of them can work.
-In general, avoid expressions that can match the same string in
-multiple ways.
-
 @item @samp{+}
 @cindex @samp{+} in regexp
 is a postfix operator, similar to @samp{*} except that it must match
@@ -1060,7 +1052,8 @@ customization.
 
 The various forms in @code{rx} regexps are described below.  The
 shorthand @var{rx} represents any @code{rx} form, and @var{rx}@dots{}
-means zero or more @code{rx} forms.  Where the corresponding string
+means zero or more @code{rx} forms.  These are all valid arguments to
+the @code{rx} macro.  Where the corresponding string
 regexp syntax is given, @var{A}, @var{B}, @dots{} are string regexp
 subexpressions.
 
@@ -1356,7 +1349,8 @@ names:
 For details, @pxref{Syntax Class Table}.  Please note that
 @code{(syntax punctuation)} is @emph{not} equivalent to the character class
 @code{punctuation}.@*
-Corresponding string regexp: @samp{\s@var{code}}
+Corresponding string regexp: @samp{\s@var{char}} where @var{char} is the
+syntax character.
 
 @item @code{(category @var{category})}
 @cindex @code{category} in rx
@@ -1413,7 +1407,8 @@ the names below or its category character.
 For more information about currently defined categories, run the
 command @kbd{M-x describe-categories @key{RET}}.  For how to define
 new categories, @pxref{Categories}.@*
-Corresponding string regexp: @samp{\c@var{code}}
+Corresponding string regexp: @samp{\c@var{char}} where @var{char} is the
+category character.
 @end table
 
 @subsubheading Zero-width assertions
@@ -1543,11 +1538,18 @@ in the current global environment.
 @node Rx Functions
 @subsubsection Functions and macros using @code{rx} regexps
 
-@defmac rx rx-expr@dots{}
-Translate the @var{rx-expr}s to a string regexp, as if they were the
+@defmac rx rx-form@dots{}
+Translate the @var{rx-form}s to a string regexp, as if they were the
 body of a @code{(seq @dots{})} form.  The @code{rx} macro expands to a
 string constant, or, if @code{literal} or @code{regexp} forms are
-used, a Lisp expression that evaluates to a string.
+used, a Lisp expression that evaluates to a string.  Example:
+
+@example
+@group
+(rx (+ alpha) "=" (+ digit))
+  @result{} "[[:alpha:]]+=[[:digit:]]+"
+@end group
+@end example
 @end defmac
 
 @defun rx-to-string rx-expr &optional no-group
@@ -1555,6 +1557,14 @@ Translate @var{rx-expr} to a string regexp which is 
returned.
 If @var{no-group} is absent or nil, bracket the result in a
 non-capturing group, @samp{\(?:@dots{}\)}, if necessary to ensure that
 a postfix operator appended to it will apply to the whole expression.
+Example:
+
+@example
+@group
+(rx-to-string '(seq (+ alpha) "=" (+ digit)) t)
+  @result{} "[[:alpha:]]+=[[:digit:]]+"
+@end group
+@end example
 
 Arguments to @code{literal} and @code{regexp} forms in @var{rx-expr}
 must be string literals.
@@ -1651,7 +1661,7 @@ package prefix to avoid name clashes with definitions 
elsewhere, as is
 usual when naming non-local variables and functions.
 
 Forms defined this way only perform simple template substitution.
-For arbitrary computations, use them together with with the @code{rx}
+For arbitrary computations, use them together with the @code{rx}
 forms @code{eval}, @code{regexp} or @code{literal}.  Example:
 
 @example
@@ -1866,6 +1876,73 @@ variables that may be set to a pattern that actually 
matches
 something.
 @end defvar
 
+@node Regexp Problems
+@subsection Problems with Regular Expressions
+@cindex regular expression problems
+@cindex regexp stack overflow
+@cindex stack overflow in regexp
+
+The Emacs regexp implementation, like many of its kind, is generally
+robust but occasionally causes trouble in either of two ways: matching
+may run out of internal stack space and signal an error, and it can
+take a long time to complete.  The advice below will make these
+symptoms less likely and help alleviate problems that do arise.
+
+@itemize
+@item
+Anchor regexps at the beginning of a line, string or buffer using
+zero-width assertions (@samp{^} and @code{\`}). This takes advantage
+of fast paths in the implementation and can avoid futile matching
+attempts.  Other zero-width assertions may also bring benefits by
+causing a match to fail early.
+
+@item
+Avoid or-patterns in favour of character alternatives: write
+@samp{[ab]} instead of @samp{a\|b}.  Recall that @samp{\s-} and @samp{\sw}
+are equivalent to @samp{[[:space:]]} and @samp{[[:word:]]}, respectively.
+
+@item
+Since the last branch of an or-pattern does not add a backtrack point
+on the stack, consider putting the most likely matched pattern last.
+For example, @samp{^\(?:a\|.b\)*c} will run out of stack if trying to
+match a very long string of @samp{a}s, but the equivalent
+@samp{^\(?:.b\|a\)*c} will not.
+
+(It is a trade-off: successfully matched or-patterns run faster with
+the most frequently matched pattern first.)
+
+@item
+Try to ensure that any part of the text can only match in a single
+way.  For example, @samp{a*a*} will match the same set of strings as
+@samp{a*}, but the former can do so in many ways and will therefore
+cause slow backtracking if the match fails later on.  Make or-pattern
+branches mutually exclusive if possible, so that matching will not go
+far into more than one branch before failing.
+
+Be especially careful with nested repetitions: they can easily result
+in very slow matching in the presence of ambiguities.  For example,
+@samp{\(?:a*b*\)+c} will take a long time attempting to match even a
+moderately long string of @samp{a}s before failing.  The equivalent
+@samp{\(?:a\|b\)*c} is much faster, and @samp{[ab]*c} better still.
+
+@item
+Don't use capturing groups unless they are really needed; that is, use
+@samp{\(?:@dots{}\)} instead of @samp{\(@dots{}\)} for bracketing
+purposes.
+
+@ifnottex
+@item
+Consider using @code{rx} (@pxref{Rx Notation}); it can optimise some
+or-patterns automatically and will never introduce capturing groups
+unless explicitly requested.
+@end ifnottex
+@end itemize
+
+If you run into regexp stack overflow despite following the above
+advice, don't be afraid of performing the matching in multiple
+function calls, each using a simpler regexp where backtracking can
+more easily be contained.
+
 @node Regexp Search
 @section Regular Expression Searching
 @cindex regular expression searching
@@ -1968,7 +2045,7 @@ feature for matching regular expressions from end to 
beginning.  It's
 not worth the trouble of implementing that.
 @end deffn
 
-@defun string-match regexp string &optional start
+@defun string-match regexp string &optional start inhibit-modify
 This function returns the index of the start of the first match for
 the regular expression @var{regexp} in @var{string}, or @code{nil} if
 there is no match.  If @var{start} is non-@code{nil}, the search starts
@@ -1993,8 +2070,10 @@ For example,
 The index of the first character of the
 string is 0, the index of the second character is 1, and so on.
 
-If this function finds a match, the index of the first character beyond
-the match is available as @code{(match-end 0)}.  @xref{Match Data}.
+By default, if this function finds a match, the index of the first
+character beyond the match is available as @code{(match-end 0)}.
+@xref{Match Data}.  If @var{inhibit-modify} is non-@code{nil}, the
+match data isn't modified.
 
 @example
 @group
@@ -2015,16 +2094,18 @@ This predicate function does what @code{string-match} 
does, but it
 avoids modifying the match data.
 @end defun
 
-@defun looking-at regexp
+@defun looking-at regexp &optional inhibit-modify
 This function determines whether the text in the current buffer directly
 following point matches the regular expression @var{regexp}.  ``Directly
 following'' means precisely that: the search is ``anchored'' and it can
 succeed only starting with the first character following point.  The
 result is @code{t} if so, @code{nil} otherwise.
 
-This function does not move point, but it does update the match data.
-@xref{Match Data}.  If you need to test for a match without modifying
-the match data, use @code{looking-at-p}, described below.
+This function does not move point, but it does update the match data
+(if @var{inhibit-modify} is @code{nil} or missing, which is the
+default).  @xref{Match Data}.  As a convenience, instead of using the
+@var{inhibit-modify} argument, you can use @code{looking-at-p},
+described below.
 
 In this example, point is located directly before the @samp{T}.  If it
 were anywhere else, the result would be @code{nil}.
@@ -2131,13 +2212,13 @@ backtracking specified by the POSIX standard for 
regular expression
 matching.
 @end deffn
 
-@defun posix-looking-at regexp
+@defun posix-looking-at regexp &optional inhibit-modify
 This is like @code{looking-at} except that it performs the full
 backtracking specified by the POSIX standard for regular expression
 matching.
 @end defun
 
-@defun posix-string-match regexp string &optional start
+@defun posix-string-match regexp string &optional start inhibit-modify
 This is like @code{string-match} except that it performs the full
 backtracking specified by the POSIX standard for regular expression
 matching.
diff --git a/doc/lispref/spellfile b/doc/lispref/spellfile
index 45a122d26a..11a6ce813a 100644
--- a/doc/lispref/spellfile
+++ b/doc/lispref/spellfile
@@ -179,6 +179,8 @@ copyleft
 counterintuitive
 cr
 creatable
+customization
+customizations
 customize
 deactivate
 deactivated
@@ -243,6 +245,8 @@ fmakunbound
 fo
 fol
 following'
+fontification
+fontified
 fooba
 foobaz
 foox
@@ -257,6 +261,7 @@ garbles
 gc
 getenv
 gid
+glyphs
 gp
 grep
 gtr
@@ -270,6 +275,8 @@ hostname
 hpux
 hscroll
 ick
+iconified
+iconify
 id
 idiom
 ii
@@ -314,6 +321,7 @@ mathsurround
 memq
 mh
 mini
+minibuf
 minibuffer's
 minibuffers
 misalignment
@@ -387,6 +395,7 @@ passwd
 ped
 perverse
 pid
+pixelwise
 plist
 pointer'
 pointm
@@ -417,6 +426,10 @@ reader'
 rebind
 rec
 rechecking
+redisplay
+redisplayed
+redisplaying
+redisplays
 redo
 redrawing
 redraws
@@ -430,6 +443,7 @@ reinitialize
 reinitialized
 reinstall
 reinstalled
+resizable
 resize
 resized
 resizes
@@ -486,6 +500,8 @@ terpri
 text'
 tildes
 time's
+tooltip
+tooltips
 towards
 transportable
 txt
@@ -494,6 +510,7 @@ unbind
 unbinding
 unbinds
 unclutters
+uncustomized
 undefine
 undefines
 underfull
@@ -520,6 +537,7 @@ vconcat
 vectorp
 vn
 voidness
+whitespace
 window'
 windowing
 windowp
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index b4d7bc729f..0914f20411 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -402,7 +402,7 @@ Remove the trailing text that matches @var{regexp} from 
@var{string}.
 
 @defun string-trim string &optional trim-left trim-right
 Remove the leading text that matches @var{trim-left} and trailing text
-that matches @var{trim-right} from from @var{string}.  Both regexps
+that matches @var{trim-right} from @var{string}.  Both regexps
 default to @samp{[ \t\n\r]+}.
 @end defun
 
@@ -414,18 +414,24 @@ will not be shortened.
 @end defun
 
 @defun string-limit string length &optional end coding-system
-If @var{string} is shorter than @var{length}, @var{string} is returned
-as is.  Otherwise, return a substring of @var{string} consisting of
-the first @var{length} characters.  If the optional @var{end}
-parameter is given, return a string of the @var{length} last
+If @var{string} is shorter than @var{length} characters, @var{string}
+is returned as is.  Otherwise, return a substring of @var{string}
+consisting of the first @var{length} characters.  If the optional
+@var{end} parameter is given, return a string of the @var{length} last
 characters instead.
 
 If @var{coding-system} is non-@code{nil}, @var{string} will be encoded
 before limiting, and the result will be a unibyte string that's
-shorter than @code{length}.  If @var{string} contains characters that
-are encoded into several bytes (for instance, when using
+shorter than @code{length} bytes.  If @var{string} contains characters
+that are encoded into several bytes (for instance, when using
 @code{utf-8}), the resulting unibyte string is never truncated in the
 middle of a character representation.
+
+This function measures the string length in characters or bytes, and
+thus is generally inappropriate if you need to shorten strings for
+display purposes; use @code{truncate-string-to-width} or
+@code{window-text-pixel-size} or @code{string-glyph-split} instead
+(@pxref{Size of Displayed Text}).
 @end defun
 
 @defun string-lines string &optional omit-nulls
diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi
index ed36f5139a..b30a16927e 100644
--- a/doc/lispref/symbols.texi
+++ b/doc/lispref/symbols.texi
@@ -29,6 +29,9 @@ otherwise.
 * Creating Symbols::         How symbols are kept unique.
 * Symbol Properties::        Each symbol has a property list
                                for recording miscellaneous information.
+* Shorthands::               Properly organize your symbol names but
+                               type less of them.
+
 @end menu
 
 @node Symbol Components
@@ -67,7 +70,10 @@ important not to have two symbols with the same name.  The 
Lisp reader
 ensures this: every time it reads a symbol, it looks for an existing
 symbol with the specified name before it creates a new one.  To get a
 symbol's name, use the function @code{symbol-name} (@pxref{Creating
-Symbols}).
+Symbols}).  However, although each symbol has only one unique
+@emph{print name}, it is nevertheless possible to refer to that same
+symbol via different alias names called ``shorthands''
+(@pxref{Shorthands}).
 
   The value cell holds a symbol's value as a variable, which is what
 you get if the symbol itself is evaluated as a Lisp expression.
@@ -166,26 +172,39 @@ definitions.  @xref{Name Help,,, emacs, The GNU Emacs 
Manual}.
 @section Creating and Interning Symbols
 @cindex reading symbols
 
-  To understand how symbols are created in GNU Emacs Lisp, you must know
-how Lisp reads them.  Lisp must ensure that it finds the same symbol
-every time it reads the same set of characters.  Failure to do so would
-cause complete confusion.
+  To understand how symbols are created in GNU Emacs Lisp, you must
+know how Lisp reads them.  Lisp must ensure that it finds the same
+symbol every time it reads the same sequence of characters in the same
+context.  Failure to do so would cause complete confusion.
 
 @cindex symbol name hashing
 @cindex hashing
 @cindex obarray
 @cindex bucket (in obarray)
-  When the Lisp reader encounters a symbol, it reads all the characters
-of the name.  Then it hashes those characters to find an index in a
-table called an @dfn{obarray}.  Hashing is an efficient method of
-looking something up.  For example, instead of searching a telephone
-book cover to cover when looking up Jan Jones, you start with the J's
-and go from there.  That is a simple version of hashing.  Each element
-of the obarray is a @dfn{bucket} which holds all the symbols with a
-given hash code; to look for a given name, it is sufficient to look
-through all the symbols in the bucket for that name's hash code.  (The
-same idea is used for general Emacs hash tables, but they are a
-different data type; see @ref{Hash Tables}.)
+  When the Lisp reader encounters a name that references a symbol in
+the source code, it reads all the characters of that name.  Then it
+looks up that name in a table called an @dfn{obarray} to find the
+symbol that the programmer meant.  The technique used in this lookup
+is called ``hashing'', an efficient method of looking something up by
+converting a sequence of characters to a number, known as a ``hash
+code''.  For example, instead of searching a telephone book cover to
+cover when looking up Jan Jones, you start with the J's and go from
+there.  That is a simple version of hashing.  Each element of the
+obarray is a @dfn{bucket} which holds all the symbols with a given
+hash code; to look for a given name, it is sufficient to look through
+all the symbols in the bucket for that name's hash code.  (The same
+idea is used for general Emacs hash tables, but they are a different
+data type; see @ref{Hash Tables}.)
+
+When looking up names, the Lisp reader also considers ``shorthands''.
+If the programmer supplied them, this allows the reader to find a
+symbol even if its name isn't present in its full form in the source
+code.  Of course, the reader needs to be aware of some pre-established
+context about such shorthands, much as one needs context to be to able
+to refer uniquely to Jan Jones by just the name ``Jan'': it's probably
+fine when amongst the Joneses, or when Jan has been mentioned
+recently, but very ambiguous in any other situation.
+@xref{Shorthands}.
 
 @cindex interning
   If a symbol with the desired name is found, the reader uses that
@@ -200,9 +219,13 @@ same obarray.  Thus, the reader gets the same symbols for 
the same
 names, as long as you keep reading with the same obarray.
 
   Interning usually happens automatically in the reader, but sometimes
-other programs need to do it.  For example, after the @kbd{M-x} command
-obtains the command name as a string using the minibuffer, it then
-interns the string, to get the interned symbol with that name.
+other programs may want to do it.  For example, after the @kbd{M-x}
+command obtains the command name as a string using the minibuffer, it
+then interns the string, to get the interned symbol with that name.
+As another example, a hypothetical telephone book program could intern
+the name of each looked up person's name as a symbol, even if the
+obarray did not contain it, so that it could attach information to
+that new symbol, such as the last time someone looked it up.
 
 @cindex symbol equality
 @cindex uninterned symbol
@@ -210,11 +233,8 @@ interns the string, to get the interned symbol with that 
name.
 obarray.  They are called @dfn{uninterned symbols}.  An uninterned
 symbol has the same four cells as other symbols; however, the only way
 to gain access to it is by finding it in some other object or as the
-value of a variable.
-
-  Creating an uninterned symbol is useful in generating Lisp code,
-because an uninterned symbol used as a variable in the code you generate
-cannot clash with any variables used in other Lisp programs.
+value of a variable.  Uninterned symbols are sometimes useful in
+generating Lisp code, see below.
 
   In Emacs Lisp, an obarray is actually a vector.  Each element of the
 vector is a bucket; its value is either an interned symbol whose name
@@ -236,7 +256,10 @@ not work---only @code{intern} can enter a symbol in an 
obarray properly.
 @cindex CL note---symbol in obarrays
 @quotation
 @b{Common Lisp note:} Unlike Common Lisp, Emacs Lisp does not provide
-for interning a single symbol in several obarrays.
+for interning the same name in several different ``packages'', thus
+creating multiple symbols with the same name but different packages.
+Emacs Lisp provides a different namespacing system called
+``shorthands'' (@pxref{Shorthands}).
 @end quotation
 
   Most of the functions below take a name and sometimes an obarray as
@@ -258,6 +281,11 @@ change the name of the symbol, but fails to update the 
obarray, so don't
 do it!
 @end defun
 
+@cindex uninterned symbol, and generating Lisp code
+Creating an uninterned symbol is useful in generating Lisp code,
+because an uninterned symbol used as a variable in the code you
+generate cannot clash with any variables used in other Lisp programs.
+
 @defun make-symbol name
 This function returns a newly-allocated, uninterned symbol whose name is
 @var{name} (which must be a string).  Its value and function definition
@@ -275,10 +303,16 @@ distinct uninterned symbol whose name is also @samp{foo}.
 
 @defun gensym &optional prefix
 This function returns a symbol using @code{make-symbol}, whose name is
-made by appending @code{gensym-counter} to @var{prefix}.  The prefix
-defaults to @code{"g"}.
+made by appending @code{gensym-counter} to @var{prefix} and incrementing
+that counter, guaranteeing that no two calls to this function will
+generate a symbol with the same name.  The prefix defaults to
+@code{"g"}.
 @end defun
 
+To avoid problems when accidentally interning printed representation
+of generated code (@pxref{Printed Representation}), it is recommended
+to use @code{gensym} instead of @code{make-symbol}.
+
 @defun intern name &optional obarray
 This function returns the interned symbol whose name is @var{name}.  If
 there is no such symbol in the obarray @var{obarray}, @code{intern}
@@ -600,3 +634,120 @@ If non-@code{nil}, this specifies the named variable's 
documentation
 string.  This is set automatically by @code{defvar} and related
 functions.  @xref{Defining Faces}.
 @end table
+
+@node Shorthands
+@section Shorthands
+@cindex shorthands
+@cindex symbolic shorthands
+@cindex namespacing
+@cindex namespaces
+
+  The symbol @dfn{shorthands}, sometimes known as ``renamed symbols'', are
+symbolic forms found in Lisp source.  They're just like regular
+symbolic forms, except that when the Lisp reader encounters them, it
+produces symbols which have a different and usually longer @dfn{print
+name} (@pxref{Symbol Components}).
+
+It is useful to think of shorthands as @emph{abbreviating} the full
+names of intended symbols.  Despite this, do not confuse shorthands with the
+Abbrev system @pxref{Abbrevs}.
+
+@cindex namespace etiquette
+Shorthands make Emacs Lisp's @dfn{namespacing etiquette} easier to work
+with.  Since all symbols are stored in a single obarray
+(@pxref{Creating Symbols}), programmers commonly prefix each symbol
+name with the name of the library where it originates.  For example,
+the functions @code{text-property-search-forward} and
+@code{text-property-search-backward} both belong to the
+@file{text-property-search.el} library (@pxref{Loading}).  By properly
+prefixing symbol names, one effectively prevents clashes between
+similarly named symbols which belong to different libraries and thus do
+different things.  However, this practice commonly originates very
+long symbols names, which are inconvenient to type and read after a
+while.  Shorthands solve these issues in a clean way.
+
+@defvar read-symbol-shorthands
+This variable's value is an alist whose elements have the form
+@code{(@var{shorthand-prefix} . @var{longhand-prefix})}.  Each element
+instructs the Lisp reader to read every symbol form which starts with
+@var{shorthand-prefix} as if it started with @var{longhand-prefix}
+instead.
+
+This variable may only be set in file-local variables (@pxref{File Variables, ,
+Local Variables in Files, emacs, The GNU Emacs Manual}).
+@end defvar
+
+Here's an example of shorthands usage in a hypothetical string
+manipulating library @file{some-nice-string-utils.el}.
+
+@smalllisp
+(defun some-nice-string-utils-split (separator s &optional omit-nulls)
+  "A match-data saving variant of `split-string'."
+  (save-match-data (split-string s separator omit-nulls)))
+
+(defun some-nice-string-utils-lines (s)
+  "Split string S at newline characters into a list of strings."
+  (some-nice-string-utils-split "\\(\r\n\\|[\n\r]\\)" s))
+@end smalllisp
+
+As can be seen, it's quite tedious to read or develop this code since
+the symbol names to type are so long.  We can use shorthands to
+alleviate that.
+
+@lisp
+(defun snu-split (separator s &optional omit-nulls)
+  "A match-data saving variation on `split-string'."
+  (save-match-data (split-string s separator omit-nulls)))
+
+(defun snu-lines (s)
+  "Split string S into a list of strings on newline characters."
+  (snu-split "\\(\r\n\\|[\n\r]\\)" s))
+
+;; Local Variables:
+;; read-symbol-shorthands: (("snu-" . "some-nice-string-utils-"))
+;; End:
+@end lisp
+
+Even though the two excerpts look different, they are quite identical
+after the Lisp reader processes them.  Both will lead to the very same
+symbols being interned (@pxref{Creating Symbols}).  Thus loading or
+byte-compiling any of the two files has equivalent results.  The
+shorthands @code{snu-split} and @code{snu-lines} used in the second
+version are @emph{not} interned in the obarray.  This is easily seen
+by moving point to the location where the shorthands are used and
+waiting for ElDoc (@pxref{Lisp Doc, , Local Variables in Files, emacs,
+The GNU Emacs Manual}) to hint at the true full name of the symbol
+under point in the echo area.
+
+Since @code{read-symbol-shorthands} is a file-local variable, it is
+possible that multiple libraries depending on
+@file{some-nice-string-utils-lines.el} refer to the same symbols under
+@emph{different} shorthands, or not using shorthands at all.  In the
+next example, the @file{my-tricks.el} library refers to the symbol
+@code{some-nice-string-utils-lines} using the @code{sns-} prefix
+instead of @code{snu-}.
+
+@example
+(defun t-reverse-lines (s) (string-join (reverse (sns-lines s)) "\n")
+
+;; Local Variables:
+;; read-symbol-shorthands: (("t-" . "my-tricks-")
+;;                          ("sns-" . "some-nice-string-utils-"))
+;; End:
+@end example
+
+@subsection Exceptions
+
+There are two exceptions to rules governing Shorthand transformations:
+
+@itemize @bullet
+@item
+Symbol forms comprised entirely of characters in the Emacs Lisp symbol
+constituent class (@pxref{Syntax Class Table}) are not transformed.
+For example, it's possible to use @code{-} or @code{/=} as shorthand
+prefixes, but that won't shadow the arithmetic @emph{functions} of
+those names.
+
+@item
+Symbol forms whose names start with @samp{#_} are not transformed.
+@end itemize
diff --git a/doc/lispref/syntax.texi b/doc/lispref/syntax.texi
index deec3f44c0..87ade73c2a 100644
--- a/doc/lispref/syntax.texi
+++ b/doc/lispref/syntax.texi
@@ -900,6 +900,7 @@ arrived at a top level position.
 @defun syntax-ppss-context state
 Return @code{string} if the end position of the scan returning
 @var{state} is in a string, and @code{comment} if it's in a comment.
+Otherwise return @code{nil}.
 @end defun
 
 @node Low-Level Parsing
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index f83ca97163..937680c200 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -319,7 +319,7 @@ The argument @var{thing} is a symbol which specifies a kind 
of
 syntactic entity.  Possibilities include @code{symbol}, @code{list},
 @code{sexp}, @code{defun}, @code{filename}, @code{existing-filename},
 @code{url}, @code{word}, @code{sentence}, @code{whitespace},
-@code{line}, @code{page}, and others.
+@code{line}, @code{page}, @code{string}, and others.
 
 When the optional argument @var{no-properties} is non-@code{nil}, this
 function strips text properties from the return value.
@@ -599,6 +599,19 @@ This command indents to the left margin if that is not 
zero.
 The value returned is @code{nil}.
 @end deffn
 
+@deffn Command ensure-empty-lines &optional number-of-empty-lines
+This command can be used to ensure that you have a specific number of
+empty lines before point.  (An ``empty line'' is here defined as a
+line with no characters on it---a line with space characters isn't an
+empty line.)  It defaults to ensuring that there's a single empty line
+before point.
+
+If point isn't at the beginning of a line, a newline character is
+inserted first.  If there's more empty lines before point than
+specified, the number of empty lines is reduced.  Otherwise it's
+increased to the specified number.
+@end deffn
+
 @defvar overwrite-mode
 This variable controls whether overwrite mode is in effect.  The value
 should be @code{overwrite-mode-textual}, @code{overwrite-mode-binary},
@@ -1329,7 +1342,7 @@ that @kbd{C-y} should yank.
 @defopt kill-ring-max
 The value of this variable is the maximum length to which the kill
 ring can grow, before elements are thrown away at the end.  The default
-value for @code{kill-ring-max} is 60.
+value for @code{kill-ring-max} is 120.
 @end defopt
 
 @node Undo
@@ -1493,6 +1506,11 @@ continuing to undo.
 This function does not bind @code{undo-in-progress}.
 @end defun
 
+@defmac with-undo-amalgamate body@dots{}
+This macro removes all the undo boundaries inserted during the
+execution of @var{body} so that it can be undone as a single step.
+@end defmac
+
 Some commands leave the region active after execution in such a way that
 it interferes with selective undo of that command.  To make @code{undo}
 ignore the active region when invoked immediately after such a command,
@@ -3602,6 +3620,11 @@ edited even in read-only buffers.  @xref{Read Only 
Buffers}.
 A non-@code{nil} @code{invisible} property can make a character invisible
 on the screen.  @xref{Invisible Text}, for details.
 
+@kindex inhibit-isearch @r{(text property)}
+@item inhibit-isearch
+A non-@code{nil} @code{inhibit-isearch} property will make isearch
+skip the text.
+
 @item intangible
 @kindex intangible @r{(text property)}
 If a group of consecutive characters have equal and non-@code{nil}
diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi
index a72ab88cef..cbfcbd8d14 100644
--- a/doc/lispref/tips.texi
+++ b/doc/lispref/tips.texi
@@ -252,6 +252,13 @@ themselves; Lisp programmers find this disconcerting.
 Please put a copyright notice and copying permission notice on the
 file if you distribute copies.  @xref{Library Headers}.
 
+@item
+For variables holding (or functions returning) a file or directory name,
+avoid using @code{path} in its name, preferring @code{file},
+@code{file-name}, or @code{directory} instead, since Emacs follows the
+GNU convention to use the term @emph{path} only for search paths,
+which are lists of directory names.
+
 @end itemize
 
 @node Key Binding Conventions
@@ -393,7 +400,13 @@ Don't use @code{message}, @code{throw}, @code{sleep-for}, 
or
 
 @item
 An error message should start with a capital letter but should not end
-with a period.
+with a period or other punctuation.
+
+It is occasionally useful to tell the user where an error originated,
+even if @code{debug-on-error} is @code{nil}.  In such cases, a
+lower-case Lisp symbol can be prepended to the error message.  For
+example, the error message ``Invalid input'' could be extended to say
+``some-function: Invalid input''.
 
 @item
 A question asked in the minibuffer with @code{yes-or-no-p} or
@@ -755,6 +768,20 @@ anchor}.  The Info file name defaults to @samp{emacs}.  
For example,
 See Info node `Font Lock' and Info node `(elisp)Font Lock Basics'.
 @end smallexample
 
+To make a hyperlink to a man page, write the single-quoted name of the
+man page, preceded by @samp{Man page}, @samp{man page}, or @samp{man
+page for}.  For example,
+
+@smallexample
+See the man page `chmod(1)' for details.
+@end smallexample
+
+@noindent
+The Info documentation is always preferable to man pages, so be sure
+to link to an Info manual where available.  For example,
+@command{chmod} is documented in the GNU Coreutils manual, so it is
+better to link to that instead of the man page.
+
 To link to a customization group, write the single-quoted name of the
 group, preceded by @samp{customization group} (the first character in
 each word is case-insensitive).  For example,
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index a1d1919b4b..d2247004bc 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -1695,12 +1695,14 @@ buffer-local variables interactively.
 @end deffn
 
 @cindex local variables, killed by major mode
-@defun kill-all-local-variables
+@defun kill-all-local-variables &optional kill-permanent
 This function eliminates all the buffer-local variable bindings of the
-current buffer except for variables marked as permanent and local
-hook functions that have a non-@code{nil} @code{permanent-local-hook}
-property (@pxref{Setting Hooks}).  As a result, the buffer will see
-the default values of most variables.
+current buffer.  As a result, the buffer will see the default values
+of most variables.  By default, for variables marked as permanent and
+local hook functions that have a non-@code{nil}
+@code{permanent-local-hook} property (@pxref{Setting Hooks}) won't be
+killed, but if the optional @var{kill-permanent} argument is
+non-@code{nil}, even these variables will be killed.
 
 This function also resets certain other information pertaining to the
 buffer: it sets the local keymap to @code{nil}, the syntax table to the
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 679744884a..d718ac59be 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -14,6 +14,7 @@ is displayed in windows.
 @menu
 * Basic Windows::           Basic information on using windows.
 * Windows and Frames::      Relating windows to the frame they appear on.
+* Selecting Windows::       The selected window is the one that you edit in.
 * Window Sizes::            Accessing a window's size.
 * Resizing Windows::        Changing the sizes of windows.
 * Preserving Window Sizes:: Preserving the size of windows.
@@ -21,7 +22,6 @@ is displayed in windows.
 * Deleting Windows::        Removing a window from its frame.
 * Recombining Windows::     Preserving the frame layout when splitting and
                               deleting windows.
-* Selecting Windows::       The selected window is the one that you edit in.
 * Cyclic Window Ordering::  Moving around the existing windows.
 * Buffers and Windows::     Each window displays the contents of a buffer.
 * Switching Buffers::       Higher-level functions for switching to a buffer.
@@ -53,32 +53,37 @@ is displayed in windows.
 @section Basic Concepts of Emacs Windows
 @cindex window
 
-A @dfn{window} is an area of the screen that is used to display a buffer
-(@pxref{Buffers}).  In Emacs Lisp, windows are represented by a special
-Lisp object type.
-
 @cindex multiple windows
-  Windows are grouped into frames (@pxref{Frames}).  Each frame
-contains at least one window; the user can subdivide it into multiple,
-non-overlapping windows to view several buffers at once.  Lisp
-programs can use multiple windows for a variety of purposes.  In
-Rmail, for example, you can view a summary of message titles in one
-window, and the contents of the selected message in another window.
+A @dfn{window} is an area of the screen that can be used to display a
+buffer (@pxref{Buffers}).  Windows are grouped into frames
+(@pxref{Frames}).  Each frame contains at least one window; the user can
+subdivide a frame into multiple, non-overlapping windows to view several
+buffers at once.  Lisp programs can use multiple windows for a variety
+of purposes.  In Rmail, for example, you can view a summary of message
+titles in one window, and the contents of the selected message in
+another window.
 
 @cindex terminal screen
 @cindex screen of terminal
-  Emacs uses the word ``window'' with a different meaning than in
-graphical desktop environments and window systems, such as the X
-Window System.  When Emacs is run on X, each of its graphical X
-windows is an Emacs frame (containing one or more Emacs windows).
-When Emacs is run on a text terminal, the frame fills the entire
-terminal screen.
+@cindex window-system window
+  Emacs uses the term ``window'' with a different meaning than in
+graphical desktop environments and window systems, such as the X Window
+System.  When Emacs is run on X, each graphical X window owned by the
+Emacs process corresponds to one Emacs frame.  When Emacs is run on a
+text terminal, each Emacs frame fills the entire terminal screen.  In
+either case, the frame may contain one or more Emacs windows.  For
+disambiguation, we use the term @dfn{window-system window} when we mean
+the window-system window corresponding to an Emacs frame.
 
 @cindex tiled windows
   Unlike X windows, Emacs windows are @dfn{tiled}; they never overlap
-within the area of the frame.  When a window is created, resized, or
-deleted, the change in window space is taken from or given to the
-adjacent windows, so that the total area of the frame is unchanged.
+within the area of their frame.  When a window is created, resized, or
+deleted, the change in window space is taken from or given to other
+windows on the same frame, so that the total area of the frame is
+unchanged.
+
+In Emacs Lisp, windows are represented by a special Lisp object type
+(@pxref{Window Type}).
 
 @defun windowp object
 This function returns @code{t} if @var{object} is a window (whether or
@@ -117,94 +122,145 @@ internal window in a window tree.  Otherwise, it returns 
@code{nil},
 including for the case where @var{object} is a deleted window.
 @end defun
 
-@cindex selected window
-@cindex window selected within a frame
-  In each frame, at any time, exactly one Emacs window is designated
-as @dfn{selected within the frame}.  For the selected frame, that
-window is called the @dfn{selected window}---the one in which most
-editing takes place, and in which the cursor for selected windows
-appears (@pxref{Cursor Parameters}).  Keyboard input that inserts or
-deletes text is also normally directed to this window.   The selected
-window's buffer is usually also the current buffer, except when
-@code{set-buffer} has been used (@pxref{Current Buffer}).  As for
-non-selected frames, the window selected within the frame becomes the
-selected window if the frame is ever selected.  @xref{Selecting
-Windows}.
+  The following schematic shows the structure of a live window:
 
-@defun selected-window
-This function returns the selected window (which is always a live
-window).
-@end defun
+@smallexample
+@group
+        ____________________________________________
+       |________________ Tab Line _______________|RD| ^
+       |______________ Header Line ______________|  | |
+     ^ |LS|LM|LF|                       |RF|RM|RS|  | |
+     | |  |  |  |                       |  |  |  |  | |
+Window |  |  |  |                       |  |  |  |  | Window
+Body | |  |  |  |      Window Body      |  |  |  |  | Total
+Height |  |  |  |                       |  |  |  |  | Height
+     | |  |  |  |<- Window Body Width ->|  |  |  |  | |
+     v |__|__|__|_______________________|__|__|__|  | |
+       |_________ Horizontal Scroll Bar _________|  | |
+       |_______________ Mode Line _______________|__| |
+       |_____________ Bottom Divider _______________| v
+        <---------- Window Total Width ------------>
 
-@anchor{Window Group}Sometimes several windows collectively and
-cooperatively display a buffer, for example, under the management of
-Follow Mode (@pxref{Follow Mode,,, emacs}), where the windows together
-display a bigger portion of the buffer than one window could alone.
-It is often useful to consider such a @dfn{window group} as a single
-entity.  Several functions such as @code{window-group-start}
-(@pxref{Window Start and End}) allow you to do this by supplying, as
-an argument, one of the windows as a stand in for the whole group.
+@end group
+@end smallexample
 
-@defun selected-window-group
-@vindex selected-window-group-function
-When the selected window is a member of a group of windows, this
-function returns a list of the windows in the group, ordered such that
-the first window in the list is displaying the earliest part of the
-buffer, and so on.  Otherwise the function returns a list containing
-just the selected window.
+@cindex window body
+@cindex body of a window
+@cindex window decorations
+@cindex left and right window decorations
+@cindex top and bottom window decorations
+  At the center of that window is the @dfn{body}, where the buffer
+text is displayed.  The body can be surrounded by a series of optional
+areas which we will call @dfn{window decorations}.  On the left and
+right, from innermost to outermost, these are the left and right
+fringes, denoted by LF and RF (@pxref{Fringes}); the left and right
+margins, denoted by LM and RM in the schematic (@pxref{Display
+Margins}); the left or right vertical scroll bar, only one of which is
+present at any time, denoted by LS and RS (@pxref{Scroll Bars}); and
+the right divider, denoted by RD (@pxref{Window Dividers}).  Together
+these are the window's @dfn{left and right decorations}.
+
+@cindex text area of a window
+  At the top of the window are the tab line and the header line
+(@pxref{Header Lines}).  The @dfn{text area} of the window includes
+the header line and the tab line, if they are present in the window.
+At the bottom of the window are the horizontal scroll bar
+(@pxref{Scroll Bars}); the mode line (@pxref{Mode Line Format}); and
+the bottom divider (@pxref{Window Dividers}).  Together these form the
+window's @dfn{top and bottom decorations}.
+
+  There are two special areas omitted in the schematic:
+
+@itemize @bullet
+@item
+When any of the fringes is missing, the display engine may use one
+character cell in its place for showing a continuation or truncation
+glyph provided a text line doesn't fit in a window.
+
+@item
+When both, the vertical scroll bar and the right divider are missing,
+the display engine usurps one pixel for drawing a vertical divider line
+between this window and the window on its right, provided such a window
+exists.  On a text terminal, this divider always occupies an entire
+character cell.
+@end itemize
+
+In either case, the resulting artifact is considered part of the
+window's body although its screen space cannot be used for displaying
+buffer text.
+
+  Note also, that line numbers (and their surrounding whitespace) as
+displayed by @code{display-line-numbers-mode} (@pxref{Display Custom,,,
+emacs, The GNU Emacs Manual}) do not count as decorations either; they
+are part of the window's body too.
+
+  Internal windows neither show any text nor do they have decorations.
+Hence, the concept of ``body'' does not make sense for them.  In fact,
+most functions operating on the body of a window will yield an error
+when applied to an internal window.
+
+@cindex minibuffer window
+@cindex tooltip window
+  By default, an Emacs frame exhibits one special live window that is
+used for displaying messages and accepting user input---the
+@dfn{minibuffer window} (@pxref{Minibuffer Windows}).  Since the
+minibuffer window is used for displaying text, it has a body but it does
+not have a tab or header line or any margins.  Finally, a @dfn{tooltip
+window} which is used for displaying a tooltip in a tooltip frame
+(@pxref{Tooltips}) has a body too but no decorations at all.
 
-The selected window is considered part of a group when the buffer
-local variable @code{selected-window-group-function} is set to a
-function.  In this case, @code{selected-window-group} calls it with no
-arguments and returns its result (which should be the list of windows
-in the group).
-@end defun
 
 @node Windows and Frames
 @section Windows and Frames
 
-Each window belongs to exactly one frame (@pxref{Frames}).
+Each window belongs to exactly one frame (@pxref{Frames}).  For all
+windows belonging to a specific frame, we sometimes also say that these
+windows are @dfn{owned} by that frame or simply that they are on that
+frame.
 
 @defun window-frame &optional window
-This function returns the frame that the window @var{window} belongs
-to.  If @var{window} is @code{nil}, it defaults to the selected
-window.
+This function returns the specified @var{window}'s frame---the frame
+that @var{window} belongs to.  If @var{window} is omitted or @code{nil},
+it defaults to the selected window (@pxref{Selecting Windows}).
 @end defun
 
 @defun window-list &optional frame minibuffer window
-This function returns a list of live windows belonging to the frame
+This function returns a list of all live windows owned by the specified
 @var{frame}.  If @var{frame} is omitted or @code{nil}, it defaults to
-the selected frame.
+the selected frame (@pxref{Input Focus}).
 
-The optional argument @var{minibuffer} specifies whether to include
-the minibuffer window in the returned list.  If @var{minibuffer} is
-@code{t}, the minibuffer window is included.  If @var{minibuffer} is
+The optional argument @var{minibuffer} specifies whether to include the
+minibuffer window (@pxref{Minibuffer Windows}) in that list.  If
+@var{minibuffer} is @code{t}, the minibuffer window is included.  If
 @code{nil} or omitted, the minibuffer window is included only if it is
 active.  If @var{minibuffer} is neither @code{nil} nor @code{t}, the
 minibuffer window is never included.
 
-The optional argument @var{window}, if non-@code{nil}, should be a live
+The optional argument @var{window}, if non-@code{nil}, must be a live
 window on the specified frame; then @var{window} will be the first
 element in the returned list.  If @var{window} is omitted or @code{nil},
-the window selected within the frame is the first element.
+the window selected within @var{frame} (@pxref{Selecting Windows}) is
+the first element.
 @end defun
 
 @cindex window tree
 @cindex root window
-  Windows in the same frame are organized into a @dfn{window tree},
+  Windows on the same frame are organized into a @dfn{window tree},
 whose leaf nodes are the live windows.  The internal nodes of a window
 tree are not live; they exist for the purpose of organizing the
 relationships between live windows.  The root node of a window tree is
-called the @dfn{root window}.  It can be either a live window (if the
-frame has just one window), or an internal window.
-
-  A minibuffer window (@pxref{Minibuffer Windows}) that is not alone
-on its frame does not have a parent window, so it strictly speaking is
-not part of its frame's window tree.  Nonetheless, it is a sibling
-window of the frame's root window, and thus can be reached via
-@code{window-next-sibling}.  Also, the function @code{window-tree}
-described at the end of this section lists the minibuffer window
-alongside the actual window tree.
+called the @dfn{root window}.  It is either a live window or an
+internal window.  If it is a live window, then the frame has just one
+window besides the minibuffer window, or the frame is a
+minibuffer-only frame, @pxref{Frame Layout}.
+
+  A minibuffer window (@pxref{Minibuffer Windows}) that is not alone on
+its frame does not have a parent window, so it strictly speaking is not
+part of its frame's window tree.  Nonetheless, it is a sibling window of
+the frame's root window, and thus can be reached from the root window via
+@code{window-next-sibling}, see below.  Also, the function
+@code{window-tree} described at the end of this section lists the
+minibuffer window alongside the actual window tree.
 
 @defun frame-root-window &optional frame-or-window
 This function returns the root window for @var{frame-or-window}.  The
@@ -217,15 +273,15 @@ of that window's frame.
 @cindex parent window
 @cindex child window
 @cindex sibling window
-  When a window is split, there are two live windows where previously
-there was one.  One of these is represented by the same Lisp window
-object as the original window, and the other is represented by a
-newly-created Lisp window object.  Both of these live windows become
-leaf nodes of the window tree, as @dfn{child windows} of a single
-internal window.  If necessary, Emacs automatically creates this
-internal window, which is also called the @dfn{parent window}, and
-assigns it to the appropriate position in the window tree.  A set of
-windows that share the same parent are called @dfn{siblings}.
+  When a live window is split (@pxref{Splitting Windows}), there are two
+live windows where previously there was one.  One of these is
+represented by the same Lisp window object as the original window, and
+the other is represented by a newly-created Lisp window object.  Both of
+these live windows become leaf nodes of the window tree, as @dfn{child
+windows} of a single internal window.  If necessary, Emacs automatically
+creates this internal window, which is also called the @dfn{parent
+window}, and assigns it to the appropriate position in the window tree.
+The set of windows that share the same parent are called @dfn{siblings}.
 
 @cindex parent window
 @defun window-parent &optional window
@@ -235,16 +291,16 @@ window.  The return value is @code{nil} if @var{window} 
has no parent
 (i.e., it is a minibuffer window or the root window of its frame).
 @end defun
 
-  Each internal window always has at least two child windows.  If this
-number falls to one as a result of window deletion, Emacs
-automatically deletes the internal window, and its sole remaining
-child window takes its place in the window tree.
+  A parent window always has at least two child windows.  If this number
+were to fall to one as a result of window deletion (@pxref{Deleting
+Windows}), Emacs automatically deletes the parent window too, and its
+sole remaining child window takes its place in the window tree.
 
-  Each child window can be either a live window, or an internal window
+  A child window can be either a live window, or an internal window
 (which in turn would have its own child windows).  Therefore, each
 internal window can be thought of as occupying a certain rectangular
-@dfn{screen area}---the union of the areas occupied by the live
-windows that are ultimately descended from it.
+@dfn{screen area}---the union of the areas occupied by the live windows
+that are ultimately descended from it.
 
 @cindex window combination
 @cindex vertical combination
@@ -284,7 +340,9 @@ windows @var{W4} and @var{W5}.  Hence, the live windows in 
this
 window tree are @var{W2}, @var{W4}, and @var{W5}.
 
   The following functions can be used to retrieve a child window of an
-internal window, and the siblings of a child window.
+internal window, and the siblings of a child window.  Their @var{window}
+argument always defaults to the selected window (@pxref{Selecting
+Windows}).
 
 @defun window-top-child &optional window
 This function returns the topmost child window of @var{window}, if
@@ -309,8 +367,7 @@ the leftmost child window for a horizontal combination.  If
 
 @defun window-combined-p &optional window horizontal
 This function returns a non-@code{nil} value if and only if
-@var{window} is part of a vertical combination.  If @var{window} is
-omitted or @code{nil}, it defaults to the selected one.
+@var{window} is part of a vertical combination.
 
 If the optional argument @var{horizontal} is non-@code{nil}, this
 means to return non-@code{nil} if and only if @var{window} is part of
@@ -318,24 +375,21 @@ a horizontal combination.
 @end defun
 
 @defun window-next-sibling &optional window
-This function returns the next sibling of the window @var{window}.  If
-omitted or @code{nil}, @var{window} defaults to the selected window.
-The return value is @code{nil} if @var{window} is the last child of
-its parent.
+This function returns the next sibling of the specified @var{window}.  The
+return value is @code{nil} if @var{window} is the last child of its
+parent.
 @end defun
 
 @defun window-prev-sibling &optional window
-This function returns the previous sibling of the window @var{window}.
-If omitted or @code{nil}, @var{window} defaults to the selected
-window.  The return value is @code{nil} if @var{window} is the first
-child of its parent.
+This function returns the previous sibling of the specified @var{window}.
+The return value is @code{nil} if @var{window} is the first child of its
+parent.
 @end defun
 
-The functions @code{window-next-sibling} and
-@code{window-prev-sibling} should not be confused with the functions
-@code{next-window} and @code{previous-window}, which return the next
-and previous window, respectively, in the cyclic ordering of windows
-(@pxref{Cyclic Window Ordering}).
+The functions @code{window-next-sibling} and @code{window-prev-sibling}
+should not be confused with the functions @code{next-window} and
+@code{previous-window}, which return the next and previous window in the
+cyclic ordering of windows (@pxref{Cyclic Window Ordering}).
 
   The following functions can be useful to locate a window within its
 frame.
@@ -408,8 +462,7 @@ Don't use this function to check whether there is @emph{no} 
window in
 much more efficient way to do that.
 @end defun
 
-The following function allows the entire window tree of a frame to be
-retrieved:
+The following function retrieves the entire window tree of a frame:
 
 @defun window-tree &optional frame
 This function returns a list representing the window tree for frame
@@ -433,54 +486,218 @@ internal window).  The @var{edges} element is a list 
@code{(@var{left}
 @end defun
 
 
+@node Selecting Windows
+@section Selecting Windows
+@cindex selecting a window
+
+@cindex selected window
+@cindex window selected within a frame
+  In each frame, at any time, exactly one Emacs window is designated
+as @dfn{selected within the frame}.  For the selected frame, that
+window is called the @dfn{selected window}---the one in which most
+editing takes place, and in which the cursor for selected windows
+appears (@pxref{Cursor Parameters}).  Keyboard input that inserts or
+deletes text is also normally directed to this window.   The selected
+window's buffer is usually also the current buffer, except when
+@code{set-buffer} has been used (@pxref{Current Buffer}).  As for
+non-selected frames, the window selected within the frame becomes the
+selected window if the frame is ever selected.
+
+@defun selected-window
+This function returns the selected window (which is always a live
+window).
+@end defun
+
+The following function explicitly selects a window and its frame.
+
+@defun select-window window &optional norecord
+This function makes @var{window} the selected window and the window
+selected within its frame, and selects that frame.  It also makes
+@var{window}'s buffer (@pxref{Buffers and Windows}) current and sets
+that buffer's value of @code{point} to the value of @code{window-point}
+(@pxref{Window Point}) in @var{window}.  @var{window} must be a live
+window.  The return value is @var{window}.
+
+By default, this function also moves @var{window}'s buffer to the front
+of the buffer list (@pxref{Buffer List}) and makes @var{window} the most
+recently selected window.  If the optional argument @var{norecord} is
+non-@code{nil}, these additional actions are omitted.
+
+In addition, this function by default also tells the display engine to
+update the display of @var{window} when its frame gets redisplayed the
+next time.  If @var{norecord} is non-@code{nil}, such updates are
+usually not performed.  If, however, @var{norecord} equals the special
+symbol @code{mark-for-redisplay}, the additional actions mentioned above
+are omitted but @var{window}'s display will be nevertheless updated.
+
+Note that sometimes selecting a window is not enough to show it, or
+make its frame the top-most frame on display: you may also need to
+raise the frame or make sure input focus is directed to that frame.
+@xref{Input Focus}.
+@end defun
+
+@cindex select window hooks
+@cindex running a hook when a window gets selected
+For historical reasons, Emacs does not run a separate hook whenever a
+window gets selected.  Applications and internal routines often
+temporarily select a window to perform a few actions on it.  They do
+that either to simplify coding---because many functions by default
+operate on the selected window when no @var{window} argument is
+specified---or because some functions did not (and still do not) take a
+window as argument and always operate(d) on the selected window instead.
+Running a hook every time a window gets selected for a short time and
+once more when the previously selected window gets restored is not
+useful.
+
+  However, when its @var{norecord} argument is @code{nil},
+@code{select-window} updates the buffer list and thus indirectly runs
+the normal hook @code{buffer-list-update-hook} (@pxref{Buffer List}).
+Consequently, that hook provides one way to run a function whenever a
+window gets selected more ``permanently''.
+
+  Since @code{buffer-list-update-hook} is also run by functions that are
+not related to window management, it will usually make sense to save the
+value of the selected window somewhere and compare it with the value of
+@code{selected-window} while running that hook.  Also, to avoid false
+positives when using @code{buffer-list-update-hook}, it is good practice
+that every @code{select-window} call supposed to select a window only
+temporarily passes a non-@code{nil} @var{norecord} argument.  If
+possible, the macro @code{with-selected-window} (see below) should be
+used in such cases.
+
+  Emacs also runs the hook @code{window-selection-change-functions}
+whenever the redisplay routine detects that another window has been
+selected since last redisplay.  @xref{Window Hooks}, for a detailed
+explanation.  @code{window-state-change-functions} (described in the
+same section) is another abnormal hook run after a different window
+has been selected but is triggered by other window changes as well.
+
+@cindex most recently selected windows
+  The sequence of calls to @code{select-window} with a non-@code{nil}
+@var{norecord} argument determines an ordering of windows by their
+selection or use time, see below.  The function @code{get-lru-window},
+for example, can then be used to retrieve the least recently selected
+window (@pxref{Cyclic Window Ordering}).
+
+@defun frame-selected-window &optional frame
+This function returns the window on @var{frame} that is selected
+within that frame.  @var{frame} should be a live frame; if omitted or
+@code{nil}, it defaults to the selected frame.
+@end defun
+
+@defun set-frame-selected-window frame window &optional norecord
+This function makes @var{window} the window selected within the frame
+@var{frame}.  @var{frame} should be a live frame; if @code{nil}, it
+defaults to the selected frame.  @var{window} should be a live window;
+if @code{nil}, it defaults to the selected window.
+
+If @var{frame} is the selected frame, this makes @var{window} the
+selected window.
+
+If the optional argument @var{norecord} is non-@code{nil}, this function
+does not alter the ordering of the most recently selected windows, nor
+the buffer list.
+@end defun
+
+  The following macros are useful to temporarily select a window without
+affecting the ordering of recently selected windows or the buffer list.
+
+@defmac save-selected-window forms@dots{}
+This macro records the selected frame, as well as the selected window
+of each frame, executes @var{forms} in sequence, then restores the
+earlier selected frame and windows.  It also saves and restores the
+current buffer.  It returns the value of the last form in @var{forms}.
+
+This macro does not save or restore anything about the sizes,
+arrangement or contents of windows; therefore, if @var{forms} change
+them, the change persists.  If the previously selected window of some
+frame is no longer live at the time of exit from @var{forms}, that
+frame's selected window is left alone.  If the previously selected
+window is no longer live, then whatever window is selected at the end of
+@var{forms} remains selected.  The current buffer is restored if and
+only if it is still live when exiting @var{forms}.
+
+This macro changes neither the ordering of recently selected windows nor
+the buffer list.
+@end defmac
+
+@defmac with-selected-window window forms@dots{}
+This macro selects @var{window}, executes @var{forms} in sequence, then
+restores the previously selected window and current buffer.  The
+ordering of recently selected windows and the buffer list remain
+unchanged unless you deliberately change them within @var{forms}; for
+example, by calling @code{select-window} with argument @var{norecord}
+@code{nil}.  Hence, this macro is the preferred way to temporarily work
+with @var{window} as the selected window without needlessly running
+@code{buffer-list-update-hook}.
+@end defmac
+
+@defmac with-selected-frame frame forms@dots{}
+This macro executes @var{forms} with @var{frame} as the selected
+frame.  The value returned is the value of the last form in
+@var{forms}.  This macro saves and restores the selected frame, and
+changes the order of neither the recently selected windows nor the
+buffers in the buffer list.
+@end defmac
+
+@cindex window use time
+@cindex use time of window
+@cindex window order by time of last use
+@defun window-use-time &optional window
+This function returns the use time of window @var{window}.  @var{window}
+must be a live window and defaults to the selected one.
+
+The @dfn{use time} of a window is not really a time value, but an
+integer that does increase monotonically with each call of
+@code{select-window} with a @code{nil} @var{norecord} argument.  The
+window with the lowest use time is usually called the least recently
+used window while the window with the highest use time is called the
+most recently used one (@pxref{Cyclic Window Ordering}).
+@end defun
+
+@defun window-bump-use-time &optional window
+This function marks @var{window} as being the most recently used
+one.  This can be useful when writing certain @code{pop-to-buffer}
+scenarios (@pxref{Switching Buffers}).  @var{window} must be a live
+window and defaults to the selected one.
+@end defun
+
+@anchor{Window Group}Sometimes several windows collectively and
+cooperatively display a buffer, for example, under the management of
+Follow Mode (@pxref{Follow Mode,,, emacs}), where the windows together
+display a bigger portion of the buffer than one window could alone.
+It is often useful to consider such a @dfn{window group} as a single
+entity.  Several functions such as @code{window-group-start}
+(@pxref{Window Start and End}) allow you to do this by supplying, as
+an argument, one of the windows as a stand-in for the whole group.
+
+@defun selected-window-group
+@vindex selected-window-group-function
+When the selected window is a member of a group of windows, this
+function returns a list of the windows in the group, ordered such that
+the first window in the list is displaying the earliest part of the
+buffer, and so on.  Otherwise the function returns a list containing
+just the selected window.
+
+The selected window is considered part of a group when the buffer
+local variable @code{selected-window-group-function} is set to a
+function.  In this case, @code{selected-window-group} calls it with no
+arguments and returns its result (which should be the list of windows
+in the group).
+@end defun
+
+
 @node Window Sizes
 @section Window Sizes
 @cindex window size
 @cindex size of window
 
-  The following schematic shows the structure of a live window:
-
-@smallexample
-@group
-        ____________________________________________
-       |______________ Header Line ______________|RD| ^
-     ^ |LS|LM|LF|                       |RF|RM|RS|  | |
-     | |  |  |  |                       |  |  |  |  | |
-Window |  |  |  |       Text Area       |  |  |  |  | Window
-Body | |  |  |  |     (Window Body)     |  |  |  |  | Total
-Height |  |  |  |                       |  |  |  |  | Height
-     | |  |  |  |<- Window Body Width ->|  |  |  |  | |
-     v |__|__|__|_______________________|__|__|__|  | |
-       |_________ Horizontal Scroll Bar _________|  | |
-       |_______________ Mode Line _______________|__| |
-       |_____________ Bottom Divider _______________| v
-        <---------- Window Total Width ------------>
-
-@end group
-@end smallexample
-
-@cindex window body
-@cindex text area of a window
-@cindex body of a window
-  At the center of the window is the @dfn{text area}, or @dfn{body},
-where the buffer text is displayed.  The text area can be surrounded by
-a series of optional areas.  On the left and right, from innermost to
-outermost, these are the left and right fringes, denoted by LF and RF
-(@pxref{Fringes}); the left and right margins, denoted by LM and RM in
-the schematic (@pxref{Display Margins}); the left or right vertical
-scroll bar, only one of which is present at any time, denoted by LS and
-RS (@pxref{Scroll Bars}); and the right divider, denoted by RD
-(@pxref{Window Dividers}).  At the top of the window is the header line
-(@pxref{Header Lines}).  At the bottom of the window are the horizontal
-scroll bar (@pxref{Scroll Bars}); the mode line (@pxref{Mode Line
-Format}); and the bottom divider (@pxref{Window Dividers}).
-
-  Emacs provides miscellaneous functions for finding the height and
-width of a window.  The return value of many of these functions can be
+Emacs provides miscellaneous functions for finding the height and width
+of a window.  The return value of many of these functions can be
 specified either in units of pixels or in units of lines and columns.
 On a graphical display, the latter actually correspond to the height and
-width of a default character specified by the frame's default font
-as returned by @code{frame-char-height} and @code{frame-char-width}
+width of a default character specified by the frame's default font as
+returned by @code{frame-char-height} and @code{frame-char-width}
 (@pxref{Frame Font}).  Thus, if a window is displaying text with a
 different font or size, the reported line height and column width for
 that window may differ from the actual number of text lines or columns
@@ -490,8 +707,7 @@ displayed within it.
 @cindex height of a window
 @cindex total height of a window
   The @dfn{total height} of a window is the number of lines comprising
-the window's body, the header line, the horizontal scroll bar, the mode
-line and the bottom divider (if any).
+its body and its top and bottom decorations (@pxref{Basic Windows}).
 
 @defun window-total-height &optional window round
 This function returns the total height, in lines, of the window
@@ -521,9 +737,8 @@ with any other @var{round} it returns the internal value of
 @cindex window width
 @cindex width of a window
 @cindex total width of a window
-The @dfn{total width} of a window is the number of lines comprising the
-window's body, its margins, fringes, scroll bars and a right divider (if
-any).
+The @dfn{total width} of a window is the number of lines comprising its
+body and its left and right decorations (@pxref{Basic Windows}).
 
 @defun window-total-width &optional window round
 This function returns the total width, in columns, of the window
@@ -564,10 +779,9 @@ window in units of pixels.
 This function returns the total height of window @var{window} in pixels.
 @var{window} must be a valid window and defaults to the selected one.
 
-The return value includes mode and header line, a horizontal scroll bar
-and a bottom divider, if any.  If @var{window} is an internal window,
-its pixel height is the pixel height of the screen areas spanned by its
-children.
+The return value includes the heights of @var{window}'s top and bottom
+decorations.  If @var{window} is an internal window, its pixel height is
+the pixel height of the screen areas spanned by its children.
 @end defun
 
 @cindex window pixel width
@@ -578,10 +792,9 @@ children.
 This function returns the width of window @var{window} in pixels.
 @var{window} must be a valid window and defaults to the selected one.
 
-The return value includes the fringes and margins of @var{window} as
-well as any vertical dividers or scroll bars belonging to @var{window}.
-If @var{window} is an internal window, its pixel width is the width of
-the screen areas spanned by its children.
+The return value includes the widths of @var{window}'s left and right
+decorations.  If @var{window} is an internal window, its pixel width is
+the width of the screen areas spanned by its children.
 @end defun
 
 @cindex full-width window
@@ -607,9 +820,9 @@ that of the root window on that frame.  If @var{window} is 
omitted or
 
 @cindex window body height
 @cindex body height of a window
-The @dfn{body height} of a window is the height of its text area, which
-does not include a mode or header line, a horizontal scroll bar, or a
-bottom divider.
+The @dfn{body height} of a window is the height of its body, which
+does not include any of its top or bottom decorations (@pxref{Basic
+Windows}).
 
 @defun window-body-height &optional window pixelwise
 This function returns the height, in lines, of the body of window
@@ -628,8 +841,10 @@ exceed its total height as returned by 
@code{window-total-height}.
 
 @cindex window body width
 @cindex body width of a window
-The @dfn{body width} of a window is the width of its text area, which
-does not include the scroll bar, fringes, margins or a right divider.
+The @dfn{body width} of a window is the width of its body and of the
+text area, which does not include any of its left or right decorations
+(@pxref{Basic Windows}).
+
 Note that when one or both fringes are removed (by setting their width
 to zero), the display engine reserves two character cells, one on each
 side of the window, for displaying the continuation and truncation
@@ -662,16 +877,11 @@ to calling @code{window-body-width}.  In either case, the 
optional
 argument @var{pixelwise} is passed to the function called.
 @end defun
 
-For compatibility with previous versions of Emacs,
-@code{window-height} is an alias for @code{window-total-height}, and
-@code{window-width} is an alias for @code{window-body-width}.  These
-aliases are considered obsolete and will be removed in the future.
-
-   The pixel heights of a window's mode and header line can be retrieved
-with the functions given below.  Their return value is usually accurate
-unless the window has not been displayed before: In that case, the
-return value is based on an estimate of the font used for the window's
-frame.
+   The pixel heights of a window's mode, tab and header line can be
+retrieved with the functions given below.  Their return value is usually
+accurate unless the window has not been displayed before: In that case,
+the return value is based on an estimate of the font used for the
+window's frame.
 
 @defun window-mode-line-height &optional window
 This function returns the height in pixels of @var{window}'s mode line.
@@ -679,6 +889,12 @@ This function returns the height in pixels of 
@var{window}'s mode line.
 @var{window} has no mode line, the return value is zero.
 @end defun
 
+@defun window-tab-line-height &optional window
+This function returns the height in pixels of @var{window}'s tab line.
+@var{window} must be a live window and defaults to the selected one.  If
+@var{window} has no tab line, the return value is zero.
+@end defun
+
 @defun window-header-line-height &optional window
 This function returns the height in pixels of @var{window}'s header
 line.  @var{window} must be a live window and defaults to the selected
@@ -720,15 +936,14 @@ size (@pxref{Preserving Window Sizes}).
 
 @defopt window-min-height
 This option specifies the minimum total height, in lines, of any window.
-Its value has to accommodate at least one text line as well as a mode
-and header line, a horizontal scroll bar and a bottom divider, if
-present.
+Its value has to accommodate at least one text line and any top or
+bottom decorations.
 @end defopt
 
 @defopt window-min-width
 This option specifies the minimum total width, in columns, of any
-window.  Its value has to accommodate two text columns as well as
-margins, fringes, a scroll bar and a right divider, if present.
+window.  Its value has to accommodate at least two text columns and any
+left or right decorations.
 @end defopt
 
 The following function tells how small a specific window can get taking
@@ -745,10 +960,9 @@ of @var{window}'s lines.
 
 The return value makes sure that all components of @var{window} remain
 fully visible if @var{window}'s size were actually set to it.  With
-@var{horizontal} @code{nil} it includes the mode and header line, the
-horizontal scroll bar and the bottom divider, if present.  With
-@var{horizontal} non-@code{nil} it includes the margins and fringes, the
-vertical scroll bar and the right divider, if present.
+@var{horizontal} @code{nil} it includes any top or bottom decorations.
+With @var{horizontal} non-@code{nil} it includes any left or right
+decorations of @var{window}.
 
 The optional argument @var{ignore}, if non-@code{nil}, means ignore
 restrictions imposed by fixed size windows, @code{window-min-height} or
@@ -770,10 +984,10 @@ minimum size of @var{window} counted in pixels.
 @cindex changing window size
 @cindex window size, changing
 
-  This section describes functions for resizing a window without
-changing the size of its frame.  Because live windows do not overlap,
-these functions are meaningful only on frames that contain two or more
-windows: resizing a window also changes the size of a neighboring
+This section describes functions for resizing a window without changing
+the size of its frame.  Because live windows do not overlap, these
+functions are meaningful only on frames that contain two or more
+windows: resizing a window also changes the size of at least one other
 window.  If there is just one window on a frame, its size cannot be
 changed except by resizing the frame (@pxref{Frame Size}).
 
@@ -801,11 +1015,10 @@ Normally, the variables @code{window-min-height} and
 (@pxref{Window Sizes}).  However, if the optional argument @var{ignore}
 is non-@code{nil}, this function ignores @code{window-min-height} and
 @code{window-min-width}, as well as @code{window-size-fixed}.  Instead,
-it considers the minimum-height window to be one consisting of a header
-and a mode line, a horizontal scrollbar and a bottom divider (if any),
-plus a text area one line tall; and a minimum-width window as one
-consisting of fringes, margins, a scroll bar and a right divider (if
-any), plus a text area two columns wide.
+it considers the minimum height of a window as the sum of its top and
+bottom decorations plus the text of one line; and its minimum width
+as the sum of its left and right decorations plus text that takes two
+columns.
 
 If the optional argument @var{pixelwise} is non-@code{nil},
 @var{delta} is interpreted as pixels.
@@ -889,7 +1102,7 @@ that this function can give @var{window}.  The optional 
argument
 @var{min-height}, if non-@code{nil}, specifies the minimum total height
 that it can give, which overrides the variable @code{window-min-height}.
 Both @var{max-height} and @var{min-height} are specified in lines and
-include mode and header line and a bottom divider, if any.
+include any top or bottom decorations of @var{window}.
 
 If @var{window} is part of a horizontal combination and the value of the
 option @code{fit-window-to-buffer-horizontally} (see below) is
@@ -900,8 +1113,8 @@ The optional argument @var{max-width} specifies a maximum 
width and
 defaults to the width of @var{window}'s frame.  The optional argument
 @var{min-width} specifies a minimum width and defaults to
 @code{window-min-width}.  Both @var{max-width} and @var{min-width} are
-specified in columns and include fringes, margins and scrollbars, if
-any.
+specified in columns and include any left or right decorations of
+@var{window}.
 
 The optional argument @var{preserve-size}, if non-@code{nil}, will
 install a parameter to preserve the size of @var{window} during future
@@ -1144,19 +1357,18 @@ Sizes}).  Thus, it signals an error if splitting would 
result in making
 a window smaller than those variables specify.  However, a
 non-@code{nil} value for @var{size} causes those variables to be
 ignored; in that case, the smallest allowable window is considered to be
-one that has space for a text area one line tall and/or two columns
+one that has space for a text that is one line tall and/or two columns
 wide.
 
 Hence, if @var{size} is specified, it's the caller's responsibility to
-check whether the emanating windows are large enough to encompass all
-areas like a mode line or a scroll bar.  The function
+check whether the emanating windows are large enough to encompass all of
+their decorations like a mode line or a scroll bar.  The function
 @code{window-min-size} (@pxref{Window Sizes}) can be used to determine
 the minimum requirements of @var{window} in this regard.  Since the new
-window usually inherits areas like the mode line or the scroll bar
-from @var{window}, that function is also a good guess for the minimum
-size of the new window.  The caller should specify a smaller size only
-if it correspondingly removes an inherited area before the next
-redisplay.
+window usually inherits areas like the mode line or the scroll bar from
+@var{window}, that function is also a good guess for the minimum size of
+the new window.  The caller should specify a smaller size only if it
+correspondingly removes an inherited area before the next redisplay.
 
 The optional third argument @var{side} determines the position of the
 new window relative to @var{window}.  If it is @code{nil} or
@@ -1762,153 +1974,6 @@ distribute its space proportionally among the two 
remaining live
 windows.
 
 
-@node Selecting Windows
-@section Selecting Windows
-@cindex selecting a window
-
-@defun select-window window &optional norecord
-This function makes @var{window} the selected window and the window
-selected within its frame (@pxref{Basic Windows}), and selects that
-frame.  It also makes @var{window}'s buffer (@pxref{Buffers and
-Windows}) current and sets that buffer's value of @code{point} to the
-value of @code{window-point} (@pxref{Window Point}) in @var{window}.
-@var{window} must be a live window.  The return value is @var{window}.
-
-By default, this function also moves @var{window}'s buffer to the front
-of the buffer list (@pxref{Buffer List}) and makes @var{window} the most
-recently selected window.  If the optional argument @var{norecord} is
-non-@code{nil}, these additional actions are omitted.
-
-In addition, this function by default also tells the display engine to
-update the display of @var{window} when its frame gets redisplayed the
-next time.  If @var{norecord} is non-@code{nil}, such updates are
-usually not performed.  If, however, @var{norecord} equals the special
-symbol @code{mark-for-redisplay}, the additional actions mentioned above
-are omitted but @var{window} will be nevertheless updated.
-
-Note that sometimes selecting a window is not enough to show it, or
-make its frame the top-most frame on display: you may also need to
-raise the frame or make sure input focus is directed to that frame.
-@xref{Input Focus}.
-@end defun
-
-@cindex select window hooks
-@cindex running a hook when a window gets selected
-For historical reasons, Emacs does not run a separate hook whenever a
-window gets selected.  Applications and internal routines often
-temporarily select a window to perform a few actions on it.  They do
-that either to simplify coding---because many functions by default
-operate on the selected window when no @var{window} argument is
-specified---or because some functions did not (and still do not) take a
-window as argument and always operate(d) on the selected window instead.
-Running a hook every time a window gets selected for a short time and
-once more when the previously selected window gets restored is not
-useful.
-
-  However, when its @var{norecord} argument is @code{nil},
-@code{select-window} updates the buffer list and thus indirectly runs
-the normal hook @code{buffer-list-update-hook} (@pxref{Buffer List}).
-Consequently, that hook provides one way to run a function whenever a
-window gets selected more ``permanently''.
-
-  Since @code{buffer-list-update-hook} is also run by functions that are
-not related to window management, it will usually make sense to save the
-value of the selected window somewhere and compare it with the value of
-@code{selected-window} while running that hook.  Also, to avoid false
-positives when using @code{buffer-list-update-hook}, it is good practice
-that every @code{select-window} call supposed to select a window only
-temporarily passes a non-@code{nil} @var{norecord} argument.  If
-possible, the macro @code{with-selected-window} (see below) should be
-used in such cases.
-
-  Emacs also runs the hook @code{window-selection-change-functions}
-whenever the redisplay routine detects that another window has been
-selected since last redisplay.  @xref{Window Hooks}, for a detailed
-explanation.  @code{window-state-change-functions} (described in the
-same section) is another abnormal hook run after a different window
-has been selected but is triggered by other window changes as well.
-
-@cindex most recently selected windows
-  The sequence of calls to @code{select-window} with a non-@code{nil}
-@var{norecord} argument determines an ordering of windows by their
-selection time.  The function @code{get-lru-window} can be used to
-retrieve the least recently selected live window (@pxref{Cyclic Window
-Ordering}).
-
-@defmac save-selected-window forms@dots{}
-This macro records the selected frame, as well as the selected window
-of each frame, executes @var{forms} in sequence, then restores the
-earlier selected frame and windows.  It also saves and restores the
-current buffer.  It returns the value of the last form in @var{forms}.
-
-This macro does not save or restore anything about the sizes,
-arrangement or contents of windows; therefore, if @var{forms} change
-them, the change persists.  If the previously selected window of some
-frame is no longer live at the time of exit from @var{forms}, that
-frame's selected window is left alone.  If the previously selected
-window is no longer live, then whatever window is selected at the end of
-@var{forms} remains selected.  The current buffer is restored if and
-only if it is still live when exiting @var{forms}.
-
-This macro changes neither the ordering of recently selected windows nor
-the buffer list.
-@end defmac
-
-@defmac with-selected-window window forms@dots{}
-This macro selects @var{window}, executes @var{forms} in sequence, then
-restores the previously selected window and current buffer.  The
-ordering of recently selected windows and the buffer list remain
-unchanged unless you deliberately change them within @var{forms}; for
-example, by calling @code{select-window} with argument @var{norecord}
-@code{nil}.  Hence, this macro is the preferred way to temporarily work
-with @var{window} as the selected window without needlessly running
-@code{buffer-list-update-hook}.
-@end defmac
-
-@defmac with-selected-frame frame forms@dots{}
-This macro executes @var{forms} with @var{frame} as the selected
-frame.  The value returned is the value of the last form in
-@var{forms}.  This macro saves and restores the selected frame, and
-changes the order of neither the recently selected windows nor the
-buffers in the buffer list.
-@end defmac
-
-@defun frame-selected-window &optional frame
-This function returns the window on @var{frame} that is selected
-within that frame.  @var{frame} should be a live frame; if omitted or
-@code{nil}, it defaults to the selected frame.
-@end defun
-
-@defun set-frame-selected-window frame window &optional norecord
-This function makes @var{window} the window selected within the frame
-@var{frame}.  @var{frame} should be a live frame; if @code{nil}, it
-defaults to the selected frame.  @var{window} should be a live window;
-if @code{nil}, it defaults to the selected window.
-
-If @var{frame} is the selected frame, this makes @var{window} the
-selected window.
-
-If the optional argument @var{norecord} is non-@code{nil}, this
-function does not alter the list of most recently selected windows,
-nor the buffer list.
-@end defun
-
-@cindex window use time
-@cindex use time of window
-@cindex window order by time of last use
-@defun window-use-time &optional window
-This functions returns the use time of window @var{window}.
-@var{window} must be a live window and defaults to the selected one.
-
-The @dfn{use time} of a window is not really a time value, but an
-integer that does increase monotonically with each call of
-@code{select-window} with a @code{nil} @var{norecord} argument.  The
-window with the lowest use time is usually called the least recently
-used window while the window with the highest use time is called the
-most recently used one (@pxref{Cyclic Window Ordering}).
-@end defun
-
-
 @node Cyclic Window Ordering
 @section Cyclic Ordering of Windows
 @cindex cyclic ordering of windows
@@ -2036,8 +2101,11 @@ criterion, without selecting it:
 @cindex least recently used window
 @defun get-lru-window &optional all-frames dedicated not-selected no-other
 This function returns a live window which is heuristically the least
-recently used.  The optional argument @var{all-frames} has
-the same meaning as in @code{next-window}.
+recently used one.  The @dfn{least recently used window} is the least
+recently selected one---the window whose use time is less than the use
+time of all other live windows (@pxref{Selecting Windows}).  The
+optional argument @var{all-frames} has the same meaning as in
+@code{next-window}.
 
 If any full-width windows are present, only those windows are
 considered.  A minibuffer window is never a candidate.  A dedicated
@@ -2053,8 +2121,14 @@ function returns @code{nil} in that case.  The optional 
argument
 @cindex most recently used window
 @defun get-mru-window &optional all-frames dedicated not-selected no-other
 This function is like @code{get-lru-window}, but it returns the most
-recently used window instead.  The meaning of the arguments is the
-same as for @code{get-lru-window}.
+recently used window instead.  The @dfn{most recently used window} is
+the most recently selected one---the window whose use time exceeds the
+use time of all other live windows (@pxref{Selecting Windows}).  The
+meaning of the arguments is the same as for @code{get-lru-window}.
+
+Since in practice the most recently used window is always the selected
+one, it usually makes sense to call this function with a non-@code{nil}
+@var{not-selected} argument only.
 @end defun
 
 @cindex largest window
@@ -2081,11 +2155,6 @@ windows to search, and have the same meanings as in
 @code{next-window}.
 @end defun
 
-@defun window-bump-use-time window
-This function marks @var{window} as having been recently used.  This
-can be useful when creating certain @code{pop-to-buffer} scenarios.
-@end defun
-
 
 @node Buffers and Windows
 @section Buffers and Windows
@@ -2924,9 +2993,9 @@ A non-@code{nil} value prevents another frame from being 
raised or
 selected, if the window chosen by @code{display-buffer} is displayed
 there.  Primarily affected by this are
 @code{display-buffer-use-some-frame} and
-@code{display-buffer-reuse-window}.
-@code{display-buffer-pop-up-frame} should be affected as well, but
-there is no guarantee that the window manager will comply.
+@code{display-buffer-reuse-window}.  Ideally,
+@code{display-buffer-pop-up-frame} should be affected as well, but there
+is no guarantee that the window manager will comply.
 
 @vindex window-parameters@r{, a buffer display action alist entry}
 @item window-parameters
@@ -2968,12 +3037,17 @@ A floating-point number specifies the fraction of the 
chosen window's
 desired total height with respect to the total height of its frame's
 root window.
 
+@item
+A cons cell whose @sc{car} is @code{body-lines} and whose @sc{cdr} is an
+integer that specifies the height of the chosen window's body in frame
+lines.
+
 @item
 If the value specifies a function, that function is called with one
 argument---the chosen window.  The function is supposed to adjust the
 height of the window; its return value is ignored.  Suitable functions
-are @code{shrink-window-if-larger-than-buffer} and
-@code{fit-window-to-buffer}, see @ref{Resizing Windows}.
+are @code{fit-window-to-buffer} and
+@code{shrink-window-if-larger-than-buffer}, see @ref{Resizing Windows}.
 @end itemize
 
 By convention, the height of the chosen window is adjusted only if the
@@ -3001,17 +3075,48 @@ A floating-point number specifies the fraction of the 
chosen window's
 desired total width with respect to the total width of the frame's
 root window.
 
+@item
+A cons cell whose @sc{car} is @code{body-columns} and whose @sc{cdr} is
+an integer that specifies the width of the chosen window's body in frame
+columns.
+
 @item
 If the value specifies a function, that function is called with one
 argument---the chosen window.  The function is supposed to adjust the
 width of the window; its return value is ignored.
 @end itemize
 
-By convention, the width of the chosen window is adjusted only if the
-window is part of a horizontal combination (@pxref{Windows and
-Frames}) to avoid changing the width of other, unrelated windows.
-Also, this entry should be processed under only certain conditions
-which are specified right below this list.
+@vindex window-size@r{, a buffer display action alist entry}
+@item window-size
+This entry is a combination of the two preceding ones and can be used to
+adjust the chosen window's height @emph{and} width.  Since windows can
+be resized in one direction only without affecting other windows,
+@code{window-size} is effective only to set up the size of a window
+appearing alone on a frame.  The value can be one of the following:
+
+@itemize @bullet
+@item
+@code{nil} means to leave the size of the chosen window alone.
+
+@item
+A cons cell of two integers specifies the desired total width and height
+of the chosen window in lines and columns.  It's effect is to adjust the
+size of the frame accordingly.
+
+@item
+A cons cell whose @sc{car} equals @code{body-chars} and whose @sc{cdr}
+is a cons cell of two integers---the desired body width and height of
+the chosen window in frame columns and lines.  It's effect is to adjust
+the size of the frame accordingly.
+
+@item
+If the value specifies a function, that function is called with one
+argument---the chosen window.  The function is supposed to adjust the
+size of the window's frame; its return value is ignored.
+@end itemize
+
+This entry should be processed under only certain conditions which are
+specified right below this list.
 
 @vindex dedicated@r{, a buffer display action alist entry}
 @item dedicated
@@ -3112,6 +3217,14 @@ the window was created earlier by @code{display-buffer} 
to show the
 buffer and never was used to show another buffer until it was reused
 by the current invocation of @code{display-buffer}.
 
+If no @code{window-height}, @code{window-width} or @code{window-size}
+entry was specified, the window may still be resized automatically when
+the buffer is temporary and @code{temp-buffer-resize-mode} has been
+enabled, @ref{Temporary Displays}.  In that case, the @sc{cdr} of a
+@code{window-height}, @code{window-width} or @code{window-size} entry
+can be used to inhibit or override the default behavior of
+@code{temp-buffer-resize-mode} for specific buffers or invocations of
+@code{display-buffer}.
 
 @node Choosing Window Options
 @subsection Additional Options for Displaying Buffers
@@ -5090,7 +5203,7 @@ window.
 If @var{count} is negative, it scrolls backward instead.  If
 @var{count} is @code{nil} (or omitted), the distance scrolled is
 @code{next-screen-context-lines} lines less than the height of the
-window's text area.
+window's body.
 
 If the selected window cannot be scrolled any further, this function
 signals an error.  Otherwise, it returns @code{nil}.
@@ -5583,16 +5696,15 @@ right of the rightmost column, and the Y coordinate one 
row down from
 the bottommost row.
 
 Note that these are the actual outer edges of the window, including any
-header line, mode line, scroll bar, fringes, window divider and display
-margins.  On a text terminal, if the window has a neighbor on its right,
-its right edge includes the separator line between the window and its
-neighbor.
+of its decorations.  On a text terminal, if the window has a neighbor on
+its right, its right edge includes the separator line between the window
+and its neighbor.
 
 If the optional argument @var{body} is @code{nil}, this means to
 return the edges corresponding to the total size of @var{window}.
 @var{body} non-@code{nil} means to return the edges of @var{window}'s
-body (aka text area).  If @var{body} is non-@code{nil}, @var{window}
-must specify a live window.
+body.  If @var{body} is non-@code{nil}, @var{window} must specify a
+live window.
 
 If the optional argument @var{absolute} is @code{nil}, this means to
 return edges relative to the native position of @var{window}'s frame.
@@ -5902,12 +6014,11 @@ all other child frames of that frame's parent frame.
 @cindex saving window information
 
 A @dfn{window configuration} records the entire layout of one
-frame---all windows, their sizes, which buffers they contain, how those
-buffers are scrolled, and their value of point; also their
-fringes, margins, and scroll bar settings.  It also includes the value
-of @code{minibuffer-scroll-window}.  As a special exception, the window
-configuration does not record the value of point in the selected window
-for the current buffer.
+frame---all windows, their sizes, their decorations, which buffers they
+contain, how those buffers are scrolled, and their value of point, It
+also includes the value of @code{minibuffer-scroll-window}.  As a
+special exception, the window configuration does not record the value of
+point in the selected window for the current buffer.
 
   You can bring back an entire frame layout by restoring a previously
 saved window configuration.  If you want to record the layout of all
diff --git a/doc/man/emacs.1.in b/doc/man/emacs.1.in
index 290be604e3..b2be8bb07b 100644
--- a/doc/man/emacs.1.in
+++ b/doc/man/emacs.1.in
@@ -1,5 +1,5 @@
 .\" See section COPYING for copyright and redistribution information.
-.TH EMACS 1 "2020-04-05" "GNU Emacs @version@" "GNU"
+.TH EMACS 1 "2021-09-28" "GNU Emacs @version@" "GNU"
 .
 .
 .SH NAME
@@ -215,6 +215,9 @@ Specify the name which should be assigned to the initial
 window.
 This controls looking up X resources as well as the window title.
 .TP
+.BR \-\-no\-x\-resources
+Do not load X resources.
+.TP
 .BI \-T " name\fR,\fP " \-\-title= "name"
 Specify the title for the initial X window.
 .TP
diff --git a/doc/man/emacsclient.1 b/doc/man/emacsclient.1
index ba64efa282..e5d1bbe09a 100644
--- a/doc/man/emacsclient.1
+++ b/doc/man/emacsclient.1
@@ -1,5 +1,5 @@
 .\" See section COPYING for conditions for redistribution.
-.TH EMACSCLIENT 1 "2020-10-18" "GNU Emacs" "GNU"
+.TH EMACSCLIENT 1 "2021-11-05" "GNU Emacs" "GNU"
 .\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
 .\" other params are allowed: see man(7), man(1)
 .SH NAME
@@ -69,6 +69,9 @@ start Emacs in daemon mode, and try to connect to it.
 .B -c, \-\-create-frame
 Create a new frame instead of trying to use the current Emacs frame.
 .TP
+.B -r \-\-reuse-frame
+Reuse an existing frame if one exists, otherwise create a new frame.
+.TP
 .B \-F, \-\-frame-parameters=ALIST
 Set the parameters of a newly-created frame.
 .TP
diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi
index e11267e7a2..c77ccf766f 100644
--- a/doc/misc/calc.texi
+++ b/doc/misc/calc.texi
@@ -2865,7 +2865,7 @@ that always equals one.  Let's try to verify this 
identity.
 @smallexample
 @group
 2:  -64        2:  -64        2:  -64        2:  9.7192e54  2:  9.7192e54
-1:  -64        1:  -3.1175e27 1:  9.7192e54  1:  -64        1:  9.7192e54
+1:  -64        1:  3.1175e27  1:  9.7192e54  1:  -64        1:  9.7192e54
     .              .              .              .              .
 
  64 n @key{RET} @key{RET}      H C            2 ^            @key{TAB}         
   H S 2 ^
diff --git a/doc/misc/cc-mode.texi b/doc/misc/cc-mode.texi
index 98ded68e71..a2ff572a3f 100644
--- a/doc/misc/cc-mode.texi
+++ b/doc/misc/cc-mode.texi
@@ -283,6 +283,8 @@ Font Locking
 * Font Locking Preliminaries::
 * Faces::
 * Doc Comments::
+* Wrong Comment Style::
+* Found Types::
 * Misc Font Locking::
 * AWK Mode Font Locking::
 
@@ -1855,6 +1857,7 @@ sections apply to the other languages.
 * Faces::
 * Doc Comments::
 * Wrong Comment Style::
+* Found Types::
 * Misc Font Locking::
 * AWK Mode Font Locking::
 @end menu
@@ -2161,6 +2164,60 @@ which aren't of the default style will be fontified with
 @code{font-lock-warning-face}.
 @end defvar
 
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+@node    Found Types
+@comment  node-name,  next,  previous,  up
+@section ``Found Type'' handling.
+@comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+In most languages handled by CC Mode, @dfn{found types} are recognized
+as types by their context in the source code.  These contrast with
+types which are basic to a language or are declared as types (e.g. by
+@code{typedef} in C).
+
+In earlier versions of @ccmode{}, when @code{jit-lock-mode} was
+enabled in Emacs (which it is by default), found types would
+frequently fail to get fontified properly.  This happened when the
+fontification functions scanned a use of the found type before
+scanning the code which caused it to be recognized.
+
+From @ccmode{} version 5.36, a timer mechanism scans the entire buffer
+for found types in the seconds immediately after starting the major
+mode.  When a found type gets recognized, all its occurrences in the
+buffer get marked for (re)fontification.  This scanning happens in
+short time slices interleaved with other processing, such as keyboard
+handling, so that the responsiveness of Emacs should be barely
+affected.  This mechanism can be disabled (see below).  It is only
+active when @code{jit-lock-mode} is also active.
+
+@defvar c-type-finder-time-slot
+@vindex type-finder-time-slot (c-)
+The approximate time in seconds that CC Mode spends in scanning source
+code before relinquishing control to other Emacs activities.  The
+default value is 0.05.  To disable the scanning mechanism, set this
+variable to @code{nil}.
+@end defvar
+
+@defvar c-type-finder-repeat-time
+@vindex type-finder-repeat-time (c-)
+The approximate frequency (in seconds) with which the scanning
+mechanism is triggered.  This time must be greater than
+@code{c-type-finder-time-slot}.  Its default value is 0.1.  If a less
+powerful machine becomes sluggish due to the scanning, increase the
+value of @code{c-type-finder-repeat-time} to compensate.
+@end defvar
+
+@defvar c-type-finder-chunk-size
+@vindex type-finder-chunk-size (c-)
+The approximate size (in characters) of the buffer chunk processed as
+a unit before the scanning mechanism checks whether
+@code{c-type-finder-time-slot} seconds have passed.  The default value
+is 1000.  A too small value here will cause inefficiencies due to the
+initialization which happens for each chunk, whereas a too large value
+will cause the processing to consume an excessive proportion of the
+@code{c-type-finder-repeat-time}.
+@end defvar
+
 @comment !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 @node    Misc Font Locking
 @comment  node-name,  next,  previous,  up
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index a6c3c32c0e..55b112cb24 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -1245,6 +1245,12 @@ blocks for other macros like @code{cl-incf}, and 
@code{cl-pushnew}.
 The @code{cl-letf} and @code{cl-letf*} macros are used in the processing
 of symbol macros; @pxref{Macro Bindings}.
 
+@defmac with-memoization @var{place} @var{code}@dots{}
+This macro provides a simple way to do memoization.  @var{code} is
+evaluated and then stashed in @var{place}.  If @var{place}'s value is
+non-@code{nil}, return that value instead of evaluating @var{code}.
+@end defmac
+
 
 @node Variable Bindings
 @section Variable Bindings
@@ -3364,9 +3370,13 @@ true for all elements.
 @end defun
 
 @defun cl-reduce function seq @t{&key :from-end :start :end :initial-value 
:key}
-This function combines the elements of @var{seq} using an associative
-binary operation.  Suppose @var{function} is @code{*} and @var{seq} is
-the list @code{(2 3 4 5)}.  The first two elements of the list are
+This function returns the result of calling @var{function} on the
+first and second element of @var{seq}, then calling @var{function}
+with that result and the third element of @var{seq}, then with that
+result and the third element of @var{seq}, etc.
+
+Here is an example.  Suppose @var{function} is @code{*} and @var{seq}
+is the list @code{(2 3 4 5)}.  The first two elements of the list are
 combined with @code{(* 2 3) = 6}; this is combined with the next
 element, @code{(* 6 4) = 24}, and that is combined with the final
 element: @code{(* 24 5) = 120}.  Note that the @code{*} function happens
@@ -5024,7 +5034,7 @@ The above @code{incf} example could be written using
 @ignore
 (defmacro concatf (place &rest args)
   (gv-letplace (getter setter) place
-    (macroexp-let2 nil v (mapconcat 'identity args "")
+    (macroexp-let2 nil v (mapconcat 'identity args)
       (funcall setter `(concat ,getter ,v)))))
 @end ignore
 @end defmac
diff --git a/doc/misc/efaq.texi b/doc/misc/efaq.texi
index 46f78220fe..18342e65b0 100644
--- a/doc/misc/efaq.texi
+++ b/doc/misc/efaq.texi
@@ -816,7 +816,7 @@ Emacs news, a history of recent user-visible changes
 
 More GNU and FSF information is available at
 
-@uref{https://www.gnu.org} and @uref{http://www.fsf.org}
+@uref{https://www.gnu.org} and @uref{https://www.fsf.org}
 
 @node Help installing Emacs
 @section Where can I get help in installing Emacs?
@@ -4136,9 +4136,6 @@ You can get the old behavior by binding @kbd{SPC} to
 @lisp
 (define-key minibuffer-local-filename-completion-map (kbd "SPC")
   'minibuffer-complete-word)
-
-(define-key minibuffer-local-filename-must-match-map (kbd "SPC")
-  'minibuffer-complete-word)
 @end lisp
 
 @c ------------------------------------------------------------
diff --git a/doc/misc/eieio.texi b/doc/misc/eieio.texi
index 63b4282731..2b0b1f7fd6 100644
--- a/doc/misc/eieio.texi
+++ b/doc/misc/eieio.texi
@@ -700,18 +700,19 @@ slot values, and use the previously mentioned set/ref 
routines.
 @defun slot-value object slot
 @anchor{slot-value}
 This function retrieves the value of @var{slot} from @var{object}.
+It can also be used on objects defined by @code{cl-defstruct}.
 
 This is a generalized variable that can be used with @code{setf} to
-modify the value stored in @var{slot}.  @xref{Generalized
-Variables,,,elisp,GNU Emacs Lisp Reference Manual}.
+modify the value stored in @var{slot}, tho not for objects defined by
+@code{cl-defstruct}.
+@xref{Generalized Variables,,,elisp,GNU Emacs Lisp Reference Manual}.
 @end defun
 
 @defun set-slot-value object slot value
 @anchor{set-slot-value}
 This function sets the value of @var{slot} from @var{object}.
 
-This is not a CLOS function, but is the obsolete setter for
-@code{slot-value} used by the @code{setf} macro.  It is therefore
+This is not a CLOS function.  It is therefore
 recommended to use @w{@code{(setf (slot-value @var{object} @var{slot})
 @var{value})}} instead.
 @end defun
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 10ced678e1..3b8e231d3a 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -2,13 +2,15 @@
 @c %**start of header
 @setfilename ../../info/erc.info
 @settitle ERC Manual
+@set ERCVER 5.4.1
+@set ERCDIST as distributed with Emacs @value{EMACSVER}
 @include docstyle.texi
 @syncodeindex fn cp
 @include emacsver.texi
 @c %**end of header
 
 @copying
-This manual is for ERC as distributed with Emacs @value{EMACSVER}.
+This manual is for ERC @value{ERCVER} @value{ERCDIST}.
 
 Copyright @copyright{} 2005--2021 Free Software Foundation, Inc.
 
diff --git a/doc/misc/ert.texi b/doc/misc/ert.texi
index fafdb8c4eb..440c61add8 100644
--- a/doc/misc/ert.texi
+++ b/doc/misc/ert.texi
@@ -260,36 +260,103 @@ unexpected result.  In the example above, there are two 
failures, both
 due to failed @code{should} forms.  @xref{Understanding Explanations},
 for more details.
 
+The following key bindings are available in the ERT results buffer:
+
+@table @kbd
+
+@item @key{RET}
+@kindex RET@r{, in ert results buffer}
+Each name of a function or macro in this buffer is a button; moving
+point to it and typing @kbd{@key{RET}} jumps to its definition.
+
+@item @key{TAB}
+@itemx S-@key{TAB}
 @kindex TAB@r{, in ert results buffer}
 @kindex S-TAB@r{, in ert results buffer}
-In the ERT results buffer, @kbd{@key{TAB}} and @kbd{S-@key{TAB}} cycle between
-buttons.  Each name of a function or macro in this buffer is a button;
-moving point to it and typing @kbd{@key{RET}} jumps to its definition.
+Cycle between buttons forward (@code{forward-button}) and backward
+(@code{backward-button}).
 
+@item r
 @kindex r@r{, in ert results buffer}
+@findex ert-results-rerun-test-at-point
+Re-run the test near point on its own
+(@code{ert-results-rerun-test-at-point}).
+
+@item d
 @kindex d@r{, in ert results buffer}
+@findex ert-results-rerun-test-at-point-debugging-errors
+Re-run the test near point on its own with the debugger enabled
+(@code{ert-results-rerun-test-at-point-debugging-errors}).
+
+@item R
+@kindex R@r{, in ert results buffer}
+@findex ert-results-rerun-all-tests
+Re-run all tests (@code{ert-results-rerun-all-tests}).
+
+@item .
 @kindex .@r{, in ert results buffer}
+@findex ert-results-find-test-at-point-other-window
+Jump to the definition of the test near point
+(@code{ert-results-find-test-at-point-other-window}).  This has the
+same effect as @kbd{@key{RET}}, but does not require point to be on
+the name of the test.
+
+@item b
 @kindex b@r{, in ert results buffer}
+@findex ert-results-pop-to-backtrace-for-test-at-point
 @cindex backtrace of a failed test
-Pressing @kbd{r} re-runs the test near point on its own.  Pressing
-@kbd{d} re-runs it with the debugger enabled.  @kbd{.} jumps to the
-definition of the test near point (@kbd{@key{RET}} has the same effect
-if point is on the name of the test).  On a failed test, @kbd{b} shows
-the backtrace of the failure.  @xref{Debugging,, Backtraces, elisp,
-GNU Emacs Lisp Reference Manual}, for more information about
-backtraces.
+Show the backtrace of a failed test
+(@code{ert-results-pop-to-backtrace-for-test-at-point}).
+@xref{Debugging,, Backtraces, elisp, GNU Emacs Lisp Reference Manual},
+for more information about backtraces.
 
+@item l
 @kindex l@r{, in ert results buffer}
-@kbd{l} shows the list of @code{should} forms executed in the test.
-If any messages were generated (with the Lisp function @code{message})
-in a test or any of the code that it invoked, @kbd{m} will show them.
-
+@findex ert-results-pop-to-should-forms-for-test-at-point
+Show the list of @code{should} forms executed in the test
+(@code{ert-results-pop-to-should-forms-for-test-at-point}).
+
+@item m
+@kindex m@r{, in ert results buffer}
+@findex ert-results-pop-to-messages-for-test-at-point
+Show any messages that were generated (with the Lisp function
+@code{message}) in in a test or any of the code that it invoked
+(@code{ert-results-pop-to-messages-for-test-at-point}).
+
+@item L
 @kindex L@r{, in ert results buffer}
+@findex ert-results-toggle-printer-limits-for-test-at-point
 By default, long expressions in the failure details are abbreviated
-using @code{print-length} and @code{print-level}.  Pressing @kbd{L}
-while point is on a test failure will increase the limits to show more
-of the expression.
+using @code{print-length} and @code{print-level}.  Increase the limits
+to show more of the expression by moving point to a test failure with
+this command (@code{ert-results-toggle-printer-limits-for-test-at-point}).
+
+@item D
+@kindex D@r{, in ert results buffer}
+@findex ert-delete-test
+@cindex delete test
+Delete a test from the running Emacs session (@code{ert-delete-test}).
 
+@item h
+@kindex h@r{, in ert results buffer}
+@findex ert-describe-test
+Show the documentation of a test (@code{ert-describe-test}).
+
+@item T
+@kindex T@r{, in ert results buffer}
+@findex ert-results-pop-to-timings
+Display test timings for the last run (@code{ert-results-pop-to-timings}).
+
+@item M-x ert-delete-all-tests
+@findex ert-delete-all-tests
+@cindex delete all tests
+Delete all tests from the running session.
+
+@item M-x ert-describe-test
+@findex ert-results-describe-test-at-point
+Prompt for a test and then show its documentation.
+
+@end table
 
 @node Running Tests in Batch Mode
 @section Running Tests in Batch Mode
@@ -348,7 +415,7 @@ emacs -batch -l ert -l my-tests.el \
 @end example
 
 By default, ERT test failure summaries are quite brief in batch
-mode--only the names of the failed tests are listed.  If the
+mode---only the names of the failed tests are listed.  If the
 EMACS_TEST_VERBOSE environment variable is set, the failure summaries
 will also include the data from the failing test.
 
@@ -419,6 +486,7 @@ to find where a test was defined if the test was loaded 
from a file.
 * Expected Failures::           Tests for known bugs.
 * Tests and Their Environment:: Don't depend on customizations; no side 
effects.
 * Useful Techniques::           Some examples.
+* erts files::                  Files containing many buffer tests.
 @end menu
 
 @node The @code{should} Macro
@@ -700,6 +768,119 @@ code is to restructure the code slightly to provide 
better interfaces
 for testing.  Usually, this makes the interfaces easier to use as
 well.
 
+@node erts files
+@section erts files
+
+@findex ert-test-erts-file
+Many relevant Emacs tests depend on comparing the contents of a buffer
+before and after executing a particular function.  These tests can be
+written the normal way---making a temporary buffer, inserting the
+``before'' text, running the function, and then comparing with the
+expected ``after'' text.  However, this often leads to test code
+that's pretty difficult to read and write, especially when the text in
+question is multi-line.
+
+So ert provides a function called @code{ert-test-erts-file} that takes
+two parameters: The name of a specially-formatted @dfn{erts} file, and
+(optionally) a function that performs the transform.
+
+@findex erts-mode
+These erts files can be edited with the @code{erts-mode} major mode.
+
+An erts file is divided into sections by the (@samp{=-=}) separator.
+
+Here's an example file containing two tests:
+
+@example
+Name: flet
+
+=-=
+(cl-flet ((bla (x)
+(* x x)))
+(bla 42))
+=-=
+(cl-flet ((bla (x)
+            (* x x)))
+  (bla 42))
+=-=-=
+
+Name: defun
+
+=-=
+(defun x ()
+  (print (quote ( thingy great
+                  stuff))))
+=-=-=
+@end example
+
+A test starts with a line containing just @samp{=-=} and ends with a
+line containing just @samp{=-=-=}.  The test may be preceded by
+freeform text (for instance, comments), and also name/value pairs (see
+below for a list of them).
+
+If there is a line with @samp{=-=} inside the test, that designates
+the start of the ``after'' text.  Otherwise, the ``before'' and
+``after'' texts are assumed to be identical, which you typically see
+when writing indentation tests.
+
+@code{ert-test-erts-file} puts the ``before'' section into a temporary
+buffer, calls the transform function, and then compares with the
+``after'' section.
+
+Here's an example usage:
+
+@lisp
+(ert-test-erts-file "elisp.erts"
+                    (lambda ()
+                      (emacs-lisp-mode)
+                      (indent-region (point-min) (point-max))))
+@end lisp
+
+A list of the name/value specifications that can appear before a test
+follows.  The general syntax is @samp{Name: Value}, but continuation
+lines can be used (along the same lines as in mail---subsequent lines
+that start with a space are part of the value).
+
+@example
+Name: foo
+Code: (indent-region
+        (point-min) (point-max))
+@end example
+
+@table @samp
+@item Name
+All tests should have a name.  This name will appear in ERT output if
+the test fails, and helps to identify the failing test.
+
+@item Code
+This is the code that will be run to do the transform.  This can also
+be passed in via the @code{ert-test-erts-file} call, but @samp{Code}
+overrides that.  It's used not only in the following test, but in all
+subsequent tests in the file (until overridden by another @samp{Code}
+specification).
+
+@item No-Before-Newline
+@itemx No-After-Newline
+These specifications say whether the ``before'' or ``after'' portions
+have a newline at the end.  (This would otherwise be impossible to
+specify.)
+
+@item Point-Char
+Sometimes it's useful to be able to put point at a specific place
+before executing the transform function.  @samp{Point-Char: |} will
+make @code{ert-test-erts-file} place point where @samp{|} is in the
+``before'' form (and remove that character), and will check that it's
+where the @samp{|} character is in the ``after'' form (and issue a
+test failure if that isn't the case).  (This is used in all subsequent
+tests, unless overridden by a new @samp{Point-Char} spec.)
+
+@item Skip
+If this is present and value is a form that evaluates to a
+non-@code{nil} value, the test will be skipped.
+@end table
+
+If you need to use the literal line single line @samp{=-=} in a test
+section, you can quote it with a @samp{\} character.
 
 @node How to Debug Tests
 @chapter How to Debug Tests
diff --git a/doc/misc/eww.texi b/doc/misc/eww.texi
index 2543dc2ff5..95e59d98f8 100644
--- a/doc/misc/eww.texi
+++ b/doc/misc/eww.texi
@@ -380,6 +380,32 @@ thus allowing for the use of the usual substitutions, such 
as
 @code{\[eww-reload]} for the current key binding of the
 @code{eww-reload} command.
 
+@vindex eww-auto-rename-buffer
+  If the @code{eww-auto-rename-buffer} user option is non-@code{nil},
+EWW buffers will be renamed after rendering a document.  If this is
+@code{title}, rename based on the title of the document.  If this is
+@code{url}, rename based on the @acronym{URL} of the document.  This
+can also be a user-defined function, which is called with no
+parameters in the EWW buffer, and should return a string.
+
+@cindex utm
+@vindex eww-url-transformers
+  EWW runs the URLs through @code{eww-url-transformers} before using
+them.  This user option is a list of functions, where each function is
+called with the URL as the parameter, and should return the (possibly)
+transformed URL.  By default, this variable contains
+@code{eww-remove-tracking}, which removes the common @samp{utm_}
+trackers from links.
+
+@cindex video
+@vindex shr-use-xwidgets-for-media
+  If Emacs has been built with xwidget support, EWW can use that to
+display @samp{<video>} elements.  However, this support is still
+experimental, and on some systems doesn't work (and even worse) may
+crash your Emacs, so this feature is off by default.  If you wish to
+switch it on, set @code{shr-use-xwidgets-for-media} to a
+non-@code{nil} value.
+
 @node Command Line
 @chapter Command Line Usage
 
diff --git a/doc/misc/flymake.texi b/doc/misc/flymake.texi
index cfe73439f3..309bed7760 100644
--- a/doc/misc/flymake.texi
+++ b/doc/misc/flymake.texi
@@ -774,7 +774,7 @@ Binding,,, elisp, The Emacs Lisp Reference Manual}) to be 
active.
           ;; Check that the process has indeed exited, as it might
           ;; be simply suspended.
           ;;
-          (when (eq 'exit (process-status proc))
+          (when (memq (process-status proc) '(exit signal))
             (unwind-protect
                 ;; Only proceed if `proc' is the same as
                 ;; `ruby--flymake-proc', which indicates that
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 5eeffbdeca..796bb3bac8 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -7130,20 +7130,15 @@ as 10, you might consider setting this variable to 
something sensible:
 (setq gnus-simplify-ignored-prefixes
       (concat
        "\\`\\[?\\("
-       (mapconcat
-        'identity
-        '("looking"
-          "wanted" "followup" "summary\\( of\\)?"
-          "help" "query" "problem" "question"
-          "answer" "reference" "announce"
-          "How can I" "How to" "Comparison of"
-          ;; ...
-          )
-        "\\|")
+       (regexp-opt '("looking"
+                     "wanted" "followup" "summary" "summary of"
+                     "help" "query" "problem" "question"
+                     "answer" "reference" "announce"
+                     "How can I" "How to" "Comparison of"
+                     ;; ...
+                     ))
        "\\)\\s *\\("
-       (mapconcat 'identity
-                  '("for" "for reference" "with" "about")
-                  "\\|")
+       (regexp-opt '("for" "for reference" "with" "about"))
        "\\)?\\]?:?[ \t]*"))
 @end lisp
 
@@ -9848,6 +9843,13 @@ Gravatarify the @code{From} header 
(@code{gnus-treat-from-gravatar}).
 Gravatarify all mail headers (i.e., @code{Cc}, @code{To})
 (@code{gnus-treat-from-gravatar}).
 
+@item W D e
+@kindex W D e @r{(Summary)}
+@findex gnus-article-emojize-symbols
+Some symbols have both a non-emoji presentation and an emoji
+presentation.  This command will make Gnus choose the emoji presentation
+(@code{gnus-article-emojize-symbols}).
+
 @item W D D
 @kindex W D D @r{(Summary)}
 @findex gnus-article-remove-images
@@ -12190,6 +12192,7 @@ controlling variable is a predicate list, as described 
above.
 @vindex gnus-treat-capitalize-sentences
 @vindex gnus-treat-overstrike
 @vindex gnus-treat-strip-cr
+@vindex gnus-treat-emojize-symbols
 @vindex gnus-treat-strip-headers-in-body
 @vindex gnus-treat-strip-leading-blank-lines
 @vindex gnus-treat-strip-multiple-blank-lines
@@ -12242,6 +12245,7 @@ possible but those listed are probably sufficient for 
most people.
 @item gnus-treat-capitalize-sentences (t, integer)
 @item gnus-treat-overstrike (t, integer)
 @item gnus-treat-strip-cr (t, integer)
+@item gnus-treat-emojize-symbols (t, integer)
 @item gnus-treat-strip-headers-in-body (t, integer)
 @item gnus-treat-strip-leading-blank-lines (t, first, integer)
 @item gnus-treat-strip-multiple-blank-lines (t, integer)
@@ -13875,11 +13879,9 @@ present in this hook.
 @item nntp-authinfo-function
 @vindex nntp-authinfo-function
 @findex nntp-send-authinfo
-@vindex nntp-authinfo-file
 This function will be used to send @samp{AUTHINFO} to the @acronym{NNTP}
 server.  The default function is @code{nntp-send-authinfo}, which looks
-through your @file{~/.authinfo} (or whatever you've set the
-@code{nntp-authinfo-file} variable to) for applicable entries.  If none
+through your @file{~/.authinfo} for applicable entries.  If none
 are found, it will prompt you for a login name and a password.  The
 format of the @file{~/.authinfo} file is (almost) the same as the
 @code{ftp} @file{~/.netrc} file, which is defined in the @code{ftp}
@@ -26324,7 +26326,7 @@ Fortunately, setting up the Gnus registry is pretty 
easy:
 @end lisp
 
 This adds registry saves to Gnus newsrc saves (which happen on exit
-and when you press @kbd{s} from the @file{*Group*} buffer.  It also
+and when you press @kbd{s} from the @file{*Group*} buffer).  It also
 adds registry calls to article actions in Gnus (copy, move, etc.)@: so
 it's not easy to undo the initialization.  See
 @code{gnus-registry-initialize} for the gory details.
diff --git a/doc/misc/mairix-el.texi b/doc/misc/mairix-el.texi
index d0ec552145..e57b5ed542 100644
--- a/doc/misc/mairix-el.texi
+++ b/doc/misc/mairix-el.texi
@@ -60,6 +60,8 @@ database.
 * Using::                       List of interactive functions
 * Extending::                   Support your favorite mail reader!
 * GNU Free Documentation License::  The license for this documentation.
+* Function Index:               Function Index.
+* Variable Index:               Variable Index.
 @end menu
 
 @node About
@@ -339,4 +341,14 @@ And that's it!
 @appendix GNU Free Documentation License
 @include doclicense.texi
 
+@node Function Index
+@unnumbered Function Index
+
+@printindex fn
+
+@node Variable Index
+@unnumbered Variable Index
+
+@printindex vr
+
 @bye
diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org
index 5bb230f892..675144d517 100644
--- a/doc/misc/modus-themes.org
+++ b/doc/misc/modus-themes.org
@@ -5,9 +5,9 @@
 #+options: ':t toc:nil author:t email:t num:t
 #+startup: content
 
-#+macro: stable-version 1.5.0
-#+macro: release-date 2021-07-15
-#+macro: development-version 1.6.0-dev
+#+macro: stable-version 1.6.0
+#+macro: release-date 2021-09-29
+#+macro: development-version 1.7.0-dev
 #+macro: file @@texinfo:@file{@@$1@@texinfo:}@@
 #+macro: space @@texinfo:@: @@
 #+macro: kbd @@texinfo:@kbd{@@$1@@texinfo:}@@
@@ -383,6 +383,7 @@ this manual.
       modus-themes-no-mixed-fonts nil
       modus-themes-subtle-line-numbers nil
       modus-themes-success-deuteranopia t
+      modus-themes-tabs-accented t
       modus-themes-inhibit-reload t ; only applies to `customize-set-variable' 
and related
 
       modus-themes-fringes nil ; {nil,'subtle,'intense}
@@ -395,9 +396,8 @@ this manual.
 
       ;; Options for `modus-themes-mode-line' are either nil, or a list
       ;; that can combine any of `3d' OR `moody', `borderless',
-      ;; `accented'.  The variable's doc string shows all possible
-      ;; combinations.
-      modus-themes-mode-line '(3d accented)
+      ;; `accented', `padded'.
+      modus-themes-mode-line '(padded accented borderless)
 
       ;; Options for `modus-themes-syntax' are either nil (the default),
       ;; or a list of properties that may include any of those symbols:
@@ -443,6 +443,7 @@ this manual.
       modus-themes-org-agenda ; this is an alist: read the manual or its doc 
string
       '((header-block . (variable-pitch scale-title))
         (header-date . (grayscale workaholic bold-today))
+        (event . (accented scale-small))
         (scheduled . uniform)
         (habit . traffic-light-deuteranopia))
 
@@ -473,7 +474,7 @@ Symbol: ~modus-themes-inhibit-reload~
 
 Possible values:
 
-1. ~nil~ 
+1. ~nil~
 2. ~t~ (default)
 
 By default, customizing a theme-related user option through the Custom
@@ -803,6 +804,7 @@ effect, color, and border visibility:
   - ~moody~
 + ~accented~
 + ~borderless~
++ ~padded~
 
 The default (a nil value or an empty list) is a two-dimensional
 rectangle with a border around it.  The active and the inactive
@@ -829,6 +831,13 @@ the same as the background, effectively creating some 
padding.
 The ~accented~ property ensures that the active mode line uses a
 colored background instead of the standard shade of gray.
 
+The ~padded~ property increases the apparent height of the mode line.
+This is done by applying box effects and combining them with an
+underline and overline.  To ensure that the underline is placed at the
+bottom, set ~x-underline-at-descent-line~ to non-nil.  The ~padded~ property
+has no effect when the ~moody~ property is also used, because Moody
+already applies its own padding.
+
 Combinations of any of those properties are expressed as a list,
 like in these examples:
 
@@ -843,7 +852,7 @@ The order in which the properties are set is not 
significant.
 In user configuration files the form may look like this:
 
 #+begin_src emacs-lisp
-(setq modus-themes-prompts '(borderless accented))
+(setq modus-themes-mode-line '(borderless accented))
 #+end_src
 
 Note that Moody does not expose any faces that the themes could style
@@ -868,6 +877,27 @@ Furthermore, because Moody expects an underline and 
overline instead of
 a box style, it is advised to set ~x-underline-at-descent-line~ to a
 non-nil value.
 
+** Option for accented background in tab interfaces
+:properties:
+:alt_title: Tab style
+:description: Toggle accented background for tabs
+:custom_id: h:27cef8f5-dc4e-4c93-ba41-b899e650d936
+:end:
+#+vindex: modus-themes-tabs-accented
+
+Symbol: ~modus-themes-tabs-accented~
+
+Possible values:
+
++ ~nil~ (default)
++ ~t~
+
+By default, all tab interfaces use backgrounds which are shades of gray.
+When this option is set to non-nil, the backgrounds become colorful.
+
+This affects the built-in ~tab-bar-mode~ and ~tab-line-mode~, as well as the
+Centaur tabs package.
+
 ** Option for completion framework aesthetics
 :properties:
 :alt_title: Completion UIs
@@ -1305,6 +1335,7 @@ all possible combinations:
 (setq modus-themes-org-agenda
       '((header-block . (variable-pitch scale-title))
         (header-date . (grayscale workaholic bold-today))
+        (event . (accented scale-small))
         (scheduled . uniform)
         (habit . traffic-light)))
 #+end_src
@@ -1346,6 +1377,11 @@ the following properties:
 - ~bold-today~ to apply a bold typographic weight to the current
   date;
 - ~bold-all~ to render all date headings in a bold weight.
+- ~scale-heading~ increases the height of the date headings to the value
+  of ~modus-themes-scale-1~ (which is the first step in the scale for
+  regular headings).
+- ~underline-today~ applies an underline to the current date while
+  removing the background it has by default.
 
 For example:
 
@@ -1355,6 +1391,31 @@ For example:
 (header-date . (grayscale bold-all))
 (header-date . (grayscale workaholic))
 (header-date . (grayscale workaholic bold-today))
+(header-date . (grayscale workaholic bold-today scale-heading))
+#+end_src
+
+An ~event~ key covers events from the diary and other entries that derive
+from a symbolic expression or sexp (e.g. phases of the moon, holidays).
+This key accepts a list of values.  By default (a nil value or an empty
+list) those have a gray foreground, while sexp events are additionally
+presented using slanted text (italics).  The properties that can form a
+list of possible values are:
+
+- ~scale-small~ reduces the height of the entries to the value of the user
+  option ~modus-themes-scale-small~ (0.9 the height of the main font size
+  by default).
+- ~accented~ applies an accent value to the event's foreground, replacing
+  the original gray.
+- ~italic~ adds a slant to the font's forms (italic or oblique forms,
+  depending on the typeface).
+
+For example:
+
+#+begin_src emacs-lisp
+(event . nil)
+(event . (scale-small))
+(event . (scale-small accented))
+(event . (scale-small accented italic))
 #+end_src
 
 A ~scheduled~ key applies to tasks with a scheduled date.  By default (a
@@ -1416,6 +1477,7 @@ Putting it all together, the alist can look like this:
 #+begin_src emacs-lisp
 '((header-block . (scale-title variable-pitch))
   (header-date . (grayscale workaholic bold-today))
+  (event . (accented scale-small))
   (scheduled . uniform)
   (habit . traffic-light))
 
@@ -1423,6 +1485,7 @@ Putting it all together, the alist can look like this:
 (setq modus-themes-org-agenda
       '((header-block . (scale-title variable-pitch))
         (header-date . (grayscale workaholic bold-today))
+        (event . (accented scale-small))
         (scheduled . uniform)
         (habit . traffic-light)))
 #+end_src
@@ -1574,7 +1637,8 @@ resource for finding a consistent scale:
       modus-themes-scale-2 1.1
       modus-themes-scale-3 1.15
       modus-themes-scale-4 1.2
-      modus-themes-scale-title 1.3)
+      modus-themes-scale-title 1.3
+      modus-themes-scale-small 0.9)
 #+end_src
 
 As for the application of that scale, the variables that range from
@@ -1593,6 +1657,11 @@ supposed to signify the primary header.  Similarly, the 
Org Agenda's
 structure headings are not part of a recognisable scale and so they also
 get ~modus-themes-scale-title~ 
([[#h:68f481bc-5904-4725-a3e6-d7ecfa7c3dbc][Option for Org agenda constructs]]).
 
+Similarly ~modus-themes-scale-small~ is not applied to regular headings,
+but reserved for special contexts where the user is presented with an
+option to use a smaller font height than the base size.  It is only
+implemented for the Org agenda.
+
 Users who wish to maintain scaled headings for the normal syntax while
 preventing special headings from standing out, can assign a value of =1.0=
 to ~modus-themes-scale-title~ to make it the same as body text (or
@@ -2321,8 +2390,8 @@ Using the above has an immediate effect, as it reloads 
the active Modus
 theme.
 
 The =my-modus-themes-saturate= function stores new color values in the
-variables =modus-themes-operandi-color-overrides= and
-=modus-themes-vivendi-color-overrides=, meaning that it undoes changes
+variables ~modus-themes-operandi-color-overrides~ and
+~modus-themes-vivendi-color-overrides~, meaning that it undoes changes
 implemented by the user on individual colors.  To have both automatic
 saturation adjustment across the board and retain per-case edits to the
 palette, some tweaks to the above function are required.  For example:
@@ -2574,9 +2643,9 @@ two):
 
 #+begin_src emacs-lisp
 (setq org-todo-keyword-faces
-      '(("MEET" . '(font-lock-preprocessor-face org-todo))
-        ("STUDY" . '(font-lock-variable-name-face org-todo))
-        ("WRITE" . '(font-lock-type-face org-todo))))
+      '(("MEET" . '(bold org-todo))
+        ("STUDY" . '(warning org-todo))
+        ("WRITE" . '(shadow org-todo))))
 #+end_src
 
 This will refashion the keywords you specify, while letting the other
@@ -2607,7 +2676,7 @@ configuration of the priority cookies:
 
 #+begin_src emacs-lisp
 (setq org-priority-faces
-      '((?A . '(org-scheduled-today org-priority))
+      '((?A . '(bold org-priority))
         (?B . org-priority)
         (?C . '(shadow org-priority))))
 #+end_src
@@ -2700,7 +2769,7 @@ A couple of examples (rounded numbers):
 ;; Pure black with pure green
 (modus-themes-contrast "#000000" "#00ff00")
 ;; => 15.3
-;; That is is a highly accessible combo
+;; That is a highly accessible combo
 #+end_src
 
 It does not matter which color value comes first.  The ratio is always
@@ -2904,6 +2973,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + alert
 + all-the-icons
 + annotate
++ ansi-color
 + anzu
 + apropos
 + apt-sources-list
@@ -2943,6 +3013,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + css-mode
 + csv-mode
 + ctrlf
++ cursor-flash
 + custom (what you get with {{{kbd(M-x customize)}}})
 + dap-mode
 + dashboard (emacs-dashboard)
@@ -2977,6 +3048,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + eldoc-box
 + elfeed
 + elfeed-score
++ elpher
 + embark
 + emms
 + enh-ruby-mode (enhanced-ruby-mode)
@@ -3033,6 +3105,7 @@ have lots of extensions, so the "full support" may not be 
100% true…
 + highlight-escape-sequences (~hes-mode~)
 + highlight-indentation
 + highlight-numbers
++ highlight-parentheses ([[#h:24bab397-dcb2-421d-aa6e-ec5bd622b913][Note on 
highlight-parentheses.el]])
 + highlight-symbol
 + highlight-tail
 + highlight-thing
@@ -3225,6 +3298,7 @@ These do not require any extra styles because they are 
configured to
 inherit from some basic faces or their dependencies which are directly
 supported by the themes.
 
++ bufler
 + counsel-notmuch
 + edit-indirect
 + evil-owl
@@ -3234,8 +3308,13 @@ supported by the themes.
 + perl-mode
 + php-mode
 + rjsx-mode
++ side-hustle
 + swift-mode
 + tab-bar-echo-area
++ tide
++ vertico-indexed
++ vertico-mouse
++ vertico-quick
 
 * Notes on individual packages
 :properties:
@@ -3415,6 +3494,135 @@ and have the foreground be indistinguishable from it.  
For example:
 
 [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the 
themes' palette]].
 
+** Note on highlight-parentheses.el
+:PROPERTIES:
+:CUSTOM_ID: h:24bab397-dcb2-421d-aa6e-ec5bd622b913
+:END:
+
+The =highlight-parentheses= package provides contextual coloration of
+surrounding parentheses, highlighting only those which are around the
+point.  The package expects users to customize the applicable colors on
+their own by configuring certain variables.
+
+To make the Modus themes work as expected with this, we need to use some
+of the techniques that are discussed at length in the various
+"Do-It-Yourself" (DIY) sections, which provide insight into the more
+advanced customization options of the themes.
+
+[[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization 
(do-it-yourself)]].
+
+In the following example, we are assuming that the user wants to (i)
+re-use color variables provided by the themes, (ii) be able to retain
+their tweaks while switching between ~modus-operandi~ and ~modus-vivendi~,
+and (iii) have the option to highlight either the foreground of the
+parentheses or the background as well.
+
+We start by defining our own variable, which will serve as a toggle
+between foreground and background coloration styles:
+
+#+begin_src emacs-lisp
+(defvar my-highlight-parentheses-use-background t
+  "Prefer `highlight-parentheses-background-colors'.")
+#+end_src
+
+Then we can update our preference with this:
+
+#+begin_src emacs-lisp
+;; Set to nil to disable backgrounds.
+(setq my-highlight-parentheses-use-background nil)
+#+end_src
+
+To re-use colors from the themes, we must wrap our code in the
+~modus-themes-with-colors~ macro.  Our implementation must interface with
+the variables ~highlight-parentheses-background-colors~ and/or
+~highlight-parentheses-colors~.
+
+So we can have something like this (the doc string of
+~modus-themes-with-colors~ explains where the names of the colors can be
+found):
+
+#+begin_src emacs-lisp
+(modus-themes-with-colors
+    ;; Our preference for setting either background or foreground
+    ;; styles, depending on `my-highlight-parentheses-use-background'.
+    (if my-highlight-parentheses-use-background
+
+        ;; Here we set color combinations that involve both a background
+        ;; and a foreground value.
+        (setq highlight-parentheses-background-colors (list cyan-refine-bg
+                                                            magenta-refine-bg
+                                                            green-refine-bg
+                                                            yellow-refine-bg)
+              highlight-parentheses-colors (list cyan-refine-fg
+                                                 magenta-refine-fg
+                                                 green-refine-fg
+                                                 yellow-refine-fg))
+
+      ;; And here we pass only foreground colors while disabling any
+      ;; backgrounds.
+      (setq highlight-parentheses-colors (list green-intense
+                                               magenta-intense
+                                               blue-intense
+                                               red-intense)
+            highlight-parentheses-background-colors nil)))
+
+;; Include this if you also want to make the parentheses bold:
+(set-face-attribute 'highlight-parentheses-highlight nil :inherit 'bold)
+
+;; Our changes must be evaluated before enabling the relevant mode, so
+;; this comes last.
+(global-highlight-parentheses-mode 1)
+#+end_src
+
+For our changes to persist while switching between the Modus themes, we
+need to include them in a function which can then get passed to
+~modus-themes-after-load-theme-hook~.  This is the complete
+implementation:
+
+#+begin_src emacs-lisp
+;; Configurations for `highlight-parentheses':
+(require 'highlight-parentheses)
+
+(defvar my-highlight-parentheses-use-background t
+  "Prefer `highlight-parentheses-background-colors'.")
+
+(setq my-highlight-parentheses-use-background nil) ; Set to nil to disable 
backgrounds
+
+(defun my-modus-themes-highlight-parentheses ()
+  (modus-themes-with-colors
+    ;; Our preference for setting either background or foreground
+    ;; styles, depending on `my-highlight-parentheses-use-background'.
+    (if my-highlight-parentheses-use-background
+
+        ;; Here we set color combinations that involve both a background
+        ;; and a foreground value.
+        (setq highlight-parentheses-background-colors (list cyan-refine-bg
+                                                            magenta-refine-bg
+                                                            green-refine-bg
+                                                            yellow-refine-bg)
+              highlight-parentheses-colors (list cyan-refine-fg
+                                                 magenta-refine-fg
+                                                 green-refine-fg
+                                                 yellow-refine-fg))
+
+      ;; And here we pass only foreground colors while disabling any
+      ;; backgrounds.
+      (setq highlight-parentheses-colors (list green-intense
+                                               magenta-intense
+                                               blue-intense
+                                               red-intense)
+            highlight-parentheses-background-colors nil)))
+
+  ;; Include this if you also want to make the parentheses bold:
+  (set-face-attribute 'highlight-parentheses-highlight nil :inherit 'bold)
+
+  ;; Our changes must be evaluated before enabling the relevant mode, so
+  ;; this comes last.
+  (global-highlight-parentheses-mode 1))
+
+(add-hook 'modus-themes-after-load-theme-hook 
#'my-modus-themes-highlight-parentheses)
+#+end_src
+
 ** Note on mmm-mode.el background colors
 :properties:
 :custom_id: h:99cf0d6c-e478-4e26-9932-3bf3427d13f6
@@ -3520,7 +3728,7 @@ With 8 colors:
   :desaturations '(0) ; do not change---may lower the contrast ratio
   :lightens '(0)      ; same
   :colors (modus-themes-with-colors
-            (list fg-special-cold
+            (list blue
                   magenta
                   magenta-alt-other
                   cyan-alt-other
@@ -3540,10 +3748,10 @@ to the themes' default aesthetic:
   :desaturations '(0) ; do not change---may lower the contrast ratio
   :lightens '(0)      ; same
   :colors (modus-themes-with-colors
-            (list fg-main
-                  cyan-alt-other
+            (list blue
+                  magenta
                   magenta-alt-other
-                  magenta)))
+                  green-alt)))
 #+end_src
 
 If you need to apply desaturation and lightening, you can use what the
@@ -3958,7 +4166,7 @@ latter case.
 ~modus-operandi~ is best used outdoors or in a room that either gets
 direct sunlight or has plenty of light.  Whereas ~modus-vivendi~ works
 better when there is not a lot of sunshine or the room has a source of
-light, preferably a faint or warm one.  It is possible to use
+light that is preferably a faint and/or warm one.  It is possible to use
 ~modus-operandi~ at night and ~modus-vivendi~ during the day, though that
 will depend on several variables, such as one's overall perception of
 color, the paint on the walls and how that contributes to the impression
@@ -4005,9 +4213,7 @@ in which you can contribute to their ongoing development.
 :end:
 #+cindex: Sources of the themes
 
-The ~modus-operandi~ and ~modus-vivendi~ themes are built into Emacs.
-Currently they are in Emacs' git main branch (trunk), which is tracking
-the next development release target.
+The ~modus-operandi~ and ~modus-vivendi~ themes are built into Emacs 28.
 
 The source code of the themes is 
[[https://gitlab.com/protesilaos/modus-themes/][available on Gitlab]], for the 
time
 being.  A [[https://github.com/protesilaos/modus-themes/][mirror on Github]] 
is also on offer.
@@ -4118,31 +4324,31 @@ The Modus themes are a collective effort.  Every bit of 
work matters.
 
 + Contributions to code or documentation :: Anders Johansson, Basil
   L.{{{space()}}} Contovounesios, Carlo Zancanaro, Eli Zaretskii, Fritz Grabo,
-  Kostadin Ninev, Madhavan Krishnan, Markus Beppler, Matthew Stevenson,
-  Mauro Aranda, Nicolas De Jaeghere, Philip Kaludercic, Rudolf
-  Adamkovič, Shreyas Ragavan, Stefan Kangas, Vincent Murphy, Xinglu
-  Chen.
-
-+ Ideas and user feedback :: Aaron Jensen, Adam Spiers, Adrian Manea,
-  Alex Griffin, Alex Peitsinis, Alexey Shmalko, Alok Singh, Anders
-  Johansson, André Alexandre Gomes, Arif Rezai, Basil L.{{{space()}}}
-  Contovounesios, Burgess Chang, Christian Tietze, Christopher Dimech,
-  Damien Cassou, Daniel Mendler, Dario Gjorgjevski, David Edmondson,
-  Davor Rotim, Divan Santana, Emanuele Michele Alberto Monterosso,
-  Farasha Euker, Gautier Ponsinet, Gerry Agbobada, Gianluca Recchia,
-  Gustavo Barros, Hörmetjan Yiltiz, Ilja Kocken, Iris Garcia, Jeremy
-  Friesen, Jerry Zhang, John Haman, Joshua O'Connor, Kevin Fleming,
-  Kévin Le Gouguec, Kostadin Ninev, Len Trigg, Manuel Uberti, Mark
-  Burton, Markus Beppler, Mauro Aranda, Michael Goldenberg, Morgan
-  Smith, Murilo Pereira, Nicky van Foreest, Nicolas De Jaeghere, Paul
-  Poloskov, Pengji Zhang, Pete Kazmier, Peter Wu, Philip Kaludercic,
-  Pierre Téchoueyres, Roman Rudakov, Ryan Phillips, Rudolf Adamkovič,
-  Sam Kleinman, Shreyas Ragavan, Simon Pugnet, Tassilo Horn, Thibaut
-  Verron, Thomas Heartman, Trey Merkley, Togan Muftuoglu, Toon Claes,
-  Uri Sharf, Utkarsh Singh, Vincent Foley.  As well as users: Ben,
-  CsBigDataHub1, Emacs Contrib, Eugene, Fourchaux, Fredrik, Moesasji,
-  Nick, TheBlob42, Trey, bepolymathe, doolio, fleimgruber, iSeeU,
-  jixiuf, okamsn, pRot0ta1p.
+  Kévin Le Gouguec, Kostadin Ninev, Madhavan Krishnan, Markus Beppler,
+  Matthew Stevenson, Mauro Aranda, Nicolas De Jaeghere, Philip
+  Kaludercic, Rudolf Adamkovič, Stephen Gildea, Shreyas Ragavan, Stefan
+  Kangas, Vincent Murphy, Xinglu Chen.
+
++ Ideas and user feedback :: Aaron Jensen, Adam Porter, Adam Spiers,
+  Adrian Manea, Alex Griffin, Alex Peitsinis, Alexey Shmalko, Alok
+  Singh, Anders Johansson, André Alexandre Gomes, Arif Rezai, Basil
+  L.{{{space()}}} Contovounesios, Burgess Chang, Christian Tietze, Christopher
+  Dimech, Damien Cassou, Daniel Mendler, Dario Gjorgjevski, David
+  Edmondson, Davor Rotim, Divan Santana, Eliraz Kedmi, Emanuele Michele
+  Alberto Monterosso, Farasha Euker, Feng Shu, Gautier Ponsinet, Gerry
+  Agbobada, Gianluca Recchia, Gustavo Barros, Hörmetjan Yiltiz, Ilja
+  Kocken, Iris Garcia, Jeremy Friesen, Jerry Zhang, John Haman, Joshua
+  O'Connor, Kevin Fleming, Kévin Le Gouguec, Kostadin Ninev, Len Trigg,
+  Manuel Uberti, Mark Burton, Markus Beppler, Mauro Aranda, Michael
+  Goldenberg, Morgan Smith, Murilo Pereira, Nicky van Foreest, Nicolas
+  De Jaeghere, Paul Poloskov, Pengji Zhang, Pete Kazmier, Peter Wu,
+  Philip Kaludercic, Pierre Téchoueyres, Roman Rudakov, Ryan Phillips,
+  Rudolf Adamkovič, Sam Kleinman, Shreyas Ragavan, Simon Pugnet, Tassilo
+  Horn, Thibaut Verron, Thomas Heartman, Trey Merkley, Togan Muftuoglu,
+  Toon Claes, Uri Sharf, Utkarsh Singh, Vincent Foley.  As well as
+  users: Ben, CsBigDataHub1, Emacs Contrib, Eugene, Fourchaux, Fredrik,
+  Moesasji, Nick, TheBlob42, Trey, bepolymathe, doolio, fleimgruber,
+  iSeeU, jixiuf, okamsn, pRot0ta1p.
 
 + Packaging :: Basil L.{{{space()}}} Contovounesios, Eli Zaretskii, Glenn
   Morris, Mauro Aranda, Richard Stallman, Stefan Kangas (core Emacs),
@@ -4178,6 +4384,7 @@ of this sort):
 + 
[[https://protesilaos.com/codelog/2020-12-27-modus-themes-review-rainbow-delimiters/][Modus
 themes: review rainbow-delimiters faces]] (2020-12-27)
 + 
[[https://protesilaos.com/codelog/2021-01-11-modus-themes-review-select-faint-colours/][Modus
 themes: review of select "faint" colours]] (2021-01-11)
 + 
[[https://protesilaos.com/codelog/2021-02-25-modus-themes-diffs-deuteranopia/][The
 Modus themes now cover deuteranopia in diffs]] (2021-02-25)
++ 
[[https://protesilaos.com/codelog/2021-06-02-modus-themes-org-agenda/][Introducing
 the variable modus-themes-org-agenda]] (2021-06-02)
 
 And here are the canonical sources of this project's documentation:
 
diff --git a/doc/misc/org.org b/doc/misc/org.org
index f072b5e00e..17fd2dc39f 100644
--- a/doc/misc/org.org
+++ b/doc/misc/org.org
@@ -82,11 +82,8 @@ probably do not need to install it.  Most users will simply 
activate
 Org and begin exploring its many features.
 
 If, for one reason or another, you want to install Org on top of this
-pre-packaged version, there are three ways to do it:
-
-- by using the Emacs package system;
-- by downloading Org as an archive; or
-- by using Org's git repository.
+pre-packaged version, you can use the Emacs package system or clone
+Org's git repository.
 
 We *strongly recommend* sticking to a single installation method.
 
@@ -106,32 +103,6 @@ visited, i.e., where no Org built-in function have been 
loaded.
 Otherwise autoload Org functions will mess up the installation.
 #+end_quote
 
-If you want to use Org's package repository, check out the 
[[https://orgmode.org/elpa.html][Org ELPA
-page]].
-
-*** Downloading Org as an archive
-:PROPERTIES:
-:UNNUMBERED: notoc
-:END:
-
-You can download Org latest release from [[https://orgmode.org/][Org's 
website]].  In this case,
-make sure you set the load path correctly in your Emacs init file:
-
-#+begin_src emacs-lisp
-(add-to-list 'load-path "~/path/to/orgdir/lisp")
-#+end_src
-
-The downloaded archive contains contributed libraries that are not
-included in Emacs.  If you want to use them, add the =contrib/=
-directory to your load path:
-
-#+begin_src emacs-lisp
-(add-to-list 'load-path "~/path/to/orgdir/contrib/lisp" t)
-#+end_src
-
-Optionally, you can compile the files and/or install them in your
-system.  Run =make help= to list compilation and installation options.
-
 *** Using Org's git repository
 :PROPERTIES:
 :UNNUMBERED: notoc
@@ -141,7 +112,7 @@ You can clone Org's repository and install Org like this:
 
 #+begin_example
 $ cd ~/src/
-$ git clone https://code.orgmode.org/bzg/org-mode.git
+$ git clone https://git.savannah.gnu.org/git/emacs/org-mode.git
 $ cd org-mode/
 $ make autoloads
 #+end_example
@@ -161,6 +132,16 @@ list of compilation/installation options.
 For more detailed explanations on Org's build system, please check the
 Org Build System page on 
[[https://orgmode.org/worg/dev/org-build-system.html][Worg]].
 
+*** Installing Org's contributed packages
+:PROPERTIES:
+:UNNUMBERED: notoc
+:END:
+
+Org's repository used to contain =contrib/= directory for add-ons
+contributed by others.  As of Org 9.5, the directory has bee moved to
+this new dedicated [[https://git.sr.ht/~bzg/org-contrib][org-contrib]] 
repository, which you can install
+separately.
+
 ** Activation
 :PROPERTIES:
 :DESCRIPTION: How to activate Org for certain buffers.
@@ -189,9 +170,9 @@ to globally available keys, like the ones reserved for 
users (see
 please modify the keys to your own liking.
 
 #+begin_src emacs-lisp
-(global-set-key (kbd "C-c l") 'org-store-link)
-(global-set-key (kbd "C-c a") 'org-agenda)
-(global-set-key (kbd "C-c c") 'org-capture)
+(global-set-key (kbd "C-c l") #'org-store-link)
+(global-set-key (kbd "C-c a") #'org-agenda)
+(global-set-key (kbd "C-c c") #'org-capture)
 #+end_src
 
 #+cindex: Org mode, turning on
@@ -273,7 +254,6 @@ shown below.
 
 ;; Add latest Org mode to load path.
 (add-to-list 'load-path (expand-file-name "/path/to/org-mode/lisp"))
-(add-to-list 'load-path (expand-file-name "/path/to/org-mode/contrib/lisp" t))
 #+end_src
 
 If an error occurs, a "backtrace" can be very useful---see below on
@@ -344,7 +324,7 @@ conventions:
 
 - =boss=, =ARCHIVE= ::
 
-  Tags are case-sensitive.  User-defined tags are written in
+  Tags are case-sensitive.  User-defined tags are usually written in
   lowercase; built-in tags with special meaning are written as they
   should appear in the document, usually with all capitals.
 
@@ -577,6 +557,10 @@ buffer:
 ,#+STARTUP: overview
 ,#+STARTUP: content
 ,#+STARTUP: showall
+,#+STARTUP: show2levels
+,#+STARTUP: show3levels
+,#+STARTUP: show4levels
+,#+STARTUP: show5levels
 ,#+STARTUP: showeverything
 #+end_example
 
@@ -656,10 +640,10 @@ The following commands jump to other headlines in the 
buffer.
   where you can use the following keys to find your destination:
 
   #+attr_texinfo: :columns 0.3 0.7
-  | {{{kbd(TAB)}}}                  | Cycle visibility.               |
+  | {{{kbd(TAB)}}}            | Cycle visibility.               |
   | {{{kbd(DOWN)}}} / {{{kbd(UP)}}} | Next/previous visible headline. |
-  | {{{kbd(RET)}}}                  | Select this location.           |
-  | {{{kbd(/)}}}                    | Do a Sparse-tree search         |
+  | {{{kbd(RET)}}}            | Select this location.           |
+  | {{{kbd(/)}}}              | Do a Sparse-tree search         |
 
   #+texinfo: @noindent
   The following keys work if you turn off ~org-goto-auto-isearch~
@@ -667,9 +651,9 @@ The following commands jump to other headlines in the 
buffer.
   #+attr_texinfo: :columns 0.3 0.7
   | {{{kbd(n)}}} / {{{kbd(p)}}}   | Next/previous visible headline.    |
   | {{{kbd(f)}}} / {{{kbd(b)}}}   | Next/previous headline same level. |
-  | {{{kbd(u)}}}                  | One level up.                      |
+  | {{{kbd(u)}}}            | One level up.                      |
   | {{{kbd(0)}}} ... {{{kbd(9)}}} | Digit argument.                    |
-  | {{{kbd(q)}}}                  | Quit.                              |
+  | {{{kbd(q)}}}            | Quit.                              |
 
   #+vindex: org-goto-interface
   #+texinfo: @noindent
@@ -932,16 +916,16 @@ commands can be accessed through a dispatcher:
   #+kindex: C-c / /
   #+findex: org-occur
   #+vindex: org-remove-highlights-with-change
-  Prompts for a regexp and shows a sparse tree with all matches.  If
-  the match is in a headline, the headline is made visible.  If the
-  match is in the body of an entry, headline and body are made
-  visible.  In order to provide minimal context, also the full
-  hierarchy of headlines above the match is shown, as well as the
-  headline following the match.  Each match is also highlighted; the
-  highlights disappear when the buffer is changed by an editing
-  command, or by pressing {{{kbd(C-c C-c)}}}[fn:8].  When called with
-  a {{{kbd(C-u)}}} prefix argument, previous highlights are kept, so
-  several calls to this command can be stacked.
+  Prompts for a regexp (see [[*Regular Expressions]]) and shows a sparse
+  tree with all matches.  If the match is in a headline, the headline
+  is made visible.  If the match is in the body of an entry, headline
+  and body are made visible.  In order to provide minimal context,
+  also the full hierarchy of headlines above the match is shown, as
+  well as the headline following the match.  Each match is also
+  highlighted; the highlights disappear when the buffer is changed by
+  an editing command, or by pressing {{{kbd(C-c C-c)}}}[fn:8].  When
+  called with a {{{kbd(C-u)}}} prefix argument, previous highlights
+  are kept, so several calls to this command can be stacked.
 
 - {{{kbd(M-g n)}}} or {{{kbd(M-g M-n)}}} (~next-error~) ::
 
@@ -1371,9 +1355,8 @@ you, configure the option ~org-table-auto-blank-field~.
   Re-align the table, move to the next field.  Creates a new row if
   necessary.
 
-- {{{kbd(C-c SPC)}}} (~org-table-blank-field~) ::
+- {{{kbd(M-x org-table-blank-field)}}} ::
 
-  #+kindex: C-c SPC
   #+findex: org-table-blank-field
   Blank the field at point.
 
@@ -1805,7 +1788,7 @@ mode with {{{kbd(M-x orgtbl-mode)}}}.  To turn it on by 
default, for
 example in Message mode, use
 
 #+begin_src emacs-lisp
-(add-hook 'message-mode-hook 'turn-on-orgtbl)
+(add-hook 'message-mode-hook #'turn-on-orgtbl)
 #+end_src
 
 Furthermore, with some special setup, it is possible to maintain
@@ -2074,6 +2057,14 @@ variable ~org-calc-default-modes~.
 
   Fraction and symbolic modes of Calc.
 
+- =u= ::
+
+  Units simplification mode of Calc.  Calc is also a symbolic
+  calculator and is capable of working with values having a unit,
+  represented with numerals followed by a unit string in Org table
+  cells.  This mode instructs Calc to simplify the units in the
+  computed expression before returning the result.
+
 - =T=, =t=, =U= ::
 
   Duration computations in Calc or Lisp, [[*Durations and time values]].
@@ -2169,38 +2160,54 @@ It is also possible to write a formula in Emacs Lisp.  
This can be
 useful for string manipulation and control structures, if Calc's
 functionality is not enough.
 
-If a formula starts with a single-quote followed by an opening
-parenthesis, then it is evaluated as a Lisp form.  The evaluation
-should return either a string or a number.  Just as with Calc
-formulas, you can specify modes and a ~printf~ format after
-a semicolon.
+A formula is evaluated as a Lisp form when it starts with a
+single-quote followed by an opening parenthesis.  Cell table
+references are interpolated into the Lisp form before execution.  The
+evaluation should return either a string or a number.  Evaluation
+modes and a ~printf~ format used to render the returned values can be
+specified after a semicolon.
+
+By default, references are interpolated as literal Lisp strings: the
+field content is replaced in the Lisp form stripped of leading and
+trailing white space and surrounded in double-quotes.  For example:
 
-With Emacs Lisp forms, you need to be conscious about the way field
-references are interpolated into the form.  By default, a reference is
-interpolated as a Lisp string (in double-quotes) containing the field.
-If you provide the =N= mode switch, all referenced elements are
-numbers---non-number fields will be zero---and interpolated as Lisp
-numbers, without quotes.  If you provide the =L= flag, all fields are
-interpolated literally, without quotes.  For example, if you want a
-reference to be interpreted as a string by the Lisp form, enclose the
-reference operator itself in double-quotes, like ="$3"=.  Ranges are
-inserted as space-separated fields, so you can embed them in list or
-vector syntax.
+: '(concat $1 $2)
 
-Here are a few examples---note how the =N= mode is used when we do
-computations in Lisp:
+#+texinfo: @noindent
+concatenates the content of columns 1 and column 2.
 
-- ='(concat (substring $1 1 2) (substring $1 0 1) (substring $1 2))= ::
+When the =N= flag is used, all referenced elements are parsed as
+numbers and interpolated as Lisp numbers, without quotes.  Fields that
+cannot be parsed as numbers are interpolated as zeros.  For example:
 
-  Swap the first two characters of the content of column 1.
+: '(+ $1 $2);N
 
-- ='(+ $1 $2);N= ::
+#+texinfo: @noindent
+adds columns 1 and 2, equivalent to Calc's =$1+$2=.  Ranges are
+inserted as space-separated fields, so they can be embedded in list or
+vector syntax.  For example:
 
-  Add columns 1 and 2, equivalent to Calc's =$1+$2=.
+: '(apply '+ '($1..$4));N
 
-- ='(apply '+ '($1..$4));N= ::
+#+texinfo: @noindent
+computes the sum of columns 1 to 4, like Calc's =vsum($1..$4)=.
+
+When the =L= flag is used, all fields are interpolated literally: the
+cell content is replaced in the Lisp form stripped of leading and
+trailing white space and without quotes.  If a reference is intended
+to be interpreted as a string by the Lisp form, the reference operator
+itself should be enclosed in double-quotes, like ="$3"=.  The =L= flag
+is useful when strings and numbers are used in the same Lisp form.  For
+example:
 
-  Compute the sum of columns 1 to 4, like Calc's =vsum($1..$4)=.
+: '(substring "$1" $2 $3);L
+
+#+texinfo: @noindent
+extracts the part of the string in column 1 between the character
+positions specified in the integers in column 2 and 3 and it is easier
+to read than the equivalent:
+
+: '(substring $1 (string-to-number $2) (string-to-number $3))
 
 *** Durations and time values
 :PROPERTIES:
@@ -2797,7 +2804,7 @@ either graphically or in ASCII art.
 
 #+cindex: @samp{PLOT}, keyword
 Org Plot can produce 2D and 3D graphs of information stored in Org
-tables using [[http://www.gnuplot.info/][Gnuplot]] and 
[[http://cars9.uchicago.edu/~ravel/software/gnuplot-mode.html][Gnuplot mode]].  
To see this in action, ensure
+tables using [[https://www.gnuplot.info/][Gnuplot]] and 
[[http://cars9.uchicago.edu/~ravel/software/gnuplot-mode.html][Gnuplot mode]].  
To see this in action, ensure
 that you have both Gnuplot and Gnuplot mode installed on your system,
 then call {{{kbd(C-c \quot g)}}} or {{{kbd(M-x org-plot/gnuplot)}}} on the
 following table.
@@ -2813,6 +2820,19 @@ following table.
 | Morelia   |    257.56 |   17.67 |
 #+end_example
 
+Org Plot supports a range of plot types, and provides the ability to add more.
+For example, a radar plot can be generated like so:
+#+begin_example
+,#+PLOT: title:"An evaluation of plaintext document formats" transpose:yes 
type:radar min:0 max:4
+| Format            | Fine-grained-control | Initial Effort | Syntax 
simplicity | Editor Support | Integrations | Ease-of-referencing | Versatility |
+|-------------------+----------------------+----------------+-------------------+----------------+--------------+---------------------+-------------|
+| Word              |                    2 |              4 |                 
4 |              2 |            3 |                   2 |           2 |
+| LaTeX             |                    4 |              1 |                 
1 |              3 |            2 |                   4 |           3 |
+| Org Mode          |                    4 |              2 |               
3.5 |              1 |            4 |                   4 |           4 |
+| Markdown          |                    1 |              3 |                 
3 |              4 |            3 |                   3 |           1 |
+| Markdown + Pandoc |                  2.5 |            2.5 |               
2.5 |              3 |            3 |                   3 |           2 |
+#+end_example
+
 Notice that Org Plot is smart enough to apply the table's headers as
 labels.  Further control over the labels, type, content, and
 appearance of plots can be exercised through the =PLOT= keyword
@@ -2843,9 +2863,15 @@ For more information and examples see the 
[[https://orgmode.org/worg/org-tutoria
   the third and fourth columns.  Defaults to graphing all other
   columns aside from the =ind= column.
 
+- transpose ::
+
+  When =y=, =yes=, or =t= attempt to transpose the table data before
+  plotting.  Also recognises the shorthand option =trans=.
+
 - =type= ::
 
-  Specify whether the plot is =2d=, =3d=, or =grid=.
+  Specify the type of the plot, by default one of  =2d=, =3d=, =radar=, or 
=grid=.
+  Available types can be customised with ~org-plot/preset-plot-types~.
 
 - =with= ::
 
@@ -2872,6 +2898,27 @@ For more information and examples see the 
[[https://orgmode.org/worg/org-tutoria
   When plotting =3d= or =grid= types, set this to =t= to graph a flat
   mapping rather than a =3d= slope.
 
+- min ::
+
+  Provides a minimum axis value that may be used by a plot type.
+  Implicitly assumes the =y= axis is being referred to.  Can
+  explicitly provide a value for a either the =x= or =y= axis with
+  =xmin= and =ymin=.
+
+- max ::
+
+  Provides a maximum axis value that may be used by a plot type.
+  Implicitly assumes the =y= axis is being referred to.  Can
+  explicitly provide a value for a either the =x= or =y= axis with
+  =xmax= and =ymax=.
+
+- ticks ::
+
+  Provides a desired number of axis ticks to display, that may be used
+  by a plot type.  If none is given a plot type that requires ticks
+  will use ~org--plot/sensible-tick-num~ to try to determine a good
+  value.
+
 - =timefmt= ::
 
   Specify format of Org mode timestamps as they will be parsed by
@@ -3113,14 +3160,14 @@ Here is the full set of built-in link types:
 
 - =file= ::
 
-   File links.  File name may be remote, absolute, or relative.
+  File links.  File name may be remote, absolute, or relative.
 
-   Additionally, you can specify a line number, or a text search.
-   In Org files, you may link to a headline name, a custom ID, or a
-   code reference instead.
+  Additionally, you can specify a line number, or a text search.
+  In Org files, you may link to a headline name, a custom ID, or a
+  code reference instead.
 
-   As a special case, "file" prefix may be omitted if the file name
-   is complete, e.g., it starts with =./=, or =/=.
+  As a special case, "file" prefix may be omitted if the file name
+  is complete, e.g., it starts with =./=, or =/=.
 
 - =attachment= ::
 
@@ -3224,9 +3271,10 @@ options:
 #+cindex: VM links
 #+cindex: Wanderlust links
 On top of these built-in link types, additional ones are available
-through the =contrib/= directory (see [[*Installation]]).  For example,
-these links to VM or Wanderlust messages are available when you load
-the corresponding libraries from the =contrib/= directory:
+through the =org-contrib= repository (see [[*Installation]]).  For
+example, these links to VM or Wanderlust messages are available when
+you load the corresponding libraries from the =org-contrib=
+repository:
 
 | =vm:folder=                            | VM folder link          |
 | =vm:folder#id=                         | VM message link         |
@@ -3291,8 +3339,9 @@ current buffer:
   =ID= property for the link[fn:29].  So using this command in Org
   buffers potentially creates two links: a human-readable link from
   the custom ID, and one that is globally unique and works even if the
-  entry is moved from file to file.  Later, when inserting the link,
-  you need to decide which one to use.
+  entry is moved from file to file.  The =ID= property can be either a
+  UUID (default) or a timestamp, depending on ~org-id-method~.  Later,
+  when inserting the link, you need to decide which one to use.
 
 - /Email/News clients: VM, Rmail, Wanderlust, MH-E, Gnus/ ::
 
@@ -3474,8 +3523,8 @@ generally, act on links.
 
   #+begin_src emacs-lisp
   (with-eval-after-load 'org
-    (define-key org-mode-map (kbd "M-n") 'org-next-link)
-    (define-key org-mode-map (kbd "M-p") 'org-previous-link))
+    (define-key org-mode-map (kbd "M-n") #'org-next-link)
+    (define-key org-mode-map (kbd "M-p") #'org-previous-link))
   #+end_src
 
 ** Using Links Outside Org
@@ -3516,7 +3565,7 @@ replacement text.  Here is an example:
 #+begin_src emacs-lisp
 (setq org-link-abbrev-alist
       '(("bugzilla"        . "http://10.1.2.9/bugzilla/show_bug.cgi?id=";)
-        ("Nu Html Checker" . "https://validator.w3.org/nu/?doc=%h";) 
+        ("Nu Html Checker" . "https://validator.w3.org/nu/?doc=%h";)
        ("duckduckgo"      . "https://duckduckgo.com/?q=%s";)
         ("omap"            . 
"http://nominatim.openstreetmap.org/search?q=%s&polygon=1";)
         ("ads"             . 
"https://ui.adsabs.harvard.edu/search/q=%20author%3A\"%s\"";)))
@@ -3616,10 +3665,10 @@ link, together with explanations for each:
 
 - =/REGEXP/= ::
 
-  Do a regular expression search for {{{var(REGEXP)}}}.  This uses the
-  Emacs command ~occur~ to list all matches in a separate window.  If
-  the target file is in Org mode, ~org-occur~ is used to create
-  a sparse tree with the matches.
+  Do a regular expression search for {{{var(REGEXP)}}} (see [[*Regular
+  Expressions]]).  This uses the Emacs command ~occur~ to list all
+  matches in a separate window.  If the target file is in Org mode,
+  ~org-occur~ is used to create a sparse tree with the matches.
 
 As a degenerate case, a file link with an empty file name can be used
 to search the current file.  For example, =[[file:::find me]]= does
@@ -3944,9 +3993,9 @@ interpretation, but it means the same as =#+TODO=, or
 A setup for using several sets in parallel would be:
 
 #+begin_example
-,#+TODO: TODO | DONE
-,#+TODO: REPORT BUG KNOWNCAUSE | FIXED
-,#+TODO: | CANCELED
+,#+TODO: TODO(t) | DONE(d)
+,#+TODO: REPORT(r) BUG(b) KNOWNCAUSE(k) | FIXED(f)
+,#+TODO: | CANCELED(c)
 #+end_example
 
 #+cindex: completion, of option keywords
@@ -4070,7 +4119,7 @@ checkboxes is blocked from switching to DONE.
 
 If you need more complex dependency structures, for example
 dependencies between entries in different trees or files, check out
-the contributed module =org-depend.el=.
+the module =org-depend.el= in the =org-contrib= repository.
 
 ** Progress Logging
 :PROPERTIES:
@@ -4158,10 +4207,6 @@ example, with the setting
       '((sequence "TODO(t)" "WAIT(w@/!)" "|" "DONE(d!)" "CANCELED(c@)")))
 #+end_src
 
-#+texinfo: @noindent
-To record a timestamp without a note for TODO keywords configured with
-=@=, just type {{{kbd(C-c C-c)}}} to enter a blank note when prompted.
-
 #+vindex: org-log-done
 You not only define global TODO keywords and fast access keys, but
 also request that a time is recorded when the entry is set to =DONE=,
@@ -4181,6 +4226,9 @@ to a buffer:
 
 : #+TODO: TODO(t) WAIT(w@/!) | DONE(d!) CANCELED(c@)
 
+To record a timestamp without a note for TODO keywords configured with
+=@=, just type {{{kbd(C-c C-c)}}} to enter a blank note when prompted.
+
 #+cindex: @samp{LOGGING}, property
 In order to define logging settings that are local to a subtree or
 a single item, define a =LOGGING= property in this entry.  Any
@@ -4443,7 +4491,7 @@ all children are done, you can use the following setup:
   (let (org-log-done org-log-states)   ; turn off logging
     (org-todo (if (= n-not-done 0) "DONE" "TODO"))))
 
-(add-hook 'org-after-todo-statistics-hook 'org-summary-todo)
+(add-hook 'org-after-todo-statistics-hook #'org-summary-todo)
 #+end_src
 
 Another possibility is the use of checkboxes to identify (a hierarchy
@@ -4794,9 +4842,10 @@ In this interface, you can also use the following 
special keys:
 
   #+kindex: TAB
   Enter a tag in the minibuffer, even if the tag is not in the
-  predefined list.  You can complete on all tags present in the
-  buffer.  You can also add several tags: just separate them with
-  a comma.
+  predefined list.  You can complete on all tags present in the buffer
+  and globally pre-defined tags from ~org-tag-alist~ and
+  ~org-tag-persistent-alist~.  You can also add several tags: just
+  separate them with a comma.
 
 - {{{kbd(SPC)}}} ::
 
@@ -4931,8 +4980,9 @@ mutually exclusive.
 
 Furthermore, the members of a group tag can also be regular
 expressions, creating the possibility of a more dynamic and rule-based
-tag structure.  The regular expressions in the group must be specified
-within curly brackets.  Here is an expanded example:
+tag structure (see [[*Regular Expressions]]).  The regular expressions in
+the group must be specified within curly brackets.  Here is an
+expanded example:
 
 #+begin_example
 ,#+TAGS: [ Vision : {V@.+} ]
@@ -5274,7 +5324,7 @@ single property:
   tree is created with all entries that define this property with the
   given value.  If you enclose the value in curly braces, it is
   interpreted as a regular expression and matched against the property
-  values.
+  values (see [[*Regular Expressions]]).
 
 ** Property Inheritance
 :PROPERTIES:
@@ -5737,8 +5787,8 @@ block.  If there is a =TBLFM= keyword after the table, 
the table is
 recalculated automatically after an update.
 
 An alternative way to capture and process property values into a table
-is provided by Eric Schulte's =org-collector.el=, which is
-a contributed package[fn:58].  It provides a general API to collect
+is provided by Eric Schulte's =org-collector.el=, which is a package
+in =org-contrib=[fn:58].  It provides a general API to collect
 properties from entries in a certain scope, and arbitrary Lisp
 expressions to process these values before inserting them into a table
 or a dynamic block.
@@ -6022,6 +6072,7 @@ dash(es) as the separator in the former case and use =+= 
as the
 separator in the latter case, e.g.:
 
 | =11am-1:15pm=  | \rArr{} 11:00-13:15   |
+| =11h-13h15=    | \rArr{} same as above |
 | =11am--1:15pm= | \rArr{} same as above |
 | =11am+2:15=    | \rArr{} same as above |
 
@@ -7197,6 +7248,16 @@ special command:
   Copying works like refiling, except that the original note is not
   deleted.
 
+- {{{kbd(C-c C-M-w)}}} (~org-refile-reverse~) ::
+
+  #+kindex: C-c C-M-w
+  #+findex: org-refile-reverse
+  Works like refiling, except that it temporarily toggles how the
+  value of ~org-reverse-note-order~ applies to the current buffer.  So
+  if ~org-refile~ would append the entry as the last entry under the
+  target header, ~org-refile-reverse~ will prepend it as the first
+  entry, and vice-versa.
+
 ** Archiving
 :PROPERTIES:
 :DESCRIPTION: What to do with finished products.
@@ -7746,6 +7807,9 @@ Now lets look at the elements of a template definition.  
Each entry in
 
     Do not save the target file after finishing the capture.
 
+  - ~:refile-targets :: Temporarily set ~org-refile-targets~ to the
+    value of this property.
+
 **** Template expansion
 :PROPERTIES:
 :DESCRIPTION: Filling in information about time and context.
@@ -7804,6 +7868,10 @@ here:
 
   Like =%a=, but only insert the literal link.
 
+- =%L= ::
+
+  Like =%l=, but without brackets (the link content itself).
+
 - =%c= ::
 
   Current kill ring head.
@@ -7859,7 +7927,8 @@ here:
 
 - =%^{PROP}p= ::
 
-  Prompt the user for a value for property {{{var(PROP)}}}.
+  Prompt the user for a value for property {{{var(PROP)}}}.  You may
+  specify a default value with =%^{PROP|default}=.
 
 - =%^{PROMPT}= ::
 
@@ -7912,7 +7981,7 @@ patches.  Then you would configure this option like this:
 
 #+begin_src emacs-lisp
 (setq org-capture-templates-contexts
-      '(("p" (in-mode . "message-mode"))))
+      '(("p" ((in-mode . "message-mode")))))
 #+end_src
 
 You can also tell that the command key {{{kbd(p)}}} should refer to
@@ -7920,7 +7989,7 @@ another template.  In that case, add this command key 
like this:
 
 #+begin_src emacs-lisp
 (setq org-capture-templates-contexts
-      '(("p" "q" (in-mode . "message-mode"))))
+      '(("p" "q" ((in-mode . "message-mode")))))
 #+end_src
 
 See the docstring of the variable for more information.
@@ -8199,7 +8268,7 @@ To make Org mode take care of versioning of attachments 
for you, add
 the following to your Emacs config:
 
 #+begin_src emacs-lisp
-  (require 'org-attach-git)
+(require 'org-attach-git)
 #+end_src
 
 *** Attach from Dired
@@ -8259,7 +8328,7 @@ variable has detailed information.  With the following
 #+begin_src emacs-lisp
 (setq org-feed-alist
       '(("Slashdot"
-         "http://rss.slashdot.org/Slashdot/slashdot";
+         "https://rss.slashdot.org/Slashdot/slashdot";
          "~/txt/org/feeds.org" "Slashdot Entries")))
 #+end_src
 
@@ -8847,8 +8916,9 @@ only tags.
 
 #+cindex: regular expressions, with tags search
 Instead of a tag, you may also specify a regular expression enclosed
-in curly braces.  For example, =work+{^boss.*}= matches headlines that
-contain the tag =:work:= and any tag /starting/ with =boss=.
+in curly braces (see [[*Regular Expressions]]).  For example,
+=work+{^boss.*}= matches headlines that contain the tag =:work:= and
+any tag /starting/ with =boss=.
 
 #+cindex: group tags, as regular expressions
 Group tags (see [[*Tag Hierarchy]]) are expanded as regular expressions.
@@ -8888,7 +8958,7 @@ to test the value of a property.  Here is a complex 
example:
 
 #+begin_example
 +work-boss+PRIORITY="A"+Coffee="unlimited"+Effort<2
-         +With={Sarah|Denny}+SCHEDULED>="<2008-10-11>"
+         +With={Sarah\|Denny}+SCHEDULED>="<2008-10-11>"
 #+end_example
 
 #+texinfo: @noindent
@@ -8918,7 +8988,7 @@ So the search string in the example finds entries tagged 
=work= but
 not =boss=, which also have a priority value =A=, a =Coffee= property
 with the value =unlimited=, an =EFFORT= property that is numerically
 smaller than 2, a =With= property that is matched by the regular
-expression =Sarah|Denny=, and that are scheduled on or after October
+expression =Sarah\|Denny=, and that are scheduled on or after October
 11, 2008.
 
 You can configure Org mode to use property inheritance during
@@ -9296,16 +9366,16 @@ filter elements are accumulated.
 
   selects entries with category =work= and effort estimates below 10
   minutes, and deselects entries with tag =John= or matching the
-  regexp =plot=.  You can leave =+= out if that does not lead to
-  ambiguities.  The sequence of elements is arbitrary.  The filter
-  syntax assumes that there is no overlap between categories and tags.
-  Otherwise, tags take priority.  If you reply to the prompt with the
-  empty string, all filtering is removed.  If a filter is specified,
-  it replaces all current filters.  But if you call the command with
-  a double prefix argument, or if you add an additional =+= (e.g.,
-  =++work=) to the front of the string, the new filter elements are
-  added to the active ones.  A single prefix argument applies the
-  entire filter in a negative sense.
+  regexp =plot= (see [[*Regular Expressions]]).  You can leave =+= out if
+  that does not lead to ambiguities.  The sequence of elements is
+  arbitrary.  The filter syntax assumes that there is no overlap
+  between categories and tags.  Otherwise, tags take priority.  If you
+  reply to the prompt with the empty string, all filtering is removed.
+  If a filter is specified, it replaces all current filters.  But if
+  you call the command with a double prefix argument, or if you add an
+  additional =+= (e.g., =++work=) to the front of the string, the new
+  filter elements are added to the active ones.  A single prefix
+  argument applies the entire filter in a negative sense.
 
 - {{{kbd(|)}}} (~org-agenda-filter-remove-all~) ::
 
@@ -10863,7 +10933,7 @@ pretty output for a number of export back-ends.
 Org mode can contain LaTeX math fragments, and it supports ways to
 process these for several export back-ends.  When exporting to LaTeX,
 the code is left as it is.  When exporting to HTML, Org can use either
-[[http://www.mathjax.org][MathJax]] (see [[*Math formatting in HTML export]]) 
or transcode the math
+[[https://www.mathjax.org][MathJax]] (see [[*Math formatting in HTML export]]) 
or transcode the math
 into images (see [[*Previewing LaTeX fragments]]).
 
 LaTeX fragments do not need any special marking at all.  The following
@@ -10968,7 +11038,7 @@ current buffer with {{{kbd(M-x org-cdlatex-mode)}}}, or 
for all Org
 files with
 
 #+begin_src emacs-lisp
-(add-hook 'org-mode-hook 'turn-on-org-cdlatex)
+(add-hook 'org-mode-hook #'turn-on-org-cdlatex)
 #+end_src
 
 When this mode is enabled, the following features are present (for
@@ -11304,7 +11374,7 @@ The following command handles footnotes:
   #+attr_texinfo: :columns 0.1 0.9
   | {{{kbd(s)}}} | Sort the footnote definitions by reference sequence.        
       |
   | {{{kbd(r)}}} | Renumber the simple =fn:N= footnotes.                       
       |
-  | {{{kbd(S)}}} | Short for first {{{kbd(r)}}}, then {{{kbd(s)}}} action.     
       |
+  | {{{kbd(S)}}} | Short for first {{{kbd(r)}}}, then {{{kbd(s)}}} action.     
                   |
   | {{{kbd(n)}}} | Rename all footnotes into a =fn:1= ... =fn:n= sequence.     
       |
   | {{{kbd(d)}}} | Delete the footnote at point, including definition and 
references. |
 
@@ -11361,7 +11431,7 @@ Users can install libraries for additional formats from 
the Emacs
 packaging system.  For easy discovery, these packages have a common
 naming scheme: ~ox-NAME~, where {{{var(NAME)}}} is a format.  For
 example, ~ox-koma-letter~ for /koma-letter/ back-end.  More libraries
-can be found in the =contrib/= directory (see [[*Installation]]).
+can be found in the =org-contrib= repository (see [[*Installation]]).
 
 #+vindex: org-export-backends
 Org only loads back-ends for the following formats by default: ASCII,
@@ -11452,7 +11522,7 @@ further alter what is exported, and how.
 
   Toggle visible-only export.  This is useful for exporting only
   certain parts of an Org document by adjusting the visibility of
-  particular headings.
+  particular headings.  See also [[*Sparse Trees]].
 
 ** Export Settings
 :PROPERTIES:
@@ -11961,7 +12031,7 @@ example
 #+texinfo: @noindent
 becomes
 
-: Rose is red, violet's blue. Life's ordered: Org assists you.
+: Rose is red, violet's blue.  Life's ordered: Org assists you.
 
 As a special case, Org parses any replacement text starting with
 =(eval= as an Emacs Lisp expression and evaluates it accordingly.
@@ -12527,7 +12597,7 @@ compatible with XHTML 1.0 strict standard.
   #+findex: org-html-export-to-html
 
   Export as HTML file with a =.html= extension.  For =myfile.org=, Org
-  exports to =myfile.html=, overwriting without warning.  {{{kbd{C-c
+  exports to =myfile.html=, overwriting without warning.  {{{kbd(C-c
   C-e h o)}}} exports to HTML and opens it in a web browser.
 
 - {{{kbd(C-c C-e h H)}}} (~org-html-export-as-html~) ::
@@ -12552,6 +12622,9 @@ settings described in [[*Export Settings]].
   multiple =DESCRIPTION= lines.  The exporter takes care of wrapping
   the lines properly.
 
+  The exporter includes a number of other meta tags, which can be customized
+  by modifying ~org-html-meta-tags~.
+
 - =HTML_DOCTYPE= ::
 
   #+cindex: @samp{HTML_DOCTYPE}, keyword
@@ -12693,8 +12766,8 @@ exports to:
 #+begin_src html
 <video controls="controls" width="350">
   <source src="movie.mp4" type="video/mp4">
-    <source src="movie.ogg" type="video/ogg">
-      <p>Your browser does not support the video tag.</p>
+  <source src="movie.ogg" type="video/ogg">
+  <p>Your browser does not support the video tag.</p>
 </video>
 #+end_src
 
@@ -12925,7 +12998,7 @@ as-is.
 
 #+vindex: org-html-mathjax-options~
 LaTeX math snippets (see [[*LaTeX fragments]]) can be displayed in two
-different ways on HTML pages.  The default is to use the 
[[http://www.mathjax.org][MathJax]],
+different ways on HTML pages.  The default is to use the 
[[https://www.mathjax.org][MathJax]],
 which should work out of the box with Org[fn:129][fn:130].  Some MathJax
 display options can be configured via ~org-html-mathjax-options~, or
 in the buffer.  For example, with the following settings,
@@ -13621,7 +13694,7 @@ placement.
 #+cindex: image, centering in LaTeX export
 The LaTeX export back-end centers all images by default.  Setting
 =:center= to =nil= disables centering.  To disable centering globally,
-set ~org-latex-images-centered~ to =t=.
+set ~org-latex-images-centered~ to =nil=.
 
 Set the =:comment-include= attribute to non-~nil~ value for the LaTeX
 export back-end to comment out the =\includegraphics= macro.
@@ -13698,7 +13771,7 @@ objects through the attributes =:float= and =:options=. 
 For =:float=:
 The LaTeX export back-end passes string values in =:options= to LaTeX
 packages for customization of that specific source block.  In the
 example below, the =:options= are set for Minted.  Minted is a source
-code highlighting LaTeX package with many configurable options.
+code highlighting LaTeX package with many configurable options[fn:134].
 
 #+begin_example
 ,#+ATTR_LATEX: :options commentstyle=\bfseries
@@ -13801,6 +13874,95 @@ The LaTeX export back-end converts horizontal rules by 
the specified
 -----
 #+end_example
 
+*** Verse blocks in LaTeX export
+:PROPERTIES:
+:DESCRIPTION: Attributes specific to special blocks.
+:END:
+
+#+cindex: verse blocks, in @LaTeX{} export
+#+cindex: @samp{ATTR_LATEX}, keyword
+
+The LaTeX export back-end accepts four attributes for verse blocks:
+=:lines=, =:center=, =:versewidth= and =:latexcode=.  The three first
+require the external LaTeX package =verse.sty=, which is an extension
+of the standard LaTeX environment.
+
+- =:lines= :: To add marginal verse numbering.  Its value is an
+  integer, the sequence in which the verses should be numbered.
+- =:center= :: With value =t= all the verses on the page are optically
+  centered (a typographic convention for poetry), taking as a
+  reference the longest verse, which must be indicated by the
+  attribute =:versewidth=.
+- =:versewidth= :: Its value is a literal text string with the longest
+  verse.
+- =:latexcode= :: It accepts any arbitrary LaTeX code that can be
+  included within a LaTeX =verse= environment.
+
+A complete example with Shakespeare's first sonnet:
+
+#+begin_src org
+,#+ATTR_LATEX: :center t :latexcode \color{red} :lines 5
+,#+ATTR_LATEX: :versewidth Feed’st thy light’s flame with self-substantial 
fuel,
+,#+BEGIN_VERSE
+From fairest creatures we desire increase,
+That thereby beauty’s rose might never die,
+But as the riper should by time decease
+His tender heir might bear his memory
+But thou, contracted to thine own bright eyes,
+Feed’st thy light’s flame with self-substantial fuel,
+Making a famine where abundance lies,
+Thyself thy foe, to thy sweet self too cruel.
+Thou that art now the world’s fresh ornament,
+And only herald to the gaudy spring,
+Within thine own bud buriest thy content,
+And, tender churl, mak’st waste in niggardly.
+Pity the world, or else this glutton be,
+To eat the world’s due, by the grave and thee.
+,#+END_VERSE
+#+end_src
+
+*** Quote blocks in LaTeX export
+:PROPERTIES:
+:DESCRIPTION: Attributes specific to quote blocks.
+:END:
+
+#+cindex: quote blocks, in @LaTeX{} export
+#+cindex: @samp{ATTR_LATEX}, keyword
+#+cindex: org-latex-default-quote-environment
+
+The LaTeX export back-end accepts two attributes for quote blocks:
+=:environment=, for an arbitrary quoting environment (the default
+value is that of ~org-latex-default-quote-environment~: ~"quote"~) and
+=:options=.  For example, to choose the environment =quotation=,
+included as an alternative to =quote= in standard LaTeX classes:
+
+#+begin_example
+,#+ATTR_LATEX: :environment quotation
+,#+BEGIN_QUOTE
+some text...
+,#+END_QUOTE
+#+end_example
+
+To choose the =foreigndisplayquote= environment, included in the LaTeX
+package =csquotes=, with the =german= option, use this syntax:
+
+#+begin_example
+,#+LATEX_HEADER:\usepackage[autostyle=true]{csquotes}
+,#+ATTR_LATEX: :environment foreigndisplayquote :options {german}
+,#+BEGIN_QUOTE
+some text in German...
+,#+END_QUOTE
+#+end_example
+
+#+texinfo: @noindent
+which is exported to LaTeX as
+
+#+begin_example
+\begin{foreigndisplayquote}{german}
+some text in German...
+\end{foreigndisplayquote}
+#+end_example
+
 ** Markdown Export
 :PROPERTIES:
 :DESCRIPTION: Exporting to Markdown.
@@ -13860,7 +14022,7 @@ a limit to a level before the absolute limit (see 
[[*Export Settings]]).
 
 The ODT export back-end handles creating of OpenDocument Text (ODT)
 format.  Documents created by this exporter use the
-{{{cite(OpenDocument-v1.2 specification)}}}[fn:134] and are compatible
+{{{cite(OpenDocument-v1.2 specification)}}}[fn:135] and are compatible
 with LibreOffice 3.4.
 
 *** Pre-requisites for ODT export
@@ -14261,7 +14423,7 @@ document in one of the following ways:
   variables ~org-latex-to-mathml-convert-command~ and
   ~org-latex-to-mathml-jar-file~.
 
-  If you prefer to use MathToWeb[fn:135] as your converter, you can
+  If you prefer to use MathToWeb[fn:136] as your converter, you can
   configure the above variables as shown below.
 
   #+begin_src emacs-lisp
@@ -14272,7 +14434,7 @@ document in one of the following ways:
   #+end_src
 
   #+texinfo: @noindent
-  or, to use LaTeX​ML[fn:136] instead,
+  or, to use LaTeX​ML[fn:137] instead,
 
   #+begin_src emacs-lisp
   (setq org-latex-to-mathml-convert-command
@@ -14591,7 +14753,7 @@ with the =#+ATTR_ODT= line.  For a discussion on 
default formatting of
 tables, see [[*Tables in ODT export]].
 
 This feature closely mimics the way table templates are defined in the
-OpenDocument-v1.2 specification[fn:137].
+OpenDocument-v1.2 specification[fn:138].
 
 #+vindex: org-odt-table-styles
 For quick preview of this feature, install the settings below and export the
@@ -14625,7 +14787,7 @@ templates, define new styles there.
 
 To use this feature proceed as follows:
 
-1. Create a table template[fn:138].
+1. Create a table template[fn:139].
 
    A table template is set of =table-cell= and =paragraph= styles for
    each of the following table cell categories:
@@ -14664,7 +14826,7 @@ To use this feature proceed as follows:
    =</office:automatic-styles>= element of the content template file
    (see [[x-orgodtcontenttemplate-xml][Factory styles]]).
 
-2. Define a table style[fn:139].
+2. Define a table style[fn:140].
 
    #+vindex: org-odt-table-styles
    To define a table style, create an entry for the style in the
@@ -15159,7 +15321,7 @@ To specify the author of the quotation, use the 
=:author= attribute.
 ,#+BEGIN_QUOTE
 The Lady of the Lake, her arm clad in the purest shimmering samite,
 held aloft Excalibur from the bosom of the water, signifying by divine
-providence that I, Arthur, was to carry Excalibur. That is why I am
+providence that I, Arthur, was to carry Excalibur.  That is why I am
 your king.
 ,#+END_QUOTE
 #+end_example
@@ -15422,7 +15584,7 @@ BACKEND is the export back-end being used, as a symbol."
   (org-map-entries
    (lambda () (delete-region (point) (line-beginning-position 2)))))
 
-(add-hook 'org-export-before-parsing-hook 'my-headline-removal)
+(add-hook 'org-export-before-parsing-hook #'my-headline-removal)
 #+end_src
 
 *** Filters
@@ -15768,17 +15930,17 @@ following properties
 Publishing means that a file is copied to the destination directory
 and possibly transformed in the process.  The default transformation
 is to export Org files as HTML files, and this is done by the function
-~org-publish-org-to-html~ which calls the HTML exporter (see [[*HTML
+~org-html-publish-to-html~ which calls the HTML exporter (see [[*HTML
 Export]]).  But you can also publish your content as PDF files using
-~org-publish-org-to-pdf~, or as ASCII, Texinfo, etc., using the
+~org-latex-publish-to-pdf~, or as ASCII, Texinfo, etc., using the
 corresponding functions.
 
 If you want to publish the Org file as an =.org= file but with
 /archived/, /commented/, and /tag-excluded/ trees removed, use
-~org-publish-org-to-org~.  This produces =file.org= and put it in the
+~org-org-publish-to-org~.  This produces =file.org= and puts it in the
 publishing directory.  If you want a htmlized version of this file,
 set the parameter ~:htmlized-source~ to ~t~.  It produces
-=file.org.html= in the publishing directory[fn:140].
+=file.org.html= in the publishing directory[fn:141].
 
 Other files like images only need to be copied to the publishing
 destination; for this you can use ~org-publish-attachment~.  For
@@ -16247,12 +16409,13 @@ directory on the local machine.
 (setq org-publish-project-alist
       '(("org"
          :base-directory "~/org/"
+         :publishing-function org-html-publish-to-html
          :publishing-directory "~/public_html"
          :section-numbers nil
-         :table-of-contents nil
-         :style "<link rel=\"stylesheet\"
-                href=\"../other/mystyle.css\"
-                type=\"text/css\"/>")))
+         :with-toc nil
+         :html-head "<link rel=\"stylesheet\"
+                    href=\"../other/mystyle.css\"
+                    type=\"text/css\"/>")))
 #+end_src
 
 *** Example: complex publishing configuration
@@ -16347,6 +16510,127 @@ of the commands above, or by customizing the variable
 particular if files include other files via =SETUPFILE= or =INCLUDE=
 keywords.
 
+* Citation handling
+:PROPERTIES:
+:DESCRIPTION: create, follow and export citations.
+:END:
+#+cindex: citation
+
+The =oc.el= library provides tooling to handle citations in Org via
+"citation processors" that offer some or all of the following
+capabilities:
+
+- activate :: Fontification, tooltip preview, etc.
+- follow :: At-point actions on citations via ~org-open-at-point~.
+- insert :: Add and edit citations via ~org-cite-insert~.
+- export :: Via different libraries for different target formats.
+
+The user can configure these with ~org-cite-activate-processor~,
+~org-cite-follow-processor~, ~org-cite-insert-processor~, and
+~org-cite-export-processors~ respectively.
+
+The included "basic" processor provides all four capabilities.
+
+** Citations
+
+Before adding citations, first set one-or-more bibliographies, either
+globally with ~org-cite-global-bibliography~, or locally using one or
+more "bibliography" keywords.
+
+#+begin_example
+#+bibliography: SomeFile.bib
+#+bibliography: /some/other/file.json
+#+bibliography: "/some/file/with spaces/in its name.bib"
+#+end_example
+
+#+kindex: C-c C-x @@
+#+findex: org-cite-insert
+One can then insert and edit citations using ~org-cite-insert~, called
+with {{{kbd(C-c C-x @)}}}.
+
+A /citation/ requires one or more citation /key(s)/, elements
+identifying a reference in the bibliography.
+
+- Each citation is surrounded by brackets and uses the =cite= type.
+
+- Each key starts with the character =@=.
+
+- Each key can be qualified by a /prefix/ (e.g.\nbsp{}"see ") and/or
+  a /suffix/ (e.g.\nbsp{}"p.\nbsp{}123"), giving informations useful or 
necessary
+  fo the comprehension of the citation but not included in the
+  reference.
+
+- A single citation can cite more than one reference ; the keys are
+  separated by semicolons ; the formatting of such citation groups is
+  specified by the style.
+
+- One can also specify a stylistic variation for the citations by
+  inserting a =/= and a style name between the =cite= keyword and the
+  colon; this usually makes sense only for the author-year styles.
+
+: [cite/style:common prefix ;prefix @key suffix; ... ; common suffix]
+
+The only mandatory elements are:
+
+- The =cite= keyword and the colon.
+- The =@= character immediately preceding each key.
+- The brackets surrounding the citation(s) (group).
+
+** Citation export processors
+
+Org currently includes the following export processors:
+
+- Two processors can export to a variety of formats, including =latex=
+  (and therefore =pdf=), =html=, =odt= and plain (UTF8) text:
+
+  - basic :: a basic export processor, well adapted to situations
+    where backward compatibility is not a requirement and formatting
+    needs are minimal;
+
+  - csl :: this export processor uses format files written in 
[[https://en.wikipedia.org/wiki/Citation_Style_Language][Citation
+    Style Language]] via 
[[https://github.com/andras-simonyi/citeproc-el][citeproc-el]];
+
+- In contrast, two other processors target LaTeX and LaTeX-derived
+  formats exclusively:
+
+  - natbib :: this export processor uses BibTeX, the historical
+    bibliographic processor used with LaTeX, thus allowing the use of
+    data and style files compatible with this processor (including
+    a large number of publishers' styles).  It uses citation commands
+    implemented in the LaTeX package =natbib=, allowing more stylistic
+    variants that LaTeX's =\cite= command.
+
+  - biblatex :: this backend allows the use of data and formats
+    prepared for BibLaTeX, an alternate bibliographic processor used
+    with LaTeX, which overcomes some serious BibTeX limitations, but
+    has not (yet?)\nbsp{}been widely adopted by publishers.
+
+The =CITE_EXPORT= keyword specifies the export processor and the
+citation (and possibly reference) style(s); for example (all arguments
+are optional)
+
+: #+cite_export: basic author author-year
+
+#+texinfo: @noindent
+specifies the "basic" export processor with citations inserted as
+author's name and references indexed by author's names and year;
+
+: #+cite_export: csl /some/path/to/vancouver-brackets.csl
+
+#+texinfo: @noindent
+specifies the "csl" processor and CSL style, which in this case
+defines numeric citations and numeric references according to the
+=Vancouver= specification (as style used in many medical journals),
+following a typesetting variation putting citations between brackets;
+
+: #+cite_export: natbib kluwer
+
+#+texinfo: @noindent
+specifies the =natbib= export processor with a label citation style
+conformant to the Harvard style and the specification of the
+Wolkers-Kluwer publisher; since it relies on the ~bibtex~ processor of
+your LaTeX installation, it won't export to anything but PDF.
+
 * Working with Source Code
 :PROPERTIES:
 :DESCRIPTION: Export, evaluate, and tangle code blocks.
@@ -16393,7 +16677,7 @@ extract, export, and publish source code blocks.  Org 
can also compile
 and execute a source code block, then capture the results.  The Org
 mode literature sometimes refers to source code blocks as /live code/
 blocks because they can alter the content of the Org document or the
-material that it exports.  Users can control how live they want each
+material that it exports.  Users can control the "liveliness" of each
 source code block by tweaking the header arguments (see [[*Using Header
 Arguments]]) for compiling, execution, extraction, and exporting.
 
@@ -16736,7 +17020,11 @@ the =var= header argument.
 body.  {{{var(ASSIGN)}}} is a literal value, such as a string,
 a number, a reference to a table, a list, a literal example, another
 code block---with or without arguments---or the results of evaluating
-a code block.
+a code block.  {{{var(ASSIGN)}}} may specify a filename for references
+to elements in a different file, using a =:= to separate the filename
+from the reference.
+
+: :var NAME=FILE:REFERENCE
 
 Here are examples of passing values by reference:
 
@@ -16815,6 +17103,9 @@ Here are examples of passing values by reference:
   | two | 16 | 17 | 18 | 19 | 20 |
   #+end_example
 
+To refer to a table in another file, join the filename and table name with
+a colon, for example: =:var table=other-file.org:example-table=.
+
 - list ::
 
   A simple named list.
@@ -17156,13 +17447,13 @@ See [[*Languages]] to enable other languages.
 #+kindex: C-c C-v e
 #+findex: org-babel-execute-src-block
 Org provides many ways to execute code blocks.  {{{kbd(C-c C-c)}}} or
-{{{kbd(C-c C-v e)}}} with the point on a code block[fn:141] calls the
+{{{kbd(C-c C-v e)}}} with the point on a code block[fn:142] calls the
 ~org-babel-execute-src-block~ function, which executes the code in the
 block, collects the results, and inserts them in the buffer.
 
 #+cindex: @samp{CALL}, keyword
 #+vindex: org-babel-inline-result-wrap
-By calling a named code block[fn:142] from an Org mode buffer or
+By calling a named code block[fn:143] from an Org mode buffer or
 a table.  Org can call the named code blocks from the current Org mode
 buffer or from the "Library of Babel" (see [[*Library of Babel]]).
 
@@ -17363,7 +17654,7 @@ they are mutually exclusive.
 
 - =value= ::
 
-  Default for most Babel libraries[fn:142].  Functional mode.  Org
+  Default for most Babel libraries[fn:143].  Functional mode.  Org
   gets the value by wrapping the code in a function definition in the
   language of the source block.  That is why when using =:results
   value=, code should execute like a function and return a value.  For
@@ -17488,10 +17779,12 @@ default behavior is to automatically determine the 
result type.
   #+end_example
 
   #+cindex: @samp{file-desc}, header argument
-  The =file-desc= header argument defines the description (see
-  [[*Link Format]]) for the link.  If =file-desc= is present but has no value,
+  The =file-desc= header argument defines the description (see [[*Link
+  Format]]) for the link.  If =file-desc= is present but has no value,
   the =file= value is used as the link description.  When this
-  argument is not present, the description is omitted.
+  argument is not present, the description is omitted.  If you want to
+  provide the =file-desc= argument but omit the description, you can
+  provide it with an empty vector (i.e., :file-desc []).
 
   #+cindex: @samp{sep}, header argument
   By default, Org assumes that a table written to a file has
@@ -17549,7 +17842,7 @@ follows from the type specified above.
 
   #+begin_example
   ,#+begin_src shell :results file link :file "download.tar.gz"
-  wget -c "http://example.com/download.tar.gz";
+  wget -c "https://example.com/download.tar.gz";
   ,#+end_src
   #+end_example
 
@@ -17595,15 +17888,20 @@ value listed above.  E.g.,
 
 Handling options after collecting the results.
 
+- =replace= ::
+
+  Default.  Insert results in the Org buffer.  Remove previous
+  results.  Usage example: =:results output replace=.
+
 - =silent= ::
 
   Do not insert results in the Org mode buffer, but echo them in the
   minibuffer.  Usage example: =:results output silent=.
 
-- =replace= ::
+- =none= ::
 
-  Default.  Insert results in the Org buffer.  Remove previous
-  results.  Usage example: =:results output replace=.
+  Do not process results at all.  No inserting in the Org mode buffer
+  nor echo them in the minibuffer.  Usage example: =:results none=.
 
 - =append= ::
 
@@ -17929,35 +18227,8 @@ code block header arguments:
 #+cindex: source code, languages
 #+cindex: code block, languages
 
-Code blocks in the following languages are supported.
-
-#+attr_texinfo: :columns 0.25 0.25 0.25 0.20
-| Language   | Identifier    | Language       | Identifier   |
-|------------+---------------+----------------+--------------|
-| Asymptote  | =asymptote=   | Lisp           | =lisp=       |
-| Awk        | =awk=         | Lua            | =lua=        |
-| C          | =C=           | MATLAB         | =matlab=     |
-| C++        | =C++=[fn:143] | Mscgen         | =mscgen=     |
-| Clojure    | =clojure=     | Objective Caml | =ocaml=      |
-| CSS        | =css=         | Octave         | =octave=     |
-| D          | =D=[fn:144]   | Org mode       | =org=        |
-| ditaa      | =ditaa=       | Oz             | =oz=         |
-| Emacs Calc | =calc=        | Perl           | =perl=       |
-| Emacs Lisp | =emacs-lisp=  | Plantuml       | =plantuml=   |
-| Eshell     | =eshell=      | Processing.js  | =processing= |
-| Fortran    | =fortran=     | Python         | =python=     |
-| Gnuplot    | =gnuplot=     | R              | =R=          |
-| GNU Screen | =screen=      | Ruby           | =ruby=       |
-| Graphviz   | =dot=         | Sass           | =sass=       |
-| Haskell    | =haskell=     | Scheme         | =scheme=     |
-| Java       | =java=        | Sed            | =sed=        |
-| Javascript | =js=          | shell          | =sh=         |
-| LaTeX      | =latex=       | SQL            | =sql=        |
-| Ledger     | =ledger=      | SQLite         | =sqlite=     |
-| Lilypond   | =lilypond=    | Vala           | =vala=       |
-
-Additional documentation for some languages is at
-https://orgmode.org/worg/org-contrib/babel/languages.html.
+Code blocks in dozens of languages are supported.  See Worg for
+[[https://orgmode.org/worg/org-contrib/babel/languages/index.html][language 
specific documentation]].
 
 #+vindex: org-babel-load-languages
 By default, only Emacs Lisp is enabled for evaluation.  To enable or
@@ -18071,7 +18342,7 @@ for Python and Emacs Lisp languages.
 
 #+cindex: @samp{noweb-ref}, header argument
 Source code blocks can include references to other source code blocks,
-using a noweb[fn:145] style syntax:
+using a noweb[fn:144] style syntax:
 
 : <<CODE-BLOCK-ID>>
 
@@ -18582,14 +18853,14 @@ Org Tempo expands snippets to structures defined in
 ~org-structure-template-alist~ and ~org-tempo-keywords-alist~.  For
 example, {{{kbd(< s TAB)}}} creates a code block.  Enable it by
 customizing ~org-modules~ or add =(require 'org-tempo)= to your Emacs
-init file[fn:146].
+init file[fn:145].
 
 #+attr_texinfo: :columns 0.1 0.9
 | {{{kbd(a)}}} | =#+BEGIN_EXPORT ascii= ... =#+END_EXPORT= |
 | {{{kbd(c)}}} | =#+BEGIN_CENTER= ... =#+END_CENTER=       |
 | {{{kbd(C)}}} | =#+BEGIN_COMMENT= ... =#+END_COMMENT=     |
 | {{{kbd(e)}}} | =#+BEGIN_EXAMPLE= ... =#+END_EXAMPLE=     |
-| {{{kbd(E)}}} | =#+BEGIN_EXPORT= ... =#+END_EXPORT= |
+| {{{kbd(E)}}} | =#+BEGIN_EXPORT= ... =#+END_EXPORT=       |
 | {{{kbd(h)}}} | =#+BEGIN_EXPORT html= ... =#+END_EXPORT=  |
 | {{{kbd(l)}}} | =#+BEGIN_EXPORT latex= ... =#+END_EXPORT= |
 | {{{kbd(q)}}} | =#+BEGIN_QUOTE= ... =#+END_QUOTE=         |
@@ -18616,14 +18887,14 @@ the variable ~org-use-speed-commands~ to a non-~nil~ 
value.  To
 trigger a Speed Key, point must be at the beginning of an Org
 headline, before any of the stars.
 
-#+vindex: org-speed-commands-user
+#+vindex: org-speed-commands
 #+findex: org-speed-command-help
 Org comes with a pre-defined list of Speed Keys.  To add or modify
-Speed Keys, customize the variable, ~org-speed-commands-user~.  For
-more details, see the variable's docstring.  With Speed Keys
-activated, {{{kbd(M-x org-speed-command-help)}}}, or {{{kbd(?)}}} when
-point is at the beginning of an Org headline, shows currently active
-Speed Keys, including the user-defined ones.
+Speed Keys, customize the option ~org-speed-commands~.  For more
+details, see the variable's docstring.  With Speed Keys activated,
+{{{kbd(M-x org-speed-command-help)}}}, or {{{kbd(?)}}} when point is at the
+beginning of an Org headline, shows currently active Speed Keys,
+including the user-defined ones.
 
 ** A Cleaner Outline View
 :PROPERTIES:
@@ -18662,7 +18933,7 @@ in the desired amount with hard spaces and hiding 
leading stars.
 To display the buffer in the indented view, activate Org Indent minor
 mode, using {{{kbd(M-x org-indent-mode)}}}.  Text lines that are not
 headlines are prefixed with virtual spaces to vertically align with
-the headline text[fn:147].
+the headline text[fn:146].
 
 #+vindex: org-indent-indentation-per-level
 To make more horizontal space, the headlines are shifted by two
@@ -18690,15 +18961,15 @@ use =STARTUP= keyword as follows:
 
 It is possible to use hard spaces to achieve the indentation instead,
 if the bare ASCII file should have the indented look also outside
-Emacs[fn:148].  With Org's support, you have to indent all lines to
+Emacs[fn:147].  With Org's support, you have to indent all lines to
 line up with the outline headers.  You would use these
-settings[fn:149]:
+settings[fn:148]:
 
-  #+begin_src emacs-lisp
-  (setq org-adapt-indentation t
-        org-hide-leading-stars t
-        org-odd-levels-only t)
-  #+end_src
+#+begin_src emacs-lisp
+(setq org-adapt-indentation t
+      org-hide-leading-stars t
+      org-odd-levels-only t)
+#+end_src
 
 - /Indentation of text below headlines/ (~org-adapt-indentation~) ::
 
@@ -18955,11 +19226,15 @@ changes.
   | =overview=       | Top-level headlines only.  |
   | =content=        | All headlines.             |
   | =showall=        | No folding on any entry.   |
+  | =show2levels=    | Headline levels 1-2.       |
+  | =show3levels=    | Headline levels 1-3.       |
+  | =show4levels=    | Headline levels 1-4.       |
+  | =show5levels=    | Headline levels 1-5.       |
   | =showeverything= | Show even drawer contents. |
 
   #+vindex: org-startup-indented
   Dynamic virtual indentation is controlled by the variable
-  ~org-startup-indented~[fn:150].
+  ~org-startup-indented~[fn:149].
 
   | =indent=   | Start with Org Indent mode turned on.  |
   | =noindent= | Start with Org Indent mode turned off. |
@@ -19095,6 +19370,22 @@ changes.
   These lines set the TODO keywords and their interpretation in the
   current file.  The corresponding variable is ~org-todo-keywords~.
 
+** Regular Expressions
+:PROPERTIES:
+:DESCRIPTION: Elisp regular expressions.
+:END:
+#+cindex: regular expressions syntax
+#+cindex: regular expressions, in searches
+
+Org, as an Emacs mode, makes use of Elisp regular expressions for
+searching, matching and filtering.  Elisp regular expressions have a
+somewhat different syntax then some common standards.  Most notably,
+alternation is indicated using =\|= and matching groups are denoted by
+=\(...\)=.  For example the string =home\|work= matches either =home=
+or =work=.
+
+For more information, see [[info:emacs::Regexps][Regular Expressions in 
Emacs]].
+
 ** Org Syntax
 :PROPERTIES:
 :DESCRIPTION: Formal description of Org's syntax.
@@ -19533,7 +19824,7 @@ passed to Emacs through the =emacsclient= command, so 
you also need to
 ensure an Emacs server is running.  More precisely, when the
 application calls
 
-: emacsclient org-protocol://PROTOCOL?key1=val1&key2=val2
+: emacsclient "org-protocol://PROTOCOL?key1=val1&key2=val2"
 
 #+texinfo: @noindent
 Emacs calls the handler associated to {{{var(PROTOCOL)}}} with
@@ -19556,7 +19847,7 @@ Using the ~store-link~ handler, you can copy links, to 
that they can
 be inserted using {{{kbd(M-x org-insert-link)}}} or yanking.  More
 precisely, the command
 
-: emacsclient org-protocol://store-link?url=URL&title=TITLE
+: emacsclient "org-protocol://store-link?url=URL&title=TITLE"
 
 #+texinfo: @noindent
 stores the following link:
@@ -19570,11 +19861,20 @@ slashes, and probably quote those for the shell.
 To use this feature from a browser, add a bookmark with an arbitrary
 name, e.g., =Org: store-link= and enter this as /Location/:
 
+#+begin_example
+javascript:location.href='org-protocol://store-link?' +
+      new URLSearchParams({url:location.href, title:document.title});
+#+end_example
+
+Title is an optional parameter.  Another expression was recommended earlier:
+
 #+begin_example
 javascript:location.href='org-protocol://store-link?url='+
       encodeURIComponent(location.href);
 #+end_example
 
+The latter form is compatible with older Org versions from 9.0 to 9.4.
+
 *** The ~capture~ protocol
 :PROPERTIES:
 :DESCRIPTION: Fill a buffer with external information.
@@ -19585,11 +19885,20 @@ 
javascript:location.href='org-protocol://store-link?url='+
 Activating the "capture" handler pops up a =Capture= buffer in Emacs,
 using acapture template.
 
-: emacsclient org-protocol://capture?template=X?url=URL?title=TITLE?body=BODY
+: emacsclient "org-protocol://capture?template=X&url=URL&title=TITLE&body=BODY"
 
 To use this feature, add a bookmark with an arbitrary name, e.g.,
 =Org: capture=, and enter this as =Location=:
 
+#+begin_example
+javascript:location.href='org-protocol://capture?' +
+      new URLSearchParams({
+            template: 'x', url: window.location.href,
+            title: document.title, body: window.getSelection()});
+#+end_example
+
+You might have seen another expression:
+
 #+begin_example
 javascript:location.href='org-protocol://capture?template=x'+
       '&url='+encodeURIComponent(window.location.href)+
@@ -19597,6 +19906,10 @@ 
javascript:location.href='org-protocol://capture?template=x'+
       '&body='+encodeURIComponent(window.getSelection());
 #+end_example
 
+It is a bit more cluttered than the former one, but it is compatible
+with previous Org versions 9.0-9.4.  In these versions encoding of
+space as "+" character was not supported by URI decoder.
+
 #+vindex: org-protocol-default-template-key
 The capture template to be used can be specified in the bookmark (like
 =X= above).  If unspecified, the template key is set in the variable
@@ -19652,13 +19965,13 @@ click the bookmark and start editing.
 #+cindex: rewritten URL in open-source protocol
 #+cindex: protocol, open-source rewritten URL
 However, such mapping may not always yield the desired results.
-Suppose you maintain an online store located at =http://example.com/=.
+Suppose you maintain an online store located at =https://example.com/=.
 The local sources reside in =/home/user/example/=.  It is common
 practice to serve all products in such a store through one file and
 rewrite URLs that do not match an existing file on the server.  That
-way, a request to =http://example.com/print/posters.html= might be
+way, a request to =https://example.com/print/posters.html= might be
 rewritten on the server to something like
-=http://example.com/shop/products.php/posters.html.php=.  The
+=https://example.com/shop/products.php/posters.html.php=.  The
 ~open-source~ handler probably cannot find a file named
 =/home/user/example/print/posters.html.php= and fails.
 
@@ -19673,7 +19986,7 @@ adding ~:rewrites~ rules like this:
 #+begin_src emacs-lisp
 (setq org-protocol-project-alist
       '(("example.com"
-         :base-url "http://example.com/";
+         :base-url "https://example.com/";
          :working-directory "/home/user/example/"
          :online-suffix ".php"
          :working-suffix ".php"
@@ -19704,8 +20017,8 @@ an Org file that is part of a publishing project.
 :END:
 
 Org Crypt encrypts the text of an entry, but not the headline, or
-properties.  Behind the scene, it uses the Emacs EasyPG library to
-encrypt and decrypt files.
+properties.  Behind the scene, it uses the [[info:epa][Emacs EasyPG Library]] 
to
+encrypt and decrypt files, and EasyPG needs a correct [[info:gnupg][GnuPG]] 
setup.
 
 #+vindex: org-crypt-tag-matcher
 Any text below a headline that has a =crypt= tag is automatically
@@ -19778,7 +20091,7 @@ Tags]]) only for those set in these variables.
 
 #+vindex: org-mobile-directory
 The mobile application needs access to a file directory on
-a server[fn:151] to interact with Emacs.  Pass its location through
+a server[fn:150] to interact with Emacs.  Pass its location through
 the ~org-mobile-directory~ variable.  If you can mount that directory
 locally just set the variable to point to that directory:
 
@@ -19799,7 +20112,7 @@ With a public server, consider encrypting the files.  
Org also
 requires OpenSSL installed on the local computer.  To turn on
 encryption, set the same password in the mobile application and in
 Emacs.  Set the password in the variable
-~org-mobile-use-encryption~[fn:152].  Note that even after the mobile
+~org-mobile-use-encryption~[fn:151].  Note that even after the mobile
 application encrypts the file contents, the file name remains visible
 on the file systems of the local computer, the server, and the mobile
 device.
@@ -19815,15 +20128,15 @@ The command ~org-mobile-push~ copies files listed in
 ~org-mobile-files~ into the staging area.  Files include agenda files
 (as listed in ~org-agenda-files~).  Customize ~org-mobile-files~ to
 add other files.  File names are staged with paths relative to
-~org-directory~, so all files should be inside this directory[fn:153].
+~org-directory~, so all files should be inside this directory[fn:152].
 
 Push creates a special Org file =agendas.org= with custom agenda views
-defined by the user[fn:154].
+defined by the user[fn:153].
 
 Finally, Org writes the file =index.org=, containing links to other
 files.  The mobile application reads this file first from the server
 to determine what other files to download for agendas.  For faster
-downloads, it is expected to only read files whose checksums[fn:155]
+downloads, it is expected to only read files whose checksums[fn:154]
 have changed.
 
 *** Pulling from the mobile application
@@ -19840,7 +20153,7 @@ data in an inbox file format, through the following 
steps:
 
 1.
    #+vindex: org-mobile-inbox-for-pull
-   Org moves all entries found in =mobileorg.org=[fn:156] and appends
+   Org moves all entries found in =mobileorg.org=[fn:155] and appends
    them to the file pointed to by the variable
    ~org-mobile-inbox-for-pull~.  It should reside neither in the
    staging area nor on the server.  Each captured entry and each
@@ -19904,12 +20217,10 @@ https://orgmode.org/worg/doc.html#hooks.
 :END:
 #+cindex: add-on packages
 
-Various authors wrote a large number of add-on packages for Org.
-
-These packages are not part of Emacs, but they are distributed as
-contributed packages with the separate release available at
-https://orgmode.org.  See the =contrib/README= file in the source code
-directory for a list of contributed files.  Worg page with more
+Various authors wrote a large number of add-on packages for Org.  Some
+of these packages used to be part of the =org-mode= repository but are
+now hosted in a separate =org-contrib= repository
+[[https://git.sr.ht/~bzg/org-contrib][here]].  A Worg page with more
 information is at: https://orgmode.org/worg/org-contrib/.
 
 ** Adding Hyperlink Types
@@ -20136,9 +20447,9 @@ of these strategies:
 #+cindex: @LaTeX{}, and Orgtbl mode
 
 To wrap a source table in LaTeX, use the =comment= environment
-provided by =comment.sty=[fn:157].  To activate it, put
+provided by =comment.sty=[fn:156].  To activate it, put
 ~\usepackage{comment}~ in the document header.  Orgtbl mode inserts
-a radio table skeleton[fn:158] with the command {{{kbd(M-x
+a radio table skeleton[fn:157] with the command {{{kbd(M-x
 orgtbl-insert-radio-table)}}}, which prompts for a table name.  For
 example, if =salesfigures= is the name, the template inserts:
 
@@ -20157,7 +20468,7 @@ The line =#+ORGTBL: SEND= tells Orgtbl mode to use the 
function
 ~orgtbl-to-latex~ to convert the table to LaTeX format, then insert
 the table at the target (receive) location named =salesfigures=.  Now
 the table is ready for data entry.  It can even use spreadsheet
-features[fn:159]:
+features[fn:158]:
 
 #+begin_example
 % BEGIN RECEIVE ORGTBL salesfigures
@@ -20373,7 +20684,7 @@ Dynamic blocks, like any other block, can be narrowed 
with
 #+vindex: org-agenda-skip-function
 #+vindex: org-agenda-skip-function-global
 Org provides a special hook to further limit items in agenda views:
-~agenda~, ~agenda*~[fn:160], ~todo~, ~alltodo~, ~tags~, ~tags-todo~,
+~agenda~, ~agenda*~[fn:159], ~todo~, ~alltodo~, ~tags~, ~tags-todo~,
 ~tags-tree~.  Specify a custom function that tests inclusion of every
 matched item in the view.  This function can also skip as much as is
 needed.
@@ -20416,7 +20727,7 @@ meaningful string suitable for the agenda view.
 #+vindex: org-agenda-skip-function
 Search for entries with a limit set on levels for the custom search.
 This is a general approach to creating custom searches in Org.  To
-include all levels, use =LEVEL>0=[fn:161].  Then to selectively pick
+include all levels, use =LEVEL>0=[fn:160].  Then to selectively pick
 the matched entries, use ~org-agenda-skip-function~, which also
 accepts Lisp forms, such as ~org-agenda-skip-entry-if~ and
 ~org-agenda-skip-subtree-if~.  For example:
@@ -21017,6 +21328,9 @@ be complete if the ones above were not mentioned in 
this manual.
 - Charles Cave's suggestion sparked the implementation of templates
   for Remember, which are now templates for capture.
 
+- Timothy E Chapman worked on a complete overhaul of the orgmode.org
+  website in 2020 and helped fixing various bugs.
+
 - Pavel Chalmoviansky influenced the agenda treatment of items with
   specified time.
 
@@ -21106,6 +21420,9 @@ be complete if the ones above were not mentioned in 
this manual.
 
 - Jason\nbsp{}F.\nbsp{}McBrayer suggested agenda export to CSV format.
 
+- Kyle Meyer helped setting up the [[https://public-inbox.org/][public-inbox]] 
archive of the [[https://orgmode.org/list/][Org
+  mailing list]] and has been fixing many bugs.
+
 - Max Mikhanosha came up with the idea of refiling.
 
 - Dmitri Minaev sent a patch to set priority limits on a per-file
@@ -21143,6 +21460,9 @@ be complete if the ones above were not mentioned in 
this manual.
 - Martin Pohlack provided the code snippet to bundle character
   insertion into bundles of 20 for undo.
 
+- Ihor Radchenko helped with fixing bugs and improving the user
+  experience regarding Org's speed.
+
 - T.\nbsp{}V.\nbsp{}Raman reported bugs and suggested improvements.
 
 - Matthias Rempe (Oelde) provided ideas, Windows support, and quality
@@ -21173,7 +21493,7 @@ be complete if the ones above were not mentioned in 
this manual.
   literal examples, and remote highlighting for referenced code lines.
 
 - Stathis Sideris wrote the =ditaa.jar= ASCII to PNG converter that is
-  now packaged into Org's =contrib/= directory.
+  now packaged into the [[https://git.sr.ht/~bzg/org-contrib][org-contrib]] 
repository.
 
 - Daniel Sinder came up with the idea of internal archiving by locking
   subtrees.
@@ -21296,7 +21616,7 @@ modify this GNU manual."
 * Footnotes
 
 [fn:1] If you do not use Font Lock globally turn it on in Org buffer
-with =(add-hook 'org-mode-hook 'turn-on-font-lock)=.
+with =(add-hook 'org-mode-hook #'turn-on-font-lock)=.
 
 [fn:2] Please consider subscribing to the mailing list in order to
 minimize the work the mailing list moderators have to do.
@@ -21597,12 +21917,12 @@ lognoteclock-out=.
 line---the line is broken here only to fit it into the manual.
 
 [fn:81] On computers using macOS, idleness is based on actual user
-idleness, not just Emacs' idle time.  For X11, you can install
-a utility program =x11idle.c=, available in the =contrib/scripts/=
-directory of the Org Git distribution, or install the xprintidle
-package and set it to the variable ~org-clock-x11idle-program-name~ if
-you are running Debian, to get the same general treatment of idleness.
-On other systems, idle time refers to Emacs idle time only.
+idleness, not just Emacs' idle time.  For X11, you can install a
+utility program =x11idle.c=, available in the =org-contrib/=
+repository, or install the xprintidle package and set it to the
+variable ~org-clock-x11idle-program-name~ if you are running Debian,
+to get the same general treatment of idleness.  On other systems, idle
+time refers to Emacs idle time only.
 
 [fn:82] Please note the pitfalls of summing hierarchical data in
 a flat list (see [[*Using Column View in the Agenda]]).
@@ -21733,7 +22053,7 @@ a fragment, see the documentation of the function
 version 1.34 of the =htmlize.el= package, which you need to install).
 Fontified code chunks in LaTeX can be achieved using either the
 [[https://www.ctan.org/pkg/listings][listings]] package or the 
[[https://www.ctan.org/pkg/minted][minted]] package.  Refer to
-~org-export-latex-listings~ for details.
+~org-latex-listings~ for details.
 
 [fn:115] Source code in code blocks may also be evaluated either
 interactively or on export.  See [[*Working with Source Code]] for more
@@ -21762,7 +22082,9 @@ and =#+STARTUP: nofnadjust=.
 [fn:122] The variable ~org-export-date-timestamp-format~ defines how
 this timestamp are exported.
 
-[fn:123] DEFINITION NOT FOUND.
+[fn:123] For export to LaTeX format---or LaTeX-related formats such as
+Beamer---, the =org-latex-package-alist= variable needs further
+configuration.  See [[LaTeX specific export settings]].
 
 [fn:124] At the moment, some export back-ends do not obey this
 specification.  For example, LaTeX export excludes every unnumbered
@@ -21785,7 +22107,7 @@ to make it visible.  The tag serves as a visual aid and 
has no
 semantic relevance.
 
 [fn:129] By default Org loads MathJax from [[https://cdnjs.com][cdnjs.com]] as 
recommended by
-[[http://www.mathjax.org][MathJax]].
+[[https://www.mathjax.org][MathJax]].
 
 [fn:130] Please note that exported formulas are part of an HTML
 document, and that signs such as =<=, =>=, or =&= have special
@@ -21802,93 +22124,89 @@ use the variables ~org-html-todo-kwd-class-prefix~ and
 for different files.  However, "smart" LaTeX compilation systems, such
 as latexmk, can select the correct bibliography compiler.
 
-[fn:134] See 
[[http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.html][Open Document 
Format for Office Applications
+[fn:134] Minted uses an external Python package for code highlighting,
+which requires the flag =-shell-escape= to be added to
+~org-latex-pdf-process~.
+
+[fn:135] See 
[[http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.html][Open Document 
Format for Office Applications
 (OpenDocument) Version 1.2]].
 
-[fn:135] See [[http://www.mathtoweb.com/cgi-bin/mathtoweb_home.pl][MathToWeb]].
+[fn:136] See [[http://www.mathtoweb.com/cgi-bin/mathtoweb_home.pl][MathToWeb]].
 
-[fn:136] See [[http://dlmf.nist.gov/LaTeXML/]].
+[fn:137] See [[http://dlmf.nist.gov/LaTeXML/]].
 
-[fn:137] 
[[http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.html][OpenDocument-v1.2
 Specification]]
+[fn:138] 
[[http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.html][OpenDocument-v1.2
 Specification]]
 
-[fn:138] See the =<table:table-template>= element of the
+[fn:139] See the =<table:table-template>= element of the
 OpenDocument-v1.2 specification.
 
-[fn:139] See the attributes =table:template-name=,
+[fn:140] See the attributes =table:template-name=,
 =table:use-first-row-styles=, =table:use-last-row-styles=,
 =table:use-first-column-styles=, =table:use-last-column-styles=,
 =table:use-banding-rows-styles=, and =table:use-banding-column-styles=
 of the =<table:table>= element in the OpenDocument-v1.2 specification.
 
-[fn:140] If the publishing directory is the same as the source
+[fn:141] If the publishing directory is the same as the source
 directory, =file.org= is exported as =file.org.org=, so you probably
 do not want to do this.
 
-[fn:141] The option ~org-babel-no-eval-on-ctrl-c-ctrl-c~ can be used
+[fn:142] The option ~org-babel-no-eval-on-ctrl-c-ctrl-c~ can be used
 to remove code evaluation from the {{{kbd(C-c C-c)}}} key binding.
 
-[fn:142] Actually, the constructs =call_<name>()= and =src_<lang>{}=
+[fn:143] Actually, the constructs =call_<name>()= and =src_<lang>{}=
 are not evaluated when they appear in a keyword (see [[*Summary of
 In-Buffer Settings]]).
 
-[fn:143] C++ language is handled in =ob-C.el=.  Even though the
-identifier for such source blocks is =C++=, you activate it by loading
-the C language.
-
-[fn:144] D language is handled in =ob-C.el=.  Even though the
-identifier for such source blocks is =D=, you activate it by loading
-the C language.
-
-[fn:145] For noweb literate programming details, see
+[fn:144] For noweb literate programming details, see
 http://www.cs.tufts.edu/~nr/noweb/.
 
-[fn:146] For more information, please refer to the commentary section
+[fn:145] For more information, please refer to the commentary section
 in =org-tempo.el=.
 
-[fn:147] Org Indent mode also sets ~wrap-prefix~ correctly for
+[fn:146] Org Indent mode also sets ~wrap-prefix~ correctly for
 indenting and wrapping long lines of headlines or text.  This minor
 mode also handles Visual Line mode and directly applied settings
 through ~word-wrap~.
 
-[fn:148] This works, but requires extra effort.  Org Indent mode is
+[fn:147] This works, but requires extra effort.  Org Indent mode is
 more convenient for most applications.
 
-[fn:149] ~org-adapt-indentation~ can also be set to ='headline-data=,
+[fn:148] ~org-adapt-indentation~ can also be set to ='headline-data=,
 in which case only data lines below the headline will be indented.
 
-[fn:150] Note that Org Indent mode also sets the ~wrap-prefix~
+[fn:149] Note that Org Indent mode also sets the ~wrap-prefix~
 property, such that Visual Line mode (or purely setting ~word-wrap~)
 wraps long lines, including headlines, correctly indented.
 
-[fn:151] For a server to host files, consider using a WebDAV server,
+[fn:150] For a server to host files, consider using a WebDAV server,
 such as [[https://nextcloud.com][Nextcloud]].  Additional help is at this 
[[https://orgmode.org/worg/org-faq.html#mobileorg_webdav][FAQ entry]].
 
-[fn:152] If Emacs is configured for safe storing of passwords, then
+[fn:151] If Emacs is configured for safe storing of passwords, then
 configure the variable ~org-mobile-encryption-password~; please read
 the docstring of that variable.
 
-[fn:153] Symbolic links in ~org-directory~ need to have the same name
+[fn:152] Symbolic links in ~org-directory~ need to have the same name
 as their targets.
 
-[fn:154] While creating the agendas, Org mode forces =ID= properties
+[fn:153] While creating the agendas, Org mode forces =ID= properties
 on all referenced entries, so that these entries can be uniquely
 identified if Org Mobile flags them for further action.  To avoid
 setting properties configure the variable
 ~org-mobile-force-id-on-agenda-items~ to ~nil~.  Org mode then relies
 on outline paths, assuming they are unique.
 
-[fn:155] Checksums are stored automatically in the file
+[fn:154] Checksums are stored automatically in the file
 =checksums.dat=.
 
-[fn:156] The file will be empty after this operation.
+[fn:155] The file will be empty after this operation.
 
-[fn:157] https://www.ctan.org/pkg/comment
+[fn:156] https://www.ctan.org/pkg/comment
 
-[fn:158] By default this works only for LaTeX, HTML, and Texinfo.
+[fn:157] By default this works only for LaTeX, HTML, and Texinfo.
 Configure the variable ~orgtbl-radio-table-templates~ to install
 templates for other modes.
 
-[fn:159] If the =TBLFM= keyword contains an odd number of dollar
+[fn:158] If the =TBLFM= keyword contains an odd number of dollar
 characters, this may cause problems with Font Lock in LaTeX mode.  As
 shown in the example you can fix this by adding an extra line inside
 the =comment= environment that is used to balance the dollar
@@ -21896,9 +22214,9 @@ expressions.  If you are using AUCTeX with the 
font-latex library,
 a much better solution is to add the =comment= environment to the
 variable ~LaTeX-verbatim-environments~.
 
-[fn:160] The ~agenda*~ view is the same as ~agenda~ except that it
+[fn:159] The ~agenda*~ view is the same as ~agenda~ except that it
 only considers /appointments/, i.e., scheduled and deadline items that
 have a time specification =[h]h:mm= in their time-stamps.
 
-[fn:161] Note that, for ~org-odd-levels-only~, a level number
+[fn:160] Note that, for ~org-odd-levels-only~, a level number
 corresponds to order in the hierarchy, not to the number of stars.
diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi
index 47de523737..a4ca54a8b0 100644
--- a/doc/misc/rcirc.texi
+++ b/doc/misc/rcirc.texi
@@ -823,17 +823,18 @@ active and only omits a message if the nick has not been 
active.  The
 window @code{rcirc} considers is controlled by the
 @code{rcirc-omit-threshold} variable.
 
-@vindex rcirc-omit-responses-after-join
-Right after connecting to a server, rcirc will also hide all messages
-in @code{rcirc-omit-responses-after-join}, next to
-@code{rcirc-omit-responses}. For example,
+@vindex rcirc-omit-unless-requested
+Certain messages can be omitted by default, unless the user manual
+requests them. For example, if you don't want to display @code{TOPIC}
+and @code{NAMES} messages, after reconnecting, you can configure
+@code{rcirc-omit-unless-requested} to hide:
 
 @example
-(setq rcirc-omit-responses-after-join '("TOPIC" "NICK"))
+(setq rcirc-omit-unless-requested '("TOPIC" "NAMES"))
 @end example
 
-would hide the topic message and the list of users in the current
-channel right after joining a new channel.
+Now NAMES will only be displayed, after it has been requested via the
+@code{rcirc-cmd-name} command.
 
 @node Hacking and Tweaking
 @chapter Hacking and Tweaking
@@ -976,9 +977,6 @@ displayed. A simple configuration to fix the above example 
might be:
       rcirc-channel-filter #'local/rcirc-soju-suffix)
 @end smallexample
 
-The effect is that buffer names, nicks in messages, nick-completion
-all strip away the suffix introduced by the bouncer.
-
 @node GNU Free Documentation License
 @appendix GNU Free Documentation License
 @include doclicense.texi
diff --git a/doc/misc/reftex.texi b/doc/misc/reftex.texi
index 8ca5fcca5b..8bde241e18 100644
--- a/doc/misc/reftex.texi
+++ b/doc/misc/reftex.texi
@@ -658,9 +658,9 @@ variable @code{reftex-auto-recenter-toc}.
 
 @end table
 
-@vindex reftex-toc-map
+@vindex reftex-toc-mode-map
 In order to define additional commands for the @file{*toc*} buffer, the
-keymap @code{reftex-toc-map} may be used.
+keymap @code{reftex-toc-mode-map} may be used.
 
 @findex reftex-toc-recenter
 @vindex reftex-auto-recenter-toc
@@ -1021,9 +1021,9 @@ document and let you select a label from there 
(@pxref{LaTeX xr Package,,xr}).
 
 @end table
 
-@vindex reftex-select-label-map
+@vindex reftex-select-label-mode-map
 In order to define additional commands for the selection process, the
-keymap @code{reftex-select-label-map} may be used.
+keymap @code{reftex-select-label-mode-map} may be used.
 
 @node Builtin Label Environments
 @section Builtin Label Environments
@@ -1871,9 +1871,9 @@ entries.
 
 @end table
 
-@vindex reftex-select-bib-map
+@vindex reftex-select-bib-mode-map
 In order to define additional commands for this selection process, the
-keymap @code{reftex-select-bib-map} may be used.
+keymap @code{reftex-select-bib-mode-map} may be used.
 
 Note that if you do not use Emacs to edit the @BibTeX{} database files,
 @RefTeX{} will ask if the related buffers should be updated once it
@@ -3960,7 +3960,7 @@ Normal hook which is run when a @file{*toc*} buffer is
 created.
 @end deffn
 
-@deffn Keymap reftex-toc-map
+@deffn Keymap reftex-toc-mode-map
 The keymap which is active in the @file{*toc*} buffer.
 (@pxref{Table of Contents}).
 @end deffn
@@ -4425,7 +4425,7 @@ Normal hook which is run when a selection buffer enters
 @code{reftex-select-label-mode}.
 @end deffn
 
-@deffn Keymap reftex-select-label-map
+@deffn Keymap reftex-select-label-mode-map
 The keymap which is active in the labels selection process
 (@pxref{Referencing Labels}).
 @end deffn
@@ -4586,7 +4586,7 @@ Normal hook which is run when a selection buffer enters
 @code{reftex-select-bib-mode}.
 @end deffn
 
-@deffn Keymap reftex-select-bib-map
+@deffn Keymap reftex-select-bib-mode-map
 The keymap which is active in the citation-key selection process
 (@pxref{Creating Citations}).
 @end deffn
@@ -4792,7 +4792,7 @@ into blocks.  Sorting will then preserve blocks, so that 
lines are
 re-arranged only within blocks.
 @end defopt
 
-@defopt reftex-index-phrases-map
+@defopt reftex-index-phrases-mode-map
 Keymap for the Index Phrases buffer.
 @end defopt
 
@@ -4824,7 +4824,7 @@ the document.  This flag can be toggled from within the 
@file{*Index*}
 buffer with the @kbd{f} key.
 @end defopt
 
-@deffn Keymap reftex-index-map
+@deffn Keymap reftex-index-mode-map
 The keymap which is active in the @file{*Index*} buffer
 (@pxref{Index Support}).
 @end deffn
@@ -5813,8 +5813,8 @@ buffer).
 @noindent @b{Version 3.12}
 @itemize @bullet
 @item
-There are 3 new keymaps for customization: @code{reftex-toc-map},
-@code{reftex-select-label-map}, @code{reftex-select-bib-map}.
+There are 3 new keymaps for customization: @code{reftex-toc-mode-map},
+@code{reftex-select-label-mode-map}, @code{reftex-select-bib-mode-map}.
 @item
 Refontification uses more standard font-lock stuff.
 @item
diff --git a/doc/misc/speedbar.texi b/doc/misc/speedbar.texi
index 9991917b3f..70d4b05416 100644
--- a/doc/misc/speedbar.texi
+++ b/doc/misc/speedbar.texi
@@ -896,7 +896,7 @@ augmented with speedbar.
 
 @enumerate
 @item
-Create the keymap variable @code{@var{name}-speedbar-key-map}.
+Create the keymap variable @code{@var{name}-speedbar-mode-map}.
 
 @item
 Create a function, named whatever you like, which assigns values into your
@@ -904,7 +904,7 @@ keymap.  Use this command to create the keymap before 
assigning
 bindings:
 
 @smallexample
-    (setq @var{name}-speedbar-key-map (speedbar-make-specialized-keymap))
+    (setq @var{name}-speedbar-mode-map (speedbar-make-specialized-keymap))
 @end smallexample
 
 This function creates a special keymap for use in speedbar.
@@ -977,7 +977,7 @@ Next, register your extension like this;
 @example
   (speedbar-add-expansion-list '("MyExtension"
                                  MyExtension-speedbar-menu-items
-                                 MyExtension-speedbar-key-map
+                                 MyExtension-speedbar-mode-map
                                  MyExtension-speedbar-buttons))
 @end example
 
diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex
index a91181b116..e48383defc 100644
--- a/doc/misc/texinfo.tex
+++ b/doc/misc/texinfo.tex
@@ -3,9 +3,9 @@
 % Load plain if necessary, i.e., if running under initex.
 \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
 %
-\def\texinfoversion{2020-11-25.18}
+\def\texinfoversion{2021-04-25.21}
 %
-% Copyright 1985, 1986, 1988, 1990-2020 Free Software Foundation, Inc.
+% Copyright 1985, 1986, 1988, 1990-2021 Free Software Foundation, Inc.
 %
 % This texinfo.tex file is free software: you can redistribute it and/or
 % modify it under the terms of the GNU General Public License as
@@ -574,7 +574,7 @@
 
 
 % @end foo calls \checkenv and executes the definition of \Efoo.
-\parseargdef\end{
+\parseargdef\end{%
   \if 1\csname iscond.#1\endcsname
   \else
     % The general wording of \badenverr may not be ideal.
@@ -1002,6 +1002,14 @@ where each line of input produces a line of output.}
   \global\everypar = {}%
 }
 
+% leave vertical mode without cancelling any first paragraph indent
+\gdef\imageindent{%
+  \toks0=\everypar
+  \everypar={}%
+  \ptexnoindent
+  \global\everypar=\toks0
+}
+
 
 % @refill is a no-op.
 \let\refill=\relax
@@ -1181,7 +1189,7 @@ where each line of input produces a line of output.}
 % double any backslashes.  Otherwise, a name like "\node" will be
 % interpreted as a newline (\n), followed by o, d, e.  Not good.
 %
-% See https://mailman.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
 % related messages.  The final outcome is that it is up to the TeX user
 % to double the backslashes and otherwise make the string valid, so
 % that's what we do.  pdftex 1.30.0 (ca.2005) introduced a primitive to
@@ -1862,19 +1870,23 @@ output) for that.)}
       \closein 1
     \endgroup
     %
-    \def\xetexpdfext{pdf}%
-    \ifx\xeteximgext\xetexpdfext
-      \XeTeXpdffile "#1".\xeteximgext ""
-    \else
-      \def\xetexpdfext{PDF}%
+    % Putting an \hbox around the image can prevent an over-long line
+    % after the image.
+    \hbox\bgroup
+      \def\xetexpdfext{pdf}%
       \ifx\xeteximgext\xetexpdfext
         \XeTeXpdffile "#1".\xeteximgext ""
       \else
-        \XeTeXpicfile "#1".\xeteximgext ""
+        \def\xetexpdfext{PDF}%
+        \ifx\xeteximgext\xetexpdfext
+          \XeTeXpdffile "#1".\xeteximgext ""
+        \else
+          \XeTeXpicfile "#1".\xeteximgext ""
+        \fi
       \fi
-    \fi
-    \ifdim \wd0 >0pt width \xeteximagewidth \fi
-    \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+      \ifdim \wd0 >0pt width \xeteximagewidth \fi
+      \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+    \egroup
   }
 \fi
 
@@ -3539,7 +3551,7 @@ $$%
 % We use the free feym* fonts from the eurosym package by Henrik
 % Theiling, which support regular, slanted, bold and bold slanted (and
 % "outlined" (blackboard board, sort of) versions, which we don't need).
-% It is available from https://www.ctan.org/tex-archive/fonts/eurosym.
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
 %
 % Although only regular is the truly official Euro symbol, we ignore
 % that.  The Euro is designed to be slightly taller than the regular
@@ -4289,82 +4301,8 @@ $$%
   \doitemize{#1.}\flushcr
 }
 
-% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
-% to @enumerate.
-%
-\def\alphaenumerate{\enumerate{a}}
-\def\capsenumerate{\enumerate{A}}
-\def\Ealphaenumerate{\Eenumerate}
-\def\Ecapsenumerate{\Eenumerate}
-
 
 % @multitable macros
-% Amy Hendrickson, 8/18/94, 3/6/96
-%
-% @multitable ... @end multitable will make as many columns as desired.
-% Contents of each column will wrap at width given in preamble.  Width
-% can be specified either with sample text given in a template line,
-% or in percent of \hsize, the current width of text on page.
-
-% Table can continue over pages but will only break between lines.
-
-% To make preamble:
-%
-% Either define widths of columns in terms of percent of \hsize:
-%   @multitable @columnfractions .25 .3 .45
-%   @item ...
-%
-%   Numbers following @columnfractions are the percent of the total
-%   current hsize to be used for each column. You may use as many
-%   columns as desired.
-
-
-% Or use a template:
-%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
-%   @item ...
-%   using the widest term desired in each column.
-
-% Each new table line starts with @item, each subsequent new column
-% starts with @tab. Empty columns may be produced by supplying @tab's
-% with nothing between them for as many times as empty columns are needed,
-% ie, @tab@tab@tab will produce two empty columns.
-
-% @item, @tab do not need to be on their own lines, but it will not hurt
-% if they are.
-
-% Sample multitable:
-
-%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
-%   @item first col stuff @tab second col stuff @tab third col
-%   @item
-%   first col stuff
-%   @tab
-%   second col stuff
-%   @tab
-%   third col
-%   @item first col stuff @tab second col stuff
-%   @tab Many paragraphs of text may be used in any column.
-%
-%         They will wrap at the width determined by the template.
-%   @item@tab@tab This will be in third column.
-%   @end multitable
-
-% Default dimensions may be reset by user.
-% @multitableparskip is vertical space between paragraphs in table.
-% @multitableparindent is paragraph indent in table.
-% @multitablecolmargin is horizontal space to be left between columns.
-% @multitablelinespace is space to leave between table items, baseline
-%                                                            to baseline.
-%   0pt means it depends on current normal line spacing.
-%
-\newskip\multitableparskip
-\newskip\multitableparindent
-\newdimen\multitablecolspace
-\newskip\multitablelinespace
-\multitableparskip=0pt
-\multitableparindent=6pt
-\multitablecolspace=12pt
-\multitablelinespace=0pt
 
 % Macros used to set up halign preamble:
 %
@@ -4412,8 +4350,6 @@ $$%
   \go
 }
 
-% multitable-only commands.
-%
 % @headitem starts a heading row, which we typeset in bold.  Assignments
 % have to be global since we are inside the implicit group of an
 % alignment entry.  \everycr below resets \everytab so we don't have to
@@ -4430,14 +4366,8 @@ $$%
 % default for tables with no headings.
 \let\headitemcrhook=\relax
 %
-% A \tab used to include \hskip1sp.  But then the space in a template
-% line is not enough.  That is bad.  So let's go back to just `&' until
-% we again encounter the problem the 1sp was intended to solve.
-%                                      --karl, nathan@acm.org, 20apr99.
 \def\tab{\checkenv\multitable &\the\everytab}%
 
-% @multitable ... @end multitable definitions:
-%
 \newtoks\everytab  % insert after every tab.
 %
 \envdef\multitable{%
@@ -4452,9 +4382,8 @@ $$%
   %
   \tolerance=9500
   \hbadness=9500
-  \setmultitablespacing
-  \parskip=\multitableparskip
-  \parindent=\multitableparindent
+  \parskip=0pt
+  \parindent=6pt
   \overfullrule=0pt
   \global\colcount=0
   %
@@ -4484,47 +4413,24 @@ $$%
   % continue for many paragraphs if desired.
   \halign\bgroup &%
     \global\advance\colcount by 1
-    \multistrut
+    \strut
     \vtop{%
-      % Use the current \colcount to find the correct column width:
+      \advance\hsize by -1\leftskip
+      % Find the correct column width
       \hsize=\expandafter\csname col\the\colcount\endcsname
       %
-      % In order to keep entries from bumping into each other
-      % we will add a \leftskip of \multitablecolspace to all columns after
-      % the first one.
-      %
-      % If a template has been used, we will add \multitablecolspace
-      % to the width of each template entry.
-      %
-      % If the user has set preamble in terms of percent of \hsize we will
-      % use that dimension as the width of the column, and the \leftskip
-      % will keep entries from bumping into each other.  Table will start at
-      % left margin and final column will justify at right margin.
-      %
-      % Make sure we don't inherit \rightskip from the outer environment.
       \rightskip=0pt
       \ifnum\colcount=1
-       % The first column will be indented with the surrounding text.
-       \advance\hsize by\leftskip
+        \advance\hsize by\leftskip % Add indent of surrounding text
       \else
-       \ifsetpercent \else
-         % If user has not set preamble in terms of percent of \hsize
-         % we will advance \hsize by \multitablecolspace.
-         \advance\hsize by \multitablecolspace
-       \fi
-       % In either case we will make \leftskip=\multitablecolspace:
-      \leftskip=\multitablecolspace
+        % In order to keep entries from bumping into each other.
+        \leftskip=12pt
+        \ifsetpercent \else
+          % If a template has been used
+          \advance\hsize by \leftskip
+        \fi
       \fi
-      % Ignoring space at the beginning and end avoids an occasional spurious
-      % blank line, when TeX decides to break the line at the space before the
-      % box from the multistrut, so the strut ends up on a line by itself.
-      % For example:
-      % @multitable @columnfractions .11 .89
-      % @item @code{#}
-      % @tab Legal holiday which is valid in major parts of the whole country.
-      % Is automatically provided with highlighting sequences respectively
-      % marking characters.
-      \noindent\ignorespaces##\unskip\multistrut
+      \noindent\ignorespaces##\unskip\strut
     }\cr
 }
 \def\Emultitable{%
@@ -4533,31 +4439,6 @@ $$%
   \global\setpercentfalse
 }
 
-\def\setmultitablespacing{%
-  \def\multistrut{\strut}% just use the standard line spacing
-  %
-  % Compute \multitablelinespace (if not defined by user) for use in
-  % \multitableparskip calculation.  We used define \multistrut based on
-  % this, but (ironically) that caused the spacing to be off.
-  % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
-\ifdim\multitablelinespace=0pt
-\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
-\global\advance\multitablelinespace by-\ht0
-\fi
-% Test to see if parskip is larger than space between lines of
-% table. If not, do nothing.
-%        If so, set to same dimension as multitablelinespace.
-\ifdim\multitableparskip>\multitablelinespace
-\global\multitableparskip=\multitablelinespace
-\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
-                                      % than skip between lines in the table.
-\fi%
-\ifdim\multitableparskip=0pt
-\global\multitableparskip=\multitablelinespace
-\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
-                                      % than skip between lines in the table.
-\fi}
-
 
 \message{conditionals,}
 
@@ -5171,30 +5052,29 @@ $$%
   \let\lbracechar\{%
   \let\rbracechar\}%
   %
+  % Non-English letters.
+  \def\AA{AA}%
+  \def\AE{AE}%
+  \def\DH{DZZ}%
+  \def\L{L}%
+  \def\OE{OE}%
+  \def\O{O}%
+  \def\TH{TH}%
+  \def\aa{aa}%
+  \def\ae{ae}%
+  \def\dh{dzz}%
+  \def\exclamdown{!}%
+  \def\l{l}%
+  \def\oe{oe}%
+  \def\ordf{a}%
+  \def\ordm{o}%
+  \def\o{o}%
+  \def\questiondown{?}%
+  \def\ss{ss}%
+  \def\th{th}%
   %
   \let\do\indexnofontsdef
   %
-  % Non-English letters.
-  \do\AA{AA}%
-  \do\AE{AE}%
-  \do\DH{DZZ}%
-  \do\L{L}%
-  \do\OE{OE}%
-  \do\O{O}%
-  \do\TH{TH}%
-  \do\aa{aa}%
-  \do\ae{ae}%
-  \do\dh{dzz}%
-  \do\exclamdown{!}%
-  \do\l{l}%
-  \do\oe{oe}%
-  \do\ordf{a}%
-  \do\ordm{o}%
-  \do\o{o}%
-  \do\questiondown{?}%
-  \do\ss{ss}%
-  \do\th{th}%
-  %
   \do\LaTeX{LaTeX}%
   \do\TeX{TeX}%
   %
@@ -8931,7 +8811,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
       \else
         \ifhavexrefs
           % We (should) know the real title if we have the xref values.
-          \def\printedrefname{\refx{#1-title}{}}%
+          \def\printedrefname{\refx{#1-title}}%
         \else
           % Otherwise just copy the Info node name.
           \def\printedrefname{\ignorespaces #1}%
@@ -9025,7 +8905,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     % If the user specified the print name (third arg) to the ref,
     % print it instead of our usual "Figure 1.2".
     \ifdim\wd\printedrefnamebox = 0pt
-      \refx{#1-snt}{}%
+      \refx{#1-snt}%
     \else
       \printedrefname
     \fi
@@ -9060,9 +8940,9 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     \else
       % Reference within this manual.
       %
-      % Only output a following space if the -snt ref is nonempty; for
-      % @unnumbered and @anchor, it won't be.
-      \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+      % Only output a following space if the -snt ref is nonempty, as the ref
+      % will be empty for @unnumbered and @anchor.
+      \setbox2 = \hbox{\ignorespaces \refx{#1-snt}}%
       \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
       %
       % output the `[mynode]' via the macro below so it can be overridden.
@@ -9073,7 +8953,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
         ,\space
         %
         % output the `page 3'.
-        \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+        \turnoffactive \putwordpage\tie\refx{#1-pg}%
         % Add a , if xref followed by a space
         \if\space\noexpand\tokenafterxref ,%
         \else\ifx\     \tokenafterxref ,% @TAB
@@ -9150,9 +9030,8 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \fi\fi\fi
 }
 
-% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME.  SUFFIX
-% is output afterwards if non-empty.
-\def\refx#1#2{%
+% \refx{NAME} - reference a cross-reference string named NAME.
+\def\refx#1{%
   \requireauxfile
   {%
     \indexnofonts
@@ -9179,7 +9058,6 @@ might help (with 'rm \jobname.?? \jobname.??s')%
     % It's defined, so just use it.
     \thisrefX
   \fi
-  #2% Output the suffix in any case.
 }
 
 % This is the macro invoked by entries in the aux file.  Define a control
@@ -9289,10 +9167,10 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   \catcode`\[=\other
   \catcode`\]=\other
   \catcode`\"=\other
-  \catcode`\_=\other
-  \catcode`\|=\other
-  \catcode`\<=\other
-  \catcode`\>=\other
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
   \catcode`\$=\other
   \catcode`\#=\other
   \catcode`\&=\other
@@ -9539,7 +9417,7 @@ might help (with 'rm \jobname.?? \jobname.??s')%
   % On the other hand, if we are in the case of @center @image, we don't
   %  want to start a paragraph, which will create a hsize-width box and
   %  eradicate the centering.
-  \ifx\centersub\centerV\else \noindent \fi
+  \ifx\centersub\centerV \else \imageindent \fi
   %
   % Output the image.
   \ifpdf
@@ -11731,3 +11609,4 @@ directory should work if nowhere else does.}
 @c vim:sw=2:
 
 @enablebackslashhack
+
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index 7109ca67dc..a17a8d67e5 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -290,7 +290,7 @@ file's contents.
 
 For external transfers, @value{tramp} sends a command as follows:
 @example
-rcp user@@host:/path/to/remote/file /tmp/tramp.4711
+$ rcp user@@host:/path/to/remote/file /tmp/tramp.4711
 @end example
 @value{tramp} reads the local temporary file @file{/tmp/tramp.4711}
 into a buffer, and then deletes the temporary file.
@@ -1071,7 +1071,7 @@ capable of servicing requests from @value{tramp}.
 
 This non-native @value{tramp} method connects via the Server Message
 Block (SMB) networking protocol to hosts running file servers that are
-typically based on @url{https://www.samba.org/,,Samba} or MS Windows.
+typically based on @uref{https://www.samba.org/,,Samba} or MS Windows.
 
 Using @command{smbclient} requires a few tweaks when working with
 @value{tramp}:
@@ -1323,7 +1323,7 @@ possible, @value{tramp} emulates those operations 
otherwise.
 
 @vindex tramp-rclone-program
 The program @command{rclone} allows to access different system
-storages in the cloud, see @url{https://rclone.org/} for a list of
+storages in the cloud, see @uref{https://rclone.org/} for a list of
 supported systems.  If the @command{rclone} program isn't found in
 your @env{PATH} environment variable, you can tell @value{tramp} its
 absolute path via the user option @code{tramp-rclone-program}.
@@ -1362,7 +1362,7 @@ for accessing the system storage, you should use it.
 On local hosts which have installed the @command{sshfs} client for
 mounting a file system based on @command{sftp}, this method can be
 used, see
-@url{https://github.com/libfuse/sshfs/blob/master/README.rst/}.  If
+@uref{https://github.com/libfuse/sshfs/blob/master/README.rst/}.  If
 the @command{sshfs} program isn't found in your @env{PATH} environment
 variable, you can tell @value{tramp} its absolute path via the user
 option @code{tramp-sshfs-program}.
@@ -2610,7 +2610,7 @@ where @samp{192.168.0.1} is the remote host IP address
 @node FUSE setup
 @section @acronym{FUSE} setup hints
 
-The @acronym{FUSE} file systems are mounted per default at
+The @acronym{FUSE} file systems are mounted by default at
 @file{/tmp/tramp.method.user@@host#port}.  The user name and port
 number are optional.  If the file system is already mounted, it will
 be used as it is.  If the mount point does not exist yet,
@@ -2629,6 +2629,11 @@ Example:
 @end group
 @end lisp
 
+@vindex tramp-fuse-unmount-on-cleanup
+The user option @code{tramp-fuse-unmount-on-cleanup}, when set to
+non-@code{nil}, controls, whether a mount point is unmounted on
+connection cleanup or on Emacs exiting.
+
 
 @anchor{Setup of rclone method}
 @subsection @option{rclone} setup
@@ -3741,27 +3746,27 @@ To open @command{powershell} as a remote shell, use 
this:
 @vindex process-connection-type
 @cindex tramp-process-connection-type
 
-Asynchronous processes differ in the way, whether they use a pseudo
-tty, or not.  This is controlled by the variable
+Asynchronous processes behave differently based on whether they use a
+pseudo tty or not.  This is controlled by the variable
 @code{process-connection-type}, which can be @code{t} or @code{pty}
-(use a pseudo tty), or @code{nil} or @code{pipe} (don't use it).
+(use a pseudo tty), or @code{nil} or @code{pipe} (don't use one).
 @value{tramp} is based on running shells on the remote host, which
-require a pseudo tty.  Therefore, it declares the variable
+requires a pseudo tty.  Therefore, it declares the variable
 @code{tramp-process-connection-type}, which carries this information
-for remote processes.  Per default, its value is @code{t}, and there's
-no need to change it.  The name of the remote pseudo tty is returned
-by the function @code{process-tty-name}.
+for remote processes.  Its default value is @code{t}, and there is no
+need to change it.  The name of the remote pseudo tty is returned by
+the function @code{process-tty-name}.
 
-If a remote process, started by @code{start-file-process}, shouldn't
-use a pseudo tty, this can be indicated by setting
+If a remote process, started by @code{start-file-process}, should
+@emph{not} use a pseudo tty, this can be requested by setting
 @code{process-connection-type} to @code{nil} or @code{pipe}.  There is
 still a pseudo tty for the started process, but some terminal
 properties are changed, like suppressing translation of carriage
 return characters into newline.
 
-The function @code{make-process} allows an explicit setting by the
-@code{:connection-type} keyword.  If this keyword is not used, the
-value of @code{process-connection-type} is applied instead.
+The function @code{make-process} allows controlling this explicitly by
+using the @code{:connection-type} keyword.  If this keyword is not
+used, the value of @code{process-connection-type} is applied instead.
 
 
 @anchor{Improving performance of asynchronous remote processes}
@@ -4289,6 +4294,14 @@ passwords from @file{auth-source.el} (@pxref{Password 
handling}).  The
 latter does not happen for the @option{sudoedit} method, otherwise it
 would be unusable.
 
+If you use the GNU ELPA version of @value{tramp}, you must load it
+explicitly, because @command{emacs -Q} ignores installed ELPA
+packages.  Call (version number adapted)
+
+@example
+$ emacs -Q -l ~/.emacs.d/elpa/tramp-2.4.5.1/tramp-autoloads
+@end example
+
 When including @value{tramp}'s messages in the bug report, increase
 the verbosity level to 6 (@pxref{Traces and Profiles, Traces}) in the
 @file{~/.emacs} file before repeating steps to the bug.  Include the
@@ -4298,6 +4311,11 @@ non-@acronym{ASCII} characters which are relevant for 
analysis, append
 the buffers as attachments to the bug report.  This is also needed in
 order to avoid line breaks during mail transfer.
 
+If you send the message from Emacs, you are asked about to append
+these buffers to the bug report.  If you use an external mail program,
+you must save these buffers to files, and append them with that mail
+program.
+
 @strong{Note} that a verbosity level greater than 6 is not necessary
 at this stage.  Also note that a verbosity level of 6 or greater, the
 contents of files and directories will be included in the debug
@@ -5091,7 +5109,7 @@ location.
 Then start Emacs Client from the command line:
 
 @example
-emacsclient @trampfn{ssh,user@@host,/file/to/edit}
+$ emacsclient @trampfn{ssh,user@@host,/file/to/edit}
 @end example
 
 @code{user} and @code{host} refer to the local host.
@@ -5111,7 +5129,7 @@ Then change the environment variable @env{EDITOR} to 
point to the
 wrapper script:
 
 @example
-export EDITOR=/path/to/emacsclient.sh
+$ export EDITOR=/path/to/emacsclient.sh
 @end example
 
 
@@ -5174,12 +5192,15 @@ tramp-compat-with-mutex}
 
 @value{tramp} comes with compatibility code for different Emacs
 versions.  When you see such a message (the text might differ), you
-don't use the Emacs built-in version of @value{tramp}.  In case you
-have installed @value{tramp} from GNU ELPA, see the package README
-file for instructions how to recompile it.
+don't use the Emacs built-in version of @value{tramp}, and you must
+recompile it.  In case you have installed @value{tramp} from GNU ELPA,
 @ifset installchapter
-@xref{Recompilation}.
+@xref{ELPA Installation}.  Otherwise, @xref{Recompilation}.
 @end ifset
+@ifclear installchapter
+see @uref{@value{trampurl}#ELPA-Installation}.  Otherwise, see
+@uref{@value{trampurl}#Recompilation}.
+@end ifclear
 
 
 @item
@@ -5308,6 +5329,12 @@ handlers.
 
 @node External packages
 @section Integrating with external Lisp packages
+
+In general, it is not recommended to use @value{tramp} functions and
+variables not described in this manual.  They might change their
+signature and/or semantics without any announcement.
+
+
 @subsection File name completion
 
 @vindex non-essential
diff --git a/etc/DEBUG b/etc/DEBUG
index fae8726186..555370588f 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -573,6 +573,28 @@ debugging did not (yet) happen.  Here are some useful 
techniques for that:
    GET_FROM_IMAGE for displaying an image, etc.  See 'enum it_method' in
    dispextern.h for the full list of values.
 
+** Debugging problems with native-compiled Lisp.
+
+When you encounter problems specific to native-compilation of Lisp, we
+recommend to follow the procedure below to try to identify the cause:
+
+ . Reduce the problematic .el file to the minimum by bisection, and
+   try identifying the function that causes the problem.
+
+ . Reduce the problematic function to the minimal code that still
+   reproduces the problem.
+
+ . Study the problem's artifacts, like Lisp or C backtraces, to try
+   identifying the cause of the problem.
+
+If you cannot figure out the cause for the problem using the above,
+native-compile the problematic file after setting the variable
+'comp-libgccjit-reproducer' to a non-nil value.  That should produce a
+file named ELNFILENAME_libgccjit_repro.c, where ELNFILENAME is the
+name of the problematic .eln file, in the same directory where the
+.eln file is produced.  Then attach that reproducer C file to your bug
+report.
+
 ** Following longjmp call.
 
 Recent versions of glibc (2.4+?) encrypt stored values for setjmp/longjmp which
@@ -875,15 +897,6 @@ It is also useful to look at the corrupted object or data 
structure in
 a fresh Emacs session and compare its contents with a session that you
 are debugging.
 
-** Debugging problems with non-ASCII characters
-
-If you experience problems which seem to be related to non-ASCII
-characters, such as \201 characters appearing in the buffer or in your
-files, set the variable byte-debug-flag to t.  This causes Emacs to do
-some extra checks, such as look for broken relations between byte and
-character positions in buffers and strings; the resulting diagnostics
-might pinpoint the cause of the problem.
-
 ** Debugging the TTY (non-windowed) version
 
 The most convenient method of debugging the character-terminal display
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 8c9306b5ca..31ea3de620 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -3,8 +3,181 @@ ERC NEWS                                                      
 -*- outline -*-
 Copyright (C) 2006-2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
-* For changes after ERC 5.3, see the main Emacs NEWS file
+Please send ERC bug reports to 'bug-gnu-emacs@gnu.org',
+and Cc the 'emacs-erc@gnu.org' mailing list as well.
+If possible, use 'M-x erc-bug' or 'M-x report-emacs-bug'.
 
+This file is about changes in ERC, the powerful, modular, and
+extensible IRC (Internet Relay Chat) client distributed with
+GNU Emacs since Emacs version 22.1.
+
+
+* Changes in ERC 5.4.1
+
+** No user-visible changes since ERC 5.4, but a few tweaks in some ERC
+file headers and the ERC manual in order to successfully build ERC for
+GNU ELPA.  (See below for the news item of ERC now being distributed
+on GNU ELPA in addition to its continued inclusion in GNU Emacs core.)
+
+
+* Changes in ERC 5.4
+
+** Starting with Emacs 28.1 and ERC 5.4, ERC NEWS are added here again.
+After ERC 5.3, since November 2012, ERC's NEWS items were added in the
+main Emacs NEWS file, and users were referred to there.  Now, starting
+with Emacs 28.1 and ERC 5.4, which mark ERC's release to GNU ELPA, ERC
+NEWS have been moved to this file again, so that we can include a NEWS
+file consisting only of ERC changes in ERC's package on GNU ELPA.
+
+The NEWS entries for ERC changes in Emacs 28.1 have been moved from
+the main Emacs NEWS file to here.  For ERC NEWS entries corresponding
+to Emacs versions before 28, to avoid modifying the NEWS file for all
+of those releases, the ERC NEWS entries have only been copied below,
+and the NEWS.* files were left intact.
+
+** ERC is now available on GNU ELPA.
+Starting with ERC 5.4, in addition to being distributed with GNU Emacs
+itself, ERC is also included in GNU ELPA, allowing users to enjoy the
+improvements of newer ERC versions on older Emacs versions as well.
+
+ERC's package page on GNU ELPA: https://elpa.gnu.org/packages/erc.html
+
+** New option 'erc-rename-buffers'.
+
+** New faces 'erc-my-nick-prefix-face' and 'erc-nick-prefix-face'.
+
+** 'erc-format-@nick' displays all user modes instead of only op and voice.
+
+** The display of irc commands in the current buffer has been disabled.
+
+** 'erc-version' now follows the Emacs version.
+
+** ERC can now hide message types by network or channel.
+'erc-hide-list' will hide all messages of the specified type, while
+'erc-network-hide-list' and 'erc-channel-hide-list' will only hide the
+specified message types for the respective specified targets.
+
+** Reconnection is now asynchronous.
+
+** Nick completion is now case-insensitive again after inadvertently
+being made case-sensitive in Emacs 24.2.
+
+** New variable 'erc-default-port-tls' used to connect to TLS IRC
+servers.
+
+** New hook 'erc-insert-done-hook'.
+This hook is called after strings have been inserted into the buffer,
+and is free to alter point and window configurations, as it's not
+called from inside a 'save-excursion', as opposed to 'erc-insert-post-hook'.
+
+** 'erc-button-google-url' has been renamed to 'erc-button-search-url'
+and its value has been changed to Duck Duck Go.
+
+** 'erc-send-pre-hook' and 'erc-send-this' have been obsoleted.
+The user option to use instead to alter text to be sent is now
+'erc-pre-send-functions'.
+
+** Improve matching/highlighting of nicknames.
+Open and close parenthesis and apostrophe are not considered valid
+nick characters anymore, matching the given grammar in RFC 2812
+section 2.3.1.  This enables correct matching and highlighting of
+nicks when they are surrounded by parentheses, like "(nick)", and when
+adjacent to an apostrophe, like "nick's".
+
+** Set 'erc-button-url-regexp' to 'browse-url-button-regexp'
+which better handles surrounding pair of parentheses.
+
+** New function 'erc-switch-to-buffer-other-window'
+which is like 'erc-switch-to-buffer', but opens the buffer in another
+window.
+
+** New function 'erc-track-switch-buffer-other-window'
+which is like 'erc-track-switch-buffer', but opens the buffer in
+another window.
+
+** NickServ passwords can now be retrieved from auth-source.
+The 'erc-use-auth-source-for-nickserv-password' user option enables
+querying auth-source for NickServ passwords.  To enable this, add the
+following to your init file:
+
+    (setq erc-use-auth-source-for-nickserv-password t)
+
+** NickServ identification now prompts for password last.
+When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
+be unconditionally prompted interactively for a password, regardless
+of the value of 'erc-nickserv-passwords', which was effectively
+ignored (same for the new
+'erc-use-auth-source-for-nickserv-password').  This limitation is now
+lifted, and the user is interactively prompted last, after the other
+identification methods have run.
+
+** The '/ignore' command will now ask for a timeout to stop ignoring the user.
+Allowed inputs are seconds or ISO8601-like periods like "1h" or "4h30m".
+
+** ERC now recognizes 'C-]' for italic text.
+Italic text is displayed in the new 'erc-italic-face'.
+
+** erc-match.el now supports 'message' highlight type (not including the nick).
+The 'erc-current-nick-highlight-type', 'erc-pal-highlight-type',
+'erc-fool-highlight-type', 'erc-keyword-highlight-type', and
+'erc-dangerous-host-highlight-type' user options now support a
+'message' type for highlighting the entire message but not the
+sender's nick.
+
+** erc-status-sidebar.el is now part of ERC.
+The 'erc-status-sidebar' package which provides a HexChat-like
+activity overview sidebar for joined IRC channels is now part of ERC.
+
+** erc-tls now supports specifying a TLS client certificate.
+The 'erc-tls' function has been updated to allow specifying a TLS
+client certificate for authentication, as an alternative to NickServ
+password-based authentication.  This is referred to as "CertFP" (short
+for Certificate Fingerprint) by several IRC networks.  See the Info
+node "(erc) Connecting" in the ERC manual for more details and
+examples on how to specify and use TLS client certificates with
+'erc-tls'.
+
+** Update IRC-related references to point to Libera.Chat.
+The Free Software Foundation and the GNU Project have moved their
+official IRC channels from the Freenode network to Libera.Chat.
+For the original announcement and the follow-up update, including
+more details, see:
+
+https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00005.html
+https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00007.html
+
+Given the relocation of GNU and FSF's official IRC channels, as well
+as #emacs and various other Emacs-themed channels (see the link below)
+to Libera.Chat, IRC-related references in the Emacs repository have
+now been updated to point to Libera.Chat.
+
+https://lists.gnu.org/archive/html/info-gnu-emacs/2021-06/msg00000.html
+
+** Add 'erc-track-select-mode-line-face' (obsoletes 'erc-track-find-face').
+The 'erc-track-find-face' function of the erc-track module has been
+declared obsolete and rewritten as 'erc-track-select-mode-line-face',
+with different expected arguments (the current and old faces are now
+separated) and clearer documentation.
+
+** Add '/opme' and '/deopme' convenience commands.
+The new '/opme' convenience command asks ChanServ to set the operator
+status for the current nick in the current channel, and '/deopme'
+unsets it.
+
+** Add '/wii' convenience command for whois with idle time.
+The new '/wii' convenience command calls the '/whois' command with the
+given nick as both arguments, which is useful for displaying the whois
+information for the nick along with idle time, even if the nick is on
+a different server than the one the current user is connected to.
+Using the given nick itself instead of the server it is connected to
+is not standardized, but is widely supported across IRC networks.
+
+** Add 'erc-bug' command for reporting ERC bugs.
+The new 'erc-bug' command prompts for a subject, and passes it on to
+'report-emacs-bug' along with the current ERC version, and adds the
+ERC mailing list in Cc.
+
+
 * Changes in ERC 5.3
 
 ** New function `erc-tls' is to be used for connecting to a server via TLS.
@@ -249,6 +422,7 @@ message types are "333" and "353", respectively.
 **** Turn this into the "xdcc" module for ERC, so that it can be more
 easily enabled.
 
+
 * Changes in ERC 5.2
 
 ** M-x erc RET now starts ERC.
@@ -528,6 +702,7 @@ not.
 **** New function: `erc-toggle-timestamps'.
 Toggles display of timestamps.
 
+
 * Changes in ERC 5.1.4
 
 ** Make find-function and find-variable work in Emacs 22 for
@@ -551,6 +726,7 @@ is deactivated.
 **** Fix some errors that occur when exiting Emacs without first
 quitting open IRC servers.
 
+
 * Changes in ERC 5.1.3
 
 ** Fix use of /quote command with no initial whitespace.
@@ -665,6 +841,7 @@ modules.
 
 **** Don't complete the user's current nickname.
 
+
 * Changes in ERC 5.1.2
 
 ** Fix compiler errors in erc-autojoin.el and erc-dcc.el.
@@ -701,6 +878,7 @@ A side effect of using this new method is that there will 
only be one
 space before a right timestamp in any saved logs.  If this is
 unacceptable, set `erc-timestamp-use-align-to' to nil.
 
+
 * Changes in ERC 5.1.1
 
 ** Fix a requirement on cl.el.
@@ -734,6 +912,7 @@ new `erc-timestamp-right-align-by-pixel' option to non-nil.
 **** Since most of these changes are now merged into Emacs22, detect
 whether we need these changes and install them only if necessary.
 
+
 * Changes in ERC 5.1
 
 ** Improve XEmacs compatibility.
@@ -940,10 +1119,12 @@ the right margin.
 
 **** Helps ERC work correctly in viper-mode.
 
+
 * Changes in ERC 5.0.4
 
 ** Fix a problem with undo in channels.
 
+
 * Changes in ERC 5.0.3
 
 ** Fix typo in the `ctcp-request-to' entry of the English catalog.
@@ -985,6 +1166,7 @@ indicator.  Previously, there was an additional 
unnecessary space.
 **** Fix an error that occurred when unchecked buffers existed when
 invoking /QUIT.
 
+
 * Changes in ERC 5.0.2
 
 ** If a channel key is required for a certain channel, ERC will prompt
@@ -1018,6 +1200,7 @@ choice anymore.
 
 **** You can now save logs and truncate buffers from the menu-bar.
 
+
 * Changes in ERC 5.0.1
 
 ** Narrowing in ERC buffers no longer causes formatting errors.
@@ -1032,6 +1215,7 @@ choice anymore.
 This means that `erc-track-priority-faces-only', `erc-track-exclude',
 and `erc-track-exclude-types' now work with server buffers.
 
+
 * Changes in ERC 5.0
 
 ** Channel members are now stored as a hash-table.
@@ -1276,6 +1460,7 @@ in XEmacs.
     mode-line where modified channels are shown (only works in GNU
     Emacs versions above 21.3).
 
+
 * Changes in ERC 4.0
 
 ** The module system has again changed a lot.  You can now customize
@@ -1299,6 +1484,7 @@ in XEmacs.
   openprojects to freenode.  You may need to update your configuration
   for a successful automatic nickserv identification.
 
+
 * Changes in ERC 3.0.cvs.20030119
 
 ** New module erc-dcc:
@@ -1330,6 +1516,7 @@ Same applies to timestamps.  You no longer need to 
(require
 the rest should be automatic.
 
 
+----------------------------------------------------------------------
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
@@ -1344,3 +1531,10 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+
+Local variables:
+coding: utf-8
+mode: outline
+paragraph-separate: "[         ]*$"
+end:
diff --git a/etc/HELLO b/etc/HELLO
index 577c2828de..8bd489fb40 100644
--- a/etc/HELLO
+++ b/etc/HELLO
@@ -38,7 +38,7 @@ Czech (čeština)       Dobrý den
 Danish (dansk) Hej / Goddag / Halløj
 Dutch (Nederlands)     Hallo / Dag
 Efik  /ˈɛfɪk/  Mɔkɔm
-Egyptian Hieroglyphs (𓂋𓐰𓏤𓈖𓆎𓅓𓏏𓐰𓊖)       𓅓𓊵𓐰𓐷𓏏𓊪𓐸, 𓇍𓇋𓂻𓍘𓇋
+Egyptian Hieroglyphs (𓂋𓏤𓈖𓆎𓅓‌𓏏𓊖)        𓅓𓊵𓏏𓊪, 𓇍𓇋𓂻𓍘𓇋
 Emacs  emacs --no-splash -f view-hello-file
 Emoji  👋
 English /ˈɪŋɡlɪʃ/      Hello
diff --git a/etc/NEWS b/etc/NEWS
index 1b67ef98b6..3cad0995ac 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1,15 +1,15 @@
 GNU Emacs NEWS -- history of user-visible changes.
 
-Copyright (C) 2019-2021 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
 Please send Emacs bug reports to 'bug-gnu-emacs@gnu.org'.
 If possible, use 'M-x report-emacs-bug'.
 
-This file is about changes in Emacs version 28.
+This file is about changes in Emacs version 29.
 
 See file HISTORY for a list of GNU Emacs versions and release dates.
-See files NEWS.27, NEWS.26, ..., NEWS.18, and NEWS.1-17 for changes
+See files NEWS.28, NEWS.27, ..., NEWS.18, and NEWS.1-17 for changes
 in older Emacs versions.
 
 You can narrow news to a specific version by calling 'view-emacs-news'
@@ -22,438 +22,236 @@ When you add a new item, use the appropriate mark if you 
are sure it
 applies, and please also update docstrings as needed.
 
 
-* Installation Changes in Emacs 28.1
-
-** Emacs now optionally supports native compilation of Lisp files.
-To enable this, configure Emacs with the '--with-native-compilation' option.
-This requires the libgccjit library to be installed and functional,
-and also requires GCC and Binutils to be available when Lisp code is
-natively compiled.  See the Info node "(elisp) Native Compilation" for
-more details.
-
-If you build Emacs with native compilation, but without zlib, be sure
-to configure with the '--without-compress-install' option, so that the
-installed *.el files are not compressed; otherwise, you will not be
-able to use JIT native compilation of the installed *.el files.
-
-** The Cairo graphics library is now used by default if present.
-'--with-cairo' is now the default, if the appropriate development files
-are found by 'configure'.  Note that building with Cairo means using
-Pango instead of libXFT for font support.  Since Pango 1.44 has
-removed support for bitmapped fonts, this may require you to adjust
-your font settings.
-
-Note also that 'FontBackend' settings in ".Xdefaults" or
-".Xresources", or 'font-backend' frame parameter settings in your init
-files, may need to be adjusted, as 'xft' is no longer a valid backend
-when using Cairo.  Use 'ftcrhb' if your Emacs was built with HarfBuzz
-text shaping support, and 'ftcr' otherwise.  You can determine this by
-checking 'system-configuration-features'.  The 'ftcr' backend will
-still be available when HarfBuzz is supported, but will not be used by
-default.  We strongly recommend building with HarBuzz support.  'x' is
-still a valid backend.
+* Installation Changes in Emacs 29.1
 
----
-** 'configure' now warns about building with libXft support.
-libXft is unmaintained, and causes a number of problems with modern
-fonts including but not limited to crashes; support for it may be
-removed in a future version of Emacs.  Please consider using
-Cairo + HarfBuzz instead.
-
----
-** 'configure' now warns about not using HarfBuzz if using Cairo.
-We want to encourage people to use the most modern font features
-available, and this is the Cairo graphics library + HarfBuzz for font
-shaping, so 'configure' now recommends that combination.
-
----
-** Building without double buffering support.
-'configure --with-xdbe=no' can now be used to disable double buffering
-at build time.
-
----
-** Support for building with Motif has been removed.
-
----
-** The configure option '--without-makeinfo' has been removed.
-This was only ever relevant when building from a repository checkout.
-This now requires makeinfo, which is part of the texinfo package.
-
----
-** Support for building with '-fcheck-pointer-bounds' has been removed.
-GCC has withdrawn the '-fcheck-pointer-bounds' option and support for
-its implementation has been removed from the Linux kernel.
-
----
-** The ftx font backend driver has been removed.
-It was declared obsolete in Emacs 27.1.
-
----
-** Emacs no longer supports old OpenBSD systems.
-OpenBSD 5.3 and older releases are no longer supported, as they lack
-proper pty support that Emacs needs.
-
-
-* Startup Changes in Emacs 28.1
-
----
-** In GTK builds, Emacs now supports startup notification.
-This means that Emacs won't steal keyboard focus upon startup
-(when started via the Desktop) if the user is typing into another
-application.
-
----
-** Errors in 'kill-emacs-hook' no longer prevent Emacs from shutting down.
-If a function in that hook signals an error in an interactive Emacs,
-the user will be prompted on whether to continue.  If the user doesn't
-answer within five seconds, Emacs will continue shutting down anyway.
-
-** Emacs now supports loading a Secure Computing filter.
-This is supported only on capable GNU/Linux systems.  To activate,
-invoke Emacs with the '--seccomp=FILE' command-line option.  FILE must
-name a binary file containing an array of 'struct sock_filter'
-structures.  Emacs will then install that list of Secure Computing
-filters into its own process early during the startup process.  You
-can use this functionality to put an Emacs process in a sandbox to
-avoid security issues when executing untrusted code.  See the manual
-page for 'seccomp' system call, for details about Secure Computing
-filters.
-
-** Emacs can support 24-bit color TTY without terminfo database.
-If your text-mode terminal supports 24-bit true color, but your system
-lacks the terminfo database, you can instruct Emacs to support 24-bit
-true color by setting 'COLORTERM=truecolor' in the environment.  This is
-useful on systems such as FreeBSD which ships only with "etc/termcap".
-
----
-** File names given on the command line are now be pushed onto history.
-The file names will be pushed onto 'file-name-history', like the names
-of files visited via 'C-x C-f' and other commands.
+** Emacs now installs the ".pdmp" file using a unique fingerprint in the name.
+The file is typically installed using a file name akin to
+"...dir/libexec/emacs/29.1/x86_64-pc-linux-gnu/emacs-<fingerprint>.pdmp".
+If a constant file name is required, the file can be renamed to
+"emacs.pdmp", and Emacs will find it during startup anyway.
 
 
-* Changes in Emacs 28.1
-
----
-** Emacs now supports Unicode Standard version 14.0.
+* Startup Changes in Emacs 29.1
 
 +++
-** New character script 'emoji' has been created.
-Various blocks of codepoints have been split out of the 'symbol'
-script into their own 'emoji' script to allow easier specification of
-their treatment.  Which codepoints are treated as emoji is derived
-from the Unicode specifications.  Also, Emacs will now use "Noto Color
-Emoji" by default for that script.  Use:
+** Emacs now has a '--fingerprint' option.
+This will output a string identifying the current Emacs build.
 
-(set-fontset-font t 'emoji
-                  '("My New Emoji Font" . "iso10646-1") nil 'prepend)
++++
+** New hook 'after-pdump-load-hook'.
+This is run at the end of the Emacs startup process, and it meant to
+be used to reinitialize structures that would normally be done at load
+time.
 
-to change the font used.
+
+* Changes in Emacs 29.1
 
-+++
-** Zero Width Joiner (ZWJ) and emoji sequences are now composed.
-Emacs can now compose (almost) all the Unicode-14 ZWJ and emoji
-sequences (if a suitable font is installed) so that they are displayed
-as single glyphs instead of multiple ones.  'Noto Color Emoji' is one
-such suitable font.
+** Emoji
 
 +++
-** New command 'execute-extended-command-for-buffer'.
-This new command, bound to 'M-S-x', works like
-'execute-extended-command', but limits the set of commands to the
-commands that have been determined to be particularly useful with the
-current mode.
+*** Emacs now has several new methods for inserting Emojis.
+The Emoji commands are under the new 'C-x 8 e' prefix.
 
 +++
-** New user option 'read-extended-command-predicate'.
-This user option controls how 'M-x' performs completion of commands when
-you type 'TAB'.  By default, any command that matches what you have
-typed is considered a completion candidate, but you can customize this
-option to exclude commands that are not applicable to the current
-buffer's major and minor modes, and respect the command's completion
-predicate (if any).
+*** New command 'emoji-insert' (bound to 'C-x 8 e e' and 'C-x 8 e i').
+This command guides you through various Emoji categories and
+combinations in a graphical menu system.
 
 +++
-** Completion on 'M-x' shows key bindings for commands.
-When 'suggest-key-bindings' is non-nil (as it is by default), the
-completion list popped up by 'M-x' shows the key bindings for all the
-commands shown in the list of candidate completions that have a key
-binding.
+*** New command 'emoji-search' (bound to 'C-x 8 e s').
+This command lets you search for Emojis based on names.
 
 +++
-** New user option 'completions-detailed'.
-When non-nil, some commands like 'describe-symbol' show more detailed
-completions with more information in completion prefix and suffix.
-The default is nil.
+*** New command 'emoji-list' (bound to 'C-x 8 e l').
+This command lists all Emojis (categorized by themes) in a special
+buffer and lets you choose one of them.
 
 ---
-** 'C-s' in 'M-x' now once again searches over completions.
-In Emacs 23, typing 'M-x' ('read-extended-command') and then 'C-s' (to
-do an interactive search) would search over possible completions.
-This was lost in Emacs 24, but is now back again.
-
----
-** User option 'completions-format' supports a new value 'one-column'.
-
-+++
-** New system for displaying documentation for groups of functions.
-This can either be used by saying 'M-x shortdoc-display-group' and
-choosing a group, or clicking a button in the "*Help*" buffers when
-looking at the doc string of a function that belongs to one of these
-groups.
+*** New command 'emoji-recent' (bound to 'C-x 8 e r').
+This command lets you choose among the Emojis you have recently
+inserted.
 
 +++
-** New minor mode 'context-menu-mode' for context menus popped by 'mouse-3'.
-When this mode is enabled, clicking 'down-mouse-3' anywhere in the buffer
-pops up a menu whose contents depends on surrounding context near the
-mouse click.  You can change the order of the default sub-menus in the
-context menu by customizing the user option 'context-menu-functions'.
-You can also invoke the context menu by pressing 'S-<F10>' or,
-on macOS, by clicking 'C-down-mouse-1'.
+*** New command 'emoji-describe' (bound to 'C-x 8 e d').
+This command will tell you the name of the Emoji at point.  (This
+command also works for non-Emoji characters.)
 
-+++
-** A new keymap for buffer actions has been added.
-The 'C-x x' keymap now holds keystrokes for various buffer-oriented
-commands.  The new keystrokes are 'C-x x g' ('revert-buffer-quick'),
-'C-x x r' ('rename-buffer'), 'C-x x u' ('rename-uniquely'), 'C-x x n'
-('clone-buffer'), 'C-x x i' ('insert-buffer'), 'C-x x t'
-('toggle-truncate-lines') and 'C-x x f' ('font-lock-update').
+** Help
 
-+++
-** Modifiers now go outside angle brackets in pretty-printed key bindings.
-For example, 'RET' with Control and Meta modifiers is now shown as
-'C-M-<return>' instead of '<C-M-return>'.  Either variant can be used
-as input; functions such as 'kbd' and 'read-kbd-macro' accept both
-styles as equivalent (they have done so for a long time).
+---
+*** 'C-h b' uses outlining by default.
+Set 'describe-bindings-outline' to nil to get the old behaviour.
 
 ---
-** 'eval-expression' no longer signals an error on incomplete expressions.
-Previously, typing 'M-: ( RET' would result in Emacs saying "End of
-file during parsing" and dropping out of the minibuffer.  The user
-would have to type 'M-: M-p' to edit and redo the expression.  Now
-Emacs will echo the message and allow the user to continue editing.
+*** Jumping to function/variable source now saves mark before moving point.
+Jumping to source from "*Help*" buffer moves the point when the source
+buffer is already open.  Now, the old point is pushed to mark ring.
 
 +++
-** 'eval-last-sexp' now handles 'defvar'/'defcustom'/'defface' specially.
-This command would previously not redefine values defined by these
-forms, but this command has now been changed to work more like
-'eval-defun', and reset the values as specified.
+*** New key bindings in *Help* buffers: 'n' and 'p'.
+These will take you (respectively) to the next and previous "page".
 
 ---
-** New user option 'use-short-answers'.
-When non-nil, the function 'y-or-n-p' is used instead of
-'yes-or-no-p'.  This eliminates the need to define an alias that maps
-one to another in the init file.  The same user option also controls
-whether the function 'read-answer' accepts short answers.
+*** 'describe-char' now also outputs the name of emoji combinations.
 
-+++
-** New user option 'kill-buffer-delete-auto-save-files'.
-If non-nil, killing a buffer that has an auto-save file will prompt
-the user for whether that file should be deleted.  (Note that
-'delete-auto-save-files', if non-nil, was previously documented to
-result in deletion of auto-save files when killing a buffer without
-unsaved changes, but this has apparently not worked for several
-decades, so the documented semantics of this variable has been changed
-to match the behavior.)
+** Outline Minor Mode
 
 +++
-** New user option 'next-error-message-highlight'.
-In addition to a fringe arrow, 'next-error' error may now optionally
-highlight the current error message in the 'next-error' buffer.
-This user option can be also customized to keep highlighting on all
-visited errors, so you can have an overview what errors were already visited.
+*** New user option 'outline-minor-mode-use-buttons'.
+If non-nil, Outline Minor Mode will use buttons to hide/show outlines
+in addition to the ellipsis.
 
 ---
-** New choice 'next-error-quit-window' for 'next-error-found-function'.
-When 'next-error-found-function' is customized to 'next-error-quit-window',
-then typing the numeric prefix argument 0 before the command 'next-error'
-will quit the source window after visiting the next occurrence.
+*** New user option 'outline-minor-mode-buttons'.
+This is a list of pairs of open/close strings used to display buttons.
 
 +++
-** New user option 'file-preserve-symlinks-on-save'.
-This controls what Emacs does when saving buffers that visit files via
-symbolic links, and 'file-precious-flag' is non-nil.
+** Support for the WebP image format.
+This support is built by default when the libwebp library is
+available.  To disable it, use the '--without-webp' configure flag.
+Image specifiers can now use ':type webp'.
 
-+++
-** New user option 'copy-directory-create-symlink'.
-If non-nil, will make 'copy-directory' (when used on a symbolic
-link) copy the link instead of following the link.  The default is
-nil, so the default behavior is unchanged.
+** Windows
 
 +++
-** New user option 'ignored-local-variable-values'.
-This is the opposite of 'safe-local-variable-values' -- it's an alist
-of variable-value pairs that are to be ignored when reading a
-local-variables section of a file.
+*** 'display-buffer' now can set up the body size of the chosen window.
+For example, an alist entry as '(window-width . (body-columns . 40))'
+will make the body of the chosen window 40 columns wide.
 
----
-** Specific warnings can now be disabled from the warning buffer.
-When a warning is displayed to the user, the resulting buffer now has
-buttons which allow making permanent changes to the treatment of that
-warning.  Automatic showing of the warning can be disabled (although
-it is still logged to the "*Messages*" buffer), or the warning can be
-disabled entirely.
+** Better detection of text suspiciously reordered on display.
+The function 'bidi-find-overridden-directionality' has been extended
+to detect reordering effects produced by embeddings and isolates
+(started by directional formatting control characters such as RLO and
+LRI).  The new command 'highlight-confusing-reorderings' finds and
+highlights segments of buffer text whose reordering for display is
+suspicious and could be malicious.
+
+
+
+** Emacs server and client changes
 
 +++
-** ".dir-locals.el" now supports setting 'auto-mode-alist'.
-The new 'auto-mode-alist' specification in ".dir-locals.el" files can
-now be used to override the global 'auto-mode-alist' in the current
-directory tree.
+*** New command-line option '-r' for emacsclient.
+With this command-line option, Emacs reuses an existing graphical client
+frame if one exists; otherwise it creates a new frame.
 
----
-** User option 'uniquify-buffer-name-style' can now be a function.
-This user option can be one of the predefined styles or a function to
-personalize the uniquified buffer name.
+* Editing Changes in Emacs 29.1
 
 ---
-** 'remove-hook' is now an interactive command.
+** Indentation of 'cl-flet' and 'cl-labels' has changed.
+These forms now indent like this:
 
----
-** 'expand-file-name' now checks for null bytes in filenames.
-The function will now check for null bytes in both NAME and
-DEFAULT-DIRECTORY arguments, as well as in the 'default-directory'
-buffer-local variable, when its value is used.  If null bytes are
-found, 'expand-file-name' will signal an error.
-This means that practically all file-related operations will now check
-file names for null bytes, thus avoiding subtle bugs with silently
-using only the part of file name up to the first null byte.
+    (cl-flet ((bla (x)
+               (* x x)))
+      (bla 42))
 
----
-** Frames
+This change also affects 'cl-macrolet', 'cl-flet*' and
+'cl-symbol-macrolet'.
 
 +++
-*** The key prefix 'C-x 5 5' displays next command buffer in a new frame.
-It's bound to the command 'other-frame-prefix' that requests the buffer
-of the next command to be displayed in a new frame.
+** New user option 'translate-upper-case-key-bindings'.
+This can be set to nil to inhibit translating upper case keys to lower
+case keys.
 
 +++
-*** New command 'clone-frame' (bound to 'C-x 5 c').
-This is like 'C-x 5 2', but uses the frame parameters of the current
-frame instead of 'default-frame-alist'.
+** New command 'ensure-empty-lines'.
+This command increases (or decreases) the number of empty lines before
+point.
 
 ---
-*** Default values of 'frame-title-format' and 'icon-title-format' have 
changed.
-These variables are used to display the title bar of visible frames
-and the title bar of an iconified frame.  They now show the name of
-the current buffer and the text "GNU Emacs" instead of the value of
-'invocation-name'.  To get the old behavior back, add the following to
-your init file:
-
-    (setq frame-title-format '(multiple-frames "%b"
-                              ("" invocation-name "@" system-name)))
-
-+++
-*** New frame parameter 'drag-with-tab-line'.
-This parameter, similar to 'drag-with-header-line', allows moving frames
-by dragging the tab lines of their topmost windows with the mouse.
+*** Improved mouse behavior with auto-scrolling modes.
+When clicking inside the 'scroll-margin' or 'hscroll-margin' region
+the point is now moved only when releasing the mouse button.  This no
+longer results in a bogus selection, unless the mouse has been
+effectively dragged.
 
 +++
-*** New optional behavior of 'delete-other-frames'.
-When invoked with a prefix argument, 'delete-other-frames' now
-iconifies frames, rather than deleting them.
+** 'kill-ring-max' now defaults to 120.
 
 ---
-*** Commands 'set-frame-width' and 'set-frame-height' now prompt for values.
-These commands now prompt for the value via the minibuffer, instead of
-requiring the user to specify the value via the prefix argument.
+** New user option 'yank-menu-max-items'.
+Customize this option to limit the amount of entries in the menu
+"Edit->Paste from Kill Menu".  The default is 60.
 
-** Windows
+** show-paren-mode
 
-*** The key prefix 'C-x 4 1' displays next command buffer in the same window.
-It's bound to the command 'same-window-prefix' that requests the buffer
-of the next command to be displayed in the same window.
++++
+*** New user option 'show-paren-context-when-offscreen'.
+When non-nil, if the point is in a closing delimiter and the opening
+delimiter is offscreen, shows some context around the opening
+delimiter in the echo area.
 
-*** The key prefix 'C-x 4 4' displays next command buffer in a new window.
-It's bound to the command 'other-window-prefix' that requests the buffer
-of the next command to be displayed in a new window.
+** Comint
 
 +++
-*** New command 'recenter-other-window', bound to 'S-M-C-l'.
-Like 'recenter-top-bottom' acting on the other window.
+*** 'comint-term-environment' is now aware of connection-local variables.
+The user option 'comint-terminfo-terminal' and variable
+'system-uses-terminfo' can now be set as connection-local variables to
+change the terminal used on a remote host.
 
-+++
-*** New user option 'delete-window-choose-selected'.
-This allows to choose a window that will be the frame's selected
-window after deleting the currently selected one.
+
+* Changes in Specialized Modes and Packages in Emacs 29.1
 
-+++
-*** New argument NO-OTHER for some window functions.
-'get-lru-window', 'get-mru-window' and 'get-largest-window' now accept a
-new optional argument NO-OTHER which, if non-nil, avoids returning a
-window whose 'no-other-window' parameter is non-nil.
+** vc
 
-+++
-*** New 'display-buffer' function 'display-buffer-use-least-recent-window'.
-This is like 'display-buffer-use-some-window', but won't reuse the
-current window, and when called repeatedly will try not to reuse a
-previously selected window.
+---
+*** 'C-x v v' on an unregistered file will now use the most specific backend.
+Previously, if you had an SVN-covered ~/ directory, and a Git-covered
+directory in ~/foo/bar, using 'C-x v v' on a new, unregistered file
+~/foo/bar/zot would register it in the SVN repository in ~/ instead of
+in the Git repository in ~/foo/bar.  This makes this command
+consistent with 'vc-responsible-backend'.
 
-+++
-*** New function 'window-bump-use-time'.
-This updates the use time of a window.
+** Message
 
-** Minibuffer
+---
+*** New user option 'mml-attach-file-at-the-end'.
+If non-nil, 'C-c C-a' will put attached files at the end of the message.
 
-+++
-*** Minibuffer scrolling is now conservative by default.
-This is controlled by the new variable 'scroll-minibuffer-conservatively'.
-It is t by default; setting it to nil will cause scrolling in the
-minibuffer obey the value of 'scroll-conservatively'.
+---
+*** Message Mode now supports image yanking.
 
-+++
-*** Improved handling of minibuffers on switching frames.
-By default, when you switch to another frame, an active minibuffer now
-moves to the newly selected frame.  Nevertheless, the effect of what
-you type in the minibuffer happens in the frame where the minibuffer
-was first activated.  An alternative behavior is available by
-customizing 'minibuffer-follows-selected-frame' to nil.  Here, the
-minibuffer stays in the frame where you first opened it, and you must
-switch back to this frame to continue or abort its command.  The old
-behavior, which mixed these two, can be approximated by customizing
-'minibuffer-follows-selected-frame' to a value which is neither nil
-nor t.
+---
+*** HTML Mode now supports text/html and image/* yanking.
 
-+++
-*** New user option 'read-minibuffer-restore-windows'.
-When customized to nil, it uses 'minibuffer-restore-windows' in
-'minibuffer-exit-hook' to remove only the window showing the
-"*Completions*" buffer.
+** Texinfo Mode
 
 ---
-*** New variable 'redisplay-adhoc-scroll-in-resize-mini-windows'.
-Customizing it to nil will disable the ad-hoc auto-scrolling of
-minibuffer text shown in mini-windows when resizing those windows.
-The default heuristics of that scrolling can be counter productive in
-some corner cases, though the cure might be worse than the disease.
-This said, the effect should be negligible in the vast majority of
-cases anyway.
+*** 'texinfo-mode' now has a specialised 'narrow-to-defun' definition.
+It narrows to the current node.
 
-** Mode Line
+** eww/shr
 
 +++
-*** New user option 'mode-line-compact'.
-If non-nil, repeating spaces are compressed into a single space.  If
-'long', this is only done when the mode line is longer than the
-current window width (in columns).
+*** New user option 'shr-use-xwidgets-for-media'.
+If non-nil (and Emacs has been built with support for xwidgets),
+display <video> elements with an xwidget.  Note that this is
+experimental, and is known to crash Emacs on some systems, and just
+doesn't work on other systems.  Also see etc/PROBLEMS.
 
 +++
-*** New user options to control format of line/column numbers in the mode line.
-'mode-line-position-line-format' is the line number format (when
-'line-number-mode' is on), 'mode-line-position-column-format' is
-the column number format (when 'column-number-mode' is on), and
-'mode-line-position-column-line-format' is the combined format (when
-both modes are on).
+*** New user option 'eww-url-transformers'.
+These are used to alter an URL before using it.  By default it removes
+the common utm_ trackers from URLs.
+
+** Gnus
 
-** Tab Bars and Tab Lines
++++
+*** New user option 'gnus-treat-emojize-symbols'.
+If non-nil, symbols that have an emoji representation will be
+displayed as emojis.
 
 +++
-*** The prefix key 'C-x t t' can be used to display a buffer in a new tab.
-Typing 'C-x t t' before a command will cause the buffer shown by that
-command to be displayed in a new tab.  'C-x t t" is bound to the
-command 'other-tab-prefix'.
+*** New command 'gnus-article-emojize-symbols'.
+This is bound to 'W D e' and will display symbols that have emoji
+representation as emojis.
+
+** EIEIO
 
 +++
 *** New command 'C-x t C-r' to open file read-only in the other tab.
 
++++
 *** The tab bar now supports more mouse commands.
 Clicking 'mouse-2' closes the tab, 'mouse-3' displays the context menu
 with items that operate on the clicked tab.  Dragging the tab with
@@ -461,20 +259,20 @@ with items that operate on the clicked tab.  Dragging the 
tab with
 scrolling switches to the previous/next tab, and holding the Shift key
 during scrolling moves the tab to the left/right.
 
----
++++
 *** Frame-specific appearance of the tab bar when 'tab-bar-show' is a number.
 When 'tab-bar-show' is a number, the tab bar on different frames can
 be shown or hidden independently, as determined by the number of tabs
 on each frame compared to the numerical value of 'tab-bar-show'.
 
----
++++
 *** New command 'toggle-frame-tab-bar'.
 It can be used to enable/disable the tab bar on the currently selected
 frame regardless of the values of 'tab-bar-mode' and 'tab-bar-show'.
-This allows to enable/disable the tab bar independently on different
+This allows enabling/disabling the tab bar independently on different
 frames.
 
----
++++
 *** New user option 'tab-bar-format' defines a list of tab bar items.
 When it contains 'tab-bar-format-global' (possibly appended after
 'tab-bar-format-align-right'), then after enabling 'display-time-mode'
@@ -483,14 +281,14 @@ aligned to the right on the tab bar instead of on the 
mode line.
 When 'tab-bar-format-tabs' is replaced with 'tab-bar-format-tabs-groups',
 the tab bar displays tab groups.
 
----
++++
 *** New optional key binding for 'tab-last'.
-If you customize the variable 'tab-bar-select-tab-modifiers' for
-selecting tabs using its index numbers, the '<MODIFIER>-9' key is
-bound to 'tab-last', and switches to the last tab.  Here <MODIFIER> is
-any of the modifiers in the list that is the value of
-'tab-bar-select-tab-modifiers'.  You can also use negative indices,
-which count from the last tab: -1 is the last tab, -2 the one before
+If you customize the user option 'tab-bar-select-tab-modifiers' to
+allow selecting tabs using their index numbers, the '<MODIFIER>-9' key
+is bound to 'tab-last', and switches to the last tab.  Here <MODIFIER>
+is any of the modifiers in the list that is the value of
+'tab-bar-select-tab-modifiers'.  You can also use positive indices,
+which count from the last tab: 1 is the last tab, 2 the one before
 that, etc.
 
 ---
@@ -520,3904 +318,514 @@ move it closer to other tabs in the same group.
 ---
 *** New user option 'tab-line-tab-name-format-function'.
 
----
-*** The tabs in the tab line can now be scrolled using horizontal scroll.
-If your mouse or trackpad supports it, you can now scroll tabs when
-the mouse pointer is in the tab line by scrolling left or right.
-
----
-*** New tab-line faces and options.
-The face 'tab-line-tab-special' is used for tabs whose buffers are
-special, i.e. buffers that don't visit a file.  The face
-'tab-line-tab-inactive-alternate' is used to display inactive tabs
-with an alternating background color, making them easier to
-distinguish, especially if the face 'tab-line-tab' is configured to
-not display with a box; this alternate face is only applied when the
-option 'tab-line-tab-face-functions' is so configured.  That option
-may also be used to customize tab-line faces in other ways.
-
-** Mouse wheel
+** align
 
 ---
-*** Mouse wheel scrolling now defaults to one line at a time.
+*** Alignment in 'text-mode' has changed.
+Previously, 'M-x align' didn't do anything, and you had to say 'C-u
+M-x align' for it to work.  This has now been changed.  The default
+regexp for 'C-u M-x align-regexp' has also been changed to be easier
+for inexperienced users to use.
 
----
-*** Mouse wheel scrolling now works on more parts of frame's display.
-When using 'mwheel-mode', the mouse wheel will now scroll also when
-the mouse cursor is on the scroll bars, fringes, margins, header line,
-and mode line.  ('mwheel-mode' is enabled by default on most graphical
-displays.)
+** eww
 
 +++
-*** Mouse wheel scrolling with Shift modifier now scrolls horizontally.
-This works in text buffers and over images.  Typing a numeric prefix arg
-(e.g. 'M-5') before starting horizontal scrolling changes its step value.
-The value is saved in the user option 'mouse-wheel-scroll-amount-horizontal'.
+*** New user option to automatically rename EWW buffers.
+The 'eww-auto-rename-buffer' user option can be configured to rename
+rendered web pages by using their title, URL, or a user-defined
+function which returns a string.  For the first two cases, the length
+of the resulting name is controlled by 'eww-buffer-name-length'.  By
+default, no automatic renaming is performed.
 
-** Customize
-
----
-*** Customize buffers can now be reverted with 'C-x x g'.
+** Help
 
----
-*** Most customize commands now hide obsolete user options.
-Obsolete user options are no longer shown in the listings produced by
-the commands 'customize', 'customize-group', 'customize-apropos' and
-'customize-changed'.
+*** New user option 'help-link-key-to-documentation'.
+When this option is non-nil, key bindings displayed in the "*Help*"
+buffer will be linked to the documentation for the command they are
+bound to.  This does not affect listings of key bindings and
+functions (such as 'C-h b').
 
-To customize obsolete user options, use 'customize-option' or
-'customize-saved'.
+** info-look
 
 ---
-*** New SVG icons for checkboxes and arrows.
-They will be used automatically instead of the old icons.  If Emacs is
-built without SVG support, the old icons will be used instead.
-
-** Help
+*** info-look specs can now be expanded at run time instead of a load time.
+The new ':doc-spec-function' element can be used to compute the
+':doc-spec' element when the user asks for info on that particular
+mode (instead of at load time).
 
----
-*** The order things are displayed in the *Help* buffer has been changed.
-The indented "administrative" block (containing the "probably
-introduced" and "other relevant functions" (and similar things) has
-been moved to after the doc string.
+** subr-x
 
 +++
-*** New command 'describe-command' shows help for a command.
-This can be used instead of 'describe-function' for interactive
-commands and is globally bound to 'C-h x'.
+*** New macro 'with-memoization' provides a very primitive form of memoization.
 
-+++
-*** New command 'describe-keymap' describes keybindings in a keymap.
+** ansi-color
 
 ---
-*** New command 'apropos-function'.
-This works like 'C-u M-x apropos-command' but is more discoverable.
+*** Support for ANSI 256-color and 24-bit colors.
+256-color and 24-bit color codes are now handled by ANSI color
+filters and displayed with the specified color.
 
----
-*** New keybinding 'C-h R' prompts for an Info manual and displays it.
+** term-mode
 
 ---
-*** Keybindings in 'help-mode' use the new 'help-key-binding' face.
-This face is added by 'substitute-command-keys' to any "\[command]"
-substitution.  The return value of that function should consequently
-be assumed to be a propertized string.
+*** Support for ANSI 256-color and 24-bit colors, italic and other fonts.
+Term-mode can now display 256-color and 24-bit color codes.  It can
+also handle ANSI codes for faint, italic and blinking text, displaying
+it with new 'term-{faint,italic,slow-blink,fast-blink}' faces.
 
-Note that the new face will also be used in tooltips.  When using the
-GTK toolkit, this is only true if 'x-gtk-use-system-tooltips' is t.
-
-+++
-*** New user option 'help-enable-symbol-autoload'.
-If non-nil, displaying help for an autoloaded function whose
-'autoload' form provides no documentation string will try to load the
-file it's from.  This will give more extensive help for such
-functions.
+** Xref
 
----
-*** The 'help-for-help' ('C-h C-h') screen has been redesigned.
+*** 'project-find-file' and 'project-or-external-find-file' now accept
+a prefix argument which is interpreted to mean "include all files".
 
 +++
-*** New convenience commands with short keys in the Help buffer.
-New command 'help-view-source' ('s') will view the source file (if
-any) of the current help topic.  New command 'help-goto-info' ('i')
-will look up the current symbol (if any) in Info.  New command
-'help-customize' ('c') will customize the variable or the face
-(if any) whose doc string is being shown in the Help buffer.
+*** New command 'xref-go-forward'.
+It is bound to 'C-M-,' and jumps to the location where 'xref-go-back'
+('M-,', also known as 'xref-pop-marker-stack') was invoked previously.
 
----
-*** New user option 'describe-bindings-outline'.
-It enables outlines in the output buffer of 'describe-bindings' that
-can provide a better overview in a long list of available bindings.
-
-+++
-*** New command 'lossage-size'.
-It allows users to change the maximum number of keystrokes and
-commands recorded for the purpose of 'view-lossage'.
+** File notifications
 
 +++
-*** New commands to describe buttons and widgets.
-'widget-describe' (on a widget) will pop up a help buffer and give a
-description of the properties.  Likewise 'button-describe' does the
-same for a button.
-
----
-*** Improved "find definition" feature of "*Help*" buffers.
-Now clicking on the link to find the definition of functions generated
-by 'cl-defstruct', or variables generated by 'define-derived-mode',
-for example, will go to the exact place where they are defined.
-
----
-*** New commands 'apropos-next-symbol' and 'apropos-previous-symbol'.
-These new navigation commands are bound to 'n' and 'p' in
-'apropos-mode'.
-
----
-*** The command 'view-lossage' can now be invoked from the menu bar.
-The menu bar "Help" menu now has a "Show Recent Inputs" item under the
-"Describe" sub-menu.
+*** The new command 'file-notify-rm-all-watches' removes all file 
notifications.
 
----
-*** Closing the "*Help*" buffer from the toolbar now buries the buffer.
-In previous Emacs versions, the "*Help*" buffer was killed instead when
-clicking the "X" icon in the tool bar.
+** Sql
 
 ---
-*** 'g' ('revert-buffer') in 'help-mode' no longer requires confirmation.
-
-** File Locks
-
-+++
-*** New user option 'lock-file-name-transforms'.
-This option allows controlling where lock files are written.  It uses
-the same syntax as 'auto-save-file-name-transforms'.
-
-+++
-*** New user option 'remote-file-name-inhibit-locks'.
-When non-nil, this option suppresses lock files for remote files.
-
-+++
-*** New minor mode 'lock-file-mode'.
-This command, called interactively, toggles the local value of
-'create-lockfiles' in the current buffer.
-
-** Emacs Server
+*** Sql now supports sending of passwords in-process.
+To improve security, if an sql product has ':password-in-comint' set
+to t, a password supplied via the minibuffer will be sent in-process,
+as opposed to via the command-line.
 
-+++
-*** New user option 'server-client-instructions'.
-When emacsclient connects, Emacs will (by default) output a message
-about how to exit the client frame.  If 'server-client-instructions'
-is set to nil, this message is inhibited.
+** Image Mode
 
 +++
-*** New command 'server-edit-abort'.
-This command (not bound to any key by default) can be used to abort
-an edit instead of marking it as "Done" (which the 'C-x #' command
-does).  The 'emacsclient' program exits with an abnormal status as
-result of this command.
+*** New command 'image-transform-fit-to-window'.
+This command fits the image to the current window by scaling down or
+up as necessary.  Unlike 'image-transform-fit-both', this does not
+only scale the image down, but up as well.  It is bound to "s w" in
+Image Mode by default.
 
 +++
-*** New desktop integration for connecting to the server.
-If your operating system’s desktop environment is
-freedesktop.org-compatible (which is true of most GNU/Linux and other
-recent Unix-like desktops), you may use the new "Emacs (Client)"
-desktop menu entry to open files in an existing Emacs instance rather
-than starting a new one.  The daemon starts if it is not already
-running.
+*** 'image-transform-fit-to-(height|width)' are now obsolete.
+Use the new command 'image-transform-fit-to-window' instead.
+The keybinding for 'image-transform-fit-to-width' is now 's i'.
 
-** Miscellaneous
+---
+*** User option 'image-auto-resize' can now be set to 'fit-window'.
+This works like 'image-transform-fit-to-window'.
 
-+++
-*** New command 'font-lock-update', bound to 'C-x x f'.
-This command updates the syntax highlighting in this buffer.
+*** New user option 'image-auto-resize-max-scale-percent'.
+The new 'fit-window' options will never scale an image more than this
+much (in percent).  It is nil by default.
 
-+++
-*** New command 'memory-report'.
-This command opens a new buffer called "*Memory Report*" and gives a
-summary of where Emacs is using memory currently.
+** Image-Dired
 
 +++
-*** New command 'submit-emacs-patch'.
-This works like 'report-emacs-bug', but is more geared towards sending
-patches to the Emacs issue tracker.
+*** 'image-dired-display-image-mode' is now based on 'image-mode'.
+This avoids converting images in the background, and makes Image-Dired
+noticeably faster.  New keybindings from 'image-mode' are now
+available in the "*image-dired-display-image*" buffer; press '?' or
+'h' in that buffer to see the full list.  Finally, some commands and
+user options that are no longer needed are now obsolete:
+'image-dired-cmd-create-temp-image-options',
+'image-dired-cmd-create-temp-image-program',
+'image-dired-display-current-image-full',
+'image-dired-display-current-image-sized',
+'image-dired-display-window-height-correction',
+'image-dired-display-window-width-correction',
+'image-dired-temp-image-file'.
 
 ---
-*** New face 'apropos-button'.
-Applies to buttons that indicate a face.
-
-+++
-*** New face 'font-lock-doc-markup-face'.
-Intended for documentation mark-up syntax and tags inside text that
-uses 'font-lock-doc-face', with which it should harmonize.  It would
-typically be used in structured documentation comments in program
-source code by language-specific modes, for mark-up conventions like
-Haddock, Javadoc or Doxygen.  By default this face inherits from
-'font-lock-constant-face'.
+*** Reduce dependency on external "exiftool" command.
+The 'image-dired-copy-with-exif-file-name' no longer requires an
+external "exiftool" command to be available.  The user options
+'image-dired-cmd-read-exif-data-program' and
+'image-dired-cmd-read-exif-data-options' are now obsolete.
 
-+++
-*** New face 'flat-button'.
-This is a plain 2D button, but uses the background color instead of
-the foreground color.
+---
+*** New command for the thumbnail buffer.
+The new command 'image-dired-unmark-all-marks' has been added.  It is
+bound to "U" in the thumbnail buffer.
 
 ---
-*** New face 'shortdoc-heading'.
-Applies to headings of shortdoc sections.
+*** Support Thumbnail Managing Standard v0.9.0 (Dec 2020).
+This standard allows sharing generated thumbnails across different
+programs.  Version 0.9.0 adds two larger thumbnail sizes: 512x512 and
+1024x1024 pixels.  See the user option `image-dired-thumbnail-storage'
+to use it; it is not enabled by default.
 
 ---
-*** New face 'separator-line'.
-This is used by 'make-separator-line' (see below).
-
-*** 'redisplay-skip-fontification-on-input' helps Emacs keep up with fast 
input.
-This is another attempt to solve the problem of handling high key repeat rate
-and other "slow scrolling" situations.  It is hoped it behaves better
-than 'fast-but-imprecise-scrolling' and 'jit-lock-defer-time'.
-It is not enabled by default.
-
-*** Obsolete aliases are no longer hidden from command completion.
-Completion of command names now considers obsolete aliases as
-candidates, if they were marked obsolete in the current major version
-of Emacs.  Invoking a command via an obsolete alias now mentions the
-obsolescence fact and shows the new name of the command.
-
-*** Support for '(box . SIZE)' 'cursor-type'.
-By default, 'box' cursor always has a filled box shape.  But if you
-specify 'cursor-type' to be '(box . SIZE)', the cursor becomes a hollow
-box if the point is on an image larger than SIZE pixels in any
-dimension.
+*** Support GraphicsMagick command line tools.
+Support for the GraphicsMagick command line tool ("gm") has been
+added, and is used instead of ImageMagick when it is available.
 
-+++
-*** The user can now customize how "default" values are prompted for.
-The new utility function 'format-prompt' has been added which uses the
-new 'minibuffer-default-prompt-format' user option to format "default"
-prompts.  This means that prompts that look like "Enter a number
-(default 10)" can be customized to look like, for instance, "Enter a
-number [10]", or not have the default displayed at all, like "Enter a
-number".  (This only affects callers that were altered to use
-'format-prompt'.)
+---
+*** New face 'image-dired-thumb-flagged'.
+If 'image-dired-thumb-mark' is non-nil (the default), this face is
+used for images that are flagged for deletion in the Dired buffer
+associated with Image-Dired.
 
 ---
-*** New help window when Emacs prompts before opening a large file.
-Commands like 'find-file' or 'visit-tags-table' ask to visit a file
-normally or literally when the file is larger than a certain size (by
-default, 9.5 MiB).  Press '?' or 'C-h' in that prompt to read more
-about the different options to visit a file, how you can disable the
-prompt, and how you can tweak the file size threshold.
+*** Support for bookmark.el.
+The command 'bookmark-set' (bound to 'C-x r m') is now supported in
+the thumbnail view, and will create a bookmark that opens the current
+directory in Image-Dired.
 
 +++
-*** Emacs now defaults to UTF-8 instead of ISO-8859-1.
-This is only for the default, where the user has set no 'LANG' (or
-similar) variable or environment.  This change should lead to no
-user-visible changes for normal usage.
+*** 'image-dired-show-all-from-dir-max-files' has been increased to 500.
+This option controls asking for confirmation when starting Image-Dired
+in a directory with many files.  However, Image-Dired creates
+thumbnails in the background these days, so this is not as important
+as it used to be, back when entering a large directory could lock up
+Emacs for tens of seconds.  In addition, you can now customize this
+option to nil to disable this confirmation completely.
 
 ---
-*** 'global-display-fill-column-indicator-mode' skips some buffers.
-By default, turning on 'global-display-fill-column-indicator-mode'
-doesn't turn on 'display-fill-column-indicator-mode' in special-mode
-buffers.  This can be controlled by customizing the variable
-'global-display-fill-column-indicator-modes'.
-
-+++
-*** 'nobreak-char-display' now also affects all non-ASCII space characters.
-Previously, this was limited only to 'NO-BREAK SPACE' and hyphen
-characters.  Now it also covers the rest of the non-ASCII Unicode
-space characters.
+*** Make 'image-dired-rotate-thumbnail-(left|right)' obsolete.
+Instead, use 'M-x image-dired-refresh-thumb' to generate a new
+thumbnail, or 'M-x image-rotate' to rotate the thumbnail without
+updating the thumbnail file.
 
-+++
-*** Improved support for terminal emulators that encode the Meta flag.
-Some terminal emulators set the 8th bit of Meta characters, and then
-encode the resulting character code as if it were non-ASCII character
-above codepoint 127.  Previously, the only way of using these in Emacs
-was to set up the terminal emulator to use the 'ESC' characters to send
-Meta characters to Emacs, e.g., send "ESC x" when the user types
-'M-x'.  You can now avoid the need for this setup of such terminal
-emulators by using the new input-meta-mode with the special value
-'encoded' with these terminal emulators.
+** Dired
 
 ---
-*** 'auto-composition-mode' can now be selectively disabled on some TTYs.
-Some text-mode terminals produce display glitches trying to compose
-characters.  The 'auto-composition-mode' can now have a string value
-that names a terminal type; if the value returned by the 'tty-type'
-function compares equal with that string, automatic composition will
-be disabled in windows shown on that terminal.  The Linux terminal
-sets this up by default.
+*** New user option 'dired-make-directory-clickable'.
+If non-nil (which is the default), hitting 'RET' or 'mouse-1' on
+the directory components at the directory displayed at the start of
+the buffer will take you to that directory.
 
----
-*** Support for the 'strike-through' face attribute on TTY frames.
-If your terminal's termcap or terminfo database entry has the 'smxx'
-capability defined, Emacs will now emit the prescribed escape
-sequences necessary to render faces with the 'strike-through'
-attribute on TTY frames.
 
----
-*** TTY menu navigation is now supported in 'xterm-mouse-mode'.
-TTY menus support mouse navigation and selection when 'xterm-mouse-mode'
-is active.  When run on a terminal, clicking on the menu bar with the
-mouse now pops up a TTY menu by default instead of running the command
-'tmm-menubar'.  To restore the old behavior, set the user option
-'tty-menu-open-use-tmm' to non-nil.
+** Exif
 
----
-*** 'M-x report-emacs-bug' will no longer include "Recent messages" section.
-These were taken from the "*Messages*" buffer, and may inadvertently
-leak information from the reporting user.
+*** New function 'exif-field'.
+This is a convenience function to extract the field data from
+'exif-parse-file' and 'exif-parse-buffer'.
 
----
-*** 'C-u M-x dig' will now prompt for a query type to use.
+** Xwidgets
 
 ---
-*** Rudimentary support for the 'st' terminal emulator.
-Emacs now supports 256 color display on the 'st' terminal emulator.
+*** New user option 'xwidget-webkit-buffer-name-prefix'.
+This allows the user to change the webkit buffer names.
 
 +++
-*** Update IRC-related references to point to Libera.Chat.
-The Free Software Foundation and the GNU Project have moved their
-official IRC channels from the Freenode network to Libera.Chat.  For the
-original announcement and the follow-up update, including more details,
-see:
+*** New minor mode 'xwidget-webkit-edit-mode'.
+When this mode is enabled, self-inserting characters and other common
+web browser shotcut keys are redefined to send themselves to the
+WebKit widget.
 
-https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00005.html
-https://lists.gnu.org/archive/html/info-gnu/2021-06/msg00007.html
++++
+*** New minor mode 'xwidget-webkit-isearch-mode'.
+This mode acts similarly to incremental search, and allows to search
+the contents of a WebKit widget.  In xwidget-webkit mode, it is bound
+to 'C-s' and 'C-r'.
 
-Given the relocation of GNU and FSF's official IRC channels, as well
-as #emacs and various other Emacs-themed channels (see the link below)
-to Libera.Chat, IRC-related references in the Emacs repository have
-now been updated to point to Libera.Chat.
+---
+*** On X11, the WebKit inspector is now available inside xwidgets.
+To access the inspector, right click on the widget and select "Inspect
+Element".
 
-https://lists.gnu.org/archive/html/info-gnu-emacs/2021-06/msg00000.html
+---
+*** "Open in New Window" in a WebKit widget's context menu now works.
+The newly created buffer will be displayed via 'display-buffer', which
+can be customized through the usual mechanism of 'display-buffer-alist'
+and friends.
 
 
-* Editing Changes in Emacs 28.1
-
-** Input methods
+* New Modes and Packages in Emacs 29.1
 
 +++
-*** Emacs now supports "transient" input methods.
-A transient input method is enabled for inserting a single character,
-and is then automatically disabled.  'C-x \' temporarily enables the
-selected transient input method.  Use 'C-u C-x \' to select a
-transient input method (which can be different from the input method
-enabled by 'C-\').  For example, 'C-u C-x \ compose RET' selects the
-'compose' input method; then typing 'C-x \ 1 2' will insert the
-character '½', and disable the 'compose' input method afterwards.
-You can use 'C-x \' in incremental search to insert a single character
-to the search string.
+** New mode 'erts-mode'.
+This mode is used to edit files geared towards testing actions in
+Emacs buffers, like indentation and the like.  The new ert function
+'ert-test-erts-file' is used to parse these files.
 
----
-*** New input method 'compose' based on X Multi_key sequences.
+
+* Incompatible Lisp Changes in Emacs 29.1
 
----
-*** New input method 'iso-transl' with the same keys as 'C-x 8'.
-After selecting it as a transient input method with 'C-u C-x \
-iso-transl RET', it supports the same key sequences as 'C-x 8',
-so e.g. like 'C-x 8 [' inserts a left single quotation mark,
-'C-x \ [' does the same.
+** Fonts
 
 ---
-*** New user option 'read-char-by-name-sort'.
-It defines the sorting order of characters for completion of 'C-x 8 RET TAB'
-and can be customized to sort them by codepoints instead of character names.
-Additionally, you can group characters by Unicode blocks after customizing
-'completions-group' and 'completions-group-sort'.
+*** Emacs now supports `medium' fonts.
+Emacs previously didn't distinguish between the `regular'/`normal'
+weight and the `medium' weight, but it now also supports the (heavier)
+`medium' weight.  However, this means that if you previously specified
+a weight of `normal' and the font doesn't have this weight, Emacs
+won't find the font spec.  In these cases, replacing ":weight 'normal"
+with ":weight 'medium" should fix the issue.
 
----
-*** Improved language transliteration in Malayalam input methods.
-Added a new Mozhi scheme.  The inapplicable ITRANS scheme is now
-deprecated.  Errors in the Inscript method were corrected.
+** Keymap descriptions have changed.
+'help--describe-command', 'C-h b' and associated functions that output
+keymap descriptions have changed.  In particular, prefix commands are
+not output at all, and instead of "??" for closures/functions,
+"[closure]"/"[lambda]" is output.
 
 ---
-*** New input method 'cham'.
-There's also a Cham greeting in "etc/HELLO".
+** 'downcase' details have changed slightly.
+In certain locales, changing the case of an ASCII-range character may
+turn it into a multibyte character, most notably with "I" in Turkish
+(the lowercase is "ı", 0x0131).  Previously, 'downcase' on a unibyte
+string was buggy, and would mistakenly just return the lower byte of
+this, 0x31 (the digit "1").  'downcase' on a unibyte string has now
+been changed to downcase such characters as if they were ASCII.  To
+get proper locale-dependent downcasing, the string has to be converted
+to multibyte first.  (This goes for the other case-changing functions,
+too.)
 
 ---
-*** New input methods for Lakota language orthographies.
-Two orthographies are represented here, the Suggested Lakota
-Orthography and what is known as the White Hat Orthography.  Input
-methods 'lakota-slo-prefix', 'lakota-slo-postfix', and
-'lakota-white-hat-postfix' have been added.  There is also a Lakota
-greeting in "etc/HELLO".
-
-+++
-** Standalone 'M-y' allows interactive selection from previous kills.
-'M-y' can now be typed after a command that is not a yank command.
-When invoked like that, it prompts in the minibuffer for one of the
-previous kills, offering completion and minibuffer-history navigation
-through previous kills recorded in the kill ring.  A similar feature
-in Isearch can be invoked if you bind 'C-s M-y' to the command
-'isearch-yank-pop'.  When the user option 'yank-from-kill-ring-rotate'
-is nil the kill ring is not rotated after 'yank-from-kill-ring'.
-
-+++
-** New user option 'word-wrap-by-category'.
-When word-wrap is enabled, and this option is non-nil, that allows
-Emacs to break lines after more characters than just whitespace
-characters.  In particular, this significantly improves word-wrapping
-for CJK text mixed with Latin text.
-
-+++
-** New command 'undo-redo'.
-It undoes previous undo commands, but doesn't record itself as an
-undoable command.
+** 'def' indentation changes.
+In 'emacs-lisp-mode', forms with a symbol with a name that start with
+"def" have been automatically indented as if they were 'defun'-like
+forms, for instance:
 
-+++
-** New commands 'copy-matching-lines' and 'kill-matching-lines'.
-These commands are similar to the command 'flush-lines',
-but add the matching lines to the kill ring as a single string,
-including the newlines that separate the lines.
+    (defzot 1
+      2 3)
 
-+++
-** New user option 'kill-transform-function'.
-This can be used to transform (and suppress) strings from entering the
-kill ring.
+This heuristic has now been removed, and all functions/macros that
+want to be indented this way have to be marked with
 
-+++
-** 'save-interprogram-paste-before-kill' can now be a number.
-In that case, it's interpreted as a limit on the size of the clipboard
-data that will be saved to the 'kill-ring' prior to killing text: if
-the size of the clipboard data is greater than or equal to the limit,
-it will not be saved.
+    (declare (indent defun))
 
-+++
-** New user option 'tab-first-completion'.
-If 'tab-always-indent' is 'complete', this new user option can be used to
-further tweak whether to complete or indent.
+or the like.  If the function/macro definition itself can't be
+changed, the indentation can also be adjusted by saying something
+like:
 
----
-** 'indent-tabs-mode' is now a global minor mode instead of just a variable.
+    (put 'defzot 'lisp-indent-function 'defun)
 
 ---
-** New choice 'permanent' for 'shift-select-mode'.
-When the mark was activated by shifted motion keys, non-shifted motion
-keys don't deactivate the mark after customizing 'shift-select-mode'
-to 'permanent'.
-
-+++
-** The "Edit => Clear" menu item now obeys a rectangular region.
-
-+++
-** New command 'revert-buffer-with-fine-grain'.
-Revert a buffer trying to be as non-destructive as possible,
-preserving markers, properties and overlays.  The new variable
-'revert-buffer-with-fine-grain-max-seconds' specifies the maximum
-number of seconds that 'revert-buffer-with-fine-grain' should spend
-trying to be non-destructive.
-
-+++
-** New command 'revert-buffer-quick'.
-This is bound to 'C-x x g' and is like 'revert-buffer', but prompts
-less.
-
-+++
-** New user option 'revert-buffer-quick-short-answers'.
-This controls how the new 'revert-buffer-quick' ('C-x x g') command
-prompts.
-
-+++
-** New user option 'query-about-changed-file'.
-If non-nil (the default), Emacs prompts as before when re-visiting a
-file that has changed externally after it was visited the first time.
-If nil, Emacs does not prompt, but instead shows the buffer with its
-contents before the change, and provides instructions how to revert
-the buffer.
-
-** New value 'save-some-buffers-root' of 'save-some-buffers-default-predicate'.
-They allow to ask about saving only those files that are under the
-project root or in subdirectories of the directory that was default
-during command invocation.
+** The 'inhibit-changing-match-data' variable is now obsolete.
+Instead, functions like 'string-match' and 'looking-at' now take an
+optional 'inhibit-modify' argument.
 
 ---
-** New user option 'save-place-abbreviate-file-names'.
-This can simplify sharing the 'save-place-file' file across
-different hosts.
+** 'gnus-define-keys' is now obsolete.
+Use 'define-keymap' instead.
 
 ---
-** New user options 'copy-region-blink-delay' and 'delete-pair-blink-delay'.
-'copy-region-blink-delay' specifies a delay to indicate the region
-copied by 'kill-ring-save'.  'delete-pair-blink-delay' specifies
-a delay to show the paired character to delete.
+** MozRepl has been removed from js.el.
+MozRepl was removed from Firefox in 2017, so this code doesn't work
+with recent versions of Firefox.
 
 ---
-** 'zap-up-to-char' now uses 'read-char-from-minibuffer'.
-This allows navigating through the history of characters that have
-been input.  This is mostly useful for characters that have complex
-input methods where inputting the character again may involve many
-keystrokes.
+** The function 'image-dired-get-exif-data' is now obsolete.
+Use 'exif-parse-file' and 'exif-field' instead.
 
-+++
-** Input history for 'goto-line' can now be made local to every buffer.
-In any event, line numbers used with 'goto-line' are kept in their own
-history list.  This should help make faster the process of finding
-line numbers that were previously jumped to.  By default, all buffers
-share a single history list.  To make every buffer have its own
-history list, customize the user option 'goto-line-history-local'.
+
+* Lisp Changes in Emacs 29.1
 
 +++
-** New command 'goto-line-relative' for use in a narrowed buffer.
-It moves point to the line relative to the accessible portion of the
-narrowed buffer.  'M-g M-g' in Info is rebound to this command.
-When 'widen-automatically' is non-nil, 'goto-line' widens the narrowed
-buffer to be able to move point to the inaccessible portion.
-'goto-line-relative' is bound to 'C-x n g'.
+*** New function 'file-name-split'.
+This returns a list of all the components of a file name.
 
 +++
-** 'got-char' prompts for the character position.
-When called interactively, 'goto-char' now offers the position at
-point as the default.
-
-** Autosaving via 'auto-save-visited-mode' can now be inhibited.
-Set the variable 'auto-save-visited-mode' buffer-locally to nil to
-achieve that.
+*** New macro 'with-undo-amalgamate'
+It records a particular sequence of operations as a single undo step
 
 +++
-** New command 'kdb-macro-redisplay' to force redisplay in keyboard macros.
-This command is bound to 'C-x C-k d'.
-
----
-** 'blink-cursor-mode' is now enabled by default regardless of the UI.
-It used to be enabled when Emacs is started in GUI mode but not when started
-in text mode.  The cursor still only actually blinks in GUI frames.
+*** New command 'yank-media'.
+This command supports yanking non-plain-text media like images and
+HTML from other applications into Emacs.  It is only supported in
+modes that have registered support for it, and only on capable
+platforms.
 
 +++
-** New minor mode 'show-paren-local-mode'.
-It serves as a local counterpart for 'show-paren-mode', allowing you
-to toggle it separately in different buffers.
-
-
-* Changes in Specialized Modes and Packages in Emacs 28.1
-
-** Isearch and Replace
+*** New command 'yank-media-types'.
+This command lets you examine all data in the current selection and
+the clipboard, and insert it into the buffer.
 
 +++
-*** Interactive regular expression search now uses faces for sub-groups.
-E.g., 'C-M-s foo-\([0-9]+\)' will now use the 'isearch-group-1' face
-on the part of the regexp that matches the sub-expression "[0-9]+".
-By default, there are two faces for sub-group highlighting, but you
-can define more faces whose names are of the form 'isearch-group-N',
-where N are successive numbers above 2.
-
-This is controlled by the 'search-highlight-submatches' user option.
-This feature is available only on terminals that have enough colors to
-distinguish between sub-expression highlighting.
+*** New text property 'inhibit-isearch'.
+If set, 'isearch' will skip these areas, which can be useful (for
+instance) when covering huge amounts of data (that has no meaningful
+searchable data, like image data) with a 'display' text property.
 
 +++
-*** Interactive regular expression replace now uses faces for sub-groups.
-Like 'search-highlight-submatches', this is controlled by the new user option
-'query-replace-highlight-submatches'.
+*** 'insert-image' now takes an INHIBIT-ISEARCH optional parameter.
+It marks the image with the 'inhibit-isearch' text parameter, which
+inhibits 'isearch' matching the STRING parameter.
 
-+++
-*** New user option 'isearch-wrap-pause' defines how to wrap the search.
-There are choices to disable wrapping completely and to wrap immediately.
-When wrapping immediately, it consistently handles the numeric arguments
-of 'C-s' ('isearch-repeat-forward') and 'C-r' ('isearch-repeat-backward'),
-continuing with the remaining count after wrapping.
+---
+*** New user option 'pp-use-max-width'.
+If non-nil, 'pp' will attempt to limit the line length when formatting
+long lists and vectors.
 
-+++
-*** New user option 'isearch-repeat-on-direction-change'.
-When this option is set, direction changes in Isearch move to another
-search match, if there is one, instead of moving point to the other
-end of the current match.
-
-*** New key 'M-s M-.' starts isearch looking for the thing at point.
-This key is bound to the new command 'isearch-forward-thing-at-point'.
-The new user option 'isearch-forward-thing-at-point' defines
-a list of symbols to try to get the "thing" at point.  By default,
-the first element of the list is 'region' that tries to yank
-the currently active region to the search string.
+---
+*** New function 'pp-emacs-lisp-code'.
+'pp' formats general Lisp sexps.  This function does much the same,
+but applies formatting rules appropriate for Emacs Lisp code.
 
 +++
-*** New user option 'lazy-highlight-no-delay-length'.
-Lazy highlighting of matches in Isearch now starts immediately if the
-search string is at least this long.  'lazy-highlight-initial-delay'
-still applies for shorter search strings, which avoids flicker in the
-search buffer due to too many matches being highlighted.
+*** New function 'file-has-changed-p'.
+This convenience function is useful when writing code that parses
+files at run-time, and allows Lisp programs to re-parse files only
+when they have changed.
 
 ---
-*** The default 'search-whitespace-regexp' value has changed.
-This used to be "\\s-+", which meant that it was mode-dependent whether
-newlines were included in the whitespace set.  This has now been
-changed to only match spaces and tab characters.
+*** New function 'font-has-char-p'.
+This can be used to check whether a specific font has a glyph for a
+character.
 
-** Dired
+** XDG support
 
-+++
-*** New user option 'dired-kill-when-opening-new-dired-buffer'.
-If non-nil, Dired will kill the current buffer when selecting a new
-directory to display.
+*** New function 'xdg-state-home' returns $XDG_STATE_HOME.
+This new location, introduced in the XDG Base Directory Specification
+version 0.8 (8th May 2021), "contains state data that should persist
+between (application) restarts, but that is not important or portable
+enough to the user that it should be stored in $XDG_DATA_HOME".
 
 +++
-*** Behavior change on 'dired-do-chmod'.
-As a security precaution, Dired's M command no longer follows symbolic
-links.  Instead, it changes the symbolic link's own mode; this always
-fails on platforms where such modes are immutable.
+** New macro 'with-delayed-message'.
+This macro is like 'progn', but will output the specified message if
+the body takes longer to execute than the specified timeout.
 
 ---
-*** Behavior change on 'dired-clean-confirm-killing-deleted-buffers'.
-Previously, if 'dired-clean-up-buffers-too' was non-nil, and
-'dired-clean-confirm-killing-deleted-buffers' was nil, the buffers
-wouldn't be killed.  This combination will now kill the buffers.
-
-+++
-*** New user option 'dired-switches-in-mode-line'.
-This user option controls how 'ls' switches are displayed in the mode
-line, and allows truncating them (to preserve space on the mode line)
-or showing them literally, either instead of, or in addition to,
-displaying "by name" or "by date" sort order.
+** New function 'funcall-with-delayed-message'.
+This function is like 'funcall', but will output the specified message
+is the function take longer to execute that the specified timeout.
 
-+++
-*** New user option 'dired-compress-directory-default-suffix'.
-This user option controls default suffix for compressing a directory.
-If it's nil, ".tar.gz" will be used.  Refer to
-'dired-compress-files-alist' for a list of supported suffixes.
+** Locale
 
-+++
-*** New user option 'dired-compress-file-default-suffix'.
-This user option controls the default suffix for compressing files.
-If it's nil, ".gz" will be used.  Refer to 'dired-compress-file-alist'
-for a list of supported suffixes.
+---
+*** New variable 'current-locale-environment'.
+This holds the value of the previous call to 'set-locale-environment'.
 
 ---
-*** Broken and circular links are shown with the 'dired-broken-symlink' face.
+*** New macro 'with-locale-environment'.
+This macro can be used to change the locale temporarily while
+executing code.
 
-*** '=' ('dired-diff') will now put all backup files into the 'M-n' history.
-When using '=' on a file with backup files, the default file to use
-for diffing is the newest backup file.  You can now use 'M-n' to quickly
-select a different backup file instead.
+** Tabulated List Mode
 
 +++
-*** New user option 'dired-maybe-use-globstar'.
-If set, enables globstar (recursive globbing) in shells that support
-this feature, but turn it off by default.  This allows producing
-directory listings with files matching a wildcard in all the
-subdirectories of a given directory.  The new variable
-'dired-enable-globstar-in-shell' lists which shells can have globstar
-enabled, and how to enable it.
+*** A column can now be set to an image descriptor.
+The `tabulated-list-entries' variable now supports using an image
+descriptor, which means to insert an image in that column instead of
+text.  See the documentation string of that variable for details.
 
 +++
-*** New user option 'dired-copy-dereference'.
-If set to non-nil, Dired will dereference symbolic links when copying.
-This can be switched off on a per-usage basis by providing
-'dired-do-copy' with a 'C-u' prefix.
-
-*** New user option 'dired-do-revert-buffer'.
-Non-nil reverts the destination Dired buffer after performing one
-of these operations: 'dired-do-copy', 'dired-do-rename',
-'dired-do-symlink', 'dired-do-hardlink'.
-
-*** New user option 'dired-mark-region'.
-This option affects all Dired commands that mark files.  When non-nil
-and the region is active in Transient Mark mode, then Dired commands
-operate only on files in the active region.  The values 'file' and
-'line' of this user option define the details of marking the file at
-the end of the region.
-
-*** State changing VC operations are supported in Dired.
-These operations are supported on files and directories via the new
-command 'dired-vc-next-action'.
+** 'define-key' now understands a new strict 'kbd' representation for keys.
+The '(define-key map ["C-c M-f"] #'some-command)' syntax is now
+supported, and is like the 'kbd' representation, but is stricter.  If
+the string doesn't represent a valid key sequence, an error is
+signalled (both when evaluating and byte compiling).
 
 +++
-*** 'dired-jump' and 'dired-jump-other-window' moved from 'dired-x' to 'dired'.
-The 'dired-jump' and 'dired-jump-other-window' commands have been
-moved from the 'dired-x' package to 'dired'.  The user option
-'dired-bind-jump' no longer has any effect and is now obsolete.
-The commands are now bound to 'C-x C-j' and 'C-x 4 C-j' by default.
-
-To get the old behavior of 'dired-bind-jump' back and unbind the above
-keys, add the following to your init file:
-
-(global-set-key "\C-x\C-j" nil)
-(global-set-key "\C-x4\C-j" nil)
-
----
-*** 'dired-query' now uses 'read-char-from-minibuffer'.
-Using it instead of 'read-char-choice' allows using 'C-x o'
-to switch to the help window displayed after typing 'C-h'.
+** :keys in 'menu-item' can now be a function.
+If so, it is called whenever the menu is computed, and can be used to
+calculate the keys dynamically.
 
 +++
-** New user option 'isearch-allow-motion'.
-When 'isearch-allow-motion' is set, the commands 'beginning-of-buffer',
-'end-of-buffer', 'scroll-up-command' and 'scroll-down-command', when
-invoked during I-search, move respectively to the first occurrence of
-the current search string in the buffer, the last one, the first one
-after the current window, and the last one before the current window.
-Additionally, users can change the meaning of other motion commands
-during I-search by using their 'isearch-motion' property.  The
-option 'isearch-motion-changes-direction' controls whether the
-direction of the search changes after a motion command.
-
-** Outline
+** New major mode 'clean-mode'.
+This is a new major mode meant for debugging.  It kills absolutely all
+local variables and removes overlays and text properties.
 
 +++
-*** New commands to cycle heading visibility.
-Typing 'TAB' on a heading line cycles the current section between
-"hide all", "subheadings", and "show all" states.  Typing 'S-TAB'
-anywhere in the buffer cycles the whole buffer between "only top-level
-headings", "all headings and subheadings", and "show all" states.
+** 'kill-all-local-variables' can now kill all local variables.
+If given the new optional KILL-PERMANENT argument, also kill permanent
+local variables.
 
 +++
-*** New user option 'outline-minor-mode-cycle'.
-This user option customizes 'outline-minor-mode', with the difference
-that 'TAB' and 'S-TAB' on heading lines cycle heading visibility.
-Typing 'TAB' on a heading line cycles the current section between
-"hide all", "subheadings", and "show all" states.  Typing 'S-TAB' on a
-heading line cycles the whole buffer between "only top-level
-headings", "all headings and subheadings", and "show all" states.
+** Third 'mapconcat' argument SEPARATOR is now optional.
+An explicit nil always meant the empty string, now it can be left out.
 
 ---
-*** New user option 'outline-minor-mode-highlight'.
-This user option customizes 'outline-minor-mode'.  It puts
-highlighting on heading lines using standard outline faces.  This
-works well only when there are no conflicts with faces used by the
-major mode.
-
-** Ispell
-
-+++
-*** 'ispell-comments-and-strings' now accepts START and END arguments.
-These arguments default to active region when used interactively.
+** Themes can now be made obsolete.
+Using 'make-obsolete' on a theme is now supported.  This will make
+'load-theme' issue a warning when loading the theme.
 
 +++
-*** New command 'ispell-comment-or-string-at-point'.
-
-** Flyspell mode
+** New function 'define-keymap'.
+This function allows defining a number of keystrokes with one form.
 
 +++
-*** Corrections and actions menu can be optionally bound to 'mouse-3'.
-When Flyspell mode highlights a word as misspelled, you can click on
-it to display a menu of possible corrections and actions.  You can now
-easily bind this menu to 'down-mouse-3' (usually the right mouse button)
-instead of 'mouse-2' (the default) by enabling 'context-menu-mode'.
-
----
-*** The current dictionary is now displayed in the minor mode lighter.
-Clicking the dictionary name changes the current dictionary.
-
-** Package
-
-*** The new NonGNU ELPA archive is enabled by default alongside GNU ELPA.
-Thus, packages on NonGNU ELPA will appear by default in the list shown
-by 'list-packages'.
+** New macro 'defvar-keymap'.
+This macro allows defining keymap variables more conveniently.
 
 ---
-*** '/ s' ('package-menu-filter-by-status') changed parameter handling.
-The command was documented to take a comma-separated list of statuses
-to filter by, but instead it used the parameter as a regexp.  The
-command has been changed so that it now works as documented, and
-checks statuses not as a regexp, but instead an exact match from the
-comma-separated list.
+** 'kbd' can now be used in built-in, preloaded libraries.
+It no longer depends on edmacro.el and cl-lib.el.
 
 +++
-*** New command 'package-browse-url' and keystroke 'w'.
+** New function 'kbd-valid-p'.
+The 'kbd' function is quite permissive, and will try to return
+something usable even if the syntax of the argument isn't completely
+correct.  The 'kbd-valid-p' predicate does a stricter check of the
+syntax.
 
 +++
-*** New commands to filter the package list.
-The filter commands are bound to the following keys:
-
-key             binding
----             -------
-/ a             package-menu-filter-by-archive
-/ d             package-menu-filter-by-description
-/ k             package-menu-filter-by-keyword
-/ N             package-menu-filter-by-name-or-description
-/ n             package-menu-filter-by-name
-/ s             package-menu-filter-by-status
-/ v             package-menu-filter-by-version
-/ m             package-menu-filter-marked
-/ u             package-menu-filter-upgradable
-/ /             package-menu-filter-clear
-
-*** Option to automatically native-compile packages upon installation.
-Customize the user option 'package-native-compile' to enable automatic
-native compilation of packages when they are installed.  That option
-is nil by default; if set non-nil, and if your Emacs was built with
-native-compilation support, each package will be natively compiled
-when it is installed, by invoking an asynchronous Emacs subprocess to
-run the native-compilation of the package files.  (Be sure to leave
-Emacs running until these asynchronous subprocesses exit, or else the
-native-compilation will be aborted when you exit Emacs.)
-
----
-*** Column widths in 'list-packages' display can now be customized.
-See the new user options 'package-name-column-width',
-'package-version-column-width', 'package-status-column-width', and
-'package-archive-column-width'.
-
-** Info
-
----
-*** New user option 'Info-warn-on-index-alternatives-wrap'.
-This option affects what happens when using the ',' command after
-looking up an entry with 'i' in info buffers.  If non-nil (the
-default), the ',' command will now display a warning when proceeding
-beyond the final index match, and tapping ',' once more will then take
-you to the first match.
-
-** Abbrev mode
+** New function 'image-at-point-p'.
+This function returns t if point is on a valid image, and nil
+otherwise.
 
 +++
-*** Emacs can now suggest to use an abbrev based on text you type.
-A new user option, 'abbrev-suggest', enables the new abbrev suggestion
-feature.  When enabled, if a user manually types a piece of text that
-could have saved enough typing by using an abbrev, a hint will be
-displayed in the echo area, mentioning the abbrev that could have been
-used instead.
-
-** Bookmarks
-
-*** Bookmarks can now be targets for new tabs.
-When the bookmark.el library is loaded, a customize choice is added
-to 'tab-bar-new-tab-choice' for new tabs to show the bookmark list.
-
----
-*** The 'list-bookmarks' menu is now based on 'tabulated-list-mode'.
-The interactive bookmark list will now benefit from features in
-'tabulated-list-mode' like sorting columns or changing column width.
-
-Support for the optional "inline" header line, allowing for a header
-without using 'header-line-format', has been dropped.  Consequently,
-the variables 'bookmark-bmenu-use-header-line' and
-'bookmark-bmenu-inline-header-height' are now declared obsolete.
-
----
-*** New user option 'bookmark-set-fringe-mark'.
-If non-nil, setting a bookmark will set a fringe mark on the current
-line, and jumping to a bookmark will also set this mark.
-
----
-*** New user option 'bookmark-menu-confirm-deletion'.
-In Bookmark Menu mode, Emacs by default does not prompt for
-confirmation when you type 'x' to execute the deletion of bookmarks
-that have been marked for deletion.  However, if this new option is
-non-nil then Emacs will require confirmation with 'yes-or-no-p' before
-deleting.
-
-** Recentf
-
----
-*** The recentf files are no longer backed up.
-
----
-*** 'recentf-auto-cleanup' now repeats daily when set to a time string.
-When 'recentf-auto-cleanup' is set to a time string, it now repeats
-every day, rather than only running once after the mode is turned on.
-
-** Calc
-
----
-*** The behavior when doing forward-delete has been changed.
-Previously, using the 'C-d' command would delete the final number in
-the input field, no matter where point was.  This has been changed to
-work more traditionally, with 'C-d' deleting the next character.
-Likewise, point isn't moved to the end of the string before inserting
-digits.
+** New function 'string-pixel-width'.
+This returns the width of a string in pixels.  This can be useful when
+dealing with variable pitch fonts and glyphs that have widths that
+aren't integer multiples of the default font.
 
 +++
-*** Setting the word size to zero disables word clipping.
-The word size normally clips the results of certain bit-oriented
-operations such as shifts and bitwise XOR.  A word size of zero, set
-by 'b w', makes the operation have effect on the whole argument values
-and the result is not truncated in any way.
-
----
-*** The '/' operator now has higher precedence in (La)TeX input mode.
-It no longer has lower precedence than '+' and '-'.
+** New function 'string-glyph-split'.
+This function splits a string into a list of strings representing
+separate glyphs.  This takes into account combining characters and
+grapheme clusters.
 
 ---
-*** Calc now marks its windows dedicated.
-The new user option 'calc-make-windows-dedicated' controls this.  It
-is t by default; set to nil to get back the old behavior.
+** 'lookup-key' is more allowing when searching for extended menu items.
+In Emacs 28.1, the behavior of 'lookup-key' was changed: when looking
+for a menu item '[menu-bar Foo-Bar]', first try to find an exact
+match, then look for the lowercased '[menu-bar foo-bar]'.
 
-** Calendar
+This has been extended, so that when looking for a menu item with a
+symbol containing spaces, as in '[menu-bar Foo\ Bar]', first look for
+an exact match, then the lowercased '[menu-bar foo\ bar]' and finally
+'[menu-bar foo-bar]'.  This further improves backwards-compatibility
+when converting menus to use 'easy-menu-define'.
 
 +++
-*** New user option 'calendar-time-zone-style'.
-If 'numeric', calendar functions (eg 'calendar-sunrise-sunset') that display
-time zones will use a form like "+0100" instead of "CET".
-
-** ido
-
----
-*** Switching on 'ido-mode' now also overrides 'ffap-file-finder'.
-
----
-*** Killing virtual ido buffers interactively will make them go away.
-Previously, killing a virtual ido buffer with 'ido-kill-buffer' didn't
-do anything.  This has now been changed, and killing virtual buffers
-with that command will remove the buffer from recentf.
+** xwidgets
 
-** So Long
-
----
-*** New 'so-long-predicate' function 'so-long-statistics-excessive-p'.
-It efficiently detects the presence of a long line anywhere in the
-buffer using 'buffer-line-statistics' (see above).  This is now the
-default predicate (replacing 'so-long-detected-long-line-p').
-
----
-*** Default values 'so-long-threshold' and 'so-long-max-lines' increased.
-The values of these variables have been raised to 10000 bytes and 500
-lines respectively, to reduce the likelihood of false-positives when
-'global-so-long-mode' is enabled.  The latter value is now only used
-by the old predicate, as the new predicate knows the longest line in
-the entire buffer.
-
----
-*** 'so-long-target-modes' now includes 'fundamental-mode' by default.
-This means that 'global-so-long-mode' will also process files which were
-not recognised.  (This only has an effect if 'set-auto-mode' chooses
-'fundamental-mode'; buffers which are simply in 'fundamental-mode' by
-default are unaffected.)
-
----
-*** New user options to preserve modes and variables.
-The new options 'so-long-mode-preserved-minor-modes' and
-'so-long-mode-preserved-variables' allow specified mode and variable
-states to be maintained if 'so-long-mode' replaces the original major
-mode.  By default, these new options support 'view-mode'.
-
-** Grep
+*** The function 'make-xwidget' now accepts an optional RELATED argument.
+This argument is used as another widget for the newly created WebKit
+widget to share settings and subprocesses with.  It must be another
+WebKit widget.
 
 +++
-*** New user option 'grep-match-regexp' matches grep markers to highlight.
-Grep emits SGR ANSI escape sequences to color its output.  The new
-user option 'grep-match-regexp' holds the regular expression to match
-the appropriate markers in order to provide highlighting in the source
-buffer.  The user option can be customized to accommodate other
-grep-like tools.
-
----
-*** The 'lgrep' command now ignores directories.
-On systems where the grep command supports it, directories will be
-skipped.
-
-*** Commands that use 'grep-find' now follow symlinks for command-line args.
-This is because the default value of 'grep-find-template' now includes
-the 'find' option '-H'.  Commands that use that variable, including
-indirectly via a call to 'xref-matches-in-directory', might be
-affected.  In particular, there should be no need anymore to ensure
-any directory names on the 'find' command lines end in a slash.
-This change is for better compatibility with old versions of non-GNU
-'find', such as the one used on macOS.
-
----
-*** New utility function 'grep-file-at-point'.
-This returns the name of the file at point (if any) in 'grep-mode'
-buffers.
-
-** Shell
-
----
-*** New command in 'shell-mode': 'narrow-to-prompt'.
-This is bound to 'C-x n d' in 'shell-mode' buffers, and narrows to the
-command line under point (and any following output).
+*** New function 'xwidget-perform-lispy-event'.
+This function allows you to send events to xwidgets.  Usually, some
+equivalent of the event will be sent, but there is no guarantee of
+what the widget will actually receive.
 
----
-*** New user option 'shell-has-auto-cd'.
-If non-nil, 'shell-mode' handles implicit "cd" commands, changing the
-directory if the command is a directory.  Useful for shells like "zsh"
-that has this feature.
-
-** term-mode
-
----
-*** New user option 'term-scroll-snap-to-bottom'.
-By default, 'term' and 'ansi-term' will now recenter the buffer so
-that the prompt is on the final line in the window.  Setting this new
-user option to nil inhibits this behavior.
-
----
-*** New user option 'term-set-terminal-size'
-If non-nil, the 'LINES' and 'COLUMNS' environment variables will be set
-based on the current window size.  In previous versions of Emacs, this
-was always done (and that could lead to odd displays when resizing the
-window after starting).  This variable defaults to nil.
-
-** Eshell
+On GTK+, only key and function key events are implemented.
 
----
-*** 'eshell-hist-ignoredups' can now also be used to mimic "erasedups" in bash.
++++
+*** New functions for performing searches on WebKit xwidgets.
+Some new functions, such as 'xwidget-webkit-search', have been added
+for performing searches on WebKit xwidgets.
 
----
-*** Environment variable 'INSIDE_EMACS' is now copied to subprocesses.
-Its value contains the result of evaluating '(format "%s,eshell"
-emacs-version)'.  Other package names, like "tramp", could also be included.
++++
+*** 'load-changed' xwidget events are now more detailed.
+In particular, they can now have different arguments based on the
+state of the WebKit widget.  'load-finished' is sent when a load has
+completed, 'load-started' when a load first starts, 'load-redirected'
+after a redirect, and 'load-committed' when the WebKit widget first
+commits to the load.
 
----
-*** Eshell no longer re-initializes its keymap every call.
-This allows users to use (define-key eshell-mode-map ...) as usual.
-Some modules have their own minor mode now to account for these
-changes.
++++
+*** New event type 'xwidget-display-event'.
+These events are sent whenever an xwidget requests that Emacs display
+another xwidget.  The only argument to this event is the xwidget that
+should be displayed.
 
-** Archive mode
+
+* Changes in Emacs 29.1 on Non-Free Operating Systems
 
----
-*** Archive Mode can now parse ".squashfs" files.
-
-*** Can now modify members of 'ar' archives.
-
-*** Display of summaries is unified between backends.
-
-*** New user option and command to control displayed columns.
-New user option 'archive-hidden-columns' and new command
-'archive-hideshow-column' let you control which columns are displayed
-and which are kept hidden.
-
----
-*** New command bound to 'C': 'archive-copy-file'.
-This command extracts the file at point and writes its data to a
-file.
-
-** browse-url
-
-*** Added support for custom URL handlers.
-There is a new variable 'browse-url-default-handlers' and a user
-option 'browse-url-handlers' being alists with '(REGEXP-OR-PREDICATE
-. FUNCTION)' entries allowing to define different browsing FUNCTIONs
-depending on the URL to be browsed.  The variable is for default
-handlers provided by Emacs itself or external packages, the user
-option is for the user (and allows for overriding the default
-handlers).
-
-Formerly, one could do the same by setting
-'browse-url-browser-function' to such an alist.  This usage is still
-supported but deprecated.
-
-*** Categorization of browsing commands into internal vs. external.
-All standard browsing commands such as 'browse-url-firefox',
-'browse-url-mail', or 'eww' have been categorized into internal (URL
-is browsed in Emacs) or external (an external application is spawned
-with the URL).  This is done by adding a 'browse-url-browser-kind'
-symbol property to the browsing commands.  With a new command
-'browse-url-with-browser-kind', an URL can explicitly be browsed with
-either an internal or external browser.
-
----
-*** Support for browsing of remote files.
-If a remote file is specified, a local temporary copy of that file is
-passed to the browser.
-
-*** Support for the conkeror browser is now obsolete.
-
-*** Support for the Mosaic browser has been removed.
-This support has been obsolete since 25.1.
-
-** Completion List Mode
-
-*** Improved navigation in the "*Completions*" buffer.
-New key bindings have been added to 'completion-list-mode': 'n' and
-'p' now navigate completions, and 'M-g M-c' switches to the
-minibuffer and back to the completion list buffer.
-
-+++
-** profiler.el
-The results displayed by 'profiler-report' now have the usage figures
-at the left hand side followed by the function name.  This is intended
-to make better use of the horizontal space, in particular eliminating
-the truncation of function names.  There is no way to get the former
-layout back.
-
-** Python mode
-
----
-*** New user option 'python-forward-sexp-function'.
-This allows the user easier customization of whether to use block-based
-navigation or not.
-
----
-*** 'python-shell-interpreter' now defaults to python3 on systems with python3.
-
----
-*** 'C-c C-r' can now be used on arbitrary regions.
-The command previously extended the start of the region to the start
-of the line, but will now actually send the marked region, as
-documented.
-
-** Perl mode
-
----
-*** New face 'perl-non-scalar-variable'.
-This is used to fontify non-scalar variables.
-
-** Icomplete
-
----
-*** New user option 'icomplete-matches-format'.
-This allows controlling the current/total number of matches for the
-prompt prefix.
-
-+++
-*** New minor modes 'icomplete-vertical-mode' and 'fido-vertical-mode'.
-These modes modify Icomplete ('M-x icomplete-mode') and Fido ('M-x
-fido-mode'), to display completion candidates vertically instead of
-horizontally.  In Icomplete, completions are rotated and selection
-kept at the top.  In Fido, completions scroll like a typical dropdown
-widget.  Both these new minor modes will turn on their non-vertical
-counterparts first, if they are not on already.
-
----
-*** Default value of 'icomplete-compute-delay' has been changed to 0.15 s.
-
----
-*** Default value of 'icomplete-max-delay-chars' has been changed to 2.
-
----
-*** Reduced blinking while completing the next completions set.
-Icomplete doesn't hide the hint with the previously computed
-completions anymore when compute delay is in effect, or the previous
-computation has been aborted by input.  Instead it shows the previous
-completions until the new ones are ready.
-
----
-*** Change in meaning of 'icomplete-show-matches-on-no-input'.
-Previously, choosing a different completion with commands like 'C-.'
-and then hitting 'RET' would choose the default completion.  Doing this
-will now choose the completion under point instead.  Also when this option
-is nil, completions are not shown when the minibuffer reads a file name
-with initial input as the default directory.
-
-** Windmove
-
-+++
-*** New user options to customize windmove keybindings.
-These options include 'windmove-default-keybindings',
-'windmove-display-default-keybindings',
-'windmove-delete-default-keybindings',
-'windmove-swap-states-default-keybindings'.
-
-** Occur mode
-
-*** New bindings in occur-mode.
-The command 'next-error-no-select' is now bound to 'n' and
-'previous-error-no-select' is bound to 'p'.
-
-*** The new command 'recenter-current-error'.
-It is bound to 'l' in Occur or compilation buffers, and recenters the
-current displayed occurrence/error.
-
-*** Matches in target buffers are now highlighted as in 'compilation-mode'.
-The method of highlighting is specified by the user options
-'next-error-highlight' and 'next-error-highlight-no-select'.
-
----
-*** A fringe arrow in the "*Occur*" buffer indicates the selected match.
-
----
-*** Occur mode may use a different type for 'occur-target' property values.
-The value was previously always a marker set to the start of the first
-match on the line but can now also be a list of '(BEGIN . END)' pairs
-of markers delimiting each match on the line.
-This is a fully compatible change to the internal occur-mode
-implementation, and code creating their own occur-mode buffers will
-work as before.
-
-** Emacs Lisp mode
-
-*** The mode-line now indicates whether we're using lexical or dynamic scoping.
-
-*** A space between an open paren and a symbol changes the indentation rule.
-The presence of a space between an open paren and a symbol now is
-taken as a statement by the programmer that this should be indented
-as a data list rather than as a piece of code.
-
-** Lisp Mode
-
-*** New minor mode 'cl-font-lock-built-in-mode' for 'lisp-mode'.
-The mode provides refined highlighting of built-in functions, types,
-and variables.
-
----
-*** Lisp mode now uses 'common-lisp-indent-function'.
-To revert to the previous behavior,
-'(setq lisp-indent-function 'lisp-indent-function)' from 'lisp-mode-hook'.
-
-** Change Logs and VC
-
-+++
-*** 'vc-revert-show-diff' now has a third possible value: 'kill'.
-If this user option is 'kill', then the diff buffer will be killed
-after the 'vc-revert' action instead of buried.
-
-*** More VC commands can be used from non-file buffers.
-The relevant commands are those that don't change the VC state.
-The non-file buffers which can use VC commands are those that have
-their 'default-directory' under VC.
-
-*** New command 'vc-dir-root' uses the root directory without asking.
-
----
-*** New face 'log-view-commit-body'.
-This is used when expanding commit messages from 'vc-print-root-log'
-and similar commands.
-
----
-*** New faces for 'vc-dir' buffers.
-Those are: 'vc-dir-header', 'vc-dir-header-value', 'vc-dir-directory',
-'vc-dir-file', 'vc-dir-mark-indicator', 'vc-dir-status-warning',
-'vc-dir-status-edited', 'vc-dir-status-up-to-date',
-'vc-dir-status-ignored'.
-
----
-*** The responsible VC backend is now the most specific one.
-'vc-responsible-backend' loops over the backends in
-'vc-handled-backends' to determine which backend is responsible for a
-specific (unregistered) file.  Previously, the first matching backend
-was chosen, but now the one with the most specific path is chosen (in
-case there's a directory handled by one backend inside another).
-
-*** New commands 'vc-dir-mark-registered-files' (bound to '* r') and
-'vc-dir-mark-unregistered-files'.
-
-*** Support for bookmark.el.
-Bookmark locations can refer to VC directory buffers.
-
----
-*** New user option 'vc-hg-create-bookmark'.
-It controls whether a bookmark or branch will be created when you
-invoke 'C-u C-x v s' ('vc-create-tag').
-
----
-*** 'vc-hg' now uses 'hg summary' to populate extra 'vc-dir' headers.
-
----
-*** New user option 'vc-git-revision-complete-only-branches'.
-If non-nil, only branches and remotes are considered when doing
-completion over Git branch names.  The default is nil, which causes
-tags to be considered as well.
-
----
-*** New user option 'vc-git-log-switches'.
-String or list of strings specifying switches for Git log under VC.
-
-** Gnus
-
-+++
-*** New user option 'gnus-topic-display-predicate'.
-This can be used to inhibit the display of some topics completely.
-
-+++
-*** nnimap now supports the oauth2.el library.
-
-+++
-*** New Summary buffer sort options for extra headers.
-The extra header sort option ('C-c C-s C-x') prompts for a header
-and fails if no sort function has been defined.  Sorting by
-Newsgroups ('C-c C-s C-u') has been pre-defined.
-
-+++
-*** The '#' command in the Group and Summary buffer now toggles,
-instead of sets, the process mark.
-
-+++
-*** New user option 'gnus-process-mark-toggle'.
-If non-nil (the default), the '#' command in the Group and Summary
-buffers will toggle, instead of set, the process mark.
-
-
-+++
-*** New user option 'gnus-registry-register-all'.
-If non-nil (the default), create registry entries for all messages.
-If nil, don't automatically create entries, they must be created
-manually.
-
-+++
-*** New user options to customise the summary line specs "%[" and "%]".
-Four new options introduced in customisation group
-'gnus-summary-format'.  These are 'gnus-sum-opening-bracket',
-'gnus-sum-closing-bracket', 'gnus-sum-opening-bracket-adopted', and
-'gnus-sum-closing-bracket-adopted'.  Their default values are "[", "]",
-"<", ">" respectively.  These options control the appearance of "%["
-and "%]" specs in the summary line format.  "%[" will normally display
-the value of 'gnus-sum-opening-bracket', but can also be
-'gnus-sum-opening-bracket-adopted' for the adopted articles.  "%]" will
-normally display the value of 'gnus-sum-closing-bracket', but can also
-be 'gnus-sum-closing-bracket-adopted' for the adopted articles.
-
-+++
-*** New user option 'gnus-paging-select-next'.
-This controls what happens when using commands like 'SPC' and 'DEL' to
-page the current article.  If non-nil (the default), go to the
-next/prev article, but if nil, do nothing at the end/start of the article.
-
-+++
-*** New gnus-search library.
-A new unified search syntax which can be used across multiple
-supported search engines.  Set 'gnus-search-use-parsed-queries' to
-non-nil to enable.
-
-+++
-*** New value for user option 'smiley-style'.
-Smileys can now be rendered with emojis instead of small images when
-using the new 'emoji' value in 'smiley-style'.
-
-+++
-*** New user option 'gnus-agent-eagerly-store-articles'.
-If non-nil (which is the default), the Gnus Agent will store all read
-articles in the Agent cache.
-
-+++
-*** New user option 'gnus-global-groups'.
-Gnus handles private groups differently from public (i.e., NNTP-like)
-groups.  Most importantly, Gnus doesn't download external images from
-mail-like groups.  This can be overridden by putting group names in
-'gnus-global-groups': Any group present in that list will be treated
-like a public group.
-
-+++
-*** New scoring types for the Date header.
-You can now score based on the relative age of an article with the new
-'<' and '>' date scoring types.
-
-+++
-*** User-defined scoring is now possible.
-The new type is 'score-fn'.  More information in the Gnus manual node
-"(gnus) Score File Format".
-
-+++
-*** New backend 'nnselect'.
-The newly added 'nnselect' backend allows creating groups from an
-arbitrary list of articles that may come from multiple groups and
-servers.  These groups generally behave like any other group: they may
-be ephemeral or persistent, and allow article marking, moving,
-deletion, etc.  'nnselect' groups may be created like any other group,
-but there are three convenience functions for the common case of
-obtaining the list of articles as a result of a search:
-'gnus-group-make-search-group' ('G g') that will prompt for an 'nnir'
-search query and create a persistent group for that search;
-'gnus-group-read-ephemeral-search-group' ('G G') that will prompt for
-an 'nnir' search query and create an ephemeral group for that search;
-and 'gnus-summary-make-group-from-search' ('C-c C-p') that will create
-a persistent group with the search parameters of a current ephemeral
-search group.
-
-As part of this addition, the user option 'nnir-summary-line-format'
-has been removed; its functionality is now available directly in the
-'gnus-summary-line-format' specs '%G' and '%g'.  The user option
-'gnus-refer-thread-use-nnir' has been renamed to
-'gnus-refer-thread-use-search'.
-
-+++
-*** New user option 'gnus-dbus-close-on-sleep'.
-On systems with D-Bus support, it is now possible to register a signal
-to close all Gnus servers before the system sleeps.
-
-+++
-*** The key binding of 'gnus-summary-search-article-forward' has changed.
-This command was previously on 'M-s' and shadowed the global 'M-s'
-search prefix.  The command has now been moved to 'M-s M-s'.  (For
-consistency, the 'M-s M-r' key binding has been added for the
-'gnus-summary-search-article-backward' command.)
-
----
-*** The value of "all" in the 'large-newsgroup-initial' group parameter 
changes.
-It was previously nil, which didn't work, because nil is
-indistinguishable from not being present.  The new value for "all" is
-the symbol 'all'.
-
-+++
-*** The name of dependent Gnus sessions has changed from "slave" to "child".
-The names of the commands 'gnus-slave', 'gnus-slave-no-server' and
-'gnus-slave-unplugged' have changed to 'gnus-child',
-'gnus-child-no-server' and 'gnus-child-unplugged' respectively.
-
-+++
-*** The 'W Q' summary mode command now takes a numerical prefix to
-allow adjusting the fill width.
-
-+++
-*** New variable 'mm-inline-font-lock'.
-This variable is supposed to be bound by callers to determine whether
-inline MIME parts (that support it) are supposed to be font-locked or
-not.
-
-** Message
-
----
-*** Respect 'message-forward-ignored-headers' more.
-Previously, this user option would not be consulted if
-'message-forward-show-mml' was nil and forwarding as MIME.
-
-+++
-*** New user option 'message-forward-included-mime-headers'.
-This is used when forwarding messages as MIME, but not using MML.
-
-+++
-*** Message now supports the OpenPGP header.
-To generate these headers, add the new function
-'message-add-openpgp-header' to 'message-send-hook'.  The header will
-be generated according to the new 'message-openpgp-header' variable.
-
----
-*** A change to how "Mail-Copies-To: never" is handled.
-If a user has specified "Mail-Copies-To: never", and Message was asked
-to do a "wide reply", some other arbitrary recipient would end up in
-the resulting "To" header, while the remaining recipients would be put
-in the "Cc" header.  This is somewhat misleading, as it looks like
-you're responding to a specific person in particular.  This has been
-changed so that all the recipients are put in the "To" header in these
-instances.
-
-+++
-*** New command to start Emacs in Message mode to send an email.
-Emacs can be defined as a handler for the "x-scheme-handler/mailto"
-MIME type with the following command: "emacs -f message-mailto %u".
-An "emacs-mail.desktop" file has been included, suitable for
-installing in desktop directories like "/usr/share/applications" or
-"~/.local/share/applications".
-Clicking on a 'mailto:' link in other applications will then open
-Emacs with headers filled out according to the link, e.g.
-"mailto:larsi@gnus.org?subject=This+is+a+test";.  If you prefer
-emacsclient, use "emacsclient -e '(message-mailto "%u")'"
-or "emacsclient-mail.desktop".
-
----
-*** Change to default value of 'message-draft-headers' user option.
-The 'Date' symbol has been removed from the default value, meaning that
-draft or delayed messages will get a date reflecting when the message
-was sent.  To restore the original behavior of dating a message
-from when it is first saved or delayed, add the symbol 'Date' back to
-this user option.
-
-+++
-*** New command to take screenshots.
-In Message mode buffers, the 'C-c C-p' ('message-insert-screenshot')
-command has been added.  It depends on using an external program to
-take the actual screenshot, and defaults to "ImageMagick import".
-
-** Smtpmail
-
-+++
-*** smtpmail now supports using the oauth2.el library.
-
-+++
-*** New user option 'smtpmail-store-queue-variables'.
-If non-nil, SMTP variables will be stored together with the queued
-messages, and will then be used when sending with
-'M-x smtpmail-send-queued-mail'.
-
-+++
-*** Allow direct selection of smtp authentication mechanism.
-A server entry retrieved by auth-source can request a desired smtp
-authentication mechanism by setting a value for the key 'smtp-auth'.
-
-** ElDoc
-
-+++
-*** New user option 'eldoc-echo-area-display-truncation-message'.
-If non-nil (the default), eldoc will display a message saying
-something like "(Documentation truncated.  Use `M-x eldoc-doc-buffer'
-to see rest)" when a message has been truncated.  If nil, truncated
-messages will be marked with just "..." at the end.
-
-+++
-*** New hook 'eldoc-documentation-functions'.
-This hook is intended to be used for registering doc string functions.
-These functions don't need to produce the doc string right away, they
-may arrange for it to be produced asynchronously.  The results of all
-doc string functions are accessible to the user through the user
-option 'eldoc-documentation-strategy'.
-
-*** New hook 'eldoc-display-functions'.
-This hook is intended to be used for displaying doc strings.  The
-functions receive the doc string composed according to
-'eldoc-documentation-strategy' and are tasked with displaying it to
-the user.  Examples of such functions would use the echo area, a
-separate buffer, or a tooltip.
-
-+++
-*** New user option 'eldoc-documentation-strategy'.
-The built-in choices available for this user option let users compose
-the results of 'eldoc-documentation-functions' in various ways, even
-if some of those functions are synchronous and some asynchronous.
-The user option replaces 'eldoc-documentation-function', which is now
-obsolete.
-
-*** 'eldoc-echo-area-use-multiline-p' is now handled by ElDoc.
-The user option 'eldoc-echo-area-use-multiline-p' is now handled
-by the ElDoc library itself.  Functions in
-'eldoc-documentation-functions' don't need to worry about consulting
-it when producing a doc string.
-
-** Tramp
-
-+++
-*** New connection method "mtp".
-It allows accessing media devices like cell phones, tablets or
-cameras.
-
-+++
-*** New connection method "sshfs".
-It allows accessing remote files via a file system mounted with
-'sshfs'.
-
-+++
-*** Tramp supports SSH authentication via a hardware security key now.
-This requires at least OpenSSH 8.2, and a FIDO U2F compatible
-security key, like yubikey, solokey, or nitrokey.
-
-+++
-*** Trashed remote files are moved to the local trash directory.
-All remote files that are trashed are moved to the local trash
-directory, except remote encrypted files, which are always deleted.
-
-+++
-*** New command 'tramp-crypt-add-directory'.
-This command marks a remote directory to contain only encrypted files.
-See the "(tramp) Keeping files encrypted" node of the Tramp manual for
-details.  This feature is experimental.
-
-+++
-*** Support of direct asynchronous process invocation.
-When Tramp connection property "direct-async-process" is set to
-non-nil for a given connection, 'make-process' and 'start-file-process'
-calls are performed directly as in "ssh ... <command>".  This avoids
-initialization performance penalties.  See the "(tramp) Improving
-performance of asynchronous remote processes" node of the Tramp manual
-for details, and also for a discussion or restrictions.  This feature
-is experimental.
-
-+++
-*** New user option 'tramp-debug-to-file'.
-When non-nil, this user option instructs Tramp to mirror the debug
-buffer to a file under the "/tmp/" directory.  This is useful, if (in
-rare cases) Tramp blocks Emacs, and we need further debug information.
-
-+++
-*** Tramp supports lock files now.
-In order to deactivate this, set user option
-'remote-file-name-inhibit-locks' to t.
-
-+++
-*** Writing sensitive data locally requires confirmation.
-Writing auto-save, backup or lock files to the local temporary
-directory must be confirmed.  In order to suppress this confirmation,
-set user option 'tramp-allow-unsafe-temporary-files' to t.
-
-+++
-*** 'make-directory' of a remote directory honors the default file modes.
-
-** gdb-mi
-
-*** New user option 'gdb-registers-enable-filter'.
-If non-nil, apply a register filter based on
-'gdb-registers-filter-pattern-list'.
-
-+++
-*** gdb-mi can now save and restore window configurations.
-Use 'gdb-save-window-configuration' to save window configuration to a
-file and 'gdb-load-window-configuration' to load from a file.  These
-commands can also be accessed through the menu bar under "Gud =>
-GDB-Windows".  'gdb-default-window-configuration-file', when non-nil,
-is loaded when GDB starts up.
-
-+++
-*** gdb-mi can now restore window configuration after quitting.
-Set 'gdb-restore-window-configuration-after-quit' to non-nil and Emacs
-will remember the window configuration before GDB started and restore
-it after GDB quits.  A toggle button is also provided under "Gud =>
-GDB-Windows" menu item.
-
-+++
-*** gdb-mi now has a better logic for displaying source buffers.
-Now GDB only uses one source window to display source file by default.
-Customize 'gdb-max-source-window-count' to use more than one window.
-Control source file display by 'gdb-display-source-buffer-action'.
-
-+++
-*** The default value of 'gdb-mi-decode-strings' is now t.
-This means that the default coding-system is now used to decode strings
-and source file names from GDB.
-
-** Compilation mode
-
----
-*** New function 'ansi-color-compilation-filter'.
-This function is meant to be used in 'compilation-filter-hook'.
-
----
-*** New user option 'ansi-color-for-compilation-mode'.
-This controls what 'ansi-color-compilation-filter' does.
-
-*** Regexp matching of messages is now case-sensitive by default.
-The variable 'compilation-error-case-fold-search' can be set for
-case-insensitive matching of messages when the old behavior is
-required, but the recommended solution is to use a correctly matching
-regexp instead.
-
----
-*** New user option 'compilation-search-all-directories'.
-When doing parallel builds, directories and compilation errors may
-arrive in the "*compilation*" buffer out-of-order.  If this variable is
-non-nil (the default), Emacs will now search backwards in the buffer
-for any directory the file with errors may be in.  If nil, this won't
-be done (and this restores how this previously worked).
-
----
-*** Messages from ShellCheck are now recognized.
-
----
-*** Messages from Visual Studio that mention column numbers are now recognized.
-
-** Hi Lock mode
-
----
-*** Matching in 'hi-lock-mode' can be case-sensitive.
-The matching is case-sensitive when a regexp contains upper case
-characters and 'search-upper-case' is non-nil.  'highlight-phrase'
-also uses 'search-whitespace-regexp' to substitute spaces in regexp
-search.
-
----
-*** The default value of 'hi-lock-highlight-range' was enlarged.
-The new default value is 2000000 (2 megabytes).
-
-** Whitespace mode
-
-+++
-*** New style 'missing-newline-at-eof'.
-If present in 'whitespace-style' (as it is by default), the final
-character in the buffer will be highlighted if the buffer doesn't end
-with a newline.
-
----
-*** The default 'whitespace-enable-predicate' predicate has changed.
-It used to check elements in the list version of
-'whitespace-global-modes' with 'eq', but now uses 'derived-mode-p'.
-
-** Texinfo
-
----
-*** New user option 'texinfo-texi2dvi-options'.
-This is used when invoking 'texi2dvi' from 'texinfo-tex-buffer'.
-
----
-*** New commands for moving in and between environments.
-An "environment" is something that ends with '@end'.  The commands are
-'C-c C-c C-f' (next end), 'C-c C-c C-b' (previous end),
-'C-c C-c C-n' (next start) and 'C-c C-c C-p' (previous start), as well
-as 'C-c .', which will alternate between the start and the end of the
-current environment.
-
-** Rmail
-
----
-*** New user option 'rmail-re-abbrevs'.
-Its default value matches localized abbreviations of the "reply"
-prefix on the Subject line in various languages.
-
----
-*** New user option 'shr-offer-extend-specpdl'.
-If this is nil, rendering of HTML in the email message body that
-requires to enlarge 'max-specpdl-size', the number of Lisp variable
-bindings, will be aborted, and Emacs will not ask you whether to
-enlarge 'max-specpdl-size' to complete the rendering.  The default is
-t, which preserves the original behavior.
-
----
-*** New user option 'rmail-show-message-set-modified'.
-If set non-nil, showing an unseen message will set the Rmail buffer's
-modified flag.  The default is nil, to preserve the old behavior.
-
-** CC Mode
-
-+++
-*** Added support for Doxygen documentation style.
-'doxygen' is now a valid 'c-doc-comment-style' which recognises all
-comment styles supported by Doxygen (namely '///', '//!', '/** … */'
-and '/*! … */'.  'gtkdoc' remains the default for C and C++ modes; to
-use 'doxygen' by default one might evaluate:
-
-    (setq-default c-doc-comment-style
-                  '((java-mode . javadoc)
-                    (pike-mode . autodoc)
-                    (c-mode    . doxygen)
-                    (c++-mode  . doxygen)))
-
-or use it in a custom 'c-style'.
-
-+++
-*** Added support to line up '?' and ':' of a ternary operator.
-The new 'c-lineup-ternary-bodies' function can be used as a lineup
-function to align question mark and colon which are part of a ternary
-operator ('?:').  For example:
-
-    return arg % 2 == 0 ? arg / 2
-                        : (3 * arg + 1);
-
-To enable, add it to appropriate entries in 'c-offsets-alist', e.g.:
-
-    (c-set-offset 'arglist-cont '(c-lineup-ternary-bodies
-                                  c-lineup-gcc-asm-reg))
-    (c-set-offset 'arglist-cont-nonempty '(c-lineup-ternary-bodies
-                                           c-lineup-gcc-asm-reg
-                                           c-lineup-arglist))
-    (c-set-offset 'statement-cont '(c-lineup-ternary-bodies +))
-
-** Images
-
----
-*** You can explicitly specify base_uri for svg images.
-':base-uri' image property can be used to explicitly specify base_uri
-for embedded images into svg.  ':base-uri' is supported for both file
-and data svg images.
-
-+++
-*** 'svg-embed-base-uri-image' added to embed images.
-'svg-embed-base-uri-image' can be used to embed images located
-relatively to 'file-name-directory' of the ':base-uri' svg image property.
-This works much faster then 'svg-embed'.
-
-+++
-*** New function 'image-cache-size'.
-This function returns the size of the current image cache, in bytes.
-
----
-*** Animated images stop automatically under high CPU pressure sooner.
-Previously, an animated image would stop animating if any single image
-took more than two seconds to display.  The new algorithm maintains a
-decaying average of delays, and if this number gets too high, the
-animation is stopped.
-
-+++
-*** The 'n' and 'p' commands (next/previous image) now respect Dired order.
-These commands would previously display the next/previous image in
-lexicographic order, but will now find the "parent" Dired buffer and
-select the next/previous image file according to how the files are
-sorted there.  The commands have also been extended to work when the
-"parent" buffer is an archive mode (i.e., zip file or the like) or tar
-mode buffer.
-
----
-*** 'image-converter' is now restricted to formats in 'auto-mode-alist'.
-When using external image converters, the external program is queried
-for what formats it supports.  This list may contain formats that are
-problematic in some contexts (like PDFs), so this list is now filtered
-based on 'auto-mode-alist'.  Only file names that map to 'image-mode'
-are now supported.
-
----
-*** The background and foreground of images now default to face colors.
-When an image doesn't specify a foreground or background color, Emacs
-now uses colors from the face used to draw the surrounding text
-instead of the frame's default colors.
-
-To load images with the default frame colors use the ':foreground' and
-':background' image attributes, for example:
-
-    (create-image "filename" nil nil
-                  :foreground (face-attribute 'default :foreground)
-                  :background (face-attribute 'default :background))
-
-This change only affects image types that support foreground and
-background colors or transparency, such as xbm, pbm, svg, png and gif.
-
-+++
-*** Image smoothing can now be explicitly enabled or disabled.
-Smoothing applies a bilinear filter while scaling or rotating an image
-to prevent aliasing and other unwanted effects.  The new image
-property ':transform-smoothing' can be set to t to force smoothing
-and nil to disable smoothing.
-
-The default behavior of smoothing on down-scaling and not smoothing
-on up-scaling remains unchanged.
-
-+++
-*** New user option 'image-transform-smoothing'.
-This controls whether to use smoothing or not for an image.  Values
-include nil (no smoothing), t (do smoothing) or a predicate function
-that's called with the image object and should return nil/t.
-
-+++
-*** SVG images now support user stylesheets.
-The ':css' image attribute can be used to override the default CSS
-stylesheet for an image.  The default sets 'font-family' and
-'font-size' to match the current face, so an image with 'height="1em"'
-will match the font size in use where it is embedded.
-
-This feature relies on librsvg 2.48 or above being available.
-
-+++
-*** Image properties support 'em' sizes.
-Size image properties, for example ':height', ':max-height', etc., can
-be given a cons of the form '(SIZE . em)', where SIZE is an integer or
-float which is multiplied by the font size to calculate the image
-size, and 'em' is a symbol.
-
-** EWW
-
-+++
-*** New user option 'eww-use-browse-url'.
-This is a regexp that can be set to alter how links are followed in eww.
-
-+++
-*** New user option 'eww-retrieve-command'.
-This can be used to download data via an external command.  If nil
-(the default), then 'url-retrieve' is used.  When 'sync', then
-'url-retrieve-synchronously' is used.
-
-+++
-*** New Emacs command line convenience command.
-The 'eww-browse' command has been added, which allows you to register
-Emacs as a MIME handler for "text/x-uri", and will call 'eww' on the
-supplied URL.  Usage example: "emacs -f eww-browse https://gnu.org";.
-
-+++
-*** 'eww-download-directory' will now use the XDG location, if defined.
-However, if "~/Downloads/" already exists, that will continue to be
-used.
-
----
-*** The command 'eww-follow-link' now supports custom mailto handlers.
-The function that is invoked when clicking on or otherwise following a
-'mailto:' link in an EWW buffer can now be customized.  For more
-information, see the related entry about 'shr-browse-url' above.
-
-** SHR
-
----
-*** The command 'shr-browse-url' now supports custom mailto handlers.
-Clicking on or otherwise following a 'mailto:' link in a HTML buffer
-rendered by SHR previously invoked the command 'browse-url-mailto'.
-This is still the case by default, but if you customize
-'browse-url-mailto-function' or 'browse-url-handlers' to call some
-other function, it will now be called instead of the default.
-
-+++
-*** New user option 'shr-max-width'.
-If this user option is non-nil, and 'shr-width' is nil, then SHR will
-use the value of 'shr-max-width' to limit the width of the rendered
-HTML.  The default is 120 characters, so even if you have very wide
-frames, HTML text will be rendered more narrowly, which usually leads
-to a more readable text.  Set this user option to nil to get the
-previous behavior of rendering as wide as the 'window-width' allows.
-If 'shr-width' is non-nil, it overrides this variable.
-
----
-*** New faces for heading elements.
-Those are 'shr-h1', 'shr-h2', 'shr-h3', 'shr-h4', 'shr-h5', 'shr-h6'.
-
-** Project
-
-*** New user option 'project-vc-merge-submodules'.
-
-*** Project commands now have their own history.
-Previously used project directories are now suggested by all commands
-that prompt for a project directory.
-
-+++
-*** New prefix keymap 'project-prefix-map'.
-Key sequences that invoke project-related commands start with the
-prefix 'C-x p'.  Type "C-x p C-h" to show the full list.
-
-+++
-*** New commands 'project-dired', 'project-vc-dir', 'project-shell',
-'project-eshell'.  These commands run Dired/VC-Dir and Shell/Eshell in
-a project's root directory, respectively.
-
-+++
-*** New command 'project-compile'.
-This command runs compilation in the current project's root
-directory.
-
-+++
-*** New command 'project-switch-project'.
-This command lets you "switch" to another project and run a project
-command chosen from a dispatch menu.
-
-+++
-*** New commands 'project-shell-command' and 'project-async-shell-command'.
-These commands run 'shell-command' and 'async-shell-command' in a
-project's root directory, respectively.
-
-+++
-*** New user option 'project-list-file'.
-This specifies the file in which to save the list of known projects.
-
-+++
-*** New command 'project-remember-projects-under'.
-This command can automatically locate and index projects in a
-directory and optionally also its subdirectories, storing them in
-'project-list-file'.
-
-+++
-*** New commands 'project-forget-project' and 'project-forget-projects-under'.
-These command lets you interactively remove entries from the list of projects
-in 'project-list-file'.
-
-+++
-*** New command 'project-forget-zombie-projects'.
-This command detects indexed projects that have since been deleted,
-and removes them from the list of known projects in 'project-list-file'.
-
----
-*** 'project-find-file' now accepts non-existent file names.
-This is to allow easy creation of files inside some nested
-sub-directory.
-
-+++
-*** 'project-find-file' doesn't use the string at point as default input.
-Now it's only suggested as part of the "future history".
-
-+++
-*** New command 'project-find-dir' runs Dired in a directory inside project.
-
-** Xref
-
----
-*** Prefix arg of 'xref-goto-xref' quits the "*xref*" buffer.
-So typing 'C-u RET' in the "*xref*" buffer quits its window
-before navigating to the selected location.
-
-+++
-*** New user options to automatically show the first Xref match.
-The new user option 'xref-auto-jump-to-first-definition' controls the
-behavior of 'xref-find-definitions' and its variants, like
-'xref-find-definitions-other-window': if it's t or 'show', the first
-match is automatically displayed; if it's 'move', point in the
-"*xref*" buffer is automatically moved to the first match without
-displaying it.
-The new user option 'xref-auto-jump-to-first-xref' changes the
-behavior of Xref commands such as 'xref-find-references',
-'xref-find-apropos', and 'project-find-regexp', which are expected to
-display many matches that the user would like to
-visit. 'xref-auto-jump-to-first-xref' changes their behavior much in
-the same way as 'xref-auto-jump-to-first-definition' affects the
-"find-definitions" commands.
-
-*** New user options 'xref-search-program' and 'xref-search-program-alist'.
-So far 'grep' and 'ripgrep' are supported.  'ripgrep' seems to offer better
-performance in certain cases, in particular for case-insensitive
-searches.
-
-+++
-*** New commands 'xref-prev-group' and 'xref-next-group'.
-These commands are bound respectively to 'P' and 'N', and navigate to
-the first item of the previous or next group in the "*xref*" buffer.
-
-*** New alternative value for 'xref-show-definitions-function':
-'xref-show-definitions-completing-read'.
-
-*** The two existing alternatives for 'xref-show-definitions-function'
-have been renamed to have "proper" public names and documented
-('xref-show-definitions-buffer' and
-'xref-show-definitions-buffer-at-bottom').
-
-+++
-*** New command 'xref-quit-and-pop-marker-stack'.
-This command is bound to 'M-,' in "*xref*" buffers.  This combination
-is easy to press semi-accidentally if the user wants to go back in the
-middle of choosing the exact definition to go to, and this should do
-TRT.
-
----
-*** New value 'project-relative' for 'xref-file-name-display'.
-If chosen, file names in "*xref*" buffers will be displayed relative
-to the 'project-root' of the current project, when available.
-
-+++
-*** The 'TAB' key binding in "*xref*" buffers is obsolete.
-Use 'C-u RET' instead.  The 'TAB' binding in "*xref*" buffers is still
-supported, but we plan on removing it in a future version; at that
-time, the command 'xref-quit-and-goto-xref' will no longer have a key
-binding in 'xref--xref-buffer-mode-map'.
-
----
-*** New user option 'etags-xref-prefer-current-file'.
-When non-nil, matches for identifiers in the file visited by the
-current buffer will be shown first in the "*xref*" buffer.
-
-+++
-*** The etags Xref backend now honors 'tags-apropos-additional-actions'.
-You can customize it to augment the output of 'xref-find-apropos',
-like it affected the output of 'tags-apropos', which is obsolete since
-Emacs 25.1.
-
-** Battery
-
----
-*** UPower is now the default battery status backend when available.
-UPower support via the function 'battery-upower' was added in Emacs
-26.1, but was disabled by default.  It is now the default value of
-'battery-status-function' when the system provides a UPower D-Bus
-service.  The user options 'battery-upower-device' and
-'battery-upower-subscribe' control which power sources to query and
-whether to respond to status change notifications in addition to
-polling, respectively.
-
----
-*** A richer syntax can be used to format battery status information.
-The user options 'battery-mode-line-format' and
-'battery-echo-area-format' now support the full formatting syntax of
-the function 'format-spec' documented under node "(elisp) Custom Format
-Strings".  The new syntax includes specifiers for padding and
-truncation, amongst other things.
-
-** bug-reference.el
-
----
-*** Bug reference mode uses auto-setup.
-If 'bug-reference-mode' or 'bug-reference-prog-mode' have been
-activated, their respective hook has been run and still
-'bug-reference-bug-regexp' and 'bug-reference-url-format' aren't both
-set, it tries to guess appropriate values for those two variables.
-There are three guessing mechanisms so far: based on version control
-information of the current buffer's file, based on
-newsgroup/mail-folder name and several news and mail message headers
-in Gnus buffers, and based on IRC channel and network in rcirc and ERC
-buffers.  All the mechanisms are extensible with custom rules, see the
-variables 'bug-reference-setup-from-vc-alist',
-'bug-reference-setup-from-mail-alist', and
-'bug-reference-setup-from-irc-alist'.
-
-** HTML Mode
-
----
-*** A new skeleton for adding relative URLs has been added.
-It's bound to the 'C-c C-c f' keystroke, and prompts for a local file
-name.
-
-** Widget
-
-+++
-*** 'widget-choose' now supports menus in extended format.
-
----
-*** The 'editable-list' widget now supports moving items up and down.
-You can now move items up and down by deleting and then reinserting
-them, using the 'DEL' and 'INS' buttons respectively.  This is useful
-in Custom buffers, for example, to change the order of the elements in
-a list.
-
-** Diff
-
----
-*** New face 'diff-changed-unspecified'.
-This is used to highlight "changed" lines (those marked with '!') in
-context diffs, when 'diff-use-changed-face' is non-nil.
-
----
-*** New 'diff-mode' font locking face 'diff-error'.
-This face is used for error messages from 'diff'.
-
-+++
-*** New command 'diff-refresh-hunk'.
-This new command (bound to 'C-c C-l') regenerates the current hunk.
-
-** thing-at-point
-
-+++
-*** New 'thing-at-point' target: 'existing-filename'.
-This is like 'filename', but is a full path, and is nil if the file
-doesn't exist.
-
-*** New 'thing-at-point' target: 'list-or-string'.
-This is like 'list, but if point is inside a string that's enclosed in
-the list, it returns the enclosed string and not the enclosing list.
-
-This is like 'list', but also prefers to find of any enclosing string.
-
-+++
-*** New variable 'thing-at-point-provider-alist'.
-This allows mode-specific alterations to how 'thing-at-point' works.
-
----
-*** thing-at-point now respects fields.
-'thing-at-point' (and all functions that use it, like
-'symbol-at-point') will narrow to the current field (if any) before
-trying to identify the thing at point.
-
-*** New function 'thing-at-mouse'.
-
-** image-dired
-
----
-*** 'image-dired-mouse-toggle-mark' now toggles files in the active region.
-
-+++
-*** New user option 'image-dired-thumb-visible-marks'.
-If non-nil (the default), use 'image-dired-thumb-mark' to say what
-images are marked.
-
----
-*** New command 'image-dired-delete-marked'.
-
-** Flymake mode
-
-+++
-*** New command 'flymake-show-project-diagnostics'
-This lists all diagnostics for buffers in the currently active
-project.  The listing is similar to the one obtained by
-'flymake-show-buffer-diagnostics', but adds a column for the
-project-relative file name.  For backends which support it,
-'flymake-show-project-diagnostics' also lists diagnostics for files
-that have not yet been visited.
-
-+++
-*** New user options to customize Flymake's mode-line.
-The new user option 'flymake-mode-line-format' is a mix of strings and
-symbols like 'flymake-mode-line-title', 'flymake-mode-line-exception'
-and 'flymake-mode-line-counters'.  The new user option
-'flymake-mode-line-counter-format' is a mix of strings and symbols
-like 'flymake-mode-line-error-counter',
-'flymake-mode-line-warning-counter' and 'flymake-mode-line-note-counter'.
-
-** Time
-
----
-*** 'display-time-world' has been renamed to 'world-clock'.
-'world-clock' creates a buffer with an updating time display using
-several time zones.  It is hoped that the new names are more
-discoverable.
-
-The following commands have been renamed:
-
-  'display-time-world'         to 'world-clock'
-  'display-time-world-mode'    to 'world-clock-mode'
-  'display-time-world-display' to 'world-clock-display'
-  'display-time-world-timer'   to 'world-clock-update'
-
-The following user options have been renamed:
-
-  'display-time-world-list'         to 'world-clock-list'
-  'display-time-world-time-format'  to 'world-clock-time-format'
-  'display-time-world-buffer-name'  to 'world-clock-buffer-name'
-  'display-time-world-timer-enable' to 'world-clock-timer-enable'
-  'display-time-world-timer-second' to 'world-clock-timer-second'
-
-The old names are now obsolete.
-
----
-*** 'world-clock-mode' can no longer be turned on interactively.
-Use 'world-clock' to turn on that mode.
-
-** CPerl Mode
-
----
-*** New face 'perl-heredoc', used for heredoc elements.
-
----
-*** The command 'cperl-set-style' offers the new value "PBP".
-This value customizes Emacs to use the style recommended in Damian
-Conway's book "Perl Best Practices" for indentation and formatting
-of conditionals.
-
-** Octave Mode
-
-+++
-*** Line continuations in double-quoted strings now use a backslash.
-Typing 'C-M-j' (bound to 'octave-indent-new-comment-line') now follows
-the behavior introduced in Octave 3.8 of using a backslash as a line
-continuation marker within double-quoted strings, and an ellipsis
-everywhere else.
-
-+++
-** EasyPG
-GPG key servers can now be queried for keys with the
-'M-x epa-search-keys' command.  Keys can then be added to your
-personal key ring.
-
-** Etags
-
-+++
-*** Etags now supports the Mercury programming language.
-See https://mercurylang.org.
-
-+++
-*** Etags command line option '--declarations' now has Mercury-specific 
behavior.
-All Mercury declarations are tagged by default.  However, for
-compatibility with 'etags' support for Prolog, predicates and
-functions appearing first in clauses will also be tagged if 'etags' is
-invoked with the '--declarations' command-line option.
-
-** Comint
-
-+++
-*** Support for OSC escape sequences.
-Adding the new 'comint-osc-process-output' to
-'comint-output-filter-functions' enables the interpretation of OSC
-("Operating System Command") escape sequences in comint buffers.  By
-default, only OSC 8, for hyperlinks, and OSC 7, for directory
-tracking, are acted upon.  Adding more entries to
-'comint-osc-handlers' allows a customized treatment of further escape
-sequences.
-
-+++
-*** 'comint-delete-output' can now save deleted text in the kill-ring.
-Interactively, 'C-u C-c C-o' triggers this new optional behavior.
-
-** ERC
-
----
-*** NickServ passwords can now be retrieved from auth-source.
-The 'erc-use-auth-source-for-nickserv-password' user option enables
-querying auth-source for NickServ passwords.  To enable this, add the
-following to your init file:
-
-    (setq erc-use-auth-source-for-nickserv-password t)
-
----
-*** NickServ identification now prompts for password last.
-When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
-be unconditionally prompted interactively for a password, regardless
-of the value of 'erc-nickserv-passwords', which was effectively
-ignored (same for the new
-'erc-use-auth-source-for-nickserv-password').  This limitation is now
-lifted, and the user is interactively prompted last, after the other
-identification methods have run.
-
----
-*** The '/ignore' command will now ask for a timeout to stop ignoring the user.
-Allowed inputs are seconds or ISO8601-like periods like "1h" or "4h30m".
-
----
-*** ERC now recognizes 'C-]' for italic text.
-Italic text is displayed in the new 'erc-italic-face'.
-
----
-*** The erc-compat.el library is now marked obsolete.
-This file contained ERC compatibility code for Emacs 21 and XEmacs
-which is no longer needed.
-
----
-*** erc-match.el now supports 'message' highlight type (not including the 
nick).
-The 'erc-current-nick-highlight-type', 'erc-pal-highlight-type',
-'erc-fool-highlight-type', 'erc-keyword-highlight-type', and
-'erc-dangerous-host-highlight-type' variables now support a 'message'
-type for highlighting the entire message but not the sender's nick.
-
----
-*** erc-status-sidebar.el is now part of ERC.
-The 'erc-status-sidebar' package which provides a HexChat-like
-activity overview sidebar for joined IRC channels is now part of ERC.
-
-+++
-*** erc-tls now supports specifying a TLS client certificate.
-The 'erc-tls' function has been updated to allow specifying a TLS
-client certificate for authentication, as an alternative to NickServ
-password-based authentication.  This is referred to as "CertFP" (short
-for Certificate Fingerprint) by several IRC networks.  See the Info
-node "(erc) Connecting" in the ERC manual for more details and
-examples on how to specify and use TLS client certificates with
-'erc-tls'.
-
----
-*** Add 'erc-track-select-mode-line-face' (obsoletes 'erc-track-find-face').
-The 'erc-track-find-face' function of the erc-track module has been
-declared obsolete and rewritten as 'erc-track-select-mode-line-face',
-with different expected arguments (the current and old faces are now
-separated) and clearer documentation.
-
-*** Add '/opme' and '/deopme' convenience commands.
-The new '/opme' convenience command asks ChanServ to set the operator
-status for the current nick in the current channel, and '/deopme'
-unsets it.
-
-** xwidget-webkit mode
-
----
-*** New xwidget commands.
-'xwidget-webkit-uri' (return the current URL), 'xwidget-webkit-title'
-(return the current title), and 'xwidget-webkit-goto-history' (goto a
-point in history).
-
----
-*** Pixel-based scrolling.
-The 'xwidget-webkit-scroll-up', 'xwidget-webkit-scroll-down' commands
-now supports scrolling arbitrary pixel values.  It now treats the
-optional 2nd argument as the pixel values to scroll.
-
----
-*** New commands for scrolling.
-The new commands 'xwidget-webkit-scroll-up-line',
-'xwidget-webkit-scroll-down-line', 'xwidget-webkit-scroll-forward',
-'xwidget-webkit-scroll-backward' can be used to scroll webkit by the
-height of lines or width of chars.
-
----
-*** New user option 'xwidget-webkit-bookmark-jump-new-session'.
-When non-nil, use a new xwidget webkit session after bookmark jump.
-Otherwise, it will use 'xwidget-webkit-last-session'.
-
-** Checkdoc
-
----
-*** No longer warns about command substitutions by default.
-Checkdoc used to warn about "too many command substitutions" (as in
-"\\[foo-command]"), even if you only used ten of them in a docstring.
-On modern machines, you can have hundreds or thousands of command
-substitutions before it becomes a performance issue, so this warning
-is now disabled by default.  To re-enable this warning, customize the
-user option 'checkdoc-max-keyref-before-warn'.
-
----
-*** New user option 'checkdoc-column-zero-backslash-before-paren'.
-Checkdoc warns if there is a left parenthesis in column zero of a
-documentation string.  That warning can now be disabled by customizing
-this new user option to nil.  This is useful if you don't expect
-your code to be edited with an Emacs older than version 27.1.
-
----
-*** Now checks the prompt format for 'yes-or-no-p'.
-In addition to verifying the format of the prompt for 'y-or-n-p',
-checkdoc will now check the format of 'yes-or-no-p'.
-
----
-*** New command 'checkdoc-dired'.
-This can be used to run checkdoc on files from a Dired buffer.
-
----
-*** No longer checks for "A-" modifiers.
-Checkdoc recommends usage of command substitutions ("\\[foo-command]")
-in favor of writing keybindings like "C-c f".  It now no longer warns
-about the "A-" modifier as it is not used very much in practice, and
-this warning therefore mostly led to false positives.
-
-** Enriched mode
-
----
-*** 'C-a' is by default no longer bound to 'beginning-of-line-text'.
-This is so 'C-a' works as in other modes, and in particular holding
-Shift while typing 'C-a', i.e. 'C-S-a', will now highlight the text.
-
-** Gravatar
-
----
-*** New user option 'gravatar-service' for host to query for gravatars.
-Defaults to 'libravatar', with 'unicornify' and 'gravatar' as options.
-
-** MH-E mail handler for Emacs
-
-Functions and variables related to handling junk mail have been
-renamed to not associate color with sender quality.
-
-+++
-*** New names for mh-junk interactive functions.
-Function 'mh-junk-whitelist' is renamed 'mh-junk-allowlist'.
-Function 'mh-junk-blacklist' is renamed 'mh-junk-blocklist'.
-
-+++
-*** New binding for 'mh-junk-allowlist'.
-The key binding for 'mh-junk-allowlist' is changed from 'J w' to 'J a'.
-The old binding is supported but warns that it is obsolete.
-
-+++
-*** New names for some hooks.
-'mh-whitelist-msg-hook' is renamed 'mh-allowlist-msg-hook'.
-'mh-blacklist-msg-hook' is renamed 'mh-blocklist-msg-hook'.
-
-+++
-*** New names for some variables.
-Variable 'mh-whitelist-preserves-sequences-flag' is renamed
-'mh-allowlist-preserves-sequences-flag'.
-
-+++
-*** New names for some faces.
-Face 'mh-folder-blacklisted' is renamed 'mh-folder-blocklisted'.
-Face 'mh-folder-whitelisted' is renamed 'mh-folder-allowlisted'.
-
-** Rcirc
-
-+++
-*** rcirc now supports SASL authentication.
-
----
-*** rcirc connects asynchronously
-
----
-*** Integrate formatting into rcirc-send-string
-The function now accepts a variable number of arguments.
-
-+++
-*** Deprecate defun-rcirc-command in favour of rcirc-define-command
-The new macro handles multiple and optional arguments.
-
----
-*** Add basic IRCv3 support
-This includes support for the capabilities: server-time, batch,
-message-ids, invite-notify, multi-prefix and standard-replies.
-
----
-*** Add mouse property support to rcirc-track-minor-mode
-
----
-*** Improve support for IRC markup codes
-
----
-*** Check auth-sources for server passwords
-
----
-*** Allow for channels to hide certain message types right after connecting.
-Set rcirc-omit-responses-after-join analogously to rcirc-omit-responses.
-
-+++
-*** Implement repeated reconnection strategy
-See rcirc-reconnect-attempts.
-
-** Miscellaneous
-
----
-*** 'shell-script-mode' now supports 'outline-minor-mode'.
-The outline headings have lines that start with "###".
-
----
-*** fileloop will now skip missing files instead of signalling an error.
-
----
-*** 'tabulated-list-mode' can now restore original display order.
-Many commands (like 'C-x C-b') are derived from 'tabulated-list-mode',
-and that mode allows the user to sort on any column.  There was
-previously no easy way to get back to the original displayed order
-after sorting, but giving a -1 numerical prefix to the sorting command
-will now restore the original order.
-
----
-*** 'M-left' and 'M-right' now move between columns in 'tabulated-list-mode'.
-
----
-*** New variable 'hl-line-overlay-priority'.
-This can be used to change the priority of the hl-line overlays.
-
-+++
-*** New command 'mailcap-view-file'.
-This command will open a viewer based on the file type, as determined
-by "~/.mailcap" and related files and variables.
-
----
-*** New user option 'remember-diary-regexp'.
-
----
-*** New user option 'remember-text-format-function'.
-
----
-*** New user option 'authinfo-hide-elements'.
-This can be set to nil to inhibit hiding passwords in ".authinfo" files.
-
----
-*** 'hexl-mode' scrolling commands now heed 'next-screen-context-lines'.
-Previously, 'hexl-scroll-down' and 'hexl-scroll-up' would scroll
-up/down an entire window, but they now work more like the standard
-scrolling commands.
-
----
-*** New user option 'bibtex-unify-case-function'.
-This new option allows the user to customize how case is converted
-when unifying entries.
-
----
-*** The user option 'bibtex-maintain-sorted-entries' now permits
-user-defined sorting schemes.
-
----
-*** New user option 'reveal-auto-hide'.
-If non-nil (the default), revealed text is automatically hidden when
-point leaves the text.  If nil, the text is not hidden again.  Instead
-'M-x reveal-hide-revealed' can be used to hide all the revealed text.
-
----
-*** New user option 'ffap-file-name-with-spaces'.
-If non-nil, 'find-file-at-point' and friends will try to guess more
-expansively to identify a file name with spaces.  Default value is
-nil.
-
----
-*** Two new commands for centering in 'doc-view-mode'.
-The new commands 'doc-view-center-page-horizontally' (bound to 'c h')
-and 'doc-view-center-page-vertically' (bound to 'c v') center the page
-horizontally and vertically, respectively.
-
----
-*** 'tempo-define-template' can now re-assign templates to tags.
-Previously, assigning a new template to an already defined tag had no
-effect.
-
----
-*** The width of the buffer-name column in 'list-buffers' is now dynamic.
-The width now depends of the width of the window, but will never be
-wider than the length of the longest buffer name, except that it will
-never be narrower than 19 characters.
-
-+++
-*** New diary sexp 'diary-offset'.
-It offsets another diary sexp by a number of days.  This is useful
-when for example your organization has a committee meeting two days
-after every monthly meeting which takes place on the third Thursday,
-or if you would like to attend a virtual meeting scheduled in a
-different timezone causing a difference in the date.
-
----
-*** The old non-SMIE indentation of 'sh-mode' has been removed.
-
----
-*** 'mspools-show' is now autoloaded.
-
----
-*** Loading dunnet.el in batch mode doesn't start the game any more.
-Instead you need to do "emacs -f dun-batch" to start the game in
-batch mode.
-
-** Ruby Mode
-
----
-** 'ruby-use-smie' is declared obsolete.
-SMIE is now always enabled and 'ruby-use-smie' only controls whether
-indentation is done using SMIE or with the old ad-hoc code.
-
----
-** Indentation has changed when 'ruby-align-chained-calls' is non-nil.
-This previously used to align subsequent lines with the last sibling,
-but it now aligns with the first sibling (which is the preferred style
-in Ruby).
-
-** Imenu
-
-+++
-*** New user option 'imenu-max-index-time'.
-If creating the imenu index takes longer than specified by this
-variable (default 5 seconds), imenu indexing is stopped.
-
-
-* New Modes and Packages in Emacs 28.1
-
-+++
-** New transient mode 'repeat-mode' to allow shorter key sequences.
-You can type 'C-x u u' instead of 'C-x u C-x u' to undo many changes,
-'C-x o o' instead of 'C-x o C-x o' to switch several windows,
-'C-x { { } } ^ ^ v v' to resize the selected window interactively,
-'M-g n n p p' to navigate next-error matches.  Any other key exits
-transient mode and then is executed normally.  'repeat-exit-key'
-defines an additional key to exit mode like 'isearch-exit' ('RET').
-The user option 'repeat-exit-timeout' specifies the number of
-seconds of idle time to break the repetition chain automatically.
-With 'repeat-keep-prefix' you can keep the prefix arg of the previous
-command.  For example, this can help to reverse the window navigation
-direction with e.g. 'C-x o M-- o o'.  Also it can help to set a new
-step with e.g. 'C-x { C-5 { { {', which will set the window resizing
-step to 5 columns.
-
----
-** New themes 'modus-vivendi' and 'modus-operandi'.
-These themes are designed to conform with the highest standard for
-color-contrast accessibility (WCAG AAA).  You can load either of them
-using 'M-x customize-themes' or 'load-theme' from your init file.
-Consult the Modus Themes Info manual for more information on the user
-options they provide.
-
-** Dictionary mode
-This is a mode for searching a RFC 2229 dictionary server.
-'dictionary' opens a buffer for starting operations.
-'dictionary-search' performs a lookup for a word.  It also supports a
-'dictionary-tooltip-mode' which performs a lookup of the word under
-the mouse in 'dictionary-tooltip-dictionary' (which must be customized
-first).
-
----
-** Lisp Data mode
-The new command 'lisp-data-mode' enables a major mode for buffers
-composed of Lisp symbolic expressions that do not form a computer
-program.  The ".dir-locals.el" file is automatically set to use this
-mode, as are other data files produced by Emacs.
-
-+++
-** New global mode 'global-goto-address-mode'.
-This will enable 'goto-address-mode' in all buffers.
-
-** transient.el
-This library implements support for powerful keyboard-driven menus.
-Such menus can be used as simple visual command dispatchers.  More
-complex menus take advantage of infix arguments, which are somewhat
-similar to prefix arguments, but are more flexible and discoverable.
-
-** hierarchy.el
-This library can create, query, navigate and display hierarchical
-structures.
-
----
-** New major mode for displaying the "etc/AUTHORS" file.
-This new 'etc-authors-mode' provides font-locking for displaying the
-"etc/AUTHORS" file from the Emacs distribution, and not much else.
-
-
-* Incompatible Editing Changes in Emacs 28.1
-
----
-** 'toggle-truncate-lines' now disables 'visual-line-mode'.
-This is for symmetry with 'visual-line-mode', which disables
-'truncate-lines'.
-
----
-** 'electric-indent-mode' now also indents inside strings and comments.
-(This only happens when indentation function also supports this.)
-
-To recover the previous behavior you can use:
-
-    (add-hook 'electric-indent-functions
-              (lambda (_) (if (nth 8 (syntax-ppss)) 'no-indent)))
-
----
-** The 'M-o' ('facemenu-keymap') global binding has been removed.
-To restore the old binding, say something like:
-
-    (require 'facemenu)
-    (define-key global-map "\M-o" 'facemenu-keymap)
-    (define-key facemenu-keymap "\es" 'center-line)
-    (define-key facemenu-keymap "\eS" 'center-paragraph)
-
-The last two lines are not strictly necessary if you don't care about
-having those two commands on the 'M-o' keymap; see the next section.
-
----
-** The 'M-o M-s' and 'M-o M-S' global bindings have been removed.
-Use 'M-x center-line' and 'M-x center-paragraph' instead.  See the
-previous section for how to get back the old bindings.  Alternatively,
-if you only want these two commands to have global bindings they had
-before, you can add the following to your init file:
-
-  (define-key global-map "\M-o\M-s" 'center-line)
-  (define-key global-map "\M-o\M-S" 'center-paragraph)
-
----
-** The 'M-o M-o' global binding has been removed.
-Use 'M-x font-lock-fontify-block' instead, or the new 'C-x x f'
-command, which updates the syntax highlighting in the current buffer.
-
----
-** The escape sequence '\e[29~' in Xterm is now mapped to 'menu'.
-Xterm sends this sequence for both 'F16' and 'Menu' keys
-It used to be mapped to 'print' but we couldn't find a terminal
-that uses this sequence for any kind of 'Print' key.
-This makes the Menu key (see https://en.wikipedia.org/wiki/Menu_key)
-work for 'context-menu-mode' in Xterm.
-
----
-** New user option 'xterm-store-paste-on-kill-ring'.
-If non-nil (the default), Emacs pushes pasted text onto the kill ring
-(if using an xterm-like terminal that supports bracketed paste).
-Setting this to nil inhibits that.
-
----
-** 'vc-print-branch-log' shows the change log from its root directory.
-It previously used to use the default directory.
-
----
-** 'project-shell' and 'shell' now use 'pop-to-buffer-same-window'.
-This is to keep the same behavior as Eshell.
-
----
-** In 'nroff-mode', 'center-line' is no longer bound to a key.
-The original key binding was 'M-s', which interfered with I-search,
-since the latter uses 'M-s' as a prefix key of the search prefix map.
-
----
-** In 'f90-mode', the backslash character ('\') no longer escapes.
-For about a decade, the backslash character has no longer had a
-special escape syntax in Fortran F90.  To get the old behavior back,
-say something like:
-
-    (modify-syntax-entry ?\\ "\\" f90-mode-syntax-table)
-
-+++
-** Setting 'fill-column' to nil is obsolete.
-This undocumented use of 'fill-column' is now obsolete.  To disable
-auto filling, turn off 'auto-fill-mode' instead.
-
-For instance, you could add something like the following to your init
-file:
-
-    (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
-
-
-* Incompatible Lisp Changes in Emacs 28.1
-
-+++
-** Emacs now prints a backtrace when signaling an error in batch mode.
-This makes debugging Emacs Lisp scripts run in batch mode easier.  To
-get back the old behavior, set the new variable
-'backtrace-on-error-noninteractive' to a nil value.
-
----
-** Some floating-point numbers are now handled differently by the Lisp reader.
-In previous versions of Emacs, numbers with a trailing dot and an exponent
-were read as integers and the exponent ignored: 2.e6 was interpreted as the
-integer 2.  Such numerals are now read as floats with the exponent included:
-2.e6 is now read as the floating-point value 2000000.0.
-That is, '(read-from-string "1.e3")' => '(1000.0 . 4)' now.
-
----
-** 'equal' no longer examines some contents of window configurations.
-Instead, it considers window configurations to be equal only if they
-are 'eq'.  To compare contents, use 'compare-window-configurations'
-instead.  This change helps fix a bug in 'sxhash-equal', which returned
-incorrect hashes for window configurations and some other objects.
-
-+++
-** The 'lexical-binding' local variable is always enabled.
-Previously, if 'enable-local-variables' was nil, a 'lexical-binding'
-local variable would not be heeded.  This has now changed, and a file
-with a 'lexical-binding' cookie is always heeded.  To revert to the
-old behavior, set 'permanently-enabled-local-variables' to nil.
-
----
-** 'kill-all-local-variables' has changed how it handles non-symbol hooks.
-The function is documented to eliminate all buffer-local bindings
-except variables with a 'permanent-local' property, or hooks that
-have elements with a 'permanent-local-hook' property.  In addition, it
-would also keep lambda expressions in hooks sometimes.  The latter has
-now been changed: The function will now also remove these.
-
-+++
-** Temporary buffers no longer run certain buffer hooks.
-The macros 'with-temp-buffer' and 'with-temp-file' no longer run the
-hooks 'kill-buffer-hook', 'kill-buffer-query-functions', and
-'buffer-list-update-hook' for the temporary buffers they create.  This
-avoids slowing them down when a lot of these hooks are defined.
-
-+++
-** New face 'child-frame-border' and frame parameter 
'child-frame-border-width'.
-The face and width of child frames borders can now be determined
-separately from those of normal frames.  To minimize backward
-incompatibility, child frames without a 'child-frame-border-width'
-parameter will fall back to using 'internal-border-width'.  However,
-the new 'child-frame-border' face does constitute a breaking change
-since child frames' borders no longer use the 'internal-border' face.
-
----
-** 'run-at-time' now tries harder to implement the t TIME parameter.
-If TIME is t, the timer runs at an integral multiple of REPEAT.
-(I.e., if given a REPEAT of 60, it'll run at 08:11:00, 08:12:00,
-08:13:00.)  However, when a machine goes to sleep (or otherwise didn't
-get a time slot to run when the timer was scheduled), the timer would
-then fire every 60 seconds after the time the timer was fired.  This
-has now changed, and the timer code now recomputes the integral
-multiple every time it runs, which means that if the laptop wakes at
-08:16:43, it'll fire at that time, but then at 08:17:00, 08:18:00...
-
----
-** 'parse-partial-sexp' now signals an error if TO is smaller than FROM.
-Previously, this would lead to the function interpreting FROM as TO and
-vice versa, which would be confusing when passing in OLDSTATE, which
-refers to the old state at FROM.
-
-+++
-** 'global-mode-string' constructs should end with a space.
-This was previously not formalized, which led to combinations of modes
-displaying data "smushed together" on the mode line.
-
-+++
-** 'overlays-in' now handles zero-length overlays slightly differently.
-Previously, zero-length overlays at the end of the buffer were included
-in the result (if the region queried for stopped at that position).
-The same was not the case if the buffer had been narrowed to exclude
-the real end of the buffer.  This has now been changed, and
-zero-length overlays at 'point-max' are always included in the results.
-
----
-** 'replace-match' now runs modification hooks slightly later.
-The function is documented to leave point after the replacement text,
-but this was not always the case if a modification hook inserted text
-in front of the replaced text -- 'replace-match' would instead leave
-point where the end of the inserted text would have been before the
-hook ran.  'replace-match' now always leaves point after the
-replacement text.
-
-+++
-** 'completing-read-default' sets completion variables buffer-locally.
-'minibuffer-completion-table' and related variables are now set buffer-locally
-in the minibuffer instead of being set via a global let-binding.
-
----
-** XML serialization functions now reject invalid characters.
-Previously, 'xml-print' would produce invalid XML when given a string
-with characters that are not valid in XML (see
-https://www.w3.org/TR/xml/#charsets).  Now it rejects such strings.
-
----
-** JSON
-
----
-*** JSON number parsing is now stricter.
-Numbers with a leading plus sign, leading zeros, or a missing integer
-component are now rejected by 'json-read' and friends.  This makes
-them more compliant with the JSON specification and consistent with
-the native JSON parsing functions.
-
----
-*** JSON functions support the semantics of RFC 8259.
-The JSON functions 'json-serialize', 'json-insert',
-'json-parse-string', and 'json-parse-buffer' now implement some of the
-semantics of RFC 8259 instead of the earlier RFC 4627.  In particular,
-these functions now accept top-level JSON values that are neither
-arrays nor objects.
-
----
-*** Some JSON encoding functions are now obsolete.
-The functions 'json-encode-number', 'json-encode-hash-table',
-'json-encode-key', and 'json-encode-list' are now obsolete.
-
-The first two are kept as aliases of 'json-encode', which should be
-used instead.  Uses of 'json-encode-list' should be changed to call
-one of 'json-encode', 'json-encode-alist', 'json-encode-plist', or
-'json-encode-array' instead.
-
-+++
-*** Native JSON functions now signal an error if libjansson is unavailable.
-This affects 'json-serialize', 'json-insert', 'json-parse-string',
-and 'json-parse-buffer'.  This can happen if Emacs was compiled with
-libjansson, but the DLL cannot be found and/or loaded by Emacs at run
-time.  Previously, Emacs would display a message and return nil in
-these cases.
-
-+++
-** The use of positional arguments in 'define-minor-mode' is obsolete.
-These were actually rendered obsolete in Emacs 21 but were never
-marked as such.
-
----
-** 'pcomplete-ignore-case' is now an obsolete alias of 
'completion-ignore-case'.
-
-+++
-** 'completions-annotations' face is not used when the caller puts own face.
-This affects the suffix specified by completion 'annotation-function'.
-
-+++
-** An active minibuffer now has major mode 'minibuffer-mode'.
-This is instead of the erroneous 'minibuffer-inactive-mode' it
-formerly had.
-
----
-** 'make-text-button' no longer modifies text properties of its first argument.
-When its first argument is a string, 'make-text-button' no longer
-modifies the string's text properties; instead, it uses and returns
-a copy of the string.  This helps avoid trouble when strings are
-shared or constants.
-
-+++
-** Some properties from completion tables are now preserved.
-If 'minibuffer-allow-text-properties' is non-nil, doing completion
-over a table of strings with properties will no longer remove all the
-properties before returning.  This affects things like 'completing-read'.
-
----
-** 'dns-query' now consistently uses Lisp integers to represent integers.
-Formerly it made an exception for integer components of SOA records,
-because SOA serial numbers can exceed fixnum ranges on 32-bit platforms.
-Emacs now supports bignums so this old glitch is no longer needed.
-
-+++
-** The '&define' keyword in an Edebug specification now disables backtracking.
-The implementation was buggy, and multiple '&define' forms in an '&or'
-form should be exceedingly rare.  See the Info node "(elisp) Backtracking" in
-the Emacs Lisp reference manual for background.
-
-+++
-** The error 'ftp-error' belongs also to category 'remote-file-error'.
-
-+++
-** The WHEN argument of 'make-obsolete' and related functions is mandatory.
-The use of those functions without a WHEN argument was marked obsolete
-back in Emacs 23.1.  The affected functions are: 'make-obsolete',
-'define-obsolete-function-alias', 'make-obsolete-variable',
-'define-obsolete-variable-alias'.
-
-+++
-** 'inhibit-nul-byte-detection' is renamed to 'inhibit-null-byte-detection'.
-
----
-** Some functions are no longer considered safe by 'unsafep':
-'replace-regexp-in-string', 'catch', 'throw', 'error', 'signal'
-and 'play-sound-file'.
-
----
-** 'sql-*-statement-starters' are no longer user options.
-These variables describe facts about the SQL standard and
-product-specific additions.  There should be no need for users to
-customize them.
-
----
-** Some locale-related variables have been removed.
-The Lisp variables 'previous-system-messages-locale' and
-'previous-system-time-locale' have been removed, as they were created
-by mistake and were not useful to Lisp code.
-
----
-** Function 'lm-maintainer' is replaced with 'lm-maintainers'.
-The former is now declared obsolete.
-
-+++
-** 'facemenu.el' is no longer preloaded.
-To use functions/variables from the package, you now have to say
-'(require 'facemenu)' or similar.
-
----
-** 'facemenu-color-alist' is now obsolete, and is not used.
-
----
-** The variable 'keyboard-type' is obsolete and not dynamically scoped any 
more.
-
-+++
-** The 'values' variable is now obsolete.
-Using it just contributes to the growth of the Emacs memory
-footprint.
-
----
-** The 'load-dangerous-libraries' variable is now obsolete.
-It was used to allow loading Lisp libraries compiled by XEmacs, a
-modified version of Emacs which is no longer actively maintained.
-This is no longer supported, and setting this variable has no effect.
-
-+++
-** The macro 'with-displayed-buffer-window' is now obsolete.
-Use macro 'with-current-buffer-window' with action alist entry 'body-function'.
-
----
-** The rfc2368.el library is now obsolete.
-Use rfc6068.el instead.  The main difference is that
-'rfc2368-parse-mailto-url' and 'rfc2368-unhexify-string' assumed that
-the strings were all-ASCII, while 'rfc6068-parse-mailto-url' and
-'rfc6068-unhexify-string' parse UTF-8 strings.
-
----
-** The inversion.el library is now obsolete.
-
----
-** The metamail.el library is now obsolete.
-
-** Edebug changes
-
----
-*** 'get-edebug-spec' is obsolete, replaced by 'edebug-get-spec'.
-
-+++
-*** The spec operator ':name NAME' is obsolete, use '&name' instead.
-
-+++
-*** The spec element 'function-form' is obsolete, use 'form' instead.
-
-+++
-*** New function 'def-edebug-elem-spec' to define Edebug spec elements.
-These used to be defined with 'def-edebug-spec' thus conflating the
-two name spaces, which lead to name collisions.
-The use of 'def-edebug-spec' to define Edebug spec elements is
-declared obsolete.
-
----
-** The sb-image.el library is now obsolete.
-This was a compatibility kludge which is no longer needed.
-
----
-** Some libraries obsolete since Emacs 23 have been removed:
-ledit.el, lmenu.el, lucid.el and old-whitespace.el.
-
----
-** Some functions and variables obsolete since Emacs 23 have been removed:
-'GOLD-map', 'advertised-xscheme-send-previous-expression',
-'allout-init', 'bookmark-jump-noselect',
-'bookmark-read-annotation-text-func', 'buffer-menu-mode-hook',
-'c-forward-into-nomenclature', 'char-coding-system-table',
-'char-valid-p', 'charset-bytes', 'charset-id', 'charset-list',
-'choose-completion-delete-max-match', 'complete-in-turn',
-'completion-base-size', 'completion-common-substring',
-'crm-minibuffer-complete', 'crm-minibuffer-complete-and-exit',
-'crm-minibuffer-completion-help', 'custom-mode', 'custom-mode-hook',
-'define-key-rebound-commands', 'define-mode-overload-implementation',
-'detect-coding-with-priority', 'dirtrack-debug',
-'dirtrack-debug-toggle', 'dynamic-completion-table',
-'easy-menu-precalculate-equivalent-keybindings',
-'epa-display-verify-result', 'epg-passphrase-callback-function',
-'erc-announced-server-name', 'erc-default-coding-system',
-'erc-process', 'erc-send-command', 'eshell-report-bug',
-'eval-next-after-load', 'exchange-dot-and-mark', 'ffap-bug',
-'ffap-submit-bug', 'ffap-version', 'file-cache-mouse-choose-completion',
-'forward-point', 'generic-char-p', 'global-highlight-changes',
-'hi-lock-face-history', 'hi-lock-regexp-history',
-'highlight-changes-active-string', 'highlight-changes-initial-state',
-'highlight-changes-passive-string',
-'icalendar--datetime-to-noneuropean-date', 'image-mode-maybe',
-'imenu-example--name-and-position', 'ispell-aspell-supports-utf8',
-'lisp-mode-auto-fill', 'locate-file-completion', 'make-coding-system',
-'menu-bar-files-menu', 'minibuffer-local-must-match-filename-map',
-'mouse-choose-completion', 'mouse-major-mode-menu',
-'mouse-popup-menubar', 'mouse-popup-menubar-stuff',
-'newsticker-groups-filename', 'nnir-swish-e-index-file',
-'nnmail-fix-eudora-headers', 'non-iso-charset-alist',
-'nonascii-insert-offset', 'nonascii-translation-table',
-'password-read-and-add', 'pre-abbrev-expand-hook', 'princ-list',
-'print-help-return-message', 'process-filter-multibyte-p',
-'read-file-name-predicate', 'remember-buffer', 'rmail-highlight-face',
-'rmail-message-filter', 'semantic-after-idle-scheduler-reparse-hooks',
-'semantic-after-toplevel-bovinate-hook',
-'semantic-before-idle-scheduler-reparse-hooks',
-'semantic-before-toplevel-bovination-hook',
-'semantic-bovinate-from-nonterminal-full',
-'semantic-bovinate-region-until-error', 'semantic-bovinate-toplevel',
-'semantic-bovination-working-type',
-'semantic-decorate-pending-decoration-hooks',
-'semantic-edits-incremental-reparse-failed-hooks',
-'semantic-eldoc-current-symbol-info', 'semantic-expand-nonterminal',
-'semantic-file-token-stream', 'semantic-find-dependency',
-'semantic-find-nonterminal', 'semantic-flex', 'semantic-flex-buffer',
-'semantic-flex-keyword-get', 'semantic-flex-keyword-p',
-'semantic-flex-keyword-put', 'semantic-flex-keywords',
-'semantic-flex-list', 'semantic-flex-make-keyword-table',
-'semantic-flex-map-keywords', 'semantic-flex-token-end',
-'semantic-flex-token-start', 'semantic-flex-token-text',
-'semantic-imenu-bucketize-type-parts',
-'semantic-imenu-expand-type-parts', 'semantic-imenu-expandable-token',
-'semantic-init-db-hooks', 'semantic-init-hooks',
-'semantic-init-mode-hooks', 'semantic-java-prototype-nonterminal',
-'semantic-nonterminal-abstract', 'semantic-nonterminal-full-name',
-'semantic-nonterminal-leaf', 'semantic-nonterminal-protection',
-'semantic-something-to-stream', 'semantic-tag-make-assoc-list',
-'semantic-token-type-parent', 'semantic-toplevel-bovine-cache',
-'semantic-toplevel-bovine-table', 'semanticdb-mode-hooks',
-'set-coding-priority', 'set-process-filter-multibyte',
-'shadows-compare-text-p', 'shell-dirtrack-toggle',
-'speedbar-navigating-speed', 'speedbar-update-speed', 't-mouse-mode',
-'term-dynamic-simple-complete', 'tooltip-hook', 'tpu-have-ispell',
-'url-generate-unique-filename', 'url-temporary-directory',
-'vc-arch-command', 'vc-default-working-revision' (variable),
-'vc-mtn-command', 'vc-revert-buffer', 'vc-workfile-version',
-'vcursor-toggle-vcursor-map', 'w32-focus-frame', 'w32-select-font',
-'wisent-lex-make-token-table'.
-
----
-** Some functions and variables obsolete since Emacs 22 have been removed:
-'erc-current-network', 'gnus-article-hide-pgp-hook',
-'gnus-inews-mark-gcc-as-read', 'gnus-treat-display-xface',
-'gnus-treat-strip-pgp', 'nnmail-spool-file'.
-
----
-** The obsolete function 'thread-alive-p' has been removed.
-
----
-** The variable 'force-new-style-backquotes' has been removed.
-This removes the final remaining trace of old-style backquotes.
-
----
-** Some obsolete variable and function aliases in dbus.el have been removed.
-In Emacs 24.3, the variable 'dbus-event-error-hooks' was renamed to
-'dbus-event-error-functions' and the function
-'dbus-call-method-non-blocking' was renamed to 'dbus-call-method'.
-The old names, which were kept as obsolete aliases of the new names,
-have now been removed.
-
----
-** 'find-function-source-path' renamed and re-documented.
-The 'find-function' command (and various related commands) were
-documented to respect 'find-function-source-path', and to search for
-objects in files specified by that variable.  It's unclear when this
-actually changed, but at some point (perhaps decades ago) these
-commands started using 'load-history' to determine where symbols had
-been defined (which is much faster).  The doc strings of all the
-affected function has been updated.  'find-function-source-path' was
-still being used by 'find-library' and related commands, so the
-variable has been renamed to 'find-library-source-path', and
-'find-function-source-path' is now an obsolete variable alias.
-
----
-** The macro 'vc-call' no longer evaluates its second argument twice.
-
-
-* Lisp Changes in Emacs 28.1
-
-+++
-** The 'interactive' syntax has been extended to allow listing applicable 
modes.
-Forms like '(interactive "p" dired-mode)' can be used to annotate the
-commands as being applicable for modes derived from 'dired-mode',
-or if the mode is a minor mode, that the current buffer has that
-minor mode activated.  Note that using this form will create byte code
-that is not compatible with byte code in previous Emacs versions.
-
-+++
-** New forms to declare how completion should happen has been added.
-'(declare (completion PREDICATE))' can be used as a general predicate
-to say whether the command should be present when completing with
-'M-x TAB'.  '(declare (modes MODE...))' can be used as a short-hand
-way of saying that the command should be present when completing from
-buffers in major modes derived from MODE..., or, if it's a minor mode,
-whether that minor mode is enabled in the current buffer.
-
-+++
-** 'define-minor-mode'  now takes an ':interactive' argument.
-This can be used for specifying which modes this minor mode is meant
-for, or to make the new minor mode non-interactive.  The default value
-is t.
-
-+++
-** 'define-derived-mode' now takes an ':interactive' argument.
-This can be used to control whether the defined mode is a command
-or not, and is useful when defining commands that aren't meant to be
-used by users directly.
-
-+++
-** 'define-globalized-minor-mode' now takes a ':predicate' parameter.
-This can be used to control which major modes the minor mode should be
-used in.
-
-+++
-** 'condition-case' now allows for a success handler.
-It is written as '(:success BODY...)' where BODY is executed
-whenever the protected form terminates without error, with the
-specified variable bound to the the value of the protected form.
-
-+++
-** New function 'benchmark-call' to measure the execution time of a function.
-Additionally, the number of repetitions can be expressed as a minimal duration
-in seconds.
-
-+++
-** The value thrown to the 'exit' label can now be a function.
-This is in addition to values t or nil.  If the value is a function,
-the command loop will call it with zero arguments before returning.
-
-+++
-** The behavior of 'format-spec' is now closer to that of 'format'.
-In order for the two functions to behave more consistently,
-'format-spec' now pads and truncates based on string width rather than
-length, and also supports format specifications that include a
-truncating precision field, such as "%.2a".
-
----
-** 'defvar' detects the error of defining a variable currently lexically bound.
-Such mixes are always signs that the outer lexical binding was an
-error and should have used dynamic binding instead.
-
----
-** New variable 'inhibit-mouse-event-check'.
-If bound to non-nil, a command with '(interactive "e")' doesn't signal
-an error when invoked by input event that is not a mouse click (e.g.,
-a key sequence).
-
----
-** New variable 'redisplay-skip-initial-frame' to enable batch redisplay tests.
-Setting it to nil forces the redisplay to do its job even in the
-initial frame used in batch mode.
-
-+++
-** Doc strings can now link to customization groups.
-Text like "customization group `whitespace'" will be made into a
-button.  When clicked, it'll take the user to a Custom buffer
-displaying that customization group.
-
-+++
-** Buffers can now be created with certain hooks disabled.
-The functions 'get-buffer-create' and 'generate-new-buffer' accept a
-new optional argument INHIBIT-BUFFER-HOOKS.  If non-nil, the new
-buffer does not run the hooks 'kill-buffer-hook',
-'kill-buffer-query-functions', and 'buffer-list-update-hook'.  This
-avoids slowing down internal or temporary buffers that are never
-presented to users or passed on to other applications.
-
-+++
-** New command 'make-directory-autoloads'.
-This does the same as the old command 'update-directory-autoloads',
-but has different semantics: Instead of passing in the output file via
-the dynamically bound 'generated-autoload-file' variable, the output
-file is now a explicit parameter.
-
----
-** Dragging a file into Emacs pushes the file name onto 'file-name-history'.
-
----
-** The 'easymenu' library is now preloaded.
-
----
-** The 'iso-transl' library is now preloaded.
-This means that keystrokes like 'Alt-[' are defined by default,
-instead of only becoming available after doing (for instance)
-'C-x 8 <letter>'.
-
----
-** ':safe' settings in 'defcustom' are now propagated to the loaddefs files.
-
-+++
-** ERT can now output more verbose test failure reports.
-If the 'EMACS_TEST_VERBOSE' environment variable is set, failure
-summaries will include the failing condition.
-
-** Byte compiler changes
-
-+++
-*** New byte-compiler check for missing dynamic variable declarations.
-It is meant as an (experimental) aid for converting Emacs Lisp code
-to lexical binding, where dynamic (special) variables bound in one
-file can affect code in another.  For details, see the manual section
-"(elisp) Converting to Lexical Binding".
-
-+++
-*** 'byte-recompile-directory' can now compile symlinked ".el" files.
-This is achieved by giving a non-nil FOLLOW-SYMLINKS parameter.
-
----
-*** The byte-compiler now warns about too wide documentation strings.
-By default, it will warn if a documentation string is wider than the
-largest of 'byte-compile-docstring-max-column' or 'fill-column'
-characters.
-
-+++
-*** 'byte-compile-file' optional argument LOAD is now obsolete.
-To load the file after byte-compiling, add a call to 'load' from Lisp
-or use 'M-x emacs-lisp-byte-compile-and-load' interactively.
-
-** Macroexp
-
----
-*** New function 'macroexp-file-name' to know the name of the current file.
-
----
-*** New function 'macroexp-compiling-p' to know if we're compiling.
-
----
-*** New function 'macroexp-warn-and-return' to help emit warnings.
-This used to be named 'macroexp--warn-and-return' and has proved useful
-and well-behaved enough to lose the "internal" marker.
-
-** map.el
-
----
-*** Alist keys are now consistently compared with 'equal' by default.
-Until now, 'map-elt' and 'map-delete' compared alist keys with 'eq' by
-default.  They now use 'equal' instead, for consistency with
-'map-put!' and 'map-contains-key'.
-
-*** Pcase 'map' pattern added keyword symbols abbreviation.
-A pattern like '(map :sym)' binds the map's value for ':sym' to 'sym',
-equivalent to '(map (:sym sym))'.
-
----
-*** The function 'map-copy' now uses 'copy-alist' on alists.
-This is a slightly deeper copy than the previous 'copy-sequence'.
-
----
-*** The function 'map-contains-key' now supports plists.
-
----
-*** More consistent duplicate key handling in 'map-merge-with'.
-Until now, 'map-merge-with' promised to call its function argument
-whenever multiple maps contained 'eql' keys.  However, this did not
-always coincide with the keys that were actually merged, which could
-be 'equal' instead.  The function argument is now called whenever keys
-are merged, for greater consistency with 'map-merge' and 'map-elt'.
-
-** pcase
-
-+++
-*** The 'or' pattern now binds the union of the vars of its sub-patterns.
-If a variable is not bound by the subpattern that matched, it gets bound
-to nil.  This was already sometimes the case, but it is now guaranteed.
-
-+++
-*** The 'pred' pattern can now take the form '(pred (not FUN))'.
-This is like '(pred (lambda (x) (not (FUN x))))' but results
-in better code.
-
----
-*** New function 'pcase-compile-patterns' to write other macros.
-
-+++
-*** Added 'cl-type' pattern.
-The new 'cl-type' pattern compares types using 'cl-typep', which allows
-comparing simple types like '(cl-type integer)', as well as forms like
-'(cl-type (integer 0 10))'.
-
-+++
-*** New macro 'pcase-setq'.
-This macro is the 'setq' equivalent of 'pcase-let', which allows for
-destructuring patterns in a 'setq' form.
-
-** Edebug
-
-*** Edebug specification lists can use some new keywords:
-
-+++
-**** '&interpose SPEC FUN ARGS..' lets FUN control parsing after SPEC.
-More specifically, FUN is called with 'HEAD PF ARGS..' where
-PF is a parsing function that expects a single argument (the specs to
-use) and HEAD is the code that matched SPEC.
-
-+++
-**** '&error MSG' unconditionally aborts the current edebug instrumentation.
-
-+++
-**** '&name SPEC FUN' extracts the current name from the code matching SPEC.
-
-** Dynamic modules changes
-
-+++
-*** Type aliases for module functions and finalizers.
-The module header 'emacs-module.h' now contains type aliases
-'emacs_function' and 'emacs_finalizer' for module functions and
-finalizers, respectively.
-
-+++
-*** Module functions can now be made interactive.
-Use 'make_interactive' to give a module function an interactive
-specification.
-
-+++
-*** Module functions can now install an optional finalizer.
-The finalizer is called when the function object is garbage-collected.
-Use 'set_function_finalizer' to set the finalizer and
-'get_function_finalizer' to retrieve it.
-
-+++
-*** Modules can now open a channel to an existing pipe process.
-Modules can use the new module function 'open_channel' to do that.
-On capable systems, modules can use this functionality to
-asynchronously send data back to Emacs.
-
-+++
-*** A new module API 'make_unibyte_string'.
-It can be used to create Lisp strings with arbitrary byte sequences
-(a.k.a. "raw bytes").
-
-+++
-** New function 'string-search'.
-This function takes two string parameters and returns the position of
-the first instance of the former string in the latter.
-
-+++
-** New function 'string-replace'.
-This function works along the line of 'replace-regexp-in-string', but
-it matches on fixed strings instead of regexps, and does not change
-the global match state.
-
-+++
-** New function 'ensure-list'.
-This function makes a list of its object if it's not a list already.
-If it's already a list, the list is returned as is.
-
-+++
-** New function 'split-string-shell-command'.
-This splits a shell command string into separate components,
-respecting quoting with single ('like this') and double ("like this")
-quotes, as well as backslash quoting (like\ this).
-
-+++
-** New function 'string-clean-whitespace'.
-This removed whitespace from a string
-
-+++
-** New function 'string-fill'.
-Word-wrap a string so that no lines are longer that a specific length.
-
-+++
-** New function 'string-limit'.
-Return (up to) a specific substring length.
-
-+++
-** New function 'string-lines'.
-Return a list of strings representing the individual lines in a
-string.
-
-+++
-** New function 'string-pad'.
-Pad a string to a specific length.
-
-+++
-** New function 'string-chop-newline'.
-Remove a trailing newline from a string.
-
-+++
-** New function 'replace-regexp-in-region'.
-
-+++
-** New function 'replace-string-in-region'.
-
-+++
-** New function 'file-name-with-extension'.
-This function allows a canonical way to set/replace the extension of a
-file name.
-
-+++
-** New function 'file-modes-number-to-symbolic' to convert a numeric
-file mode specification into symbolic form.
-
-+++
-** New function 'file-name-concat'.
-This appends file name components to a directory name and returns the
-result.
-
-+++
-** New function 'file-backup-file-names'.
-This function returns the list of file names of all the backup files
-for the specified file.
-
-+++
-** New function 'directory-empty-p'.
-This predicate tests whether a given file name is an accessible
-directory and whether it contains no other directories or files.
-
-+++
-** New function 'buffer-local-boundp'.
-This predicate says whether a symbol is bound in a specific buffer.
-
-+++
-** New function 'always'.
-This is identical to 'ignore', but returns t instead.
-
-+++
-** New function 'sxhash-equal-including-properties'.
-This is identical to 'sxhash-equal' but also accounts for string
-properties.
-
----
-** New function 'buffer-line-statistics'.
-This function returns some statistics about the line lengths in a buffer.
-
----
-** New function 'color-values-from-color-spec'.
-This can be used to parse RGB color specs in several formats and
-convert them to a list '(R G B)' of primary color values.
-
----
-** New function 'custom-add-choice'.
-This function can be used by modes to add elements to the
-'choice' customization type of a variable.
-
----
-** New function 'decoded-time-period'.
-It interprets a decoded time structure as a period and returns the
-equivalent period in seconds.
-
-+++
-** New function 'dom-print'.
-
-+++
-** New function 'dom-remove-attribute'.
-
----
-** New function 'dns-query-asynchronous'.
-It takes the same parameters as 'dns-query', but adds a callback
-parameter.
-
-** New function 'garbage-collect-maybe' to trigger GC early.
-
----
-** New function 'get-locale-names'.
-This utility function returns a list of names of locales available on
-the current system.
-
-+++
-** New function 'insert-into-buffer'.
-This inserts the contents of the current buffer into another buffer.
-
-+++
-** New function 'json-available-p'.
-This predicate returns non-nil if Emacs is built with libjansson
-support, and it is available on the current system.
-
----
-** New function 'mail-header-parse-addresses-lax'.
-This takes a comma-separated string and returns a list of mail/name
-pairs.
-
----
-** New function 'mail-header-parse-address-lax'.
-Parse a string as a mail address-like string.
-
----
-** New function 'make-separator-line'.
-Make a string appropriate for usage as a visual separator line.
-
-+++
-** New function 'object-intervals'.
-This function returns a copy of the list of intervals (i.e., text
-properties) in the object in question (which must either be a string
-or a buffer).
-
-+++
-** New function 'process-lines-ignore-status'.
-This is like 'process-lines', but does not signal an error if the
-return status is non-zero.  'process-lines-handling-status' has also
-been added, and takes a callback to handle the return status.
-
-+++
-** New function 'require-theme'.
-This function is like 'require', but searches 'custom-theme-load-path'
-instead of 'load-path'.  It can be used by Custom themes to load
-supporting Lisp files when 'require' is unsuitable.
-
-+++
-** New function 'seq-union'.
-This function takes two sequences and returns a list of all elements
-that appear in either of them, with no two elements that compare equal
-appearing in the result.
-
-+++
-** New function 'syntax-class-to-char'.
-This does almost the opposite of 'string-to-syntax' -- it returns the
-syntax descriptor (a character) given a raw syntax descriptor (an
-integer).
-
-+++
-** New functions 'null-device' and 'path-separator'.
-These functions return the connection local value of the respective
-variables.  This can be used for remote hosts.
-
-+++
-** New predicate functions 'length<', 'length>' and 'length='.
-Using these functions may be more efficient than using 'length' (if
-the length of a (long) list is being computed just to compare this
-length to a number).
-
-+++
-** New macro 'dlet' to dynamically bind variables.
-
-+++
-** New macro 'with-existing-directory'.
-This macro binds 'default-directory' to some other existing directory
-if 'default-directory' doesn't exist, and then executes the body forms.
-
-+++
-** New variable 'current-minibuffer-command'.
-This is like 'this-command', but it is bound recursively when entering
-the minibuffer.
-
-+++
-** New variable 'inhibit-interaction' to make user prompts signal an error.
-If this is bound to something non-nil, functions like
-'read-from-minibuffer', 'read-char' (and related) will signal an
-'inhibited-interaction' error.
-
----
-** New variable 'indent-line-ignored-functions'.
-This allows modes to cycle through a set of indentation functions
-appropriate for those modes.
-
-+++
-** New variable 'print-integers-as-characters' modifies integer printing.
-If this variable is non-nil, character syntax is used for printing
-numbers when this makes sense, such as '?A' for 65.
-
-+++
-** New variable 'tty-menu-calls-mouse-position-function'.
-This controls whether 'mouse-position-function' is called by functions
-that retrieve the mouse position when that happens during TTY menu
-handling.  Lisp programs that set 'mouse-position-function' should
-also set this variable non-nil if they are compatible with the tty
-menu handling.
-
-+++
-** New variables that hold default buffer names for shell output.
-The new constants 'shell-command-buffer-name' and
-'shell-command-buffer-name-async' store the default buffer names
-for the output of, respectively, synchronous and async shell
-commands.
-
----
-** New variables 'read-char-choice-use-read-key' and 'y-or-n-p-use-read-key'.
-When non-nil, then functions 'read-char-choice' and 'y-or-n-p'
-(respectively) use the function 'read-key' to read a character instead
-of using the minibuffer.
-
-+++
-** New variable 'global-minor-modes'.
-This variable holds a list of currently enabled global minor modes (as
-a list of symbols).
-
-+++
-** New buffer-local variable 'local-minor-modes'.
-This permanently buffer-local variable holds a list of currently
-enabled non-global minor modes in the current buffer (as a list of
-symbols).
-
-+++
-** New completion function 'affixation-function' to add prefix/suffix.
-It accepts a list of completions and should return a list where
-each element is a list with three elements: a completion,
-a prefix string, and a suffix string.
-
-+++
-** New completion function 'group-function' for grouping candidates.
-It takes two arguments: a completion candidate and a 'transform' flag.
-
-+++
-** New error symbol 'minibuffer-quit'.
-Signaling it has almost the same effect as 'quit' except that it
-doesn't cause keyboard macro termination.
-
-+++
-** New error 'remote-file-error', a subcategory of 'file-error'.
-It is signaled if a remote file operation fails due to internal
-reasons, and could block Emacs.  It does not replace 'file-error'
-signals for the usual cases.  Timers, process filters and process
-functions, which run remote file operations, shall protect themselves
-against this error.
-
-If such an error occurs, please report this as bug via 'M-x report-emacs-bug'.
-Until it is solved you could ignore such errors by performing
-
-    (setq debug-ignored-errors (cons 'remote-file-error debug-ignored-errors))
-
-+++
-** New macro 'named-let' added to subr-x.el.
-It provides Scheme's "named let" looping construct.
-
----
-** Emacs now attempts to test for high-rate subprocess output more fairly.
-When several subprocesses produce output simultaneously at high rate,
-Emacs will now by default attempt to service them all in a round-robin
-fashion.  Set the new variable 'process-prioritize-lower-fds' to a
-non-nil value to get back the old behavior, whereby after reading
-from a subprocess, Emacs would check for output of other subprocesses
-in a way that is likely to read from the same process again.
-
-+++
-** 'set-process-buffer' now updates the process mark.
-The mark will be set to point to the end of the new buffer.
-
-+++
-** 'unlock-buffer' displays warnings instead of signaling.
-Instead of signaling 'file-error' conditions for file system level
-errors, the function now calls 'display-warning' and continues as if
-the error did not occur.
-
-+++
-** 'read-char-from-minibuffer' and 'y-or-n-p' support 'help-form'.
-If you bind 'help-form' to a non-nil value while calling these functions,
-then pressing 'C-h' ('help-char') causes the function to evaluate 'help-form'
-and display the result.
-
-+++
-** 'read-number' now has its own history variable.
-Additionally, the function now accepts a HIST argument which can be
-used to specify a custom history variable.
-
-+++
-** 'set-window-configuration' now takes two optional parameters,
-'dont-set-frame' and 'dont-set-miniwindow'.  The first of these, when
-non-nil, instructs the function not to select the frame recorded in
-the configuration.  The second prevents the current minibuffer being
-replaced by the one stored in the configuration.
-
----
-** 'count-windows' now takes an optional parameter ALL-FRAMES.
-The semantics are as with 'walk-windows'.
-
-+++
-** 'truncate-string-ellipsis' now uses '…' by default.
-Modes that use 'truncate-string-to-width' with non-nil, non-string
-argument ELLIPSIS, will now indicate truncation using '…' when
-the selected frame can display it, and using "..." otherwise.
-
-+++
-** 'string-width' now accepts two optional arguments FROM and TO.
-This allows calculating the width of a substring without consing a
-new string.
-
-+++
-** 'directory-files' now takes an additional COUNT parameter.
-The parameter makes 'directory-files' return COUNT first file names
-from a directory.  If MATCH is also given, the function will return
-first COUNT file names that match the expression.  The same COUNT
-parameter has been added to 'directory-files-and-attributes'.
-
-+++
-** 'count-lines' now takes an optional parameter to
-ignore invisible lines.
-
----
-** 'count-words' now crosses field boundaries.
-Originally, 'count-words' would stop counting at the first field
-boundary it encountered; now it keeps counting all the way to the
-region's (or buffer's) end.
-
-+++
-** File-related APIs can optionally follow symlinks.
-The functions 'file-modes', 'set-file-modes', and 'set-file-times' now
-have an optional argument specifying whether to follow symbolic links.
-
-+++
-** 'format-seconds' can now be used for sub-second times.
-The new optional "," parameter has been added, and
-'(format-seconds "%mm %,1ss" 66.4)' will now result in "1m 6.4s".
-
-+++
-** 'parse-time-string' can now parse ISO 8601 format strings.
-These have the format like "2020-01-15T16:12:21-08:00".
-
----
-** 'make-network-process', 'make-serial-process' ':coding' behavior change.
-Previously, passing ':coding nil' to either of these functions would
-override any non-nil binding for 'coding-system-for-read' and
-'coding-system-for-write'.  For consistency with 'make-process' and
-'make-pipe-process', passing ':coding nil' is now ignored.  No code in
-Emacs depended on the previous behavior; if you really want the
-process' coding-system to be nil, use 'set-process-coding-system'
-after the process has been created, or pass in ':coding '(nil nil)'.
-
-+++
-** 'open-network-stream' now accepts a ':coding' argument.
-This allows specifying the coding systems used by a network process
-for encoding and decoding without having to bind
-'coding-system-for-{read,write}' or call 'set-process-coding-system'.
-
-+++
-** 'open-network-stream' can now take a ':capability-command' that's a 
function.
-The function is called with the greeting from the server as its only
-parameter, and allows sending different TLS capability commands to the
-server based on that greeting.
-
-+++
-** 'open-gnutls-stream' now also accepts a ':coding' argument.
-
----
-** 'process-attributes' now works under OpenBSD, too.
-
-+++
-** 'format-spec' now takes an optional SPLIT parameter.
-If non-nil, 'format-spec' will split the resulting string into a list
-of strings, based on where the format specs (and expansions) were.
-
----
-** 'unload-feature' now also tries to undo additions to buffer-local hooks.
-
----
-** 'while-no-input-ignore-events' accepts more special events.
-The special events 'dbus-event' and 'file-notify' are now ignored in
-'while-no-input' when added to this variable.
-
----
-** 'start-process-shell-command' and 'start-file-process-shell-command'
-do not support the old calling conventions any longer.
-
-+++
-** 'yes-or-no-p' and 'y-or-n-p' PROMPT parameter no longer needs trailing 
space.
-In other words, the prompt can now end with "?" instead of "? ".  This
-has been the case since Emacs 24.4 but was not announced or documented
-until now.  (Checkdoc has also been updated to accept this convention.)
-
-+++
-** The 'uniquify' argument in 'auto-save-file-name-transforms' can be a symbol.
-If this symbol is one of the members of 'secure-hash-algorithms',
-Emacs constructs the nondirectory part of the auto-save file name by
-applying that 'secure-hash' to the buffer file name.  This avoids any
-risk of excessively long file names.
-
-+++
-** New user option 'process-file-return-signal-string'.
-It controls, whether 'process-file' returns a string when a remote
-process is interrupted by a signal.
-
-** EIEIO Changes
-
-+++
-*** The macro 'oref-default' can now be used with 'setf'.
-It is now defined as a generalized variable that can be used with
-'setf' to modify the value stored in a given class slot.
-
----
-*** 'form' in '(eql form)' specializers in 'cl-defmethod' is now evaluated.
-This corresponds to the behavior of defmethod in Common Lisp Object System.
-For compatibility, '(eql SYMBOL)' does not evaluate SYMBOL, for now.
-
-** D-Bus
-
-+++
-*** Property values can be typed explicitly.
-'dbus-register-property' and 'dbus-set-property' accept now optional
-type symbols.  Both functions propagate D-Bus errors.
-
-+++
-*** Registered properties can have the new access type ':write'.
-
-+++
-*** In case of problems, handlers can emit proper D-Bus error messages now.
-
-+++
-*** D-Bus errors, which have been converted from incoming D-Bus error
-messages, contain the error name of that message now.
-
-+++
-*** D-Bus messages can be monitored with the new command 'dbus-monitor'.
-
-+++
-*** D-Bus events have changed their internal structure.
-They carry now the destination and the error-name of an event.  They
-also keep the type information of their arguments.  Use the
-'dbus-event-*' accessor functions.
-
-** Buttons
-
-+++
-*** New minor mode 'button-mode'.
-This minor mode does nothing else than install 'button-buffer-map' as
-a minor mode map (which binds the 'TAB' / 'S-TAB' key bindings to navigate
-to buttons), and can be used in any view-mode-like buffer that has
-buttons in it.
-
-+++
-*** New utility function 'button-buttonize'.
-This function takes a string and returns a string propertized in a way
-that makes it a valid button.
-
----
-** 'text-scale-mode' can now adjust font size of the header line.
-When the new buffer local variable 'text-scale-remap-header-line'
-is non-nil, 'text-scale-adjust' will also scale the text in the header
-line when displaying that buffer.
-
-This is useful for major modes that arrange their display in a tabular
-form below the header line.  It is enabled by default in
-'tabulated-list-mode' and its derived modes.
-
----
-** 'ascii' is now a coding system alias for 'us-ascii'.
-
----
-** New coding-systems for EBCDIC variants.
-New coding-systems 'ibm256', 'ibm273', 'ibm274', 'ibm277', 'ibm278',
-'ibm280', 'ibm281', 'ibm284', 'ibm285', 'ibm290', 'ibm297'.  These are
-variants of the EBCDIC encoding tailored to some European and Japanese
-locales.  They are also available as aliases 'ebcdic-cp-*' (e.g.,
-'ebcdic-cp-fi' for the Finnish variant 'ibm278'), and 'cp2xx' (e.g.,
-'cp278' for 'ibm278').  There are also new charsets 'ibm2xx' to
-support these coding-systems.
-
-+++
-** New 'Bindat type expression' description language.
-This new system is provided by the new macro 'bindat-type' and
-obsoletes the old data layout specifications.  It supports
-arbitrary-size integers, recursive types, and more.  See the Info node
-"(elisp) Byte Packing" in the ELisp manual for more details.
-
-
-* Changes in Emacs 28.1 on Non-Free Operating Systems
-
-+++
-** On MS-Windows, Emacs can now use the native image API to display images.
-Emacs can now use the MS-Windows GDI+ library to load and display
-images in JPEG, PNG, GIF and TIFF formats.  This support is available
-unless Emacs was configured '--without-native-image-api'.
-
-This feature is experimental, and needs to be turned on to be used.
-To turn this on, set the variable 'w32-use-native-image-API' to a
-non-nil value.  Please report any bugs you find while using the native
-image API via 'M-x report-emacs-bug'.
-
-+++
-** On MS-Windows, Emacs can now toggle the IME.
-A new function 'w32-set-ime-open-status' can now be used to disable
-and enable the MS-Windows native Input Method Editor (IME) at run
-time.  A companion function 'w32-get-ime-open-status' returns the
-current IME activation status.
-
---
-** On macOS, 's-<left>' and 's-<right>' are now bound to
-'move-beginning-of-line' and 'move-end-of-line' respectively.  The commands
-to select previous/next frame are still bound to 's-~' and 's-`'.
-
-+++
-** On macOS, Emacs can now load dynamic modules with a ".dylib" suffix.
-'module-file-suffix' now has the value ".dylib" on macOS, but the
-".so" suffix is supported as well.
-
----
-** On macOS, the user option 'make-pointer-invisible' is now honored.
-
----
-** On macOS, Xwidget is now supported.
-If Emacs was built with xwidget support, you can access the embedded
-webkit browser with 'M-x xwidget-webkit-browse-url'.  Viewing two
-instances of xwidget webkit is not supported.
-
----
-*** Downloading files from xwidget-webkit is now supported.
-The new variable 'xwidget-webkit-download-dir' says where to download to.
-
----
-*** New command 'xwidget-webkit-clone-and-split-below'.
-Open a new window below displaying the current URL.
-
----
-*** New command 'xwidget-webkit-clone-and-split-right'.
-Open a new window to the right displaying the current URL.
-
----
-*** New variable 'xwidget-webkit-enable-plugins'.
-If non-nil, enable plugins in xwidget.  (This is only available on
-macOS.)
+** MS-Windows
 
 +++
-** New macOS Contacts back-end for EUDC.
-This backend works on newer versions of macOS and is generally
-preferred over the eudcb-mab.el backend.
+*** Emacs now supports system dark mode.
+On Windows 10 (version 1809 and higher) and Windows 11, Emacs will now
+follow the system's dark mode: GUI frames use the appropriate light or
+dark title bar and scroll bars, based on the user's Windows-wide color
+settings.
 
 
 ----------------------------------------------------------------------
diff --git a/etc/NEWS b/etc/NEWS.28
similarity index 90%
copy from etc/NEWS
copy to etc/NEWS.28
index 1b67ef98b6..1d1b37a2d4 100644
--- a/etc/NEWS
+++ b/etc/NEWS.28
@@ -36,6 +36,12 @@ to configure with the '--without-compress-install' option, 
so that the
 installed *.el files are not compressed; otherwise, you will not be
 able to use JIT native compilation of the installed *.el files.
 
+Note that JIT native compilation is done in a fresh session of Emacs
+that is run in a subprocess, so it can legitimately report some
+warnings and errors that aren't uncovered by byte-compilation.  We
+recommend examining any such warnings before you decide they are
+false.
+
 ** The Cairo graphics library is now used by default if present.
 '--with-cairo' is now the default, if the appropriate development files
 are found by 'configure'.  Note that building with Cairo means using
@@ -50,7 +56,7 @@ when using Cairo.  Use 'ftcrhb' if your Emacs was built with 
HarfBuzz
 text shaping support, and 'ftcr' otherwise.  You can determine this by
 checking 'system-configuration-features'.  The 'ftcr' backend will
 still be available when HarfBuzz is supported, but will not be used by
-default.  We strongly recommend building with HarBuzz support.  'x' is
+default.  We strongly recommend building with HarfBuzz support.  'x' is
 still a valid backend.
 
 ---
@@ -79,6 +85,15 @@ at build time.
 This was only ever relevant when building from a repository checkout.
 This now requires makeinfo, which is part of the texinfo package.
 
+---
+** New configure option '--disable-year2038'.
+This causes Emacs to use only 32-bit time_t on platforms that have
+both 32- and 64-bit time_t.  This may help when linking Emacs with a
+library with an ABI requiring traditional 32-bit time_t.  This option
+currently affects only 32-bit ARM and x86 running GNU/Linux with glibc
+2.34 and later.  Emacs now defaults to 64-bit time_t on these
+platforms.
+
 ---
 ** Support for building with '-fcheck-pointer-bounds' has been removed.
 GCC has withdrawn the '-fcheck-pointer-bounds' option and support for
@@ -137,24 +152,34 @@ of files visited via 'C-x C-f' and other commands.
 ** Emacs now supports Unicode Standard version 14.0.
 
 +++
-** New character script 'emoji' has been created.
-Various blocks of codepoints have been split out of the 'symbol'
-script into their own 'emoji' script to allow easier specification of
-their treatment.  Which codepoints are treated as emoji is derived
-from the Unicode specifications.  Also, Emacs will now use "Noto Color
-Emoji" by default for that script.  Use:
+** Improved support for Emoji.
+On capable systems, Emacs now correctly displays Emoji and Emoji
+sequences by default, provided that a suitable font is available to
+Emacs.  With a few exceptions, all of the Emoji sequences specified by
+Unicode 14.0 are automatically composed and displayed as a single
+colorful glyph.  This is achieved by changes in the Emacs font
+configuration, and by additional character-composition rules for the
+Emoji codepoints that follow from the Unicode-defined sequences.
+
+If your system lacks a suitable font, we recommend to install "Noto
+Color Emoji"; Emacs will use it automatically if it's installed.  If
+you prefer to use another font for Emoji, customize your fontset like
+this:
 
-(set-fontset-font t 'emoji
-                  '("My New Emoji Font" . "iso10646-1") nil 'prepend)
+    (set-fontset-font t 'emoji
+                      '("My New Emoji Font" . "iso10646-1") nil 'prepend)
 
-to change the font used.
+The Emoji characters are now assigned to a special script, 'emoji', so
+as to make it easier to customize fontsets for Emoji display, as in
+the above example.  (Previously, the Emoji characters were assigned to
+the 'symbol' script, together with other symbol and punctuation
+characters.)
 
 +++
-** Zero Width Joiner (ZWJ) and emoji sequences are now composed.
-Emacs can now compose (almost) all the Unicode-14 ZWJ and emoji
-sequences (if a suitable font is installed) so that they are displayed
-as single glyphs instead of multiple ones.  'Noto Color Emoji' is one
-such suitable font.
+** 'glyphless-char-display-control' now applies to Variation Selectors.
+VS-1 through VS-16 are now displayed as 'thin-space' by default when
+not composed with previous characters (typically, as part of Emoji
+sequences).
 
 +++
 ** New command 'execute-extended-command-for-buffer'.
@@ -191,7 +216,7 @@ In Emacs 23, typing 'M-x' ('read-extended-command') and 
then 'C-s' (to
 do an interactive search) would search over possible completions.
 This was lost in Emacs 24, but is now back again.
 
----
++++
 ** User option 'completions-format' supports a new value 'one-column'.
 
 +++
@@ -203,12 +228,13 @@ groups.
 
 +++
 ** New minor mode 'context-menu-mode' for context menus popped by 'mouse-3'.
-When this mode is enabled, clicking 'down-mouse-3' anywhere in the buffer
-pops up a menu whose contents depends on surrounding context near the
-mouse click.  You can change the order of the default sub-menus in the
-context menu by customizing the user option 'context-menu-functions'.
-You can also invoke the context menu by pressing 'S-<F10>' or,
-on macOS, by clicking 'C-down-mouse-1'.
+When this mode is enabled, clicking 'down-mouse-3' (usually, the
+right mouse button) anywhere in the buffer pops up a menu whose
+contents depends on surrounding context near the mouse click.
+You can change the order of the default sub-menus in the context menu
+by customizing the user option 'context-menu-functions'.  You can also
+invoke the context menu by pressing 'S-<F10>' or, on macOS, by
+clicking 'C-down-mouse-1'.
 
 +++
 ** A new keymap for buffer actions has been added.
@@ -248,9 +274,9 @@ whether the function 'read-answer' accepts short answers.
 +++
 ** New user option 'kill-buffer-delete-auto-save-files'.
 If non-nil, killing a buffer that has an auto-save file will prompt
-the user for whether that file should be deleted.  (Note that
-'delete-auto-save-files', if non-nil, was previously documented to
-result in deletion of auto-save files when killing a buffer without
+the user for whether that auto-save file should be deleted.  (Note
+that 'delete-auto-save-files', if non-nil, was previously documented
+to result in deletion of auto-save files when killing a buffer without
 unsaved changes, but this has apparently not worked for several
 decades, so the documented semantics of this variable has been changed
 to match the behavior.)
@@ -327,8 +353,10 @@ of the next command to be displayed in a new frame.
 
 +++
 *** New command 'clone-frame' (bound to 'C-x 5 c').
-This is like 'C-x 5 2', but uses the frame parameters of the current
-frame instead of 'default-frame-alist'.
+This is like 'C-x 5 2', but uses the window configuration and frame
+parameters of the current frame instead of 'default-frame-alist'.
+When called interactively with a prefix arg, the window configuration
+is not cloned.
 
 ---
 *** Default values of 'frame-title-format' and 'icon-title-format' have 
changed.
@@ -358,22 +386,25 @@ requiring the user to specify the value via the prefix 
argument.
 
 ** Windows
 
++++
 *** The key prefix 'C-x 4 1' displays next command buffer in the same window.
 It's bound to the command 'same-window-prefix' that requests the buffer
 of the next command to be displayed in the same window.
 
++++
 *** The key prefix 'C-x 4 4' displays next command buffer in a new window.
 It's bound to the command 'other-window-prefix' that requests the buffer
 of the next command to be displayed in a new window.
 
 +++
 *** New command 'recenter-other-window', bound to 'S-M-C-l'.
-Like 'recenter-top-bottom' acting on the other window.
+Like 'recenter-top-bottom', but acting on the other window.
 
 +++
 *** New user option 'delete-window-choose-selected'.
-This allows to choose a window that will be the frame's selected
-window after deleting the currently selected one.
+This allows specifying how Emacs chooses which window will be the
+frame's selected window after the currently selected window is
+deleted.
 
 +++
 *** New argument NO-OTHER for some window functions.
@@ -416,7 +447,8 @@ nor t.
 *** New user option 'read-minibuffer-restore-windows'.
 When customized to nil, it uses 'minibuffer-restore-windows' in
 'minibuffer-exit-hook' to remove only the window showing the
-"*Completions*" buffer.
+"*Completions*" buffer, but keeps all other windows created
+while the minibuffer was active.
 
 ---
 *** New variable 'redisplay-adhoc-scroll-in-resize-mini-windows'.
@@ -448,7 +480,7 @@ both modes are on).
 +++
 *** The prefix key 'C-x t t' can be used to display a buffer in a new tab.
 Typing 'C-x t t' before a command will cause the buffer shown by that
-command to be displayed in a new tab.  'C-x t t" is bound to the
+command to be displayed in a new tab.  'C-x t t' is bound to the
 command 'other-tab-prefix'.
 
 +++
@@ -461,17 +493,17 @@ with items that operate on the clicked tab.  Dragging the 
tab with
 scrolling switches to the previous/next tab, and holding the Shift key
 during scrolling moves the tab to the left/right.
 
----
++++
 *** Frame-specific appearance of the tab bar when 'tab-bar-show' is a number.
 When 'tab-bar-show' is a number, the tab bar on different frames can
 be shown or hidden independently, as determined by the number of tabs
 on each frame compared to the numerical value of 'tab-bar-show'.
 
----
++++
 *** New command 'toggle-frame-tab-bar'.
 It can be used to enable/disable the tab bar on the currently selected
 frame regardless of the values of 'tab-bar-mode' and 'tab-bar-show'.
-This allows to enable/disable the tab bar independently on different
+This allows enabling/disabling the tab bar independently on different
 frames.
 
 ---
@@ -485,10 +517,10 @@ the tab bar displays tab groups.
 
 ---
 *** New optional key binding for 'tab-last'.
-If you customize the variable 'tab-bar-select-tab-modifiers' for
-selecting tabs using its index numbers, the '<MODIFIER>-9' key is
-bound to 'tab-last', and switches to the last tab.  Here <MODIFIER> is
-any of the modifiers in the list that is the value of
+If you customize the user option 'tab-bar-select-tab-modifiers' to
+allow selecting tabs using their index numbers, the '<MODIFIER>-9' key
+is bound to 'tab-last', and switches to the last tab.  Here <MODIFIER>
+is any of the modifiers in the list that is the value of
 'tab-bar-select-tab-modifiers'.  You can also use negative indices,
 which count from the last tab: -1 is the last tab, -2 the one before
 that, etc.
@@ -526,15 +558,17 @@ If your mouse or trackpad supports it, you can now scroll 
tabs when
 the mouse pointer is in the tab line by scrolling left or right.
 
 ---
-*** New tab-line faces and options.
+*** New tab-line faces and user options.
 The face 'tab-line-tab-special' is used for tabs whose buffers are
 special, i.e. buffers that don't visit a file.  The face
-'tab-line-tab-inactive-alternate' is used to display inactive tabs
-with an alternating background color, making them easier to
-distinguish, especially if the face 'tab-line-tab' is configured to
-not display with a box; this alternate face is only applied when the
-option 'tab-line-tab-face-functions' is so configured.  That option
-may also be used to customize tab-line faces in other ways.
+'tab-line-tab-modified' is used to display modified, file-backed
+buffers.  The face 'tab-line-tab-inactive-alternate' is used to
+display inactive tabs with an alternating background color, making
+them easier to distinguish, especially if the face 'tab-line-tab' is
+configured to not display with a box; this alternate face is only
+applied when the user option 'tab-line-tab-face-functions' is so
+configured.  That option may also be used to customize tab-line faces
+in other ways.
 
 ** Mouse wheel
 
@@ -543,9 +577,9 @@ may also be used to customize tab-line faces in other ways.
 
 ---
 *** Mouse wheel scrolling now works on more parts of frame's display.
-When using 'mwheel-mode', the mouse wheel will now scroll also when
+When using 'mouse-wheel-mode', the mouse wheel will now scroll also when
 the mouse cursor is on the scroll bars, fringes, margins, header line,
-and mode line.  ('mwheel-mode' is enabled by default on most graphical
+and mode line.  ('mouse-wheel-mode' is enabled by default on most graphical
 displays.)
 
 +++
@@ -576,7 +610,7 @@ built without SVG support, the old icons will be used 
instead.
 ** Help
 
 ---
-*** The order things are displayed in the *Help* buffer has been changed.
+*** The order of things displayed in the "*Help*" buffer has been changed.
 The indented "administrative" block (containing the "probably
 introduced" and "other relevant functions" (and similar things) has
 been moved to after the doc string.
@@ -620,7 +654,7 @@ functions.
 New command 'help-view-source' ('s') will view the source file (if
 any) of the current help topic.  New command 'help-goto-info' ('i')
 will look up the current symbol (if any) in Info.  New command
-'help-customize' ('c') will customize the variable or the face
+'help-customize' ('c') will customize the user option or the face
 (if any) whose doc string is being shown in the Help buffer.
 
 ---
@@ -628,11 +662,6 @@ will look up the current symbol (if any) in Info.  New 
command
 It enables outlines in the output buffer of 'describe-bindings' that
 can provide a better overview in a long list of available bindings.
 
-+++
-*** New command 'lossage-size'.
-It allows users to change the maximum number of keystrokes and
-commands recorded for the purpose of 'view-lossage'.
-
 +++
 *** New commands to describe buttons and widgets.
 'widget-describe' (on a widget) will pop up a help buffer and give a
@@ -655,6 +684,11 @@ These new navigation commands are bound to 'n' and 'p' in
 The menu bar "Help" menu now has a "Show Recent Inputs" item under the
 "Describe" sub-menu.
 
++++
+*** New command 'lossage-size'.
+It allows users to change the maximum number of keystrokes and
+commands recorded for the purpose of 'view-lossage'.
+
 ---
 *** Closing the "*Help*" buffer from the toolbar now buries the buffer.
 In previous Emacs versions, the "*Help*" buffer was killed instead when
@@ -673,6 +707,7 @@ the same syntax as 'auto-save-file-name-transforms'.
 +++
 *** New user option 'remote-file-name-inhibit-locks'.
 When non-nil, this option suppresses lock files for remote files.
+Default is nil.
 
 +++
 *** New minor mode 'lock-file-mode'.
@@ -726,37 +761,40 @@ Applies to buttons that indicate a face.
 +++
 *** New face 'font-lock-doc-markup-face'.
 Intended for documentation mark-up syntax and tags inside text that
-uses 'font-lock-doc-face', with which it should harmonize.  It would
-typically be used in structured documentation comments in program
-source code by language-specific modes, for mark-up conventions like
-Haddock, Javadoc or Doxygen.  By default this face inherits from
-'font-lock-constant-face'.
+uses 'font-lock-doc-face', which it should appropriately stand out
+against and harmonize with.  It would typically be used in structured
+documentation comments in program source code by language-specific
+modes, for mark-up conventions like Haddock, Javadoc or Doxygen.  By
+default this face inherits from 'font-lock-constant-face'.
 
 +++
-*** New face 'flat-button'.
+*** New face box style 'flat-button'.
 This is a plain 2D button, but uses the background color instead of
 the foreground color.
 
 ---
-*** New face 'shortdoc-heading'.
-Applies to headings of shortdoc sections.
+*** New faces 'shortdoc-heading' and 'shortdoc-section'.
+Applied to shortdoc headings and sections.
 
 ---
 *** New face 'separator-line'.
 This is used by 'make-separator-line' (see below).
 
++++
 *** 'redisplay-skip-fontification-on-input' helps Emacs keep up with fast 
input.
 This is another attempt to solve the problem of handling high key repeat rate
 and other "slow scrolling" situations.  It is hoped it behaves better
 than 'fast-but-imprecise-scrolling' and 'jit-lock-defer-time'.
 It is not enabled by default.
 
+---
 *** Obsolete aliases are no longer hidden from command completion.
 Completion of command names now considers obsolete aliases as
 candidates, if they were marked obsolete in the current major version
 of Emacs.  Invoking a command via an obsolete alias now mentions the
 obsolescence fact and shows the new name of the command.
 
++++
 *** Support for '(box . SIZE)' 'cursor-type'.
 By default, 'box' cursor always has a filled box shape.  But if you
 specify 'cursor-type' to be '(box . SIZE)', the cursor becomes a hollow
@@ -791,14 +829,31 @@ user-visible changes for normal usage.
 *** 'global-display-fill-column-indicator-mode' skips some buffers.
 By default, turning on 'global-display-fill-column-indicator-mode'
 doesn't turn on 'display-fill-column-indicator-mode' in special-mode
-buffers.  This can be controlled by customizing the variable
+buffers.  This can be controlled by customizing the user option
 'global-display-fill-column-indicator-modes'.
 
 +++
 *** 'nobreak-char-display' now also affects all non-ASCII space characters.
 Previously, this was limited only to 'NO-BREAK SPACE' and hyphen
 characters.  Now it also covers the rest of the non-ASCII Unicode
-space characters.
+space characters.  Also, unlike in previous versions of Emacs, the
+non-ASCII characters are displayed as themselves when
+'nobreak-char-display' is t, i.e. they are not replaced on display
+with the ASCII space and hyphen characters.
+
+---
+*** New backward compatibility variable 'nobreak-char-ascii-display'.
+This variable is nil by default, and non-ASCII space and hyphen
+characters are displayed as themselves, even if 'nobreak-char-display'
+is non-nil.  If 'nobreak-char-ascii-display' is set to a non-nil
+value, the non-ASCII space and hyphen characters are instead displayed
+as their ASCII counterparts: spaces and ASCII hyphen (a.k.a. "dash")
+characters.  This provides backward compatibility feature for the
+change described above, where the non-ASCII characters are no longer
+replaced with their ASCII counterparts when 'nobreak-char-display' is
+t.  You may need this on text-mode terminals that produce messed up
+display when non-ASCII spaces and hyphens are written to the display.
+(This variable is only effective when 'nobreak-char-display' is t.)
 
 +++
 *** Improved support for terminal emulators that encode the Meta flag.
@@ -865,6 +920,109 @@ now been updated to point to Libera.Chat.
 https://lists.gnu.org/archive/html/info-gnu-emacs/2021-06/msg00000.html
 
 
+* Incompatible Editing Changes in Emacs 28.1
+
+---
+** 'toggle-truncate-lines' now disables 'visual-line-mode'.
+This is for symmetry with 'visual-line-mode', which disables
+'truncate-lines'.
+
+---
+** 'electric-indent-mode' now also indents inside strings and comments.
+(This only happens when indentation function also supports this.)
+
+To recover the previous behavior you can use:
+
+    (add-hook 'electric-indent-functions
+              (lambda (_) (if (nth 8 (syntax-ppss)) 'no-indent)))
+
+---
+** The 'M-o' ('facemenu-keymap') global binding has been removed.
+To restore the old binding, say something like:
+
+    (require 'facemenu)
+    (define-key global-map "\M-o" 'facemenu-keymap)
+    (define-key facemenu-keymap "\es" 'center-line)
+    (define-key facemenu-keymap "\eS" 'center-paragraph)
+
+The last two lines are not strictly necessary if you don't care about
+having those two commands on the 'M-o' keymap; see the next section.
+
+---
+** The 'M-o M-s' and 'M-o M-S' global bindings have been removed.
+Use 'M-x center-line' and 'M-x center-paragraph' instead.  See the
+previous section for how to get back the old bindings.  Alternatively,
+if you only want these two commands to have the global bindings they
+had before, you can add the following to your init file:
+
+    (define-key global-map "\M-o\M-s" 'center-line)
+    (define-key global-map "\M-o\M-S" 'center-paragraph)
+
+---
+** The 'M-o M-o' global binding has been removed.
+Use 'M-x font-lock-fontify-block' instead, or the new 'C-x x f'
+command, which updates the syntax highlighting in the current buffer.
+
+---
+** The escape sequence '\e[29~' in Xterm is now mapped to 'menu'.
+Xterm sends this sequence for both 'F16' and 'Menu' keys
+It used to be mapped to 'print' but we couldn't find a terminal
+that uses this sequence for any kind of 'Print' key.
+This makes the Menu key (see https://en.wikipedia.org/wiki/Menu_key)
+work for 'context-menu-mode' in Xterm.
+
+---
+** New user option 'xterm-store-paste-on-kill-ring'.
+If non-nil (the default), Emacs pushes pasted text onto the kill ring
+(if using an xterm-like terminal that supports bracketed paste).
+Setting this to nil inhibits that.
+
+---
+** 'vc-print-branch-log' shows the change log from its root directory.
+It previously used to use the default directory.
+
+---
+** 'project-shell' and 'shell' now use 'pop-to-buffer-same-window'.
+This is to keep the same behavior as Eshell.
+
+---
+** In 'nroff-mode', 'center-line' is no longer bound to a key.
+The original key binding was 'M-s', which interfered with I-search,
+since the latter uses 'M-s' as a prefix key of the search prefix map.
+
+---
+** In 'f90-mode', the backslash character ('\') no longer escapes.
+For about a decade, the backslash character has no longer had a
+special escape syntax in Fortran F90.  To get the old behavior back,
+say something like:
+
+    (modify-syntax-entry ?\\ "\\" f90-mode-syntax-table)
+
++++
+** Setting 'fill-column' to nil is obsolete.
+This undocumented use of 'fill-column' is now obsolete.  To disable
+auto filling, turn off 'auto-fill-mode' instead.
+
+For instance, you could add something like the following to your init
+file:
+
+    (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
+
+** Xref migrated from EIEIO to cl-defstruct for its core objects.
+This means that 'oref' and 'with-slots' no longer works on them, and
+'make-instance' can no longer be used to create those instances (which
+wasn't recommended anyway).  Packages should restrict themselves to
+using functions like 'xref-make', 'xref-make-match',
+'xref-make-*-location', as well as accessor functions
+'xref-item-summary' and 'xref-item-location'.
+
+Among the benefits are better performance (noticeable when there are a
+lot of matches) and improved flexibility: 'xref-match-item' instances
+do not require that 'location' inherits from 'xref-location' anymore
+(that class was removed), so packages can create new location types to
+use with "match items" without adding EIEIO as a dependency.
+
+
 * Editing Changes in Emacs 28.1
 
 ** Input methods
@@ -935,7 +1093,11 @@ for CJK text mixed with Latin text.
 +++
 ** New command 'undo-redo'.
 It undoes previous undo commands, but doesn't record itself as an
-undoable command.
+undoable command.  It is bound to 'C-?' and 'C-M-_', the first binding
+works well in graphical mode, and the second one is easy to hit on tty.
+
+For full conventional undo/redo behavior, you can also customize the
+user option 'undo-no-redo' to t.
 
 +++
 ** New commands 'copy-matching-lines' and 'kill-matching-lines'.
@@ -963,11 +1125,12 @@ further tweak whether to complete or indent.
 ---
 ** 'indent-tabs-mode' is now a global minor mode instead of just a variable.
 
----
++++
 ** New choice 'permanent' for 'shift-select-mode'.
 When the mark was activated by shifted motion keys, non-shifted motion
 keys don't deactivate the mark after customizing 'shift-select-mode'
-to 'permanent'.
+to 'permanent'.  Similarly, the active mark will not be deactivated by
+typing shifted motion keys.
 
 +++
 ** The "Edit => Clear" menu item now obeys a rectangular region.
@@ -978,7 +1141,7 @@ Revert a buffer trying to be as non-destructive as 
possible,
 preserving markers, properties and overlays.  The new variable
 'revert-buffer-with-fine-grain-max-seconds' specifies the maximum
 number of seconds that 'revert-buffer-with-fine-grain' should spend
-trying to be non-destructive.
+trying to be non-destructive, with a default value of 2 seconds.
 
 +++
 ** New command 'revert-buffer-quick'.
@@ -988,7 +1151,8 @@ less.
 +++
 ** New user option 'revert-buffer-quick-short-answers'.
 This controls how the new 'revert-buffer-quick' ('C-x x g') command
-prompts.
+prompts.  A non-nil value will make it use 'y-or-n-p' rather than
+'yes-or-no-p'.  Defaults to nil.
 
 +++
 ** New user option 'query-about-changed-file'.
@@ -998,10 +1162,10 @@ If nil, Emacs does not prompt, but instead shows the 
buffer with its
 contents before the change, and provides instructions how to revert
 the buffer.
 
+---
 ** New value 'save-some-buffers-root' of 'save-some-buffers-default-predicate'.
-They allow to ask about saving only those files that are under the
-project root or in subdirectories of the directory that was default
-during command invocation.
+When using this predicate, only buffers under the current project root
+will be considered when saving buffers with 'save-some-buffers'.
 
 ---
 ** New user option 'save-place-abbreviate-file-names'.
@@ -1038,11 +1202,11 @@ buffer to be able to move point to the inaccessible 
portion.
 'goto-line-relative' is bound to 'C-x n g'.
 
 +++
-** 'got-char' prompts for the character position.
+** 'goto-char' prompts for the character position.
 When called interactively, 'goto-char' now offers the position at
 point as the default.
 
-** Autosaving via 'auto-save-visited-mode' can now be inhibited.
+** Auto-saving via 'auto-save-visited-mode' can now be inhibited.
 Set the variable 'auto-save-visited-mode' buffer-locally to nil to
 achieve that.
 
@@ -1055,10 +1219,17 @@ This command is bound to 'C-x C-k d'.
 It used to be enabled when Emacs is started in GUI mode but not when started
 in text mode.  The cursor still only actually blinks in GUI frames.
 
+** 'show-paren-mode' is now enabled by default.
+To go back to the previous behavior, customize the user option of the
+same name to nil.
+
 +++
 ** New minor mode 'show-paren-local-mode'.
 It serves as a local counterpart for 'show-paren-mode', allowing you
-to toggle it separately in different buffers.
+to toggle it separately in different buffers.  To use it only in
+programming modes, for example, add the following to your init file:
+
+    (add-hook 'prog-mode-hook #'show-paren-local-mode)
 
 
 * Changes in Specialized Modes and Packages in Emacs 28.1
@@ -1082,6 +1253,14 @@ distinguish between sub-expression highlighting.
 Like 'search-highlight-submatches', this is controlled by the new user option
 'query-replace-highlight-submatches'.
 
++++
+*** New key 'M-s M-.' starts isearch looking for the thing at point.
+This key is bound to the new command 'isearch-forward-thing-at-point'.
+The new user option 'isearch-forward-thing-at-point' defines
+a list of symbols to try to get the "thing" at point.  By default,
+the first element of the list is 'region' that tries to yank
+the currently active region to the search string.
+
 +++
 *** New user option 'isearch-wrap-pause' defines how to wrap the search.
 There are choices to disable wrapping completely and to wrap immediately.
@@ -1095,12 +1274,17 @@ When this option is set, direction changes in Isearch 
move to another
 search match, if there is one, instead of moving point to the other
 end of the current match.
 
-*** New key 'M-s M-.' starts isearch looking for the thing at point.
-This key is bound to the new command 'isearch-forward-thing-at-point'.
-The new user option 'isearch-forward-thing-at-point' defines
-a list of symbols to try to get the "thing" at point.  By default,
-the first element of the list is 'region' that tries to yank
-the currently active region to the search string.
++++
+*** New user option 'isearch-allow-motion'.
+When 'isearch-allow-motion' is set, the commands 'beginning-of-buffer',
+'end-of-buffer', 'scroll-up-command' and 'scroll-down-command', when
+invoked during I-search, move respectively to the first occurrence of
+the current search string in the buffer, the last one, the first one
+after the current window, and the last one before the current window.
+Additionally, users can change the meaning of other motion commands
+during I-search by using their 'isearch-motion' property.  The user
+option 'isearch-motion-changes-direction' controls whether the
+direction of the search changes after a motion command.
 
 +++
 *** New user option 'lazy-highlight-no-delay-length'.
@@ -1109,7 +1293,7 @@ search string is at least this long.  
'lazy-highlight-initial-delay'
 still applies for shorter search strings, which avoids flicker in the
 search buffer due to too many matches being highlighted.
 
----
++++
 *** The default 'search-whitespace-regexp' value has changed.
 This used to be "\\s-+", which meant that it was mode-dependent whether
 newlines were included in the whitespace set.  This has now been
@@ -1143,8 +1327,8 @@ displaying "by name" or "by date" sort order.
 
 +++
 *** New user option 'dired-compress-directory-default-suffix'.
-This user option controls default suffix for compressing a directory.
-If it's nil, ".tar.gz" will be used.  Refer to
+This user option controls the default suffix for compressing a
+directory.  If it's nil, ".tar.gz" will be used.  Refer to
 'dired-compress-files-alist' for a list of supported suffixes.
 
 +++
@@ -1156,6 +1340,7 @@ for a list of supported suffixes.
 ---
 *** Broken and circular links are shown with the 'dired-broken-symlink' face.
 
+---
 *** '=' ('dired-diff') will now put all backup files into the 'M-n' history.
 When using '=' on a file with backup files, the default file to use
 for diffing is the newest backup file.  You can now use 'M-n' to quickly
@@ -1164,7 +1349,7 @@ select a different backup file instead.
 +++
 *** New user option 'dired-maybe-use-globstar'.
 If set, enables globstar (recursive globbing) in shells that support
-this feature, but turn it off by default.  This allows producing
+this feature, but have it turned off by default.  This allows producing
 directory listings with files matching a wildcard in all the
 subdirectories of a given directory.  The new variable
 'dired-enable-globstar-in-shell' lists which shells can have globstar
@@ -1176,6 +1361,7 @@ If set to non-nil, Dired will dereference symbolic links 
when copying.
 This can be switched off on a per-usage basis by providing
 'dired-do-copy' with a 'C-u' prefix.
 
+---
 *** New user option 'dired-do-revert-buffer'.
 Non-nil reverts the destination Dired buffer after performing one
 of these operations: 'dired-do-copy', 'dired-do-rename',
@@ -1202,25 +1388,18 @@ The commands are now bound to 'C-x C-j' and 'C-x 4 C-j' 
by default.
 To get the old behavior of 'dired-bind-jump' back and unbind the above
 keys, add the following to your init file:
 
-(global-set-key "\C-x\C-j" nil)
-(global-set-key "\C-x4\C-j" nil)
+    (global-set-key "\C-x\C-j" nil)
+    (global-set-key "\C-x4\C-j" nil)
 
 ---
 *** 'dired-query' now uses 'read-char-from-minibuffer'.
 Using it instead of 'read-char-choice' allows using 'C-x o'
 to switch to the help window displayed after typing 'C-h'.
 
+
 +++
-** New user option 'isearch-allow-motion'.
-When 'isearch-allow-motion' is set, the commands 'beginning-of-buffer',
-'end-of-buffer', 'scroll-up-command' and 'scroll-down-command', when
-invoked during I-search, move respectively to the first occurrence of
-the current search string in the buffer, the last one, the first one
-after the current window, and the last one before the current window.
-Additionally, users can change the meaning of other motion commands
-during I-search by using their 'isearch-motion' property.  The
-option 'isearch-motion-changes-direction' controls whether the
-direction of the search changes after a motion command.
+** Emacs 28.1 comes with Org v9.5.
+See the file ORG-NEWS for user-visible changes in Org.
 
 ** Outline
 
@@ -1251,11 +1430,15 @@ major mode.
 
 +++
 *** 'ispell-comments-and-strings' now accepts START and END arguments.
-These arguments default to active region when used interactively.
+These arguments default to the active region when used interactively.
 
 +++
 *** New command 'ispell-comment-or-string-at-point'.
 
+---
+*** New user option 'ispell-help-timeout'.
+This controls how long the ispell help (on the '?' key) is displayed.
+
 ** Flyspell mode
 
 +++
@@ -1411,6 +1594,13 @@ is t by default; set to nil to get back the old behavior.
 If 'numeric', calendar functions (eg 'calendar-sunrise-sunset') that display
 time zones will use a form like "+0100" instead of "CET".
 
+** Imenu
+
++++
+*** New user option 'imenu-max-index-time'.
+If creating the imenu index takes longer than specified by this
+option (default 5 seconds), imenu indexing is stopped.
+
 ** ido
 
 ---
@@ -1432,7 +1622,7 @@ default predicate (replacing 
'so-long-detected-long-line-p').
 
 ---
 *** Default values 'so-long-threshold' and 'so-long-max-lines' increased.
-The values of these variables have been raised to 10000 bytes and 500
+The values of these user options have been raised to 10000 bytes and 500
 lines respectively, to reduce the likelihood of false-positives when
 'global-so-long-mode' is enabled.  The latter value is now only used
 by the old predicate, as the new predicate knows the longest line in
@@ -1509,6 +1699,13 @@ based on the current window size.  In previous versions 
of Emacs, this
 was always done (and that could lead to odd displays when resizing the
 window after starting).  This variable defaults to nil.
 
+---
+*** 'term-mode' now supports "bright" color codes.
+"Bright" ANSI color codes are now displayed using the color values
+defined in 'term-color-bright-*'.  In addition, bold text with regular
+ANSI colors can be displayed as "bright" if 'ansi-color-bold-is-bright'
+is non-nil.
+
 ** Eshell
 
 ---
@@ -1525,6 +1722,10 @@ This allows users to use (define-key eshell-mode-map 
...) as usual.
 Some modules have their own minor mode now to account for these
 changes.
 
+*** Support for bookmark.el.
+The command 'bookmark-set' (bound to 'C-x r m') is now supported, and
+will create a bookmark that opens the current directory in Eshell.
+
 ** Archive mode
 
 ---
@@ -1573,8 +1774,10 @@ either an internal or external browser.
 If a remote file is specified, a local temporary copy of that file is
 passed to the browser.
 
+---
 *** Support for the conkeror browser is now obsolete.
 
+---
 *** Support for the Mosaic browser has been removed.
 This support has been obsolete since 25.1.
 
@@ -1593,28 +1796,6 @@ to make better use of the horizontal space, in 
particular eliminating
 the truncation of function names.  There is no way to get the former
 layout back.
 
-** Python mode
-
----
-*** New user option 'python-forward-sexp-function'.
-This allows the user easier customization of whether to use block-based
-navigation or not.
-
----
-*** 'python-shell-interpreter' now defaults to python3 on systems with python3.
-
----
-*** 'C-c C-r' can now be used on arbitrary regions.
-The command previously extended the start of the region to the start
-of the line, but will now actually send the marked region, as
-documented.
-
-** Perl mode
-
----
-*** New face 'perl-non-scalar-variable'.
-This is used to fontify non-scalar variables.
-
 ** Icomplete
 
 ---
@@ -1689,8 +1870,10 @@ work as before.
 
 ** Emacs Lisp mode
 
+---
 *** The mode-line now indicates whether we're using lexical or dynamic scoping.
 
++++
 *** A space between an open paren and a symbol changes the indentation rule.
 The presence of a space between an open paren and a symbol now is
 taken as a statement by the programmer that this should be indented
@@ -1765,6 +1948,10 @@ tags to be considered as well.
 *** New user option 'vc-git-log-switches'.
 String or list of strings specifying switches for Git log under VC.
 
+*** Command 'vc-switch-backend' is now obsolete.
+If you are still using it with any regularity, please file a bug
+report with some details.
+
 ** Gnus
 
 +++
@@ -1885,7 +2072,7 @@ consistency, the 'M-s M-r' key binding has been added for 
the
 'gnus-summary-search-article-backward' command.)
 
 ---
-*** The value of "all" in the 'large-newsgroup-initial' group parameter 
changes.
+*** The value for "all" in the 'large-newsgroup-initial' group parameter has 
changed.
 It was previously nil, which didn't work, because nil is
 indistinguishable from not being present.  The new value for "all" is
 the symbol 'all'.
@@ -1921,7 +2108,8 @@ This is used when forwarding messages as MIME, but not 
using MML.
 *** Message now supports the OpenPGP header.
 To generate these headers, add the new function
 'message-add-openpgp-header' to 'message-send-hook'.  The header will
-be generated according to the new 'message-openpgp-header' variable.
+be generated according to the new 'message-openpgp-header' user
+option.
 
 ---
 *** A change to how "Mail-Copies-To: never" is handled.
@@ -2123,7 +2311,7 @@ regexp instead.
 ---
 *** New user option 'compilation-search-all-directories'.
 When doing parallel builds, directories and compilation errors may
-arrive in the "*compilation*" buffer out-of-order.  If this variable is
+arrive in the "*compilation*" buffer out-of-order.  If this option is
 non-nil (the default), Emacs will now search backwards in the buffer
 for any directory the file with errors may be in.  If nil, this won't
 be done (and this restores how this previously worked).
@@ -2181,14 +2369,6 @@ current environment.
 Its default value matches localized abbreviations of the "reply"
 prefix on the Subject line in various languages.
 
----
-*** New user option 'shr-offer-extend-specpdl'.
-If this is nil, rendering of HTML in the email message body that
-requires to enlarge 'max-specpdl-size', the number of Lisp variable
-bindings, will be aborted, and Emacs will not ask you whether to
-enlarge 'max-specpdl-size' to complete the rendering.  The default is
-t, which preserves the original behavior.
-
 ---
 *** New user option 'rmail-show-message-set-modified'.
 If set non-nil, showing an unseen message will set the Rmail buffer's
@@ -2343,30 +2523,43 @@ However, if "~/Downloads/" already exists, that will 
continue to be
 used.
 
 ---
-*** The command 'eww-follow-link' now supports custom mailto handlers.
+*** The command 'eww-follow-link' now supports custom mailto: handlers.
 The function that is invoked when clicking on or otherwise following a
 'mailto:' link in an EWW buffer can now be customized.  For more
-information, see the related entry about 'shr-browse-url' above.
+information, see the related entry about 'shr-browse-url' below.
+
+---
+*** Support for bookmark.el.
+The command 'bookmark-set' (bound to 'C-x r m') is now supported, and
+will create a bookmark that opens the current URL in EWW.
 
 ** SHR
 
 ---
 *** The command 'shr-browse-url' now supports custom mailto handlers.
-Clicking on or otherwise following a 'mailto:' link in a HTML buffer
+Clicking on or otherwise following a 'mailto:' link in an HTML buffer
 rendered by SHR previously invoked the command 'browse-url-mailto'.
 This is still the case by default, but if you customize
 'browse-url-mailto-function' or 'browse-url-handlers' to call some
 other function, it will now be called instead of the default.
 
+---
+*** New user option 'shr-offer-extend-specpdl'.
+If this is nil, rendering of HTML that requires enlarging
+'max-specpdl-size', the number of Lisp variable bindings, will be
+aborted, and Emacs will not ask you whether to enlarge
+'max-specpdl-size' to complete the rendering.  The default is t, which
+preserves the original behavior.
+
 +++
 *** New user option 'shr-max-width'.
 If this user option is non-nil, and 'shr-width' is nil, then SHR will
 use the value of 'shr-max-width' to limit the width of the rendered
 HTML.  The default is 120 characters, so even if you have very wide
 frames, HTML text will be rendered more narrowly, which usually leads
-to a more readable text.  Set this user option to nil to get the
-previous behavior of rendering as wide as the 'window-width' allows.
-If 'shr-width' is non-nil, it overrides this variable.
+to a more readable text.  Customize it to nil to get the previous
+behavior of rendering as wide as the 'window-width' allows.  If
+'shr-width' is non-nil, it overrides this option.
 
 ---
 *** New faces for heading elements.
@@ -2374,8 +2567,10 @@ Those are 'shr-h1', 'shr-h2', 'shr-h3', 'shr-h4', 
'shr-h5', 'shr-h6'.
 
 ** Project
 
+---
 *** New user option 'project-vc-merge-submodules'.
 
+---
 *** Project commands now have their own history.
 Previously used project directories are now suggested by all commands
 that prompt for a project directory.
@@ -2383,7 +2578,7 @@ that prompt for a project directory.
 +++
 *** New prefix keymap 'project-prefix-map'.
 Key sequences that invoke project-related commands start with the
-prefix 'C-x p'.  Type "C-x p C-h" to show the full list.
+prefix 'C-x p'.  Type 'C-x p C-h' to show the full list.
 
 +++
 *** New commands 'project-dired', 'project-vc-dir', 'project-shell',
@@ -2392,8 +2587,7 @@ a project's root directory, respectively.
 
 +++
 *** New command 'project-compile'.
-This command runs compilation in the current project's root
-directory.
+This command runs compilation in the current project's root directory.
 
 +++
 *** New command 'project-switch-project'.
@@ -2417,7 +2611,7 @@ directory and optionally also its subdirectories, storing 
them in
 
 +++
 *** New commands 'project-forget-project' and 'project-forget-projects-under'.
-These command lets you interactively remove entries from the list of projects
+These commands let you interactively remove entries from the list of projects
 in 'project-list-file'.
 
 +++
@@ -2432,7 +2626,8 @@ sub-directory.
 
 +++
 *** 'project-find-file' doesn't use the string at point as default input.
-Now it's only suggested as part of the "future history".
+Now it's only suggested as part of the "future history", accessible
+via 'M-n'.
 
 +++
 *** New command 'project-find-dir' runs Dired in a directory inside project.
@@ -2456,10 +2651,11 @@ The new user option 'xref-auto-jump-to-first-xref' 
changes the
 behavior of Xref commands such as 'xref-find-references',
 'xref-find-apropos', and 'project-find-regexp', which are expected to
 display many matches that the user would like to
-visit. 'xref-auto-jump-to-first-xref' changes their behavior much in
+visit.  'xref-auto-jump-to-first-xref' changes their behavior much in
 the same way as 'xref-auto-jump-to-first-definition' affects the
 "find-definitions" commands.
 
+---
 *** New user options 'xref-search-program' and 'xref-search-program-alist'.
 So far 'grep' and 'ripgrep' are supported.  'ripgrep' seems to offer better
 performance in certain cases, in particular for case-insensitive
@@ -2470,9 +2666,11 @@ searches.
 These commands are bound respectively to 'P' and 'N', and navigate to
 the first item of the previous or next group in the "*xref*" buffer.
 
+---
 *** New alternative value for 'xref-show-definitions-function':
 'xref-show-definitions-completing-read'.
 
+---
 *** The two existing alternatives for 'xref-show-definitions-function'
 have been renamed to have "proper" public names and documented
 ('xref-show-definitions-buffer' and
@@ -2533,9 +2731,9 @@ truncation, amongst other things.
 ---
 *** Bug reference mode uses auto-setup.
 If 'bug-reference-mode' or 'bug-reference-prog-mode' have been
-activated, their respective hook has been run and still
-'bug-reference-bug-regexp' and 'bug-reference-url-format' aren't both
-set, it tries to guess appropriate values for those two variables.
+activated, their respective hook has been run, and both
+'bug-reference-bug-regexp' and 'bug-reference-url-format' are still
+not set, it tries to guess appropriate values for those two variables.
 There are three guessing mechanisms so far: based on version control
 information of the current buffer's file, based on
 newsgroup/mail-folder name and several news and mail message headers
@@ -2586,11 +2784,9 @@ This new command (bound to 'C-c C-l') regenerates the 
current hunk.
 This is like 'filename', but is a full path, and is nil if the file
 doesn't exist.
 
-*** New 'thing-at-point' target: 'list-or-string'.
-This is like 'list, but if point is inside a string that's enclosed in
-the list, it returns the enclosed string and not the enclosing list.
-
-This is like 'list', but also prefers to find of any enclosing string.
++++
+*** New 'thing-at-point' target: 'string'.
+If point is inside a string, it returns that string.
 
 +++
 *** New variable 'thing-at-point-provider-alist'.
@@ -2602,25 +2798,29 @@ This allows mode-specific alterations to how 
'thing-at-point' works.
 'symbol-at-point') will narrow to the current field (if any) before
 trying to identify the thing at point.
 
+---
 *** New function 'thing-at-mouse'.
+This is like 'thing-at-point', but uses the mouse event position instead.
 
-** image-dired
-
----
-*** 'image-dired-mouse-toggle-mark' now toggles files in the active region.
+** Image-Dired
 
 +++
 *** New user option 'image-dired-thumb-visible-marks'.
-If non-nil (the default), use 'image-dired-thumb-mark' to say what
-images are marked.
+If non-nil (the default), use the new face 'image-dired-thumb-mark'
+for marked images.
 
 ---
 *** New command 'image-dired-delete-marked'.
 
+---
+*** 'image-dired-mouse-toggle-mark' is now sensitive to the active region.
+If the region is active, this command now toggles Dired marks of all
+the thumbnails in the region.
+
 ** Flymake mode
 
 +++
-*** New command 'flymake-show-project-diagnostics'
+*** New command 'flymake-show-project-diagnostics'.
 This lists all diagnostics for buffers in the currently active
 project.  The listing is similar to the one obtained by
 'flymake-show-buffer-diagnostics', but adds a column for the
@@ -2666,6 +2866,35 @@ The old names are now obsolete.
 *** 'world-clock-mode' can no longer be turned on interactively.
 Use 'world-clock' to turn on that mode.
 
+** Python mode
+
+---
+*** New user option 'python-forward-sexp-function'.
+This allows the user easier customization of whether to use block-based
+navigation or not.
+
+---
+*** 'python-shell-interpreter' now defaults to python3 on systems with python3.
+
+---
+*** 'C-c C-r' can now be used on arbitrary regions.
+The command previously extended the start of the region to the start
+of the line, but will now actually send the marked region, as
+documented.
+
+** Ruby Mode
+
+---
+*** 'ruby-use-smie' is declared obsolete.
+SMIE is now always enabled and 'ruby-use-smie' only controls whether
+indentation is done using SMIE or with the old ad-hoc code.
+
+---
+*** Indentation has changed when 'ruby-align-chained-calls' is non-nil.
+This previously used to align subsequent lines with the last sibling,
+but it now aligns with the first sibling (which is the preferred style
+in Ruby).
+
 ** CPerl Mode
 
 ---
@@ -2677,6 +2906,12 @@ This value customizes Emacs to use the style recommended 
in Damian
 Conway's book "Perl Best Practices" for indentation and formatting
 of conditionals.
 
+** Perl mode
+
+---
+*** New face 'perl-non-scalar-variable'.
+This is used to fontify non-scalar variables.
+
 ** Octave Mode
 
 +++
@@ -2721,80 +2956,45 @@ sequences.
 *** 'comint-delete-output' can now save deleted text in the kill-ring.
 Interactively, 'C-u C-c C-o' triggers this new optional behavior.
 
-** ERC
+** ansi-color.el
 
 ---
-*** NickServ passwords can now be retrieved from auth-source.
-The 'erc-use-auth-source-for-nickserv-password' user option enables
-querying auth-source for NickServ passwords.  To enable this, add the
-following to your init file:
-
-    (setq erc-use-auth-source-for-nickserv-password t)
+*** Colors are now defined by faces.
+ANSI SGR codes now have corresponding faces to describe their
+appearance, e.g. 'ansi-color-bold'.
 
 ---
-*** NickServ identification now prompts for password last.
-When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
-be unconditionally prompted interactively for a password, regardless
-of the value of 'erc-nickserv-passwords', which was effectively
-ignored (same for the new
-'erc-use-auth-source-for-nickserv-password').  This limitation is now
-lifted, and the user is interactively prompted last, after the other
-identification methods have run.
+*** Support for "bright" color codes.
+"Bright" ANSI color codes are now displayed when applying ANSI color
+filters using the color values defined by the faces
+'ansi-color-bright-COLOR'.  In addition, bold text with regular ANSI
+colors can be displayed as "bright" if 'ansi-color-bold-is-bright' is
+non-nil.
 
----
-*** The '/ignore' command will now ask for a timeout to stop ignoring the user.
-Allowed inputs are seconds or ISO8601-like periods like "1h" or "4h30m".
+** ERC
 
----
-*** ERC now recognizes 'C-]' for italic text.
-Italic text is displayed in the new 'erc-italic-face'.
+*** Starting with Emacs 28.1 and ERC 5.4, see the ERC-NEWS file for
+user-visible changes in ERC.
 
----
-*** The erc-compat.el library is now marked obsolete.
-This file contained ERC compatibility code for Emacs 21 and XEmacs
-which is no longer needed.
+** xwidget-webkit mode
 
 ---
-*** erc-match.el now supports 'message' highlight type (not including the 
nick).
-The 'erc-current-nick-highlight-type', 'erc-pal-highlight-type',
-'erc-fool-highlight-type', 'erc-keyword-highlight-type', and
-'erc-dangerous-host-highlight-type' variables now support a 'message'
-type for highlighting the entire message but not the sender's nick.
+*** New xwidget commands.
+'xwidget-webkit-uri' (return the current URL), 'xwidget-webkit-title'
+(return the current title), and 'xwidget-webkit-goto-history' (goto a
+point in history).
 
 ---
-*** erc-status-sidebar.el is now part of ERC.
-The 'erc-status-sidebar' package which provides a HexChat-like
-activity overview sidebar for joined IRC channels is now part of ERC.
-
-+++
-*** erc-tls now supports specifying a TLS client certificate.
-The 'erc-tls' function has been updated to allow specifying a TLS
-client certificate for authentication, as an alternative to NickServ
-password-based authentication.  This is referred to as "CertFP" (short
-for Certificate Fingerprint) by several IRC networks.  See the Info
-node "(erc) Connecting" in the ERC manual for more details and
-examples on how to specify and use TLS client certificates with
-'erc-tls'.
+*** Downloading files from xwidget-webkit is now supported.
+The new user option 'xwidget-webkit-download-dir' says where to download to.
 
 ---
-*** Add 'erc-track-select-mode-line-face' (obsoletes 'erc-track-find-face').
-The 'erc-track-find-face' function of the erc-track module has been
-declared obsolete and rewritten as 'erc-track-select-mode-line-face',
-with different expected arguments (the current and old faces are now
-separated) and clearer documentation.
-
-*** Add '/opme' and '/deopme' convenience commands.
-The new '/opme' convenience command asks ChanServ to set the operator
-status for the current nick in the current channel, and '/deopme'
-unsets it.
-
-** xwidget-webkit mode
+*** New command 'xwidget-webkit-clone-and-split-below'.
+Open a new window below displaying the current URL.
 
 ---
-*** New xwidget commands.
-'xwidget-webkit-uri' (return the current URL), 'xwidget-webkit-title'
-(return the current title), and 'xwidget-webkit-goto-history' (goto a
-point in history).
+*** New command 'xwidget-webkit-clone-and-split-right'.
+Open a new window to the right displaying the current URL.
 
 ---
 *** Pixel-based scrolling.
@@ -2842,10 +3042,10 @@ checkdoc will now check the format of 'yes-or-no-p'.
 This can be used to run checkdoc on files from a Dired buffer.
 
 ---
-*** No longer checks for "A-" modifiers.
+*** No longer checks for 'A-' modifiers.
 Checkdoc recommends usage of command substitutions ("\\[foo-command]")
-in favor of writing keybindings like "C-c f".  It now no longer warns
-about the "A-" modifier as it is not used very much in practice, and
+in favor of writing keybindings like 'C-c f'.  It now no longer warns
+about the 'A-' modifier as it is not used very much in practice, and
 this warning therefore mostly led to false positives.
 
 ** Enriched mode
@@ -2882,8 +3082,8 @@ The old binding is supported but warns that it is 
obsolete.
 'mh-blacklist-msg-hook' is renamed 'mh-blocklist-msg-hook'.
 
 +++
-*** New names for some variables.
-Variable 'mh-whitelist-preserves-sequences-flag' is renamed
+*** New names for some user options.
+User option 'mh-whitelist-preserves-sequences-flag' is renamed
 'mh-allowlist-preserves-sequences-flag'.
 
 +++
@@ -2897,37 +3097,47 @@ Face 'mh-folder-whitelisted' is renamed 
'mh-folder-allowlisted'.
 *** rcirc now supports SASL authentication.
 
 ---
-*** rcirc connects asynchronously
+*** #emacs on Libera.chat has been added to 'rcirc-server-alist'.
 
 ---
-*** Integrate formatting into rcirc-send-string
+*** rcirc connects asynchronously.
+
+---
+*** Integrate formatting into 'rcirc-send-string'.
 The function now accepts a variable number of arguments.
 
 +++
-*** Deprecate defun-rcirc-command in favour of rcirc-define-command
+*** Deprecate 'rcirc-command' in favor of 'rcirc-define-command'.
 The new macro handles multiple and optional arguments.
 
 ---
-*** Add basic IRCv3 support
-This includes support for the capabilities: server-time, batch,
-message-ids, invite-notify, multi-prefix and standard-replies.
+*** Add basic IRCv3 support.
+This includes support for the capabilities: 'server-time', 'batch',
+'message-ids', 'invite-notify', 'multi-prefix' and 'standard-replies'.
 
 ---
-*** Add mouse property support to rcirc-track-minor-mode
+*** Add mouse property support to 'rcirc-track-minor-mode'.
 
 ---
-*** Improve support for IRC markup codes
+*** Improve support for IRC markup codes.
 
 ---
-*** Check auth-sources for server passwords
+*** Check 'auth-sources' for server passwords.
+
++++
+*** Implement repeated reconnection strategy.
+See 'rcirc-reconnect-attempts'.
+
+** MPC
 
 ---
-*** Allow for channels to hide certain message types right after connecting.
-Set rcirc-omit-responses-after-join analogously to rcirc-omit-responses.
+*** New command 'mpc-goto-playing-song'.
+This command, bound to 'o' in any 'mpc-mode' buffer, moves point to
+the currently playing song in the "*MPC-Songs*" buffer.
 
-+++
-*** Implement repeated reconnection strategy
-See rcirc-reconnect-attempts.
+---
+*** New user option 'mpc-cover-image-re'.
+If non-nil, it is a regexp that should match a valid cover image.
 
 ** Miscellaneous
 
@@ -3008,7 +3218,7 @@ effect.
 
 ---
 *** The width of the buffer-name column in 'list-buffers' is now dynamic.
-The width now depends of the width of the window, but will never be
+The width now depends on the width of the window, but will never be
 wider than the length of the longest buffer name, except that it will
 never be narrower than 19 characters.
 
@@ -3031,44 +3241,34 @@ different timezone causing a difference in the date.
 Instead you need to do "emacs -f dun-batch" to start the game in
 batch mode.
 
-** Ruby Mode
-
----
-** 'ruby-use-smie' is declared obsolete.
-SMIE is now always enabled and 'ruby-use-smie' only controls whether
-indentation is done using SMIE or with the old ad-hoc code.
+
+* New Modes and Packages in Emacs 28.1
 
----
-** Indentation has changed when 'ruby-align-chained-calls' is non-nil.
-This previously used to align subsequent lines with the last sibling,
-but it now aligns with the first sibling (which is the preferred style
-in Ruby).
++++
+** New mode 'repeat-mode' to allow shorter key sequences.
+Type 'M-x repeat-mode' to enable this mode.  You can then type
+'C-x u u' instead of 'C-x u C-x u' to undo many changes, 'C-x o o'
+instead of 'C-x o C-x o' to switch windows, 'C-x { { } } ^ ^ v v' to
+resize the selected window interactively, 'M-g n n p p' to navigate
+next-error matches.  Any other key exits this temporarily enabled
+transient mode that supports shorter keys, and then after exiting from
+this mode, the last typed key uses the default key binding.
 
-** Imenu
+The user option 'repeat-exit-key' defines an additional key usable to
+exit the mode like 'isearch-exit' ('RET').
 
-+++
-*** New user option 'imenu-max-index-time'.
-If creating the imenu index takes longer than specified by this
-variable (default 5 seconds), imenu indexing is stopped.
+The user option 'repeat-exit-timeout' (default nil, which means
+forever) specifies the number of seconds of idle time after which to
+break the repetition chain automatically.
 
-
-* New Modes and Packages in Emacs 28.1
+When user option 'repeat-keep-prefix' is non-nil (the default), the
+prefix arg of the previous command is kept.  This can be used to
+e.g. reverse the window navigation direction with 'C-x o M-- o o' or
+to set a new step with 'C-x { C-5 { { {', which will set the window
+resizing step to 5 columns.
 
-+++
-** New transient mode 'repeat-mode' to allow shorter key sequences.
-You can type 'C-x u u' instead of 'C-x u C-x u' to undo many changes,
-'C-x o o' instead of 'C-x o C-x o' to switch several windows,
-'C-x { { } } ^ ^ v v' to resize the selected window interactively,
-'M-g n n p p' to navigate next-error matches.  Any other key exits
-transient mode and then is executed normally.  'repeat-exit-key'
-defines an additional key to exit mode like 'isearch-exit' ('RET').
-The user option 'repeat-exit-timeout' specifies the number of
-seconds of idle time to break the repetition chain automatically.
-With 'repeat-keep-prefix' you can keep the prefix arg of the previous
-command.  For example, this can help to reverse the window navigation
-direction with e.g. 'C-x o M-- o o'.  Also it can help to set a new
-step with e.g. 'C-x { C-5 { { {', which will set the window resizing
-step to 5 columns.
+'M-x describe-repeat-maps' will display a buffer showing
+which commands are repeatable in 'repeat-mode'.
 
 ---
 ** New themes 'modus-vivendi' and 'modus-operandi'.
@@ -3113,95 +3313,6 @@ This new 'etc-authors-mode' provides font-locking for 
displaying the
 "etc/AUTHORS" file from the Emacs distribution, and not much else.
 
 
-* Incompatible Editing Changes in Emacs 28.1
-
----
-** 'toggle-truncate-lines' now disables 'visual-line-mode'.
-This is for symmetry with 'visual-line-mode', which disables
-'truncate-lines'.
-
----
-** 'electric-indent-mode' now also indents inside strings and comments.
-(This only happens when indentation function also supports this.)
-
-To recover the previous behavior you can use:
-
-    (add-hook 'electric-indent-functions
-              (lambda (_) (if (nth 8 (syntax-ppss)) 'no-indent)))
-
----
-** The 'M-o' ('facemenu-keymap') global binding has been removed.
-To restore the old binding, say something like:
-
-    (require 'facemenu)
-    (define-key global-map "\M-o" 'facemenu-keymap)
-    (define-key facemenu-keymap "\es" 'center-line)
-    (define-key facemenu-keymap "\eS" 'center-paragraph)
-
-The last two lines are not strictly necessary if you don't care about
-having those two commands on the 'M-o' keymap; see the next section.
-
----
-** The 'M-o M-s' and 'M-o M-S' global bindings have been removed.
-Use 'M-x center-line' and 'M-x center-paragraph' instead.  See the
-previous section for how to get back the old bindings.  Alternatively,
-if you only want these two commands to have global bindings they had
-before, you can add the following to your init file:
-
-  (define-key global-map "\M-o\M-s" 'center-line)
-  (define-key global-map "\M-o\M-S" 'center-paragraph)
-
----
-** The 'M-o M-o' global binding has been removed.
-Use 'M-x font-lock-fontify-block' instead, or the new 'C-x x f'
-command, which updates the syntax highlighting in the current buffer.
-
----
-** The escape sequence '\e[29~' in Xterm is now mapped to 'menu'.
-Xterm sends this sequence for both 'F16' and 'Menu' keys
-It used to be mapped to 'print' but we couldn't find a terminal
-that uses this sequence for any kind of 'Print' key.
-This makes the Menu key (see https://en.wikipedia.org/wiki/Menu_key)
-work for 'context-menu-mode' in Xterm.
-
----
-** New user option 'xterm-store-paste-on-kill-ring'.
-If non-nil (the default), Emacs pushes pasted text onto the kill ring
-(if using an xterm-like terminal that supports bracketed paste).
-Setting this to nil inhibits that.
-
----
-** 'vc-print-branch-log' shows the change log from its root directory.
-It previously used to use the default directory.
-
----
-** 'project-shell' and 'shell' now use 'pop-to-buffer-same-window'.
-This is to keep the same behavior as Eshell.
-
----
-** In 'nroff-mode', 'center-line' is no longer bound to a key.
-The original key binding was 'M-s', which interfered with I-search,
-since the latter uses 'M-s' as a prefix key of the search prefix map.
-
----
-** In 'f90-mode', the backslash character ('\') no longer escapes.
-For about a decade, the backslash character has no longer had a
-special escape syntax in Fortran F90.  To get the old behavior back,
-say something like:
-
-    (modify-syntax-entry ?\\ "\\" f90-mode-syntax-table)
-
-+++
-** Setting 'fill-column' to nil is obsolete.
-This undocumented use of 'fill-column' is now obsolete.  To disable
-auto filling, turn off 'auto-fill-mode' instead.
-
-For instance, you could add something like the following to your init
-file:
-
-    (add-hook 'foo-mode-hook (lambda () (auto-fill-mode -1))
-
-
 * Incompatible Lisp Changes in Emacs 28.1
 
 +++
@@ -3232,6 +3343,13 @@ local variable would not be heeded.  This has now 
changed, and a file
 with a 'lexical-binding' cookie is always heeded.  To revert to the
 old behavior, set 'permanently-enabled-local-variables' to nil.
 
++++
+** '&rest' in argument lists must always be followed by a variable name.
+Omitting the variable name after '&rest' was previously tolerated in
+some cases but not consistently so; it could lead to crashes or
+outright wrong results.  Since the utility was marginal at best, it is
+now an error to omit the variable.
+
 ---
 ** 'kill-all-local-variables' has changed how it handles non-symbol hooks.
 The function is documented to eliminate all buffer-local bindings
@@ -3419,7 +3537,7 @@ by mistake and were not useful to Lisp code.
 The former is now declared obsolete.
 
 +++
-** 'facemenu.el' is no longer preloaded.
+** facemenu.el is no longer preloaded.
 To use functions/variables from the package, you now have to say
 '(require 'facemenu)' or similar.
 
@@ -3584,9 +3702,9 @@ objects in files specified by that variable.  It's 
unclear when this
 actually changed, but at some point (perhaps decades ago) these
 commands started using 'load-history' to determine where symbols had
 been defined (which is much faster).  The doc strings of all the
-affected function has been updated.  'find-function-source-path' was
+affected function have been updated.  'find-function-source-path' was
 still being used by 'find-library' and related commands, so the
-variable has been renamed to 'find-library-source-path', and
+user option has been renamed to 'find-library-source-path', and
 'find-function-source-path' is now an obsolete variable alias.
 
 ---
@@ -3599,7 +3717,7 @@ variable has been renamed to 'find-library-source-path', 
and
 ** The 'interactive' syntax has been extended to allow listing applicable 
modes.
 Forms like '(interactive "p" dired-mode)' can be used to annotate the
 commands as being applicable for modes derived from 'dired-mode',
-or if the mode is a minor mode, that the current buffer has that
+or if the mode is a minor mode, when the current buffer has that
 minor mode activated.  Note that using this form will create byte code
 that is not compatible with byte code in previous Emacs versions.
 
@@ -3610,7 +3728,7 @@ to say whether the command should be present when 
completing with
 'M-x TAB'.  '(declare (modes MODE...))' can be used as a short-hand
 way of saying that the command should be present when completing from
 buffers in major modes derived from MODE..., or, if it's a minor mode,
-whether that minor mode is enabled in the current buffer.
+when that minor mode is enabled in the current buffer.
 
 +++
 ** 'define-minor-mode'  now takes an ':interactive' argument.
@@ -3633,7 +3751,7 @@ used in.
 ** 'condition-case' now allows for a success handler.
 It is written as '(:success BODY...)' where BODY is executed
 whenever the protected form terminates without error, with the
-specified variable bound to the the value of the protected form.
+specified variable bound to the value of the protected form.
 
 +++
 ** New function 'benchmark-call' to measure the execution time of a function.
@@ -3671,8 +3789,13 @@ initial frame used in batch mode.
 +++
 ** Doc strings can now link to customization groups.
 Text like "customization group `whitespace'" will be made into a
-button.  When clicked, it'll take the user to a Custom buffer
-displaying that customization group.
+button.  When clicked, it will open a Custom buffer displaying that
+customization group.
+
++++
+** Doc strings can now link to man pages.
+Text like "man page `chmod(1)'" will be made into a button.  When
+clicked, it will open a Man mode buffer displaying that man page.
 
 +++
 ** Buffers can now be created with certain hooks disabled.
@@ -3705,6 +3828,11 @@ instead of only becoming available after doing (for 
instance)
 ---
 ** ':safe' settings in 'defcustom' are now propagated to the loaddefs files.
 
++++
+** New ':type' for 'defcustom' for nonnegative integers.
+The new 'natnum' type can be used for options that should be
+nonnegative integers.
+
 +++
 ** ERT can now output more verbose test failure reports.
 If the 'EMACS_TEST_VERBOSE' environment variable is set, failure
@@ -3846,6 +3974,17 @@ asynchronously send data back to Emacs.
 It can be used to create Lisp strings with arbitrary byte sequences
 (a.k.a. "raw bytes").
 
++++
+** Shorthands for Lisp symbols.
+Shorthands are a general purpose namespacing system to make Emacs
+Lisp's symbol-naming etiquette easier to use.  A shorthand is any
+symbolic form found in Lisp source that "abbreviates" a symbol's print
+name.  Among other applications, this feature can be used to avoid
+name clashes and namespace pollution by renaming an entire file's
+worth of symbols with proper and longer prefixes, without actually
+touching the Lisp source.  For details, see the manual section
+"(elisp) Shorthands".
+
 +++
 ** New function 'string-search'.
 This function takes two string parameters and returns the position of
@@ -3870,7 +4009,7 @@ quotes, as well as backslash quoting (like\ this).
 
 +++
 ** New function 'string-clean-whitespace'.
-This removed whitespace from a string
+This removes whitespace from a string.
 
 +++
 ** New function 'string-fill'.
@@ -3995,6 +4134,10 @@ Parse a string as a mail address-like string.
 ** New function 'make-separator-line'.
 Make a string appropriate for usage as a visual separator line.
 
++++
+** New function 'num-processors'.
+Return the number of processors on the system.
+
 +++
 ** New function 'object-intervals'.
 This function returns a copy of the list of intervals (i.e., text
@@ -4189,8 +4332,8 @@ first COUNT file names that match the expression.  The 
same COUNT
 parameter has been added to 'directory-files-and-attributes'.
 
 +++
-** 'count-lines' now takes an optional parameter to
-ignore invisible lines.
+** 'count-lines' can now ignore invisible lines.
+This is controlled by the optional parameter IGNORE-INVISIBLE-LINES.
 
 ---
 ** 'count-words' now crosses field boundaries.
@@ -4210,7 +4353,15 @@ The new optional "," parameter has been added, and
 
 +++
 ** 'parse-time-string' can now parse ISO 8601 format strings.
-These have the format like "2020-01-15T16:12:21-08:00".
+These have a format like "2020-01-15T16:12:21-08:00".
+
+---
+** 'lookup-key' is more allowing when searching for extended menu items.
+When looking for a menu item '[menu-bar Foo-Bar]', first try to find
+an exact match, then look for the lowercased '[menu-bar foo-bar]'.
+It will only try to downcase ASCII characters in the range "A-Z".
+This improves backwards-compatibility when converting menus to use
+'easy-menu-define'.
 
 ---
 ** 'make-network-process', 'make-serial-process' ':coding' behavior change.
@@ -4317,7 +4468,7 @@ also keep the type information of their arguments.  Use 
the
 
 +++
 *** New minor mode 'button-mode'.
-This minor mode does nothing else than install 'button-buffer-map' as
+This minor mode does nothing except install 'button-buffer-map' as
 a minor mode map (which binds the 'TAB' / 'S-TAB' key bindings to navigate
 to buttons), and can be used in any view-mode-like buffer that has
 buttons in it.
@@ -4335,7 +4486,8 @@ line when displaying that buffer.
 
 This is useful for major modes that arrange their display in a tabular
 form below the header line.  It is enabled by default in
-'tabulated-list-mode' and its derived modes.
+'tabulated-list-mode' and its derived modes, and disabled by default
+elsewhere.
 
 ---
 ** 'ascii' is now a coding system alias for 'us-ascii'.
@@ -4357,6 +4509,11 @@ obsoletes the old data layout specifications.  It 
supports
 arbitrary-size integers, recursive types, and more.  See the Info node
 "(elisp) Byte Packing" in the ELisp manual for more details.
 
++++
+** New macro 'with-environment-variables'.
+This macro allows setting environment variables temporarily when
+executing a form.
+
 
 * Changes in Emacs 28.1 on Non-Free Operating Systems
 
@@ -4398,19 +4555,7 @@ webkit browser with 'M-x xwidget-webkit-browse-url'.  
Viewing two
 instances of xwidget webkit is not supported.
 
 ---
-*** Downloading files from xwidget-webkit is now supported.
-The new variable 'xwidget-webkit-download-dir' says where to download to.
-
----
-*** New command 'xwidget-webkit-clone-and-split-below'.
-Open a new window below displaying the current URL.
-
----
-*** New command 'xwidget-webkit-clone-and-split-right'.
-Open a new window to the right displaying the current URL.
-
----
-*** New variable 'xwidget-webkit-enable-plugins'.
+*** New user option 'xwidget-webkit-enable-plugins'.
 If non-nil, enable plugins in xwidget.  (This is only available on
 macOS.)
 
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 2b9cbf37c4..5e7813ca7f 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -3,13 +3,583 @@ ORG NEWS -- history of user-visible changes.   -*- mode: 
org; coding: utf-8 -*-
 #+STARTUP: overview
 
 #+LINK: doc https://orgmode.org/worg/doc.html#%s
-#+LINK: git https://code.orgmode.org/bzg/org-mode/commit/%s
+#+LINK: msg https://list.orgmode.org/%s/
+#+LINK: git https://git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=%s
 
 Copyright (C) 2012-2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
 Please send Org bug reports to mailto:emacs-orgmode@gnu.org.
 
+* Version 9.5
+
+** Important announcements and breaking changes
+
+*** The =contrib/= now lives in a separate repository
+
+Org's repository has been trimmed from the =contrib/= directory.
+
+The old contents of the =contrib/= directory now lives in a separate
+repository at https://git.sr.ht/~bzg/org-contrib.
+
+You can install this repository by cloning it and updating your
+~load-path~ accordingly.  You can also install =org-contrib= as a
+[[https://elpa.nongnu.org/nongnu/][NonGNU ELPA]] package.
+
+*** Org ELPA and Org archives won't be available for Org > 9.5
+
+[[https://orgmode.org/elpa.html][Org ELPA]] is still available for installing 
Org 9.5, either with or
+without contributed packages, but future versions won't be available
+via Org ELPA, as we are deprecating this installation method.
+
+Also, Org 9.5 is available as =tar.gz= and =zip= archives, but this
+installation method is also deprecated.
+
+If you want to install the latest stable versions of Org, please use
+the GNU ELPA package.  If you want to install the contributed files,
+please use the NonGNU ELPA package.  If you want to keep up with the
+latest unstable Org, please install from the Git repository.
+
+See https://orgmode.org/org.html#Installation for the details.
+
+*** =ditaa.jar= is not bundled with Org anymore
+
+=ditaa.jar= used to be bundled with Org but it is not anymore.
+See [[https://github.com/stathissideris/ditaa][the ditaa repository]] on how 
to install it.
+
+*** ~org-adapt-indentation~ now defaults to =nil=
+
+If you want to automatically indent headlines' metadata, set it to
+=headline-data=.
+
+If you want to automatically indent every line to the headline's
+current indentation, set it to =t=.
+
+Indent added by =RET= and =C-j= also depends on the value of
+~electric-indent-mode~.  Enabling this mode by default in 9.4 revealed
+some bugs caused confusing behavior.  If you disabled
+~electric-indent-mode~ for this reason, it is time to try it again.
+Hopefully problems have been fixed.  See 
[[https://orgmode.org/worg/org-faq.html#indentation][this FAQ]] for more 
details.
+
+*** ~org-speed-commands-user~ is obsolete, use ~org-speed-commands~
+
+Setting ~org-speed-commands-user~ in your configuration won't have any
+effect.  Please set ~org-speed-commands~ instead, which see.
+
+*** Some =ob-*.el= files have been moved to the org-contrib repo
+
+These files have been moved to https://git.sr.ht/~bzg/org-contrib:
+
+- ob-abc.el
+- ob-asymptote.el
+- ob-coq.el
+- ob-ebnf.el
+- ob-hledger.el
+- ob-io.el
+- ob-J.el
+- ob-ledger.el
+- ob-mscgen.el
+- ob-picolisp.el
+- ob-shen.el
+- ob-stan.el
+- ob-vala.el
+
+See the discussion [[msg::87bl9rq29m.fsf@gnu.org][here]].
+
+*** Compatibility with Emacs versions
+
+We made it explicit that we aim at keeping the latest stable version
+of Org compatible with at least Emacs V, V-1 and V-2, where V is the
+stable major version of Emacs.
+
+For example, if the current major version of Emacs is 28.x, then the
+latest stable version of Org should be compatible with Emacs 28.x,
+27.x and 26.x – but not with Emacs 25.x.
+
+See [[https://orgmode.org/worg/org-maintenance.html#emacs-compatibility][this 
note on Worg]] and [[git::519947e508e081e71bf67db99e27b1c171ba4dfe][this 
commit]].
+
+*** The keybinding for ~org-table-blank-field~ has been removed
+
+If you prefer to keep the keybinding, you can add it back to
+~org-mode-map~ like so:
+
+#+begin_src emacs-lisp
+(define-key org-mode-map (kbd "C-c SPC") #'org-table-blank-field)
+#+end_src
+
+** New features
+
+*** New citation engine
+
+Org 9.5 provides a new library =oc.el= which provides tooling to
+handle citations in Org, e.g., activate, follow, insert, and export
+them, respectively called "activate", "follow", "insert" and "export"
+capabilities.  Libraries responsible for providing some, or all, of
+these capabilities are called "citation processors".
+
+The manual contains a few pointers to let you start and you may want
+to check [[https://blog.tecosaur.com/tmio/2021-07-31-citations.html][this blog 
post]].  If you need help using this new features,
+please ask on the mailing list.
+
+Thanks to Nicolas Goaziou for implementing this, to Bruce D’Arcus for
+helping him and to John Kitchin for paving the way with =org-ref.el=.
+
+*** Async session evaluation
+
+The =:async= header argument can be used for asynchronous evaluation
+in session blocks for certain languages.
+
+Currently, async evaluation is supported in Python.  There is also
+functionality to implement async evaluation in other languages that
+use comint, but this needs to be done on a per-language basis.
+
+By default, async evaluation is disabled unless the =:async= header
+argument is present.  You can also set =:async no= to force it off
+(for example if you've set =:async= in a property drawer).
+
+Async evaluation is disabled during export.
+*** ~ox-koma-letter.el~ is now part of Org's core
+
+~ox-koma-letter.el~ provides a KOMA scrlttr2 back-end for the Org
+export engine.  It used to be in the =contrib/= directory but it is
+now part of Org's core.
+
+*** Support exporting DOI links
+
+Org now supports export for DOI links, through its new =ol-doi.el=
+library.  For backward compatibility, it is loaded by default.
+
+*** Add a new ~:refile-targets~ template option
+
+When exiting capture mode via ~org-capture-refile~, the variable
+~org-refile-targets~ will be temporarily bound to the value of this
+template option.
+
+*** New startup options =#+startup: show<n>levels=
+
+These startup options complement the existing =overview=, =content=,
+=showall=, =showeverything= with a way to start the document with n
+levels shown, where n goes from 2 to 5.
+
+Example:
+
+: #+startup: show3levels
+
+*** New =u= table formula flag to enable Calc units simplification mode
+
+A new =u= mode flag for Calc formulas in Org tables has been added to
+enable Calc units simplification mode.
+
+*** Support fontification of inline export snippets
+
+See [[msg:87im57fh8j.fsf@gmail.com][this thread]].
+
+*** New command =org-refile-reverse= bound to =C-c C-M-w=
+
+You can now use =C-c C-M-w= to run ~org-refile-reverse~.
+
+It is almost identical to ~org-refile~, except that it temporarily
+toggles how ~org-reverse-note-order~ applies to the current buffer.
+So if ~org-refile~ would append the entry as the last entry under the
+target heading, ~org-refile-reverse~ will prepend it as the first
+entry, and vice-versa.
+
+*** LaTeX attribute ~:float~ now passes through arbitrary values
+
+LaTeX users are able to define arbitrary float types, e.g. with the
+float package.  The Org mode LaTeX exporter is now able to process and
+export arbitrary float types.  The user is responsible for ensuring
+that Org mode configures LaTeX to process any new float type.
+
+*** Support verse and quote blocks in LaTeX export
+
+The LaTeX export back-end accepts four attributes for verse blocks:
+=:lines=, =:center=, =:versewidth= and =:latexcode=. The three first
+require the external LaTeX package =verse.sty=, which is an extension
+of the standard LaTeX environment.
+
+The LaTeX export back-end accepts two attributes for quote blocks:
+=:environment=, for an arbitrary quoting environment (the default
+value is that of =org-latex-default-quote-environment=: ="quote"=) and
+=:options=.
+
+*** =org-set-tags-command= selects tags from ~org-global-tags-completion-table~
+
+Let ~org-set-tags-command~ TAB fast tag completion interface complete
+tags including from both buffer local and user defined persistent
+global list (~org-tag-alist~ and ~org-tag-persistent-alist~).  Now
+option ~org-complete-tags-always-offer-all-agenda-tags~ is honored.
+
+*** Clocktable option =:formula %= now shows the per-file time percentages
+
+This change only has an effect when multiple files are contributing to
+a given clocktable (such as when =:scope agenda= has been specified).
+The existing behavior is that such tables have an extra 'File' column,
+and each individual file that contributes has its own summary line
+with the headline value '*File time*'.  Those summary rows also
+produce a rollup time value for the file in the 'Time' column.
+
+Prior to this change, the built-in =%= formula did not produce a
+calculation for those per-file times in the '%' column (the relevant
+cells in the '%' column were blank).  With this change, the percentage
+contribution of each individual file time to the total time is shown.
+
+The more agenda files you have, the more useful this behavior becomes.
+
+*** =ob-python.el= improvements to =:return= header argument
+
+The =:return= header argument in =ob-python= now works for session
+blocks as well as non-session blocks.  Also, it now works with the
+=:epilogue= header argument -- previously, setting the =:return=
+header would cause the =:epilogue= to be ignored.
+
+This change allows more easily moving boilerplate out of the main code
+block and into the header. For example, for plotting, we need to add
+boilerplate to save the figure to a file and return the
+filename. Instead of doing this within the code block, we can now
+handle it through the header arguments as follows:
+
+#+BEGIN_SRC org
+,#+header: :var fname="/home/jack/tmp/plot.svg"
+,#+header: :epilogue plt.savefig(fname)
+,#+header: :return fname
+,#+begin_src python :results value file
+  import matplotlib, numpy
+  import matplotlib.pyplot as plt
+  fig=plt.figure(figsize=(4,2))
+  x=numpy.linspace(-15,15)
+  plt.plot(numpy.sin(x)/x)
+  fig.tight_layout()
+,#+end_src
+
+,#+RESULTS:
+[[file:/home/jack/tmp/plot.svg]]
+#+END_SRC
+
+As another example, we can use =:return= with the external 
[[https://pypi.org/project/tabulate/][tabulate]]
+package, to convert pandas Dataframes into orgmode tables:
+
+#+begin_src org
+,#+header: :prologue from tabulate import tabulate
+,#+header: :return tabulate(table, headers=table.columns, tablefmt="orgtbl")
+,#+begin_src python :results value raw :session
+  import pandas as pd
+  table = pd.DataFrame({
+      "a": [1,2,3],
+      "b": [4,5,6]
+  })
+,#+end_src
+
+,#+RESULTS:
+|   | a | b |
+|---+---+---|
+| 0 | 1 | 4 |
+| 1 | 2 | 5 |
+| 2 | 3 | 6 |
+#+end_src
+
+*** Display images with width proportional to the buffer text width
+
+Previously, if you used a =:width= attribute like =#+attr_html: :width 70%= or
+=#+attr_latex: :width 0.7\linewidth= this would be interpreted as a 70px wide 
and
+0.7px wide width specification respectively.
+
+Now, percentages are transformed into floats (i.e. 70% becomes 0.7),
+and float width specifications between 0.0 and 2.0 are now interpreted
+as that portion of the text width in the buffer. For instance, the
+above examples of =70%= and =0.7\linewidth= will result in an image
+with width equal to the pixel-width of the buffer text multiplied by 0.7.
+
+This functionality is implemented in a new function,
+~org-display-inline-image--width~ which contains the width
+determination logic previously in ~org-display-inline-images~ and the
+new behaviour.
+
+** New options
+*** Option ~org-hidden-keywords~ now also applies to #+SUBTITLE:
+
+The option ~org-hidden-keywords~ previously applied
+to #+TITLE:, #+AUTHOR:, #+DATE:, and #+EMAIL:.  Now it can also be
+used to hide the #+SUBTITLE: keyword.
+
+*** New formatting directive ~%L~ for org-capture
+
+The new ~%L~ formatting directive contains the bare link target, and
+may be used to create links with programmatically generated
+descriptions.
+
+*** New option ~org-id-ts-format~
+
+Earlier, IDs generated using =ts= method had a hard-coded format (i.e. 
=20200923T160237.891616=).
+The new option allows user to customise the format.
+Defaults are unchanged.
+
+*** New argument for ~file-desc~ babel header
+
+It is now possible to provide the =file-desc= header argument for a
+babel source block but omit the description by passing an empty vector
+as an argument (i.e., :file-desc []).  This can be useful because
+providing =file-desc= without an argument results in the result of
+=file= being used in the description.  Previously, the only way to
+omit a file description was to omit the header argument entirely,
+which made it difficult/impossible to provide a default value for
+=file-desc=.
+
+*** New option to set ~org-link-file-path-type~ to a function
+
+~org-link-file-path-type~ can now be set to a function that takes the
+full filename as an argument and returns the path to link to.
+
+For example, if you use ~project.el~, you can set this function to use
+relative links within a project as follows:
+
+#+begin_src emacs-lisp
+(setq (org-link-file-path-type
+       (lambda (path)
+         (let* ((proj (project-current))
+                (root (if proj (project-root proj) default-directory)))
+           (if (string-prefix-p (expand-file-name root) path)
+               (file-relative-name path)
+             (abbreviate-file-name path))))))
+#+end_src
+
+*** New options and new behavior for babel LaTeX SVG image files
+
+Org babel now uses a two-stage process for converting latex source
+blocks to SVG image files (when the extension of the output file is
+~.svg~).  The first stage in the process converts the latex block into
+a PDF file, which is then converted into an SVG file in the second
+stage.  The TeX->PDF part uses the existing infrastructure for
+~org-babel-latex-tex-to-pdf~.  The PDF->SVG part uses a command
+specified in a new customization,
+~org-babel-latex-pdf-svg-process~. By default, this uses inkscape for
+conversion, but since it is fully customizable, any other command can
+be used in its place. For instance, dvisvgm might be used here. This
+two-part processing replaces the previous use of htlatex to process
+LaTeX directly to SVG (htlatex is still used for HTML conversion).
+
+Conversion to SVG exposes a number of additional customizations that
+give the user full control over the contents of the latex source
+block. ~org-babel-latex-preamble~, ~org-babel-latex-begin-env~ and
+~org-babel-latex-end-env~ are new customization options added to allow
+the user to specify the preamble and code that preceedes and proceeds
+the contents of the source block.
+
+*** New option ~org-html-meta-tags~ allows for HTML meta tags customization
+
+New variable ~org-html-meta-tags~ makes it possible to customize the
+=<meta>= tags used in an HTML export.  Accepts either a static list of
+values, or a function that generates such a list (see
+~org-html-meta-tags-default~ as an example of the latter).
+
+*** Option ~org-agenda-bulk-custom-functions~ now supports collecting bulk 
arguments
+
+When specifying a custom agenda bulk option, you can now also specify
+a function which collects the arguments to be used with each call to
+the custom function.
+
+*** New faces to improve the contextuality of Org agenda views
+
+Four new faces improve certain styles and offer more flexibility for
+some Org agenda views: ~org-agenda-date-weekend-today~,
+~org-imminent-deadline~, ~org-agenda-structure-secondary~,
+~org-agenda-structure-filter~.  They inherit from existing faces in
+order to remain backward-compatible.
+
+Quoting from [[https://list.orgmode.org/87lf7q7gpq.fsf@protesilaos.com/][this 
thread]]:
+
+#+begin_quote
++ The 'org-imminent-deadline' is useful to disambiguate generic
+  warnings from deadlines.  For example, a warning could be rendered
+  in a yellow colored text and have a bold weight, whereas a deadline
+  might be red and styled with italics.
+
++ The 'org-agenda-structure-filter' applies to all tag/term filters
+  in agenda views that search for keywords or patterns.  It is
+  designed to inherit from 'org-agenda-structure' in addition to the
+  'org-warning' face that was present before (and removes the
+  generic 'warning' face from one place).  This offers the benefit
+  of consistency, as, say, an increase in font height or a change in
+  font family in 'org-agenda-structure' will propagate to the filter
+  as well.  The whole header line thus looks part of a singular
+  design.
+
++ The 'org-agenda-structure-secondary' complements the above for those
+  same views where a description follows the header.  For instance, the
+  tags view provides information to "Press N r" to filter by a
+  numbered tag.  Themes/users may prefer to disambiguate this line
+  from the header above it, such as by using a less intense color or by
+  reducing its height relative to the 'org-agenda-structure'.
+
++ The 'org-agenda-date-weekend-today' provides the option to
+  differentiate the current date on a weekend from the current date on
+  weekdays.
+#+end_quote
+
+*** New option ~org-clock-ask-before-exiting~
+
+By default, a function is now added to ~kill-emacs-query-functions~
+that asks whether to clock out and save when there's a running clock.
+Customize ~org-clock-ask-before-exiting~~ to nil to disable this new
+behavior.
+
+*** Option ~org-html-inline-image-rules~ now includes .webp
+
+By default ox-html now inlines webp images.
+
+*** ~org-html-head-include-scripts~ is now =nil= by default
+
+See [[msg:498dbe2e-0cd2-c81e-7960-4a26c566a1f7@memebeam.org][this thread]].
+
+*** New option ~org-html-content-class~
+
+This is the CSS class name to use for the top level content wrapper.
+
+*** New option ~org-babel-plantuml-svg-text-to-path~
+
+This option, nil by default, allows to add a SVG-specific post-export
+step that runs inkscape text-to-path replacement over the output file.
+
+*** You can now configure ~org-html-scripts~ and ~org-html-style-default~
+
+~org-html-scripts~ and ~org-html-style-default~ used to be constants,
+you can now configure them.
+
+*** New option ~org-attach-git-dir~
+
+~org-attach-git-dir~ will decide whether to use ~org-attach-git-dir~
+(the default) or use the attachment directory of the current node, if
+it is correctly configured as a Git repository.
+
+*** Some faces now use fixed-pitch
+
+See [[msg:875z8njaol.fsf@protesilaos.com][this thread]].
+
+*** New option ~org-attach-sync-delete-empty-dir~
+
+~org-attach-sync-delete-empty-dir~ controls the deletion of an empty
+attachment directory at calls of ~org-attach-sync~.  There is
+Never delete, Always delete and Query the user (default).
+
+*** ~org-babel-default-header-args~ can now be specified as closures or strings
+
+~org-babel-default-header-args~ now also accepts closures that
+evaluate to a string. Previously, only direct strings were
+supported. These closures are evaluated when point is at the source
+block, which allows them to make use of contextual information at the
+relevant source block. One example that illustrates the usefulness of
+this addition (also given in the documentation for
+~org-babel-default-header-args~) is:
+
+#+begin_src elisp
+(defun org-src-sha ()
+  (let ((elem (org-element-at-point)))
+    (concat (sha1 (org-element-property :value elem)) \".svg\")))
+
+(setq org-babel-default-header-args:latex
+      `((:results . \"file link replace\")
+        (:file . (lambda () (org-src-sha)))))
+#+end_src
+
+This will set the ~:file~ header argument to the sha1 checksum of the
+contents of the current latex source block.
+
+Finally, the closures are only evaluated if they're not overridden for
+a source block. This improves efficiency in cases where the result of
+a compute-expensive closure would otherwise be discarded.
+
+** Miscellaneous
+*** =org-bibtex= includes =doi= and =url= entries when exporting to BiBTeX
+=doi= and =url= entries have been made optional for some publication
+types and will be exported if present for those types.
+*** Missing or empty placeholders in "eval" macros are now =nil=
+They used to be the empty string.
+*** =org-goto-first-child= now works before first heading
+
+When point is before first heading =org-goto-first-child= will move
+point to the first child heading, or return nil if no heading exist
+in buffer.  This is in line with the fact that everything before first
+heading is regarded as outline level 0, i.e. the parent level of all
+headings in the buffer.
+
+Previously =org-goto-first-child= would do nothing before first
+heading, except return nil.
+
+*** Faces of all the heading text elements now conform to the headline face
+
+In the past, faces of todo keywords, emphasised text, tags, and
+priority cookies inherited =default= face.  The resulting headline
+fontification was not always consistent, as discussed in 
[[https://lists.gnu.org/archive/html/emacs-orgmode/2020-09/msg00331.html][this 
bug
+report]].  Now, the relevant faces adapt to face used to fontify the
+current headline level.
+
+Users who prefer to keep the old behaviour should change their face
+customisation explicitly stating that =default= face is inherited.
+
+Example of old face customisation:
+
+#+begin_src emacs-lisp
+(setq org-todo-keyword-faces '(("TODO"
+                                :background "chocolate"
+                                :height 0.75)))
+#+end_src
+
+To preserve the old behaviour the above customisation should be
+changed to
+
+#+begin_src emacs-lisp
+(setq org-todo-keyword-faces '(("TODO"
+                                :inherit default
+                                :background "chocolate"
+                                :height 0.75)))
+#+end_src
+
+*** Storing ID-links before first heading uses title as description
+
+Storing links to files using ~org-store-link~ (=<C-c l>=) when
+~org-id-link-to-org-use-id~ is not nil will now store the title as
+description of the link, if available.  If no title exists it falls
+back to the filename as before.
+
+*** Change in =org-tags-expand= signature
+
+The function does not allow for a third optional parameter anymore.
+*** LaTeX environment =#+results= are now removed
+
+If a babel src block produces a raw LaTeX environment, it will now be
+recognised as a result, and so replaced when re-evaluated.
+
+*** Tag completion now uses =completing-read-multiple=
+
+Tag completion now uses =completing-read-multiple= with a simple
+completion table, which should allow better interoperability with
+custom completion functions.
+
+*** Providing =directory-empty-p= from Emacs 28 as =org-directory-empty-p=
+
+*** =org-get-last-sibling= marked as obsolete
+
+Use =org-get-previous-sibling= instead.  This is just a rename to have
+a more consistent naming.  E.g. recall the pair of funtctions
+=next-line= / =previous-line=.
+
+*** Make org-protocol compatible with =URLSearchParams= JavaScript class
+
+Decoder of query part of org-protocol URI recognizes "+" as an encoded
+space characters now, so it is possible to avoid call to =encodeURIComponent=
+for each parameter and use more readable expression in bookmarklet:
+
+#+begin_example
+'org-protocol://store-link?' + new URLSearchParams({
+      url: location.href, title: document.title})
+#+end_example
+
+*** Remove obsolete LaTeX packages from ~org-latex-default-packages-alist~
+
+The LaTeX packages =grffile= and =textcomp= are redundant, with their
+capabilities being merged into =graphicx= and the LaTeX core
+respectively a while ago.
+
 * Version 9.4
 ** Incompatible changes
 *** Possibly broken internal file links: please check and fix
@@ -101,6 +671,40 @@ Also, ~org-startup-folded~ now defaults to 
~showeverything~.
 
 ** New features
 
+*** =RET= and =C-j= now obey ~electric-indent-mode~
+
+Since Emacs 24.4, ~electric-indent-mode~ is enabled by default.  In
+most major modes, this causes =RET= to reindent the current line and
+indent the new line, and =C-j= to insert a newline without indenting.
+
+Org mode now obeys this minor mode: when ~electric-indent-mode~ is
+enabled, and point is neither in a table nor on a timestamp or a link:
+
+- =RET= (bound to ~org-return~) reindents the current line and indents
+  the new line;
+- =C-j= (bound to the new command ~org-return-and-maybe-indent~)
+  merely inserts a newline.
+
+To get the previous behaviour back, disable ~electric-indent-mode~
+explicitly:
+
+#+begin_src emacs-lisp
+(add-hook 'org-mode-hook (lambda () (electric-indent-local-mode -1)))
+#+end_src
+
+Alternatively, if you wish to keep =RET= as the "smart-return" key,
+but dislike Org's default indentation of sections, you may prefer to
+customize ~org-adapt-indentation~ to either nil or =headline-data=.
+
+*** New allowed value for ~org-adapt-indentation~
+
+~org-adapt-indentation~ now accepts a new value, =headline-data=.
+
+When set to this value, Org will only adapt indentation of headline
+data lines, such as planning/clock lines and property/logbook drawers.
+Also, with this setting, =org-indent-mode= will keep these data lines
+correctly aligned with the headline above.
+
 *** Looping agenda commands over headlines
 
 ~org-agenda-loop-over-headlines-in-active-region~ allows you to loop
@@ -134,15 +738,6 @@ call ~org-toggle-radio-button~.
 You can also add =#+ATTR_ORG: :radio t= right before the list to tell
 Org to use radio buttons for this list only.
 
-*** New allowed value for ~org-adapt-indentation~
-
-~org-adapt-indentation~ now accepts a new value, ='headline-data=.
-
-When set to this value, Org will only adapt indentation of headline
-data lines, such as planning/clock lines and property/logbook drawers.
-Also, with this setting, =org-indent-mode= will keep these data lines
-correctly aligned with the headline above.
-
 *** Numeric priorities are now allowed (up to 65)
 
 You can now set ~org-priority-highest/lowest/default~ to integers to
@@ -212,31 +807,6 @@ can now be inserted with this prefix argument.
 Source code block header argument =:file-mode= can set file
 permissions if =:file= argument is provided.
 
-*** =RET= and =C-j= now obey ~electric-indent-mode~
-
-Since Emacs 24.4, ~electric-indent-mode~ is enabled by default.  In
-most major modes, this causes =RET= to reindent the current line and
-indent the new line, and =C-j= to insert a newline without indenting.
-
-Org mode now obeys this minor mode: when ~electric-indent-mode~ is
-enabled, and point is neither in a table nor on a timestamp or a link:
-
-- =RET= (bound to ~org-return~) reindents the current line and indents
-  the new line;
-- =C-j= (bound to the new command ~org-return-and-maybe-indent~)
-  merely inserts a newline.
-
-To get the previous behaviour back, disable ~electric-indent-mode~
-explicitly:
-
-#+begin_src emacs-lisp
-(add-hook 'org-mode-hook (lambda () (electric-indent-local-mode -1)))
-#+end_src
-
-Alternatively, if you wish to keep =RET= as the "smart-return" key,
-but dislike Org's default indentation of sections, you may prefer to
-customize ~org-adapt-indentation~ to either =nil= or ='headline-data=.
-
 *** =ob-C.el= allows the inclusion of non-system header files
 
 In C and C++ blocks, ~:includes~ arguments that do not start with a
@@ -353,7 +923,7 @@ source buffers are displayed by modifying 
~display-buffer-alist~ or
 *** New option ~org-archive-subtree-save-file-p~
 
 Archiving a subtree used to always save the target archive buffer.
-Commit [[https://code.orgmode.org/bzg/org-mode/commit/b186d1d7][b186d1d7]] 
changed this behavior by always not saving the target
+Commit [[git::b186d1d7][b186d1d7]] changed this behavior by always not saving 
the target
 buffer, because batch archiving from agenda could take too much time.
 
 This new option ~org-archive-subtree-save-file-p~ defaults to the
@@ -380,14 +950,14 @@ The value of a shell script's execution is its exit code. 
 But most
 users expect the results of executing a shell script to be its output,
 not its exit code.
 
-So we introduced this option, that you can set to =nil= if you want
-to stick using ~:results value~ as the implicit header.
+So we introduced this option, that you can set to nil if you want to
+stick using ~:results value~ as the implicit header.
 
 In all Babel libraries, the absence of a ~:results~ header should
 produce the same result than setting ~:results value~, unless there is
 an option to explicitly create an exception.
 
-See 
[[https://orgmode.org/list/CA+A2iZaziAfMeGpBqL6qGrzrWEVvLvC0DUw++T4gCF3NGuW-DQ@mail.gmail.com/][this
 thread]] for more context.
+See 
[[msg:CA+A2iZaziAfMeGpBqL6qGrzrWEVvLvC0DUw++T4gCF3NGuW-DQ@mail.gmail.com][this 
thread]] for more context.
 
 *** New option in ~org-attach-store-link-p~
 
@@ -1197,7 +1767,7 @@ With this output format, create a link to the file 
specified in
 
 #+begin_example
 ,#+begin_src shell :dir "data/tmp" :results link :file "crackzor_1.0.c.gz"
-wget -c "http://ben.akrin.com/crackzor/crackzor_1.0.c.gz";
+wget -c "https://ben.akrin.com/crackzor/crackzor_1.0.c.gz";
 ,#+end_src
 
 ,#+results:
@@ -1537,7 +2107,9 @@ Use "/!" markup when filtering TODO keywords to get only 
not-done TODO
 keywords.
 
 *** ~org-split-string~ returns ~("")~ when called on an empty string
+
 It used to return nil.
+
 *** Removal of =ob-scala.el=
 
 See [[https://github.com/ensime/emacs-scala-mode/issues/114][this github 
issue]].
@@ -1605,7 +2177,8 @@ before this let form.
 
 Creation of a new setting to specify the Cider timeout.  By setting
 the =org-babel-clojure-sync-nrepl-timeout= setting option.  The value
-is in seconds and if set to =nil= then no timeout will occur.
+is in seconds and if set to nil then no timeout will occur.
+
 **** Clojure: new header ~:show-process~
 
 A new block code header has been created for Org Babel that enables
@@ -1648,7 +2221,7 @@ this ~:prologue "fpprintprec: 2; linel: 50;"~ for 
presenting Maxima
 results in a beamer presentation.
 **** PlantUML: add support for header arguments
 
-[[http://plantuml.com/][Plantuml]] source blocks now support the 
[[https://orgmode.org/manual/prologue.html#prologue][~:prologue~]], 
[[https://orgmode.org/manual/epilogue.html#epilogue][~:epilogue~]] and
+[[https://plantuml.com/][Plantuml]] source blocks now support the 
[[https://orgmode.org/manual/prologue.html#prologue][~:prologue~]], 
[[https://orgmode.org/manual/epilogue.html#epilogue][~:epilogue~]] and
 [[https://orgmode.org/manual/var.html#var][~:var~]] header arguments.
 
 **** SQL: new engine added ~sqsh~
@@ -1821,9 +2394,8 @@ removed from Gnus circa September 2010.
 
 *** ~org-agenda-repeating-timestamp-show-all~ is removed.
 
-For an equivalent to a =nil= value, set
-~org-agenda-show-future-repeats~ to nil and
-~org-agenda-prefer-last-repeat~ to =t=.
+For an equivalent to a nil value, set ~org-agenda-show-future-repeats~
+to nil and ~org-agenda-prefer-last-repeat~ to =t=.
 
 *** ~org-gnus-nnimap-query-article-no-from-file~ is removed.
 
@@ -1841,7 +2413,7 @@ equivalent to the removed format string.
 
 *** ~org-enable-table-editor~ is removed.
 
-Setting it to a =nil= value broke some other features (e.g., speed
+Setting it to a nil value broke some other features (e.g., speed
 keys).
 
 *** ~org-export-use-babel~ cannot be set to ~inline-only~
@@ -2284,7 +2856,7 @@ The postgresql engine in a sql code block supports now 
~:dbport~ nd
 
 **** Support for additional plantuml output formats
 
-The support for output formats of [[http://plantuml.com/][plantuml]] has been 
extended to now
+The support for output formats of [[https://plantuml.com/][plantuml]] has been 
extended to now
 include:
 
 All Diagrams:
@@ -2317,7 +2889,7 @@ Alice <-- Bob: another authentication Response
 #+end_src
 
 Please note that *pdf* *does not work out of the box* and needs additional
-setup in addition to plantuml.  See [[http://plantuml.com/pdf.html]] for
+setup in addition to plantuml.  See [[https://plantuml.com/pdf.html]] for
 details and setup information.
 
 *** Rewrite of radio lists
@@ -3447,11 +4019,11 @@ then inline code snippets will be wrapped into the 
formatting string.
 ** New contributed packages
 
 - =ox-bibtex.el= by Nicolas Goaziou :: an utility to handle BibTeX
-     export to both LaTeX and HTML exports.  It uses the 
[[http://www.lri.fr/~filliatr/bibtex2html/][bibtex2html]]
+     export to both LaTeX and HTML exports.  It uses the 
[[https://www.lri.fr/~filliatr/bibtex2html/][bibtex2html]]
      software.
 
 - =org-screenshot.el= by Max Mikhanosha :: an utility to handle
-     screenshots easily from Org, using the external tool 
[[http://freecode.com/projects/scrot][scrot]].
+     screenshots easily from Org, using the external tool 
[[https://freecode.com/projects/scrot][scrot]].
 
 ** Miscellaneous
 
@@ -3602,7 +4174,7 @@ manual for details and check 
[[https://orgmode.org/worg/org-8.0.html][this Worg
 *** ~ox-md.el~ by Nicolas Goaziou
 
     =ox-md.el= allows you to export Org files to Markdown files, using the
-    vanilla [[http://daringfireball.net/projects/markdown/][Markdown syntax]].
+    vanilla [[https://daringfireball.net/projects/markdown/][Markdown syntax]].
 
 *** ~ox-texinfo.el~ by Jonathan Leech-Pepin
 
@@ -3612,14 +4184,14 @@ manual for details and check 
[[https://orgmode.org/worg/org-8.0.html][this Worg
 
 *** ~ob-julia.el~ by G. Jay Kerns
 
-    [[http://julialang.org/][Julia]] is a new programming language.
+    [[https://julialang.org/][Julia]] is a new programming language.
 
     =ob-julia.el= provides Org Babel support for evaluating Julia source
     code.
 
 *** ~ob-mathomatic.el~ by Luis Anaya
 
-    [[http://www.mathomatic.org/][mathomatic]] a portable, command-line, 
educational CAS and calculator
+    [[https://www.mathomatic.org/][mathomatic]] a portable, command-line, 
educational CAS and calculator
     software, written entirely in the C programming language.
 
     ~ob-mathomatic.el~ provides Org Babel support for evaluating mathomatic
@@ -3627,7 +4199,7 @@ manual for details and check 
[[https://orgmode.org/worg/org-8.0.html][this Worg
 
 *** ~ob-tcl.el~ by Luis Anaya
 
-    ~ob-tcl.el~ provides Org Babel support for evaluating 
[[http://www.tcl.tk/][Tcl]] source code.
+    ~ob-tcl.el~ provides Org Babel support for evaluating 
[[https://www.tcl.tk/][Tcl]] source code.
 
 *** ~org-bullets.el~ by Evgeni Sabof
 
@@ -3653,7 +4225,7 @@ manual for details and check 
[[https://orgmode.org/worg/org-8.0.html][this Worg
     presentations.  ~ox-deck.el~ exports Org files to HTML presentations
     using =deck.js=.
 
-    [[http://meyerweb.com/eric/tools/s5/][s5]] is a set of scripts which also 
allows to display HTML pages as
+    [[https://meyerweb.com/eric/tools/s5/][s5]] is a set of scripts which also 
allows to display HTML pages as
     presentations.  ~ox-s5.el~ exports Org files to HTML presentations
     using =s5=.
 
@@ -3760,13 +4332,13 @@ forward and backward.
 
 Now Org will sort this list
 
-: - [[http://abc.org][B]]
-: - [[http://def.org][A]]
+: - [[https://abc.org][B]]
+: - [[https://def.org][A]]
 
 like this:
 
-: - [[http://def.org][A]]
-: - [[http://abc.org][B]]
+: - [[https://def.org][A]]
+: - [[https://abc.org][B]]
 
 by comparing the descriptions, not the links.
 Same when sorting headlines instead of list items.
@@ -4270,8 +4842,8 @@ found here: 
https://orgmode.org/worg/org-tutorials/org-outside-org.html
 
 Here are two screencasts demonstrating Thorsten's tools:
 
-- [[http://youtu.be/nqE6YxlY0rw]["Modern conventions for Emacs Lisp files"]]
-- [[http://www.youtube.com/watch?v%3DII-xYw5VGFM][Exploring Bernt Hansen's 
Org-mode tutorial with 'navi-mode']]
+- [[https://youtu.be/nqE6YxlY0rw]["Modern conventions for Emacs Lisp files"]]
+- [[https://www.youtube.com/watch?v%3DII-xYw5VGFM][Exploring Bernt Hansen's 
Org-mode tutorial with 'navi-mode']]
 
 *** MobileOrg for iOS
 
@@ -4301,7 +4873,7 @@ lines even if `org-use-tag-inheritance' was nil.  The 
default is now
 to *never* display inherited tags in agenda lines, but to /know/ about
 them when the agenda type is listed in 
[[doc::org-agenda-use-tag-inheritance][org-agenda-use-tag-inheritance]].
 
-** New default value nil for 
[[doc::org-agenda-dim-blocked-tasks][org-agenda-dim-blocked-tasks]]
+** New default value =nil= for 
[[doc::org-agenda-dim-blocked-tasks][org-agenda-dim-blocked-tasks]]
 
 Using `nil' as the default value speeds up the agenda generation.  You
 can hit `#' (or `C-u #') in agenda buffers to temporarily dim (or turn
@@ -5130,7 +5702,7 @@ that Calc formulas can operate on them.
 
     The new system has a technically cleaner implementation and more
     possibilities for capturing different types of data.  See
-    
[[https://orgmode.org/list/C46F10DC-DE51-43D4-AFFE-F71E440D1E1F@gmail.com][Carsten's
 announcement]] for more details.
+    [[msg:C46F10DC-DE51-43D4-AFFE-F71E440D1E1F@gmail.com][Carsten's 
announcement]] for more details.
 
     To switch over to the new system:
 
@@ -5261,7 +5833,7 @@ that Calc formulas can operate on them.
 
 **** Modified link escaping
 
-     David Maus worked on `org-link-escape'.  See 
[[https://orgmode.org/list/87k4gysacq.wl%dmaus@ictsoc.de][his message]]:
+     David Maus worked on `org-link-escape'.  See 
[[msg:87k4gysacq.wl%dmaus@ictsoc.de][his message]]:
 
      : Percent escaping is used in Org mode to escape certain characters
      : in links that would either break the parser (e.g. square brackets
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 42d714bf1e..d8d4cf7a17 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -123,98 +123,6 @@ load-path.
 
 * Crash bugs
 
-** Emacs crashes when running in a terminal, if compiled with GCC 4.5.0
-
-This version of GCC is buggy: see
-
-  https://debbugs.gnu.org/6031
-  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43904
-
-You can work around this error in gcc-4.5 by omitting sibling call
-optimization.  To do this, configure Emacs with
-
- ./configure CFLAGS="-g -O2 -fno-optimize-sibling-calls"
-
-** Emacs compiled with GCC 4.6.1 crashes on MS-Windows when C-g is pressed
-
-This is known to happen when Emacs is compiled with MinGW GCC 4.6.1
-with the -O2 option (which is the default in the Windows build).  The
-reason is a bug in MinGW GCC 4.6.1; to work around, either add the
-'-fno-omit-frame-pointer' switch to GCC or compile without
-optimizations ('--no-opt' switch to the configure.bat script).
-
-** Emacs crashes in x-popup-dialog.
-
-This can happen if the dialog widget cannot find the font it wants to
-use.  You can work around the problem by specifying another font with
-an X resource--for example, 'Emacs.dialog*.font: 9x15' (or any font that
-happens to exist on your X server).
-
-** Emacs crashes when you use Bibtex mode.
-
-This happens if your system puts a small limit on stack size.  You can
-prevent the problem by using a suitable shell command (often 'ulimit')
-to raise the stack size limit before you run Emacs.
-
-Patches to raise the stack size limit automatically in 'main'
-(src/emacs.c) on various systems would be greatly appreciated.
-
-** Error message 'Symbol’s value as variable is void: x', followed by
-a segmentation fault and core dump.
-
-This has been tracked to a bug in tar!  People report that tar erroneously
-added a line like this at the beginning of files of Lisp code:
-
-   x FILENAME, N bytes, B tape blocks
-
-If your tar has this problem, install GNU tar--if you can manage to
-untar it :-).
-
-** Emacs can crash when displaying PNG images with transparency.
-
-This is due to a bug introduced in ImageMagick 6.8.2-3.  The bug should
-be fixed in ImageMagick 6.8.3-10.  See <URL:https://debbugs.gnu.org/13867>.
-
-** Crashes when displaying GIF images in Emacs built with version
-libungif-4.1.0 are resolved by using version libungif-4.1.0b1.
-Configure checks for the correct version, but this problem could occur
-if a binary built against a shared libungif is run on a system with an
-older version.
-
-** SVG images may be cropped incorrectly with librsvg 2.45 and below.
-Librsvg 2.46 and above have improved geometry code which Emacs is able
-to take advantage of.
-
-** Emacs aborts inside the function 'tparam1'.
-
-This can happen if Emacs was built without terminfo support, but the
-terminal's capabilities use format that is only supported by terminfo.
-If your system has ncurses installed, this might happen if your
-version of ncurses is broken; upgrading to a newer version of ncurses
-and reconfiguring and rebuilding Emacs should solve this.
-
-All modern systems support terminfo, so even if ncurses is not the
-problem, you should look for a way to configure Emacs so that it uses
-terminfo when built.
-
-** Emacs crashes when using some version of the Exceed X server.
-
-Upgrading to a newer version of Exceed has been reported to prevent
-these crashes.  You should consider switching to a free X server, such
-as Xming or Cygwin/X.
-
-** Emacs crashes with SIGSEGV in XtInitializeWidgetClass.
-
-It crashes on X, but runs fine when called with option "-nw".
-
-This has been observed when Emacs is linked with GNU ld but without passing
-the -z nocombreloc flag.  Emacs normally knows to pass the -z nocombreloc
-flag when needed, so if you come across a situation where the flag is
-necessary but missing, please report it via M-x report-emacs-bug.
-
-On platforms such as Solaris, you can also work around this problem by
-configuring your compiler to use the native linker instead of GNU ld.
-
 ** When Emacs is compiled with Gtk+, closing a display kills Emacs.
 
 There is a long-standing bug in GTK that prevents it from recovering
@@ -270,11 +178,31 @@ The relevant bug report is here:
 A workaround is to set XLIB_SKIP_ARGB_VISUALS=1 in the environment
 before starting Emacs, or run Emacs as root.
 
+** Emacs crashes with SIGTRAP when trying to start a WebKit xwidget.
+
+This could happen if the version of WebKitGTK installed on your system
+is buggy, and errors out trying to start a subprocess through
+Bubblewrap sandboxing.  You can avoid the crash by setting the
+environment variables SNAP, SNAP_NAME and SNAP_REVISION, which will
+make WebKit use GLib to launch subprocesses instead.  For example,
+invoke Emacs like this (where "..." stands for the other command-line
+arguments you intend to pass to Emacs):
+
+  $ SNAP=1 SNAP_NAME=1 SNAP_REVISION=1 emacs ...
+
 ** Emacs crashes when you try to view a file with complex characters.
 
 One possible reason for this could be a bug in the libotf or the
 libm17n-flt/m17n-db libraries Emacs uses for displaying complex
-scripts.  Make sure you have the latest versions of these libraries
+scripts.
+
+The easiest and the recommended way of solving these crashes is to
+build Emacs with HarfBuzz as the shaping engine library instead of
+libm17n-flt.  Building with HarfBuzz is the default since Emacs 27.1.
+
+If you must use libm17n-flt, read on.
+
+Make sure you have the latest versions of these libraries
 installed.  If the problem still persists with the latest released
 versions of these libraries, you can try building these libraries from
 their CVS repository:
@@ -322,6 +250,94 @@ element from LD_LIBRARY_PATH before starting emacs proper.
 Or you could recompile Emacs with an -Wl,-rpath option that
 gives the location of the correct libotf.
 
+** Emacs crashes in x-popup-dialog.
+
+This can happen if the dialog widget cannot find the font it wants to
+use.  You can work around the problem by specifying another font with
+an X resource--for example, 'Emacs.dialog*.font: 9x15' (or any font that
+happens to exist on your X server).
+
+** Emacs crashes when you use Bibtex mode.
+
+This happens if your system puts a small limit on stack size.  You can
+prevent the problem by using a suitable shell command (often 'ulimit')
+to raise the stack size limit before you run Emacs.
+
+Patches to raise the stack size limit automatically in 'main'
+(src/emacs.c) on various systems would be greatly appreciated.
+
+** Error message 'Symbol’s value as variable is void: x', followed by
+a segmentation fault and core dump.
+
+This has been tracked to a bug in tar!  People report that tar erroneously
+added a line like this at the beginning of files of Lisp code:
+
+   x FILENAME, N bytes, B tape blocks
+
+If your tar has this problem, install GNU tar--if you can manage to
+untar it :-).
+
+** Emacs crashes when running in a terminal, if compiled with GCC 4.5.0
+
+This version of GCC is buggy: see
+
+  https://debbugs.gnu.org/6031
+  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43904
+
+You can work around this error in gcc-4.5 by omitting sibling call
+optimization.  To do this, configure Emacs with
+
+ ./configure CFLAGS="-g -O2 -fno-optimize-sibling-calls"
+
+** Emacs compiled with GCC 4.6.1 crashes on MS-Windows when C-g is pressed
+
+This is known to happen when Emacs is compiled with MinGW GCC 4.6.1
+with the -O2 option (which is the default in the Windows build).  The
+reason is a bug in MinGW GCC 4.6.1; to work around, either add the
+'-fno-omit-frame-pointer' switch to GCC or compile without
+optimizations ('--no-opt' switch to the configure.bat script).
+
+** Emacs can crash when displaying PNG images with transparency.
+
+This is due to a bug introduced in ImageMagick 6.8.2-3.  The bug should
+be fixed in ImageMagick 6.8.3-10.  See <URL:https://debbugs.gnu.org/13867>.
+
+** Crashes when displaying GIF images in Emacs built with version
+libungif-4.1.0 are resolved by using version libungif-4.1.0b1.
+Configure checks for the correct version, but this problem could occur
+if a binary built against a shared libungif is run on a system with an
+older version.
+
+** Emacs aborts inside the function 'tparam1'.
+
+This can happen if Emacs was built without terminfo support, but the
+terminal's capabilities use format that is only supported by terminfo.
+If your system has ncurses installed, this might happen if your
+version of ncurses is broken; upgrading to a newer version of ncurses
+and reconfiguring and rebuilding Emacs should solve this.
+
+All modern systems support terminfo, so even if ncurses is not the
+problem, you should look for a way to configure Emacs so that it uses
+terminfo when built.
+
+** Emacs crashes when using some version of the Exceed X server.
+
+Upgrading to a newer version of Exceed has been reported to prevent
+these crashes.  You should consider switching to a free X server, such
+as Xming or Cygwin/X.
+
+** Emacs crashes with SIGSEGV in XtInitializeWidgetClass.
+
+It crashes on X, but runs fine when called with option "-nw".
+
+This has been observed when Emacs is linked with GNU ld but without passing
+the -z nocombreloc flag.  Emacs normally knows to pass the -z nocombreloc
+flag when needed, so if you come across a situation where the flag is
+necessary but missing, please report it via M-x report-emacs-bug.
+
+On platforms such as Solaris, you can also work around this problem by
+configuring your compiler to use the native linker instead of GNU ld.
+
 * Problems when reading or debugging Emacs C code
 
 Because Emacs does not install a copy of its C source code, users
@@ -742,6 +758,11 @@ completed" message that tls.el relies upon, causing 
affected Emacs
 functions to hang.  To work around the problem, use older or newer
 versions of gnutls-cli, or use Emacs's built-in gnutls support.
 
+*** SVG images may be cropped incorrectly with librsvg 2.45 or older.
+
+Librsvg 2.46 and above have improved geometry code which Emacs is able
+to take advantage of.
+
 * Runtime problems related to font handling
 
 ** Characters are displayed as empty boxes or with wrong font under X.
@@ -751,6 +772,18 @@ Try removing or moving aside 
"$XDG_CONFIG_HOME/fontconfig/conf.d" and
 "$XDG_CONFIG_HOME/fontconfig/fonts.conf"
 ($XDG_CONFIG_HOME is treated as "~/.config" if not set)
 
+Running Emacs as
+
+    FC_DEBUG=1024 emacs
+
+will cause fontconfig to output information about which configuration
+files it is reading.  Running Emacs as
+
+    FC_DEBUG=1 emacs
+
+will result in information about the results of fontconfig's font
+matching (including the filename(s) of the resulting fonts).
+
 *** This can occur when two different versions of FontConfig are used.
 For example, XFree86 4.3.0 has one version and Gnome usually comes
 with a newer version.  Emacs compiled with Gtk+ will then use the
@@ -763,7 +796,7 @@ same version of FontConfig as the rest of the system uses.  
For KDE,
 it is sufficient to recompile Qt.
 
 *** Some fonts have a missing glyph and no default character.  This is
-known to occur for character number 160 (no-break space) in some
+known to occur for character number 160 (no-break space, U+A0) in some
 fonts, such as Lucida but Emacs sets the display table for the unibyte
 and Latin-1 version of this character to display a space.
 
@@ -1054,14 +1087,6 @@ The solution is to remove the corresponding lines from 
the appropriate
 'fonts.alias' file, then run 'mkfontdir' in that directory, and then run
 'xset fp rehash'.
 
-** The 'oc-unicode' package doesn't work with Emacs 21.
-
-This package tries to define more private charsets than there are free
-slots now.  The current built-in Unicode support is actually more
-flexible.  (Use option 'utf-translate-cjk-mode' if you need CJK
-support.)  Files encoded as emacs-mule using oc-unicode aren't
-generally read correctly by Emacs 21.
-
 * X runtime problems
 
 ** X keyboard problems
@@ -1105,20 +1130,6 @@ you want to use fcitx with Emacs, you have two choices.  
Toggle fcitx
 by another key (e.g. C-\) by modifying ~/.fcitx/config, or be
 accustomed to use C-@ for 'set-mark-command'.
 
-*** Link-time optimization with clang doesn't work on Fedora 20.
-
-As of May 2014, Fedora 20 has broken LLVMgold.so plugin support in clang
-(tested with clang-3.4-6.fc20) - 'clang --print-file-name=LLVMgold.so'
-prints 'LLVMgold.so' instead of full path to plugin shared library, and
-'clang -flto' is unable to find the plugin with the following error:
-
-/bin/ld: error: /usr/bin/../lib/LLVMgold.so: could not load plugin library:
-/usr/bin/../lib/LLVMgold.so: cannot open shared object file: No such file
-or directory
-
-The only way to avoid this is to build your own clang from source code
-repositories, as described at http://clang.llvm.org/get_started.html.
-
 *** M-SPC seems to be ignored as input.
 
 See if your X server is set up to use this as a command
@@ -1632,6 +1643,13 @@ restart the X server after the monitor configuration has 
been changed.
 
 * Runtime problems on character terminals
 
+*** With X forwarding, mouse highlighting can make Emacs slow.
+
+If you see slow updates when moving the mouse in an Emacs running on a
+remote X server, try this:
+
+    (setq mouse-highlight nil)
+
 ** The meta key does not work on xterm.
 
 Typing M-x rings the terminal bell, and inserts a string like ";120~".
@@ -1942,6 +1960,75 @@ To avoid it, set xterm-extra-capabilities to a value 
other than
 'check' (the default).  See that variable's documentation (in
 term/xterm.el) for more details.
 
+** Incorrect or corrupted display of some Unicode characters
+
+*** Linux console problems with double-width characters
+
+The Linux console declares UTF-8 encoding, but supports only a limited
+number of Unicode characters, and can cause Emacs produce corrupted or
+garbled display with some unusual characters and sequences.  Emacs 28
+and later by default disables 'auto-composition-mode' on this console,
+for that reason, but this might not be enough.  One known problem with
+this console is that zero-width and double-width characters are
+displayed incorrectly (as a single-column characters), and that causes
+the cursor to be out of sync with the actual display.
+
+One way of working around this is to use the display-table feature to
+display the problematic characters as some other, less problematic
+ones.  Here's an example of setting up the standard display table to
+show the U+01F64F PERSON WITH FOLDED HANDS character as a diamond with
+a special face:
+
+  (or standard-display-table
+      (setq standard-display-table (make-display-table)))
+  (aset standard-display-table
+       #x1f64f (vector (make-glyph-code #xFFFD 'escape-glyph)))
+
+Similar setup can be done with any other problematic character.  If
+the console cannot even display the U+FFFD REPLACEMENT CHARACTER, you
+can use some ASCII character instead, like '?'; it will stand out due
+to the 'escape-glyph' face.  The disadvantage of this method is that
+all such characters will look the same on display, and the only way of
+knowing what is the real codepoint in the buffer is to go to the
+character and type "C-u C-x =".
+
+*** Messed-up display on the Kitty text terminal
+
+This terminal has its own peculiar ideas about display of unusual
+characters.  For example, it hides the U+00AD SOFT HYPHEN characters
+on display, which messes up Emacs cursor addressing, since Emacs
+doesn't know these characters are effectively treated as zero-width
+characters.
+
+One way of working around such "hidden" characters is to tell Emacs to
+display them as zero-width:
+
+  (aset glyphless-char-display #xAD 'zero-width)
+
+Another possibility is to use display-table to display SOFT HYPHEN as
+a regular ASCII dash character '-':
+
+  (or standard-display-table
+      (setq standard-display-table (make-display-table)))
+  (aset standard-display-table
+        #xAD (vector (make-glyph-code ?- 'escape-glyph)))
+
+Another workaround is to set 'nobreak-char-ascii-display' to a non-nil
+value, which will cause any non-ASCII space and hyphen characters to
+be displayed as their ASCII counterparts, with a special face.
+
+Kitty also differs from many other character terminals in how it
+handles character compositions.  As one example, Emoji sequences that
+begin with a non-Emoji character and end in U+FE0F VARIATION SELECTOR
+16 should be composed into an Emoji glyph; Kitty assumes that all such
+Emoji glyphs have 2-column width, whereas Emacs and many other text
+terminals display them as 1-column glyphs.  Again, this causes cursor
+addressing to get out of sync and eventually messes up the display.
+
+One possible workaround for problems caused by character composition
+is to turn off 'auto-composition-mode' on Kitty terminals.
+
+
 * Runtime problems specific to individual Unix variants
 
 ** GNU/Linux
@@ -2197,20 +2284,6 @@ are compiling with the system's 'cc' and CFLAGS 
containing '-O5'.  If
 so, you have hit a compiler bug.  Please make sure to re-configure
 Emacs so that it isn't compiled with '-O5'.
 
-*** AIX 4.3.x or 4.4: Compiling fails.
-
-This could happen if you use /bin/c89 as your compiler, instead of
-the default 'cc'.  /bin/c89 treats certain warnings, such as benign
-redefinitions of macros, as errors, and fails the build.  A solution
-is to use the default compiler 'cc'.
-
-*** AIX 4: Some programs fail when run in a Shell buffer
-with an error message like   No terminfo entry for "unknown".
-
-On AIX, many terminal type definitions are not installed by default.
-'unknown' is one of them.  Install the "Special Generic Terminal
-Definitions" to make them defined.
-
 ** Solaris
 
 We list bugs in current versions here.  See also the section on legacy
@@ -2247,7 +2320,7 @@ implementation is only available in UNICOWS.DLL, which 
implements the
 Microsoft Layer for Unicode on Windows 9X, or "MSLU".  This article on
 MSDN:
 
-  http://msdn.microsoft.com/en-us/goglobal/bb688166.aspx
+  
https://web.archive.org/web/20151224032644/https://msdn.microsoft.com/en-us/goglobal/bb688166.aspx
 
 includes a short description of MSLU and a link where it can be
 downloaded.
@@ -2262,13 +2335,6 @@ runtime shared library, distributed with Windows 9X.
 A workaround is to build Emacs with MinGW runtime 3.x (the latest
 version is 3.20).
 
-** addpm fails to run on Windows NT4, complaining about Shell32.dll
-
-This is likely to happen because Shell32.dll shipped with NT4 lacks
-the updates required by Emacs.  Installing Internet Explorer 4 solves
-the problem.  Note that it is NOT enough to install IE6, because doing
-so will not install the Shell32.dll update.
-
 ** A few seconds delay is seen at startup and for many file operations
 
 This happens when the Net Logon service is enabled.  During Emacs
@@ -2314,7 +2380,7 @@ dialogs introduced in Windows 7.  It is explicitly 
described in the
 MSDN documentation of the GetOpenFileName API used by Emacs to pop up
 the file selection dialog.  For the details, see
 
-  
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839%28v=vs.85%29.aspx
+  
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646839%28v=vs.85%29.aspx
 
 The dialog shows the last directory in which the user selected a file
 in a previous invocation of the dialog with the same initial
@@ -2382,15 +2448,6 @@ C:\Users\<UserName>\):
 
 Look for the file 'emacs.lnk' there.
 
-** Windows 95 and networking.
-
-To support server sockets, Emacs loads ws2_32.dll.  If this file is
-missing, all Emacs networking features are disabled.
-
-Old versions of Windows 95 may not have the required DLL.  To use
-Emacs's networking features on Windows 95, you must install the
-"Windows Socket 2" update available from MicroSoft's support Web.
-
 ** Emacs exits with "X protocol error" when run with an X server for 
MS-Windows.
 
 A certain X server for Windows had a bug which caused this.
@@ -2427,11 +2484,6 @@ other) messages while waiting for a system function, 
which popped up
 the menu/dialog, to return the result of the dialog or pop-up menu
 interaction.
 
-** Help text in tooltips does not work on old Windows versions
-
-Windows 95 and Windows NT up to version 4.0 do not support help text
-for menus.  Help text is only available in later versions of Windows.
-
 ** Display problems with ClearType method of smoothing
 
 When "ClearType" method is selected as the "method to smooth edges of
@@ -2656,6 +2708,23 @@ If you do, please send it to bug-gnu-emacs@gnu.org so we 
can list it here.
 
 * Runtime problems specific to macOS
 
+** Error message when opening Emacs on macOS
+
+When opening Emacs, you may see an error message saying something like
+this:
+
+  "Emacs" can't be opened because Apple cannot check it for malicious
+  software. This software needs to be updated. Contact the developer
+  for more information.
+
+The reason is that Apple incorrectly catalogs Emacs as potentially
+malicious software and thus shows this error message.
+
+To avoid this alert, open Finder, go to Applications, control-click
+the Emacs app icon, and then choose Open.  This adds a security
+exception for Emacs and from now on you should be able to open it by
+double-clicking on its icon, like any other app.
+
 ** macOS doesn't come with libxpm, so only XPM3 is supported.
 
 Libxpm is available for macOS as part of the XQuartz project.
@@ -2707,6 +2776,20 @@ above example).
 
 ** Compilation
 
+*** Link-time optimization with clang doesn't work on Fedora 20.
+
+As of May 2014, Fedora 20 has broken LLVMgold.so plugin support in clang
+(tested with clang-3.4-6.fc20) - 'clang --print-file-name=LLVMgold.so'
+prints 'LLVMgold.so' instead of full path to plugin shared library, and
+'clang -flto' is unable to find the plugin with the following error:
+
+/bin/ld: error: /usr/bin/../lib/LLVMgold.so: could not load plugin library:
+/usr/bin/../lib/LLVMgold.so: cannot open shared object file: No such file
+or directory
+
+The only way to avoid this is to build your own clang from source code
+repositories, as described at http://clang.llvm.org/get_started.html.
+
 *** Building Emacs over NFS fails with "Text file busy".
 
 This was reported to happen when building Emacs on a GNU/Linux system
@@ -3019,15 +3102,6 @@ of PURESIZE in puresize.h.
 But in some of the cases listed above, this problem is a consequence
 of something else that is wrong.  Be sure to check and fix the real problem.
 
-*** OpenBSD 4.0 macppc: Segfault during dumping.
-
-The build aborts with signal 11 when the command './temacs --batch
---load loadup bootstrap' tries to load files.el.  A workaround seems
-to be to reduce the level of compiler optimization used during the
-build (from -O2 to -O1).  It is possible this is an OpenBSD
-GCC problem specific to the macppc architecture, possibly only
-occurring with older versions of GCC (e.g. 3.3.5).
-
 *** openSUSE 10.3: Segfault in bcopy during dumping.
 
 This is due to a bug in the bcopy implementation in openSUSE 10.3.
@@ -3182,8 +3256,51 @@ should do.
 pen@lysator.liu.se says (Feb 1998) that the Compose key does work
 if you link with the MIT X11 libraries instead of the Solaris X11 libraries.
 
+** OpenBSD
+
+*** OpenBSD 4.0 macppc: Segfault during dumping.
+
+The build aborts with signal 11 when the command './temacs --batch
+--load loadup bootstrap' tries to load files.el.  A workaround seems
+to be to reduce the level of compiler optimization used during the
+build (from -O2 to -O1).  It is possible this is an OpenBSD
+GCC problem specific to the macppc architecture, possibly only
+occurring with older versions of GCC (e.g. 3.3.5).
+
+** AIX
+
+*** AIX 4.3.x or 4.4: Compiling fails.
+
+This could happen if you use /bin/c89 as your compiler, instead of
+the default 'cc'.  /bin/c89 treats certain warnings, such as benign
+redefinitions of macros, as errors, and fails the build.  A solution
+is to use the default compiler 'cc'.
+
+*** AIX 4: Some programs fail when run in a Shell buffer
+with an error message like   No terminfo entry for "unknown".
+
+On AIX, many terminal type definitions are not installed by default.
+'unknown' is one of them.  Install the "Special Generic Terminal
+Definitions" to make them defined.
+
 ** MS-Windows 95, 98, ME, and NT
 
+*** MS-Windows 95: Networking.
+
+To support server sockets, Emacs loads ws2_32.dll.  If this file is
+missing, all Emacs networking features are disabled.
+
+Old versions of Windows 95 may not have the required DLL.  To use
+Emacs's networking features on Windows 95, you must install the
+"Windows Socket 2" update available from MicroSoft's support Web.
+
+*** MS-Windows NT4: addpm fails to run, complaining about Shell32.dll
+
+This is likely to happen because Shell32.dll shipped with NT4 lacks
+the updates required by Emacs.  Installing Internet Explorer 4 solves
+the problem.  Note that it is NOT enough to install IE6, because doing
+so will not install the Shell32.dll update.
+
 *** MS-Windows NT/95: Problems running Perl under Emacs
 
 'perl -de 0' just hangs when executed in an Emacs subshell.
@@ -3247,6 +3364,11 @@ For Perl 4:
       }
       else {
 
+*** MS-Windows NT/95: Help text in tooltips does not work
+
+Windows 95 and Windows NT up to version 4.0 do not support help text
+for menus.  Help text is only available in later versions of Windows.
+
 *** MS-Windows 95: Alt-f6 does not get through to Emacs.
 
 This character seems to be trapped by the kernel in Windows 95.
diff --git a/etc/TODO b/etc/TODO
index e2d1c19a00..cd06b1ea26 100644
--- a/etc/TODO
+++ b/etc/TODO
@@ -29,99 +29,29 @@ are the ones we consider more important, but these also may 
be
 difficult to fix.  Bugs with severity "minor" may be simpler, but this
 is not always true.
 
-* Speed up Elisp execution
+* High Priority Items
 
-** Speed up function calls
-Change src/bytecode.c so that calls from byte-code functions to byte-code
-functions don't go through Ffuncall/funcall_lambda/exec_byte_code but instead
-stay within exec_byte_code.
-
-** Improve the byte-compiler to recognize immutable bindings
-Recognize immutable (lexical) bindings and get rid of them if they're
-used only once and/or they're bound to a constant expression.
-
-Such things aren't present in hand-written code, but macro expansion and
-defsubst can often end up generating things like
-(funcall (lambda (arg) (body)) actual) which then get optimized to
-(let ((arg actual)) (body)) but should additionally get optimized further
-when 'actual' is a constant/copyable expression.
-
-** Add an "indirect goto" byte-code
-Such a byte-code can be used for local lambda expressions.
-E.g. when you have code like
-
-   (let ((foo (lambda (x) bar)))
-     (dosomething
-      (funcall foo toto)
-      (blabla (funcall foo titi))))
-
-turn those 'funcalls' into jumps and their return into indirect jumps back.
-
-** Compile efficiently local recursive functions
-Similar to the previous point, we should be able to handle something like
-
-   (letrec ((loop () (blabla) (if (toto) (loop))))
-     (loop))
-
-which ideally should generate the same byte-code as
-
-   (while (progn (blabla) (toto)))
-
-* Things that were planned for Emacs-24
+** Things related to elpa.gnu.org.
+We need to figure out how to best include GNU ELPA packages in the
+Emacs tarball before doing any of the items below.
 
-** concurrency
-Including it as an "experimental" compile-time option sounds good.  Of
-course there might still be big questions around "which form of
-concurrency" we'll want.
-
-** better support for dynamic embedded graphics
-I like this idea (my mpc.el code could use it for the volume widget),
-though I wonder if the resulting efficiency will be sufficient.
-
-** Spread Semantic
-
-** Improve the "code snippets" support
-Consolidate skeleton.el, tempo.el, and expand.el (any other?) and then
-advertise/use/improve it.
-
-** Improve VC
-Yes, there's a lot of work to be done there :-(
-
-** Random things that cross my mind right now that I'd like to see
-Some of them from my local hacks, but it's not obvious at all whether
-they'll make it.
-
-*** Prog-mode could/should provide a better fill-paragraph default
-That default should use syntax-tables to recognize string/comment
-boundaries.
-
-*** Provide more completion-at-point-functions
-Make existing in-buffer completion use completion-at-point.
-
-*** "Functional" function-key-map
-It would make it easy to add (and remove) mappings like
-"FOO-mouse-4 -> FOO-scroll-down",   "FOO-tab -> ?\FOO-\t",
-"uppercase -> lowercase", "[fringe KEY...] -> [KEY]",
-"H-FOO -> M-FOO", "C-x C-y FOO -> H-FOO", ...
-
-* Things related to elpa.gnu.org.
-
-** Move idlwave to elpa.gnu.org
+*** Move idlwave to elpa.gnu.org
 Need to sync up the Emacs and external versions.
 See <https://lists.gnu.org/r/emacs-devel/2014-07/msg00008.html>
+<https://debbugs.gnu.org/39992>
 
-** Move Org mode to elpa.gnu.org
+*** Move Org mode to elpa.gnu.org
 See <https://lists.gnu.org/r/emacs-devel/2014-08/msg00300.html>
 <https://lists.gnu.org/r/emacs-devel/2014-11/msg00257.html>
 
-** Move verilog-mode to elpa.gnu.org
+*** Move verilog-mode to elpa.gnu.org
 See <https://lists.gnu.org/r/emacs-devel/2015-02/msg01180.html>
 
-** Move vhdl-mode to elpa.gnu.org
+*** Move vhdl-mode to elpa.gnu.org
 See <https://lists.gnu.org/r/emacs-devel/2015-02/msg01180.html>
 
 * Simple tasks
-These don't require much Emacs knowledge, they are suitable for anyone
+These don't require much Emacs knowledge and are suitable for anyone
 from beginners to experts.
 
 ** Convert modes that use view-mode to be derived from special-mode instead
@@ -143,6 +73,13 @@ things in their .emacs.
 
 ** See if other files can use generated-autoload-file (see eg ps-print)
 
+** Do interactive mode tagging for commands
+Change "(interactive)" to "(interactive nil foo-mode)" for command
+completion purposes.  Pick a major mode or ELisp library, and check
+all interactive commands to see if they are only relevant in one
+particular mode.  This requires care as some commands might be useful
+outside of the mode they were written for.
+
 ** Write more tests
 Pick a fixed bug from the database, write a test case to make sure it
 stays fixed.  Or pick your favorite programming major-mode, and write
@@ -235,6 +172,44 @@ https://lists.gnu.org/r/emacs-devel/2008-08/msg00456.html
 
 * Important features
 
+** Speed up Elisp execution
+
+*** Speed up function calls
+Change src/bytecode.c so that calls from byte-code functions to byte-code
+functions don't go through Ffuncall/funcall_lambda/exec_byte_code but instead
+stay within exec_byte_code.
+
+*** Improve the byte-compiler to recognize immutable bindings
+Recognize immutable (lexical) bindings and get rid of them if they're
+used only once and/or they're bound to a constant expression.
+
+Such things aren't present in hand-written code, but macro expansion and
+defsubst can often end up generating things like
+(funcall (lambda (arg) (body)) actual) which then get optimized to
+(let ((arg actual)) (body)) but should additionally get optimized further
+when 'actual' is a constant/copyable expression.
+
+** Add an "indirect goto" byte-code
+Such a byte-code can be used for local lambda expressions.
+E.g. when you have code like
+
+   (let ((foo (lambda (x) bar)))
+     (dosomething
+      (funcall foo toto)
+      (blabla (funcall foo titi))))
+
+turn those 'funcalls' into jumps and their return into indirect jumps back.
+
+*** Compile efficiently local recursive functions
+Similar to the previous point, we should be able to handle something like
+
+   (letrec ((loop () (blabla) (if (toto) (loop))))
+     (loop))
+
+which ideally should generate the same byte-code as
+
+   (while (progn (blabla) (toto)))
+
 ** "Emacs as word processor"
 https://lists.gnu.org/r/emacs-devel/2013-11/msg00515.html
  rms writes:
@@ -385,39 +360,16 @@ should invoke the 'shape' method.  'hbfont_shape' should 
be extended
 to pass to 'hb_shape_full' the required array of features, as
 mentioned in the above HarfBuzz discussion.
 
+** Concurrency
+Stefan Monnier writes: "Including it as an 'experimental' compile-time
+option sounds good.  Of course there might still be big questions
+around 'which form of concurrency' we'll want."
+
 ** Better support for displaying Emoji
 Emacs is capable of displaying Emoji and some of the Emoji sequences,
 provided that its fontsets are configured with a suitable font.  To
 make this easier out of the box, the following should be done:
 
-*** Populate composition-function-table with Emoji rules
-The Unicode Character Database (UCD) includes several data files that
-define the valid Emoji sequences.  These files should be imported into
-the Emacs tree, and should be converted by some script at Emacs build
-time to Lisp code that populates composition-function-table with the
-corresponding composition rules.
-
-*** Augment the default fontsets with Emoji-capable fonts
-The default fontsets set up by fontest.el should include known free
-fonts that provide good support for displaying Emoji sequences.  In
-addition, the rule that the default face's font is used for symbol and
-punctuation characters, disregarding the fontsets, should be modified
-to exempt Emoji from this rule (since Emoji characters belong to the
-'symbol' script in Emacs), so that use-default-font-for-symbols would
-not have to be tweaked to have Emoji display by default with a capable
-font. (This has now been implemented, but only one font is currently
-considered, please augment the list).
-
-*** Consider changing the default display of Variation Selectors
-Emacs by default displays the Variation Selector (VS) codepoints not
-composed with base characters as hex codes in a box.  The Unicode FAQ
-says that if variation sequences cannot be supported, the VS
-characters should not be shown, leaving just the base character of the
-sequence visible.  This could be handled via glyphless-char-display,
-by changing the entries for VS codepoints to 'zero-width'.  Or we
-could display them as a thin 1-pixel space, as we do with format
-control characters, by using 'thin-space' there.
-
 *** Special face for displaying text presentation of Emoji
 Emoji-capable fonts support Emoji sequences with the U+FE0F VARIATION
 SELECTOR-16 (VS16) for emoji-style display, but usually don't support
@@ -492,6 +444,25 @@ consistency checks that make sure the new code computes 
the same results
 as the old code.  And once that works well, we can remove the old code
 and old fields.
 
+** Implement Unicode-compliant display of "default-ignorable" characters
+See the "Characters Ignored for Display" section of paragraph 5.21 in
+the Unicode Standard for the details.
+
+The implementation would import the data from Unicode UCD file
+DerivedCoreProperties.txt, and provide a minor mode that arranges for
+the characters with the Default_Ignorable_Code_Point (DI) property to
+be hidden on display.  One way of implementing that could be via
+glyphless-char-display-control; that one is global, but maybe there's
+a way of making it buffer-local.  Alternatively, this could be
+implemented in C in the display engine.
+
+An additional aspect of this is the display of U+00AD SOFT HYPHEN as
+invisible except at line boundaries.  Note that this would need to
+support hard (physical) newlines in the buffer as well as soft
+wrapping of long lines under 'visual-line-mode'.  The algorithm for
+selecting the wrap point may also need be changed to break at the soft
+hyphen.
+
 ** FFI (foreign function interface)
 See eg https://lists.gnu.org/r/emacs-devel/2013-10/msg00246.html
 
@@ -662,6 +633,13 @@ could also be a button that you could use to view the 
advice.
 
 ** Add a function to get the insertion-type of the markers in an overlay
 
+** Improve VC
+Yes, there's a lot of work to be done there :-(
+
+** Improve the "code snippets" support
+Consolidate skeleton.el, tempo.el, and expand.el (any other?) and then
+advertise/use/improve it.
+
 ** ange-ftp
 
 *** Make ange-ftp understand sftp
@@ -829,11 +807,6 @@ gametree, page-ext, refbib, refer, scribe, texinfo, 
underline,
 cmacexp, hideif, pcomplete, xml, cvs-status (should be described in
 PCL-CVS manual); other progmodes, probably in separate manual.
 
-** Deprecate and remove XPM icons
-Convert the XPM bitmaps to PPM, replace the PBMs with them and scrap
-the XPMs so that the color versions work generally.  (Requires care
-with the color used for the transparent regions.)
-
 ** Convenient access to the 'values' variable
 It would be nice to have an interface that would show you the printed
 reps of the elements of the list in a menu, let you select one of the
@@ -904,6 +877,25 @@ The idea is to add an "X" of some kind, that when clicked 
deletes the
 window associated with that modeline.
 https://lists.gnu.org/r/emacs-devel/2007-09/msg02416.html
 
+** Random things that were planned for Emacs-24
+
+Stefan Monnier writes: "Random things that cross my mind right now
+that I'd like to see.  Some of them from my local hacks, but it's not
+obvious at all whether they'll make it."
+
+*** Prog-mode could/should provide a better fill-paragraph default
+That default should use syntax-tables to recognize string/comment
+boundaries.
+
+*** Provide more completion-at-point-functions
+Make existing in-buffer completion use completion-at-point.
+
+*** "Functional" function-key-map
+It would make it easy to add (and remove) mappings like
+"FOO-mouse-4 -> FOO-scroll-down",   "FOO-tab -> ?\FOO-\t",
+"uppercase -> lowercase", "[fringe KEY...] -> [KEY]",
+"H-FOO -> M-FOO", "C-x C-y FOO -> H-FOO", ...
+
 * Things to be done for specific packages or features
 
 ** NeXTstep port
@@ -1184,45 +1176,6 @@ Instead, if B has not been customized it should be 
re-initialized
 See the places where we manually call custom-reevaluate-setting,
 such as for mail-host-address and user-mail-address in startup.el.
 
-** ImageMagick support
-
-*** Image priority
-'image-type-header-regexps' prioritizes the jpeg loader over the
-ImageMagick one.  This is not wrong, but how should a user go about
-preferring the ImageMagick loader?  The user might like zooming etc in jpegs.
-
-Try (setq image-type-header-regexps nil) for a quick hack to prefer
-ImageMagick over the jpg loader.
-
-*** Slow display
-For some reason it's unbearably slow to look at a page in a large
-image bundle using the :index feature.  The ImageMagick "display"
-command is also a bit slow, but nowhere near as slow as the Emacs
-code.  It seems ImageMagick tries to unpack every page when loading the
-bundle.  This feature is not the primary usecase in Emacs though.
-
-ImageMagick 6.6.2-9 introduced a bugfix for single page djvu load.  It
-is now much faster to use the :index feature, but still not very fast.
-
-*** Try to cache the num pages calculation
-It can take a while to calculate the number of pages, and if you need
-to do it for each page view, page-flipping becomes uselessly slow.
-
-*** Integrate with image-dired
-
-*** Integrate with docview
-
-*** Integrate with image-mode
-Some work has been done, e.g. "M-x image-transform-fit-to-height" will
-fit the image to the height of the Emacs window.
-
-*** Look for optimizations for handling images with low depth
-Currently the code seems to default to 24 bit RGB which is costly for
-images with lower bit depth.
-
-*** Decide what to do with some uncommitted imagemagick support
-Functions for image size etc.
-
 ** nxml mode
 
 *** High priority
diff --git a/etc/charsets/README b/etc/charsets/README
index 0045a0f638..96cba7c613 100644
--- a/etc/charsets/README
+++ b/etc/charsets/README
@@ -27,7 +27,9 @@ character code separated by a space.  Both code points and 
Unicode
 character codes are in hexadecimal preceded by "0x".  Comments may be
 used, starting with "#".  Code ranges may also be used, with
 (inclusive) start and end code points separated by "-" followed by the
-Unicode of the start of the range
+Unicode of the start of the range.
+Code points for which there's no mapping to Unicode should be skipped,
+i.e. their lines should be omitted.
 
 Examples:
 0xA0 0x00A0  # no-break space
diff --git a/etc/e/README b/etc/e/README
index dd2c8d64e2..1293292a87 100644
--- a/etc/e/README
+++ b/etc/e/README
@@ -1,12 +1,12 @@
-eterm-color.ti is a terminfo source file.  eterm-color is a compiled
-version produced by the terminfo compiler (tic).  The compiled files
-are binary, and depend on the version of tic, but they seem to be
-system-independent and backwardly compatible.  So there should be no
-need to recompile the distributed binary version.  If it is
-necessary, use:
+eterm-color.ti is a terminfo source file.  eterm-color and
+eterm-direct are compiled versions produced by the terminfo compiler
+(tic).  The compiled files are binary, and depend on the version of
+tic, but they seem to be system-independent and backwardly compatible.
+So there should be no need to recompile the distributed binary
+version.  If it is necessary, use:
 
 tic -o ../ ./eterm-color.ti
 
-The compiled file is used by lisp/term.el, so if it is moved term.el
-needs to be changed.  terminfo requires it to be stored in an 'e'
-subdirectory (the first character of the file name).
+The compiled files are used by lisp/term.el, so if they are moved,
+term.el needs to be changed.  terminfo requires them to be stored in
+an 'e' subdirectory (the first character of the file name).
diff --git a/etc/e/eterm-color b/etc/e/eterm-color
index bd3f5003ae..bf44fa0f36 100644
Binary files a/etc/e/eterm-color and b/etc/e/eterm-color differ
diff --git a/etc/e/eterm-color.ti b/etc/e/eterm-color.ti
index a6ef814990..eeb9b0b6e6 100644
--- a/etc/e/eterm-color.ti
+++ b/etc/e/eterm-color.ti
@@ -9,15 +9,16 @@ eterm-color|Emacs term.el terminal emulator 
term-protocol-version 0.96,
 # Any change to this file should be done at the same time with a
 # corresponding change to the TERMCAP environment variable in term.el.
 # Comments in term.el specify where each of these capabilities is implemented.
-       colors#8,
+       colors#256,
        cols#80,
        lines#24,
-       pairs#64,
+       pairs#32767,
        am,
        mir,
        msgr,
        xenl,
        bel=^G,
+       blink=\E[5m,
        bold=\E[1m,
        clear=\E[H\E[J,
        cr=\r,
@@ -31,6 +32,7 @@ eterm-color|Emacs term.el terminal emulator 
term-protocol-version 0.96,
        cup=\E[%i%p1%d;%p2%dH,
        cuu1=\E[A,
        cuu=\E[%p1%dA,
+       dim=\E[2m,
        dch1=\E[P,
        dch=\E[%p1%dP,
        dl1=\E[M,
@@ -60,14 +62,16 @@ eterm-color|Emacs term.el terminal emulator 
term-protocol-version 0.96,
        rc=\E8,
        rev=\E[7m,
        ri=\EM,
+       ritm=\E[23m,
        rmir=\E[4l,
        rmso=\E[27m,
        rmul=\E[24m,
        rs1=\Ec,
        sc=\E7,
-       setab=\E[%p1%{40}%+%dm,
-       setaf=\E[%p1%{30}%+%dm,
+       setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
+       setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
        sgr0=\E[m,
+       sitm=\E[3m,
        smir=\E[4h,
        smul=\E[4m,
        smso=\E[7m,
@@ -76,3 +80,10 @@ eterm-color|Emacs term.el terminal emulator 
term-protocol-version 0.96,
 #      smcup=\E[?47h,
 #      rmcup=\E[?47l,
 #       rs2 may need to be added
+
+eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 
0.96,
+       use=eterm-color,
+       colors#0x1000000,
+       pairs#0x10000,
+       
setab=\E[%?%p1%{8}%<%t4%p1%d%e48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m,
+       
setaf=\E[%?%p1%{8}%<%t3%p1%d%e38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m,
diff --git a/etc/e/eterm-direct b/etc/e/eterm-direct
new file mode 100644
index 0000000000..c113c37136
Binary files /dev/null and b/etc/e/eterm-direct differ
diff --git a/etc/images/README b/etc/images/README
index 9bbe796cc9..561cfff765 100644
--- a/etc/images/README
+++ b/etc/images/README
@@ -68,6 +68,7 @@ Emacs images and their source in the GNOME icons stock/ 
directory:
   bookmark_add.xpm          actions/bookmark_add
   cancel.xpm                slightly modified generic/stock_stop
   connect.xpm               net/stock_connect
+  connect-to-url.xpm        net/stock_connect-to-url
   contact.xpm               net/stock_contact
   data-save.xpm             data/stock_data-save
   delete.xpm                generic/stock_delete
diff --git a/etc/images/connect-to-url.pbm b/etc/images/connect-to-url.pbm
new file mode 100644
index 0000000000..f142349f4a
Binary files /dev/null and b/etc/images/connect-to-url.pbm differ
diff --git a/etc/images/connect-to-url.xpm b/etc/images/connect-to-url.xpm
new file mode 100644
index 0000000000..38fefeaf61
--- /dev/null
+++ b/etc/images/connect-to-url.xpm
@@ -0,0 +1,281 @@
+/* XPM */
+static char *connect_to_url[] = {
+/* columns rows colors chars-per-pixel */
+"24 24 251 2 ",
+"   c black",
+".  c #010101",
+"X  c #000103",
+"o  c #010204",
+"O  c #010305",
+"+  c #020407",
+"@  c #020609",
+"#  c #03070C",
+"$  c #04080D",
+"%  c #0F0F0D",
+"&  c #030A10",
+"*  c #050B10",
+"=  c #060C11",
+"-  c #070D13",
+";  c #070D14",
+":  c #060C15",
+">  c #070E14",
+",  c #0B1824",
+"<  c #0A1B2B",
+"1  c #0A1C2E",
+"2  c #141A20",
+"3  c #161E25",
+"4  c #181E23",
+"5  c #0D2032",
+"6  c #142534",
+"7  c #1F2830",
+"8  c #1D2933",
+"9  c #102438",
+"0  c #272622",
+"q  c #21292F",
+"w  c #272F36",
+"e  c #282F33",
+"r  c #222F3A",
+"t  c #2E3337",
+"y  c #2D373E",
+"u  c #32383C",
+"i  c #33383C",
+"p  c #343A3E",
+"a  c #43423C",
+"s  c #112941",
+"d  c #102A44",
+"f  c #132D47",
+"g  c #192F46",
+"h  c #17314B",
+"j  c #15314F",
+"k  c #163351",
+"l  c #163554",
+"z  c #173554",
+"x  c #1F3A53",
+"c  c #1D3955",
+"v  c #1A3958",
+"b  c #1C3B5B",
+"n  c #1F3C58",
+"m  c #1D3C5C",
+"M  c #1E3E5D",
+"N  c #1F3F5F",
+"B  c #303B44",
+"V  c #313C44",
+"C  c #313D47",
+"Z  c #213C56",
+"A  c #233E57",
+"S  c #1F405F",
+"D  c #374148",
+"F  c #2D4050",
+"G  c #25405B",
+"H  c #25425E",
+"J  c #214262",
+"K  c #244565",
+"L  c #264665",
+"P  c #254666",
+"I  c #2A4967",
+"U  c #284969",
+"Y  c #2A4C6C",
+"T  c #2C4F6F",
+"R  c #33526E",
+"E  c #385269",
+"W  c #2D5070",
+"Q  c #2E5172",
+"!  c #335473",
+"~  c #3F5B75",
+"^  c #3D5F7D",
+"/  c #41494F",
+"(  c #646056",
+")  c #6C685E",
+"_  c #505F6C",
+"`  c #48657C",
+"'  c #556A7A",
+"]  c #5B6C78",
+"[  c #5F6F7B",
+"{  c #5D6F7D",
+"}  c #706C62",
+"|  c #726D63",
+" . c #78756B",
+".. c #7D786E",
+"X. c #60727F",
+"o. c #807D74",
+"O. c #8A857B",
+"+. c #8B877E",
+"@. c #4E6A83",
+"#. c #4A6A86",
+"$. c #4A7090",
+"%. c #587790",
+"&. c #5F7E95",
+"*. c #587B98",
+"=. c #6F7980",
+"-. c #697F8F",
+";. c #66839B",
+":. c #6A879F",
+">. c #708391",
+",. c #728A9A",
+"<. c #748898",
+"1. c #758A99",
+"2. c #7B8F9F",
+"3. c #708DA4",
+"4. c #7990A1",
+"5. c #7292AB",
+"6. c #7691A8",
+"7. c #7693AB",
+"8. c #7B98AE",
+"9. c #7E98AD",
+"0. c #7E9DB3",
+"q. c #7F9EB4",
+"w. c #8C8981",
+"e. c #989389",
+"r. c #A6A29B",
+"t. c #8093A1",
+"y. c #8598A3",
+"u. c #8498A7",
+"i. c #809AAD",
+"p. c #8F9FAA",
+"a. c #899FAE",
+"s. c #819FB5",
+"d. c #86A2B8",
+"f. c #87A5BB",
+"g. c #88A3B8",
+"h. c #89A5BA",
+"j. c #8FABBF",
+"k. c #97A7B1",
+"l. c #90AABE",
+"z. c #91ABBF",
+"x. c #98ACB9",
+"c. c #AAA7A0",
+"v. c #B1ADA4",
+"b. c #B3B1AA",
+"n. c #B7B3AA",
+"m. c #A3B1BC",
+"M. c #A5B1BC",
+"N. c #A9B6BF",
+"B. c #BEBBB5",
+"V. c #C4C2BD",
+"C. c #94AEC1",
+"Z. c #96AEC1",
+"A. c #94AFC2",
+"S. c #95AFC2",
+"D. c #96B0C3",
+"F. c #98B0C3",
+"G. c #9FB5C3",
+"H. c #99B3C6",
+"J. c #98B3C7",
+"K. c #9AB3C6",
+"L. c #9BB4C7",
+"P. c #9FB8CA",
+"I. c #9FB8CB",
+"U. c #A2B8C9",
+"Y. c #A3B9C9",
+"T. c #A0B9CB",
+"R. c #A3BACB",
+"E. c #A0B9CC",
+"W. c #A2BACC",
+"Q. c #A4BDCE",
+"!. c #A6BECF",
+"~. c #B8BEC2",
+"^. c #B8C3CA",
+"/. c #BCC5CB",
+"(. c #BDC8CE",
+"). c #A8C0D1",
+"_. c #AAC0D0",
+"`. c #ABC1D1",
+"'. c #ACC2D3",
+"]. c #AAC5D7",
+"[. c #B4C8D6",
+"{. c #BDCBD5",
+"}. c #B4C9D8",
+"|. c #B6CAD8",
+" X c #B8CBD9",
+".X c #BBCDDB",
+"XX c #B7D0E0",
+"oX c #BDD3E2",
+"OX c #BCD5E5",
+"+X c #CECAC3",
+"@X c #C5D2C8",
+"#X c #C0D2DE",
+"$X c #C4D3DF",
+"%X c #CCD7DE",
+"&X c #D2D8DC",
+"*X c #E1DFDB",
+"=X c #E2E1DD",
+"-X c #C2D3E0",
+";X c #C2D4E1",
+":X c #C5D5E1",
+">X c #C6D6E1",
+",X c #C4D6E2",
+"<X c #C5D6E3",
+"1X c #C6D7E3",
+"2X c #C3D7E4",
+"3X c #C1D7E6",
+"4X c #C7D8E3",
+"5X c #C5D8E5",
+"6X c #C7D9E5",
+"7X c #CBD9E4",
+"8X c #CBDAE5",
+"9X c #CDDAE4",
+"0X c #CCDBE5",
+"qX c #CFDBE5",
+"wX c #CBDCE7",
+"eX c #C0D9E8",
+"rX c #C2DBEA",
+"tX c #C4DAE8",
+"yX c #D0DEE7",
+"uX c #D1DFE8",
+"iX c #D0DFE9",
+"pX c #D0E0EA",
+"aX c #D1E1EB",
+"sX c #D3E1EA",
+"dX c #D4E1E9",
+"fX c #D4E1EA",
+"gX c #D5E2EA",
+"hX c #D4E2EB",
+"jX c #D6E2EB",
+"kX c #D3E2EC",
+"lX c #D8E3EA",
+"zX c #DFE6EB",
+"xX c #D9E4EC",
+"cX c #D9E5ED",
+"vX c #DAE5ED",
+"bX c #DAE6ED",
+"nX c #DCE7EE",
+"mX c #DBE8EF",
+"MX c #DDE8EF",
+"NX c #DFE8EF",
+"BX c #EAE8E3",
+"VX c #EBEAE6",
+"CX c #ECEBE8",
+"ZX c #E9EEEA",
+"AX c #F0EFEC",
+"SX c #F2F0ED",
+"DX c #E1ECF3",
+"FX c #E4EDF3",
+"GX c #E8EFF4",
+"HX c #F0F3F1",
+"JX c None",
+/* pixels */
+"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX",
+"JXJXJXJXJXJXJXJXu D p t i V w JXJXJXJXJXJXJXJXJX",
+"JXJXJXJXJXJXC X./.&XDXGX%X{.m._ r JXJXJXJXJXJXJX",
+"JXJXJXJXJXi /.DXnXnXFXuX7X$X$XjXM.w JXJXJXJXJXJX",
+"JXJXJXJX/ ^.qXbX1XkX5X5X-X;XsXqXjXN.B JXJXJXJXJX",
+"JXJXJXe (.bXMXDXaXtXtX3XoXbXjXsXyX7Xx.q JXJXJXJX",
+"JXJX7 k.jXbXbX5X3XeXrXOXXX1XsXyXwX$X|.4.3 JXJXJX",
+"JXJXX.:XuXjX'.]._.y.    G.sXW.|..X$X[.H.' JXJXJX",
+"JXJXu.$XqXT.H.>.    e.o.  sXwX}.R.R.`.H.1.- JXJX",
+"JX4 a.9.C.h.] a n.V.BXo.        p.!.T.l.4.- JXJX",
+"JX2 F.d.5.7.  =XAXc.BXo.  @X@XZX  !.C.F.@.> JXJX",
+"            o.=XAXc.BXo.        t.U.z.3.Y $ JXJX",
+"BXBXBXBXVXBXBXAXVXO.CXo.  P.C.!.I.J.C.;.L * JXJX",
+"o.o.o.o.o. . .B.b...*X .  $.*.T.J.A.h.Y c @ JXJX",
+"             .w.r.| +X .        1.C.3.L h   JXJX",
+"JXJX6 Q ^ 1.% w.r.| +X .  @X@XHX  h.:.M ,   JXJX",
+"JXJXO x T #.] 0 +.} v.)         -.s.H 9 O JXJXJX",
+"JXJXJX+ n ! i.X.% % e.(   Q Y %.0.&.f O   JXJXJX",
+"JXJXJXJX& A s.8.E A % % A K J R ` g @   JXJXJXJX",
+"JXJXJXJXJX@ C ~ m M J N M b v l < O   JXJXJXJXJX",
+"JXJXJXJXJXJX  : 5 d k z k d 1 &     JXJXJXJXJXJX",
+"JXJXJXJXJXJXJXJX                JXJXJXJXJXJXJXJX",
+"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX",
+"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX"
+};
diff --git a/etc/images/down.svg b/etc/images/down.svg
index e2760427d7..707cd23ea4 100644
--- a/etc/images/down.svg
+++ b/etc/images/down.svg
@@ -25,7 +25,7 @@
   <title id='title8473'>Gnome Symbolic Icons</title>
   <defs id='defs7386'/>
   <g inkscape:groupmode='layer' id='layer10' inkscape:label='ui' 
transform='translate(-152.00586,-952)'>
-    <path inkscape:connector-curvature='0' d='m 166,957 -5.99414,5.99999 L 
154,957 Z' id='path6424' sodipodi:nodetypes='cccc' 
style='fill:#2e3436;fill-opacity:1;stroke:none'/>
+    <path inkscape:connector-curvature='0' d='m 166,957 -5.99414,5.99999 L 
154,957 Z' id='path6424' sodipodi:nodetypes='cccc' 
style='fill-opacity:1;stroke:none'/>
   </g>
   <g inkscape:groupmode='layer' id='layer1' inkscape:label='status' 
transform='translate(-152.00586,-888)'/>
   <g inkscape:groupmode='layer' id='layer11' inkscape:label='legacy' 
transform='translate(-152.00586,-952)'/>
diff --git a/etc/images/left.svg b/etc/images/left.svg
index d6429bc410..893515d2df 100644
--- a/etc/images/left.svg
+++ b/etc/images/left.svg
@@ -25,7 +25,7 @@
   <title id='title8473'>Gnome Symbolic Icons</title>
   <defs id='defs7386'/>
   <g inkscape:groupmode='layer' id='layer10' inkscape:label='ui' 
transform='translate(-92.005848,-951.99999)'>
-    <path inkscape:connector-curvature='0' d='M 103,966 97.00585,959.99999 
103,954 Z' id='path6400' sodipodi:nodetypes='cccc' 
style='fill:#2e3436;fill-opacity:1;stroke:none'/>
+    <path inkscape:connector-curvature='0' d='M 103,966 97.00585,959.99999 
103,954 Z' id='path6400' sodipodi:nodetypes='cccc' 
style='fill-opacity:1;stroke:none'/>
   </g>
   <g inkscape:groupmode='layer' id='layer1' inkscape:label='status' 
transform='translate(-92.005848,-887.99999)'/>
   <g inkscape:groupmode='layer' id='layer11' inkscape:label='legacy' 
transform='translate(-92.005848,-951.99999)'/>
diff --git a/etc/images/right.svg b/etc/images/right.svg
index d58cd36435..6c7d715939 100644
--- a/etc/images/right.svg
+++ b/etc/images/right.svg
@@ -25,7 +25,7 @@
   <title id='title8473'>Gnome Symbolic Icons</title>
   <defs id='defs7386'/>
   <g inkscape:groupmode='layer' id='layer10' inkscape:label='ui' 
transform='translate(-112.00585,-951.99999)'>
-    <path inkscape:connector-curvature='0' d='m 117,966 6.00585,-6.00001 L 
117,954 Z' id='path6412' sodipodi:nodetypes='cccc' 
style='fill:#2e3436;fill-opacity:1;stroke:none'/>
+    <path inkscape:connector-curvature='0' d='m 117,966 6.00585,-6.00001 L 
117,954 Z' id='path6412' sodipodi:nodetypes='cccc' 
style='fill-opacity:1;stroke:none'/>
   </g>
   <g inkscape:groupmode='layer' id='layer1' inkscape:label='status' 
transform='translate(-112.00585,-887.99999)'/>
   <g inkscape:groupmode='layer' id='layer11' inkscape:label='legacy' 
transform='translate(-112.00585,-951.99999)'/>
diff --git a/etc/images/up.svg b/etc/images/up.svg
index 9e1a245be7..e358c29912 100644
--- a/etc/images/up.svg
+++ b/etc/images/up.svg
@@ -25,7 +25,7 @@
   <title id='title8473'>Gnome Symbolic Icons</title>
   <defs id='defs7386'/>
   <g inkscape:groupmode='layer' id='layer10' inkscape:label='ui' 
transform='translate(-132.00585,-952)'>
-    <path inkscape:connector-curvature='0' d='M 146,963 140.00585,956.99999 
134,963 Z' id='path6418' sodipodi:nodetypes='cccc' 
style='fill:#2e3436;fill-opacity:1;stroke:none'/>
+    <path inkscape:connector-curvature='0' d='M 146,963 140.00585,956.99999 
134,963 Z' id='path6418' sodipodi:nodetypes='cccc' 
style='fill-opacity:1;stroke:none'/>
   </g>
   <g inkscape:groupmode='layer' id='layer1' inkscape:label='status' 
transform='translate(-132.00585,-888)'/>
   <g inkscape:groupmode='layer' id='layer11' inkscape:label='legacy' 
transform='translate(-132.00585,-952)'/>
diff --git a/etc/org/csl/README b/etc/org/csl/README
new file mode 100644
index 0000000000..a9212207cc
--- /dev/null
+++ b/etc/org/csl/README
@@ -0,0 +1,10 @@
+These data files are used by Org's oc-csl.el library.
+
+LICENSE INFORMATION
+
+chicago-author-date.csl
+locales-en-US.xml
+
+  Both of these files are part of the Citation Style Language (CSL)
+  project (<https://citationstyles.org/>) and are released under the
+  Creative Commons Attribution-ShareAlike 3.0 Unported license.
diff --git a/etc/org/csl/chicago-author-date.csl 
b/etc/org/csl/chicago-author-date.csl
new file mode 100644
index 0000000000..8c133354b3
--- /dev/null
+++ b/etc/org/csl/chicago-author-date.csl
@@ -0,0 +1,658 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl"; class="in-text" version="1.0" 
demote-non-dropping-particle="display-and-sort" page-range-format="chicago">
+  <info>
+    <title>Chicago Manual of Style 17th edition (author-date)</title>
+    <id>http://www.zotero.org/styles/chicago-author-date</id>
+    <link href="http://www.zotero.org/styles/chicago-author-date"; rel="self"/>
+    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html"; 
rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <contributor>
+      <name>Richard Karnesky</name>
+      <email>karnesky+zotero@gmail.com</email>
+      <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
+    </contributor>
+    <contributor>
+      <name>Andrew Dunning</name>
+      <email>andrew.dunning@utoronto.ca</email>
+      <uri>https://orcid.org/0000-0003-0464-5036</uri>
+    </contributor>
+    <contributor>
+      <name>Matthew Roth</name>
+      <email>matthew.g.roth@yale.edu</email>
+      <uri> https://orcid.org/0000-0001-7902-6331</uri>
+    </contributor>
+    <contributor>
+      <name>Brenton M. Wiernik</name>
+    </contributor>
+    <category citation-format="author-date"/>
+    <category field="generic-base"/>
+    <summary>The author-date variant of the Chicago style</summary>
+    <updated>2018-01-24T12:00:00+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/";>This work 
is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="container-author" form="verb">by</term>
+      <term name="translator" form="verb-short">trans.</term>
+      <term name="editortranslator" form="verb">edited and translated by</term>
+      <term name="translator" form="short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" 
match="none">
+        <group delimiter=". ">
+          <names variable="editor translator" delimiter=". ">
+            <label form="verb" text-case="capitalize-first" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+          <names variable="director" delimiter=". ">
+            <label form="verb" text-case="capitalize-first" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" 
match="any">
+        <group prefix=", " delimiter=", ">
+          <names variable="container-author" delimiter=", ">
+            <label form="verb" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+          <names variable="editor translator" delimiter=", ">
+            <label form="verb" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="first" and="text" sort-separator=", " 
delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="translator">
+    <names variable="translator">
+      <name name-as-sort-order="first" and="text" sort-separator=", " 
delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="recipient">
+    <choose>
+      <if type="personal_communication">
+        <choose>
+          <if variable="genre">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+          <else>
+            <text term="letter" text-case="capitalize-first"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="substitute-title">
+    <choose>
+      <if type="article-magazine article-newspaper review review-book" 
match="any">
+        <text macro="container-title"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="contributors">
+    <group delimiter=". ">
+      <names variable="author">
+        <name and="text" name-as-sort-order="first" sort-separator=", " 
delimiter=", " delimiter-precedes-last="always"/>
+        <label form="short" prefix=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+          <names variable="director"/>
+          <text macro="substitute-title"/>
+          <text macro="title"/>
+        </substitute>
+      </names>
+      <text macro="recipient"/>
+    </group>
+  </macro>
+  <macro name="contributors-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <names variable="director"/>
+        <text macro="substitute-title"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="interviewer">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="archive">
+    <group delimiter=". ">
+      <text variable="archive_location" text-case="capitalize-first"/>
+      <text variable="archive"/>
+      <text variable="archive-place"/>
+    </group>
+  </macro>
+  <macro name="access">
+    <group delimiter=". ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive"/>
+        </if>
+        <else-if type="article-journal bill book chapter legal_case 
legislation motion_picture paper-conference" match="none">
+          <text macro="archive"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if type="webpage post-weblog" match="any">
+          <date variable="issued" form="text"/>
+        </if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed" text-case="capitalize-first"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="https://doi.org/"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="personal_communication" match="none">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture song" 
match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if variable="reviewed-author">
+        <choose>
+          <if variable="reviewed-title">
+            <group delimiter=". ">
+              <text variable="title" text-case="title" quotes="true"/>
+              <group delimiter=", ">
+                <text variable="reviewed-title" text-case="title" 
font-style="italic" prefix="Review of "/>
+                <names variable="reviewed-author">
+                  <label form="verb-short" text-case="lowercase" suffix=" "/>
+                  <name and="text" delimiter=", "/>
+                </names>
+              </group>
+            </group>
+          </if>
+          <else>
+            <group delimiter=", ">
+              <text variable="title" text-case="title" font-style="italic" 
prefix="Review of "/>
+              <names variable="reviewed-author">
+                <label form="verb-short" text-case="lowercase" suffix=" "/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </group>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="legal_case interview patent" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report 
song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=". ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short" strip-periods="true"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" text-case="capitalize-first" prefix=". "/>
+          </else>
+        </choose>
+      </if>
+      <else-if type="chapter entry-dictionary entry-encyclopedia 
paper-conference" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=", ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" prefix=", "/>
+          </else>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal">
+        <choose>
+          <if variable="volume">
+            <text variable="volume" prefix=" "/>
+            <group prefix=" (" suffix=")">
+              <choose>
+                <if variable="issue">
+                  <text variable="issue"/>
+                </if>
+                <else>
+                  <date variable="issued">
+                    <date-part name="month"/>
+                  </date>
+                </else>
+              </choose>
+            </group>
+          </if>
+          <else-if variable="issue">
+            <group delimiter=" " prefix=", ">
+              <text term="issue" form="short"/>
+              <text variable="issue"/>
+              <date variable="issued" prefix="(" suffix=")">
+                <date-part name="month"/>
+              </date>
+            </group>
+          </else-if>
+          <else>
+            <date variable="issued" prefix=", ">
+              <date-part name="month"/>
+            </date>
+          </else>
+        </choose>
+      </if>
+      <else-if type="legal_case">
+        <text variable="volume" prefix=", "/>
+        <text variable="container-title" prefix=" "/>
+        <text variable="page" prefix=" "/>
+      </else-if>
+      <else-if type="bill book graphic legal_case legislation motion_picture 
report song" match="any">
+        <group prefix=". " delimiter=". ">
+          <group>
+            <text term="volume" form="short" text-case="capitalize-first" 
suffix=" "/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group>
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" prefix=" " plural="true"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="chapter entry-dictionary entry-encyclopedia 
paper-conference" match="any">
+        <choose>
+          <if variable="page" match="none">
+            <group prefix=". ">
+              <text term="volume" form="short" text-case="capitalize-first" 
suffix=" "/>
+              <number variable="volume" form="numeric"/>
+            </group>
+          </if>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-chapter">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" 
match="any">
+        <choose>
+          <if variable="page">
+            <group prefix=", ">
+              <text variable="volume" suffix=":"/>
+              <text variable="page"/>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-article">
+    <choose>
+      <if type="article-newspaper">
+        <group prefix=", " delimiter=", ">
+          <group delimiter=" ">
+            <text variable="edition"/>
+            <text term="edition"/>
+          </group>
+          <group>
+            <text term="section" form="short" suffix=" "/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="article-journal">
+        <choose>
+          <if variable="volume issue" match="any">
+            <text variable="page" prefix=": "/>
+          </if>
+          <else>
+            <text variable="page" prefix=", "/>
+          </else>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <choose>
+      <if variable="locator">
+        <choose>
+          <if locator="page" match="none">
+            <choose>
+              <if type="bill book graphic legal_case legislation 
motion_picture report song" match="any">
+                <choose>
+                  <if variable="volume">
+                    <group>
+                      <text term="volume" form="short" suffix=" "/>
+                      <number variable="volume" form="numeric"/>
+                      <label variable="locator" form="short" prefix=", " 
suffix=" "/>
+                    </group>
+                  </if>
+                  <else>
+                    <label variable="locator" form="short" suffix=" "/>
+                  </else>
+                </choose>
+              </if>
+              <else>
+                <label variable="locator" form="short" suffix=" "/>
+              </else>
+            </choose>
+          </if>
+          <else-if type="bill book graphic legal_case legislation 
motion_picture report song" match="any">
+            <number variable="volume" form="numeric" suffix=":"/>
+          </else-if>
+        </choose>
+        <text variable="locator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-prefix">
+    <text term="in" text-case="capitalize-first"/>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="chapter entry-dictionary entry-encyclopedia paper-conference" 
match="any">
+        <text macro="container-prefix" suffix=" "/>
+      </if>
+    </choose>
+    <choose>
+      <if type="webpage">
+        <text variable="container-title" text-case="title"/>
+      </if>
+      <else-if type="legal_case" match="none">
+        <group delimiter=" ">
+          <text variable="container-title" text-case="title" 
font-style="italic"/>
+          <choose>
+            <if type="post-weblog">
+              <text value="(blog)"/>
+            </if>
+          </choose>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if variable="issued">
+        <group delimiter=" ">
+          <date variable="original-date" form="text" date-parts="year" 
prefix="(" suffix=")"/>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+      <else-if variable="status">
+        <text variable="status" text-case="capitalize-first"/>
+      </else-if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-in-text">
+    <choose>
+      <if variable="issued">
+        <group delimiter=" ">
+          <date variable="original-date" form="text" date-parts="year" 
prefix="[" suffix="]"/>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+      <else-if variable="status">
+        <text variable="status"/>
+      </else-if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="day-month">
+    <date variable="issued">
+      <date-part name="month"/>
+      <date-part name="day" prefix=" "/>
+    </date>
+  </macro>
+  <macro name="collection-title">
+    <choose>
+      <if match="none" type="article-journal">
+        <choose>
+          <if match="none" is-numeric="collection-number">
+            <group delimiter=", ">
+              <text variable="collection-title" text-case="title"/>
+              <text variable="collection-number"/>
+            </group>
+          </if>
+          <else>
+            <group delimiter=" ">
+              <text variable="collection-title" text-case="title"/>
+              <text variable="collection-number"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="collection-title-journal">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=" ">
+          <text variable="collection-title"/>
+          <text variable="collection-number"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <group delimiter=" ">
+      <choose>
+        <if variable="genre">
+          <text term="presented at"/>
+        </if>
+        <else>
+          <text term="presented at" text-case="capitalize-first"/>
+        </else>
+      </choose>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="description">
+    <choose>
+      <if variable="interviewer" type="interview" match="any">
+        <group delimiter=". ">
+          <text macro="interviewer"/>
+          <text variable="medium" text-case="capitalize-first"/>
+        </group>
+      </if>
+      <else-if type="patent">
+        <group delimiter=" " prefix=". ">
+          <text variable="authority"/>
+          <text variable="number"/>
+        </group>
+      </else-if>
+      <else>
+        <text variable="medium" text-case="capitalize-first" prefix=". "/>
+      </else>
+    </choose>
+    <choose>
+      <if variable="title" match="none"/>
+      <else-if type="thesis personal_communication speech" match="any"/>
+      <else>
+        <group delimiter=" " prefix=". ">
+          <text variable="genre" text-case="capitalize-first"/>
+          <choose>
+            <if type="report">
+              <text variable="number"/>
+            </if>
+          </choose>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue">
+    <choose>
+      <if type="legal_case">
+        <text variable="authority" prefix=". "/>
+      </if>
+      <else-if type="speech">
+        <group prefix=". " delimiter=", ">
+          <group delimiter=" ">
+            <text variable="genre" text-case="capitalize-first"/>
+            <text macro="event"/>
+          </group>
+          <text variable="event-place"/>
+          <text macro="day-month"/>
+        </group>
+      </else-if>
+      <else-if type="article-newspaper article-magazine 
personal_communication" match="any">
+        <date variable="issued" form="text" prefix=", "/>
+      </else-if>
+      <else-if type="patent">
+        <group delimiter=", " prefix=", ">
+          <group delimiter=" ">
+            <!--Needs Localization-->
+            <text value="filed"/>
+            <date variable="submitted" form="text"/>
+          </group>
+          <group delimiter=" ">
+            <choose>
+              <if variable="issued submitted" match="all">
+                <text term="and"/>
+              </if>
+            </choose>
+            <!--Needs Localization-->
+            <text value="issued"/>
+            <date variable="issued" form="text"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="article-journal" match="any"/>
+      <else>
+        <group prefix=". " delimiter=", ">
+          <choose>
+            <if type="thesis">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text macro="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" 
disambiguate-add-year-suffix="true" disambiguate-add-names="true" 
disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" 
collapse="year" after-collapse-delimiter="; ">
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <choose>
+          <if variable="issued accessed" match="any">
+            <group delimiter=" ">
+              <text macro="contributors-short"/>
+              <text macro="date-in-text"/>
+            </group>
+          </if>
+          <!---comma before forthcoming and n.d.-->
+          <else>
+            <group delimiter=", ">
+              <text macro="contributors-short"/>
+              <text macro="date-in-text"/>
+            </group>
+          </else>
+        </choose>
+        <text macro="point-locators"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" 
subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
+    <sort>
+      <key macro="contributors"/>
+      <key variable="issued"/>
+      <key variable="title"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=". ">
+        <text macro="contributors"/>
+        <text macro="date"/>
+        <text macro="title"/>
+      </group>
+      <text macro="description"/>
+      <text macro="secondary-contributors" prefix=". "/>
+      <text macro="container-title" prefix=". "/>
+      <text macro="container-contributors"/>
+      <text macro="edition"/>
+      <text macro="locators-chapter"/>
+      <text macro="collection-title-journal" prefix=", " suffix=", "/>
+      <text macro="locators"/>
+      <text macro="collection-title" prefix=". "/>
+      <text macro="issue"/>
+      <text macro="locators-article"/>
+      <text macro="access" prefix=". "/>
+    </layout>
+  </bibliography>
+</style>
diff --git a/etc/org/csl/locales-en-US.xml b/etc/org/csl/locales-en-US.xml
new file mode 100644
index 0000000000..be78c5e81f
--- /dev/null
+++ b/etc/org/csl/locales-en-US.xml
@@ -0,0 +1,357 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl"; version="1.0" xml:lang="en-US">
+  <info>
+    <translator>
+      <name>Andrew Dunning</name>
+    </translator>
+    <translator>
+      <name>Sebastian Karcher</name>
+    </translator>
+    <translator>
+      <name>Rintze M. Zelle</name>
+    </translator>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/";>This work 
is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+    <updated>2015-10-10T23:31:02+00:00</updated>
+  </info>
+  <style-options punctuation-in-quote="true"/>
+  <date form="text">
+    <date-part name="month" suffix=" "/>
+    <date-part name="day" suffix=", "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">at</term>
+    <term name="available at">available at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+    <term name="scale">scale</term>
+    <term name="version">version</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- PUNCTUATION -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">”</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+    <term name="page-range-delimiter">–</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal">th</term>
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-11">th</term>
+    <term name="ordinal-12">th</term>
+    <term name="ordinal-13">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>lines</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="number-of-pages">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraphs</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">
+      <single>bk.</single>
+      <multiple>bks.</multiple>
+    </term>
+    <term name="chapter" form="short">
+      <single>chap.</single>
+      <multiple>chaps.</multiple>
+    </term>
+    <term name="column" form="short">
+      <single>col.</single>
+      <multiple>cols.</multiple>
+    </term>
+    <term name="figure" form="short">
+      <single>fig.</single>
+      <multiple>figs.</multiple>
+    </term>
+    <term name="folio" form="short">
+      <single>fol.</single>
+      <multiple>fols.</multiple>
+    </term>
+    <term name="issue" form="short">
+      <single>no.</single>
+      <multiple>nos.</multiple>
+    </term>
+    <term name="line" form="short">
+      <single>l.</single>
+      <multiple>ll.</multiple>
+    </term>
+    <term name="note" form="short">
+      <single>n.</single>
+      <multiple>nn.</multiple>
+    </term>
+    <term name="opus" form="short">
+      <single>op.</single>
+      <multiple>opp.</multiple>
+    </term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="number-of-pages" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">
+      <single>para.</single>
+      <multiple>paras.</multiple>
+    </term>
+    <term name="part" form="short">
+      <single>pt.</single>
+      <multiple>pts.</multiple>
+    </term>
+    <term name="section" form="short">
+      <single>sec.</single>
+      <multiple>secs.</multiple>
+    </term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="director">
+      <single>director</single>
+      <multiple>directors</multiple>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="illustrator">
+      <single>illustrator</single>
+      <multiple>illustrators</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="director" form="short">
+      <single>dir.</single>
+      <multiple>dirs.</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="illustrator" form="short">
+      <single>ill.</single>
+      <multiple>ills.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran.</single>
+      <multiple>trans.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="container-author" form="verb">by</term>
+    <term name="director" form="verb">directed by</term>
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="illustrator" form="verb">illustrated by</term>
+    <term name="interviewer" form="verb">interview by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="reviewed-author" form="verb">by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="director" form="verb-short">dir. by</term>
+    <term name="editor" form="verb-short">ed. by</term>
+    <term name="editorial-director" form="verb-short">ed. by</term>
+    <term name="illustrator" form="verb-short">illus. by</term>
+    <term name="translator" form="verb-short">trans. by</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">January</term>
+    <term name="month-02">February</term>
+    <term name="month-03">March</term>
+    <term name="month-04">April</term>
+    <term name="month-05">May</term>
+    <term name="month-06">June</term>
+    <term name="month-07">July</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">October</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">Mar.</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun.</term>
+    <term name="month-07" form="short">Jul.</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Oct.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
diff --git a/etc/publicsuffix.txt b/etc/publicsuffix.txt
index 986f110b04..5cc95b9000 100644
--- a/etc/publicsuffix.txt
+++ b/etc/publicsuffix.txt
@@ -175,17 +175,21 @@ it.ao
 // aq : https://en.wikipedia.org/wiki/.aq
 aq
 
-// ar : https://nic.ar/nic-argentina/normativa-vigente
+// ar : https://nic.ar/es/nic-argentina/normativa
 ar
+bet.ar
 com.ar
+coop.ar
 edu.ar
 gob.ar
 gov.ar
 int.ar
 mil.ar
 musica.ar
+mutual.ar
 net.ar
 org.ar
+senasa.ar
 tur.ar
 
 // arpa : https://en.wikipedia.org/wiki/.arpa
@@ -838,7 +842,13 @@ gov.cu
 inf.cu
 
 // cv : https://en.wikipedia.org/wiki/.cv
+// cv : 
http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100);
 <- registration rules
 cv
+com.cv
+edu.cv
+int.cv
+nome.cv
+org.cv
 
 // cw : http://www.una.cw/cw_registry/
 // Confirmed by registry <registry@una.net> 2013-03-26
@@ -1175,6 +1185,7 @@ org.gu
 web.gu
 
 // gw : https://en.wikipedia.org/wiki/.gw
+// gw : https://nic.gw/regras/
 gw
 
 // gy : https://en.wikipedia.org/wiki/.gy
@@ -5849,7 +5860,7 @@ com.ps
 org.ps
 net.ps
 
-// pt : http://online.dns.pt/dns/start_dns
+// pt : 
https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/
 pt
 net.pt
 gov.pt
@@ -6202,29 +6213,22 @@ gov.tm
 mil.tm
 edu.tm
 
-// tn : https://en.wikipedia.org/wiki/.tn
-// http://whois.ati.tn/
+// tn : http://www.registre.tn/fr/
+// https://whois.ati.tn/
 tn
 com.tn
 ens.tn
 fin.tn
 gov.tn
 ind.tn
+info.tn
 intl.tn
+mincom.tn
 nat.tn
 net.tn
 org.tn
-info.tn
 perso.tn
 tourism.tn
-edunet.tn
-rnrt.tn
-rns.tn
-rnu.tn
-mincom.tn
-agrinet.tn
-defense.tn
-turen.tn
 
 // to : https://en.wikipedia.org/wiki/.to
 // Submitted by registry <egullich@colo.to>
@@ -7128,7 +7132,7 @@ org.zw
 
 // newGTLDs
 
-// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2021-08-19T15:13:52Z
+// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2021-10-08T15:12:46Z
 // This list is auto-generated, don't edit it manually.
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -8018,7 +8022,7 @@ duck
 // dunlop : 2015-07-02 The Goodyear Tire & Rubber Company
 dunlop
 
-// dupont : 2015-06-25 E. I. du Pont de Nemours and Company
+// dupont : 2015-06-25 DuPont Specialty Products USA, LLC
 dupont
 
 // durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
@@ -9452,9 +9456,6 @@ quebec
 // quest : 2015-03-26 XYZ.COM LLC
 quest
 
-// qvc : 2015-07-30 QVC, Inc.
-qvc
-
 // racing : 2014-12-04 Premier Registry Limited
 racing
 
@@ -9554,9 +9555,6 @@ rio
 // rip : 2014-07-10 Dog Beach, LLC
 rip
 
-// rmit : 2015-11-19 Royal Melbourne Institute of Technology
-rmit
-
 // rocher : 2014-12-18 Ferrero Trading Lux S.A.
 rocher
 
@@ -9902,9 +9900,6 @@ suzuki
 // swatch : 2015-01-08 The Swatch Group Ltd
 swatch
 
-// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited
-swiftcover
-
 // swiss : 2014-10-16 Swiss Confederation
 swiss
 
@@ -10334,7 +10329,7 @@ xin
 // xn--45q11c : 2013-11-21 Zodiac Gemini Ltd
 八卦
 
-// xn--4gbrim : 2013-10-04 Fans TLD Limited
+// xn--4gbrim : 2013-10-04 Helium TLDs Ltd
 موقع
 
 // xn--55qw42g : 2013-11-08 China Organizational Name Administration Center
@@ -10803,6 +10798,10 @@ tele.amune.org
 // Submitted by Apigee Security Team <security@apigee.com>
 apigee.io
 
+// Apphud : https://apphud.com
+// Submitted by Alexander Selivanov <alex@apphud.com>
+siiites.com
+
 // Appspace : https://www.appspace.com
 // Submitted by Appspace Security Team <security@appspace.com>
 appspacehosted.com
@@ -11054,10 +11053,6 @@ clerkstage.app
 *.stg.dev
 *.stgstage.dev
 
-// Clic2000 : https://clic2000.fr
-// Submitted by Mathilde Blanchemanche <mathilde@clic2000.fr>
-clic2000.net
-
 // ClickRising : https://clickrising.com/
 // Submitted by Umut Gumeli <infrastructure-publicsuffixlist@clickrising.com>
 clickrising.net
@@ -11611,10 +11606,14 @@ ddnss.org
 definima.net
 definima.io
 
-// DigitalOcean : https://digitalocean.com/
-// Submitted by Braxton Huggins <bhuggins@digitalocean.com>
+// DigitalOcean App Platform : 
https://www.digitalocean.com/products/app-platform/
+// Submitted by Braxton Huggins <psl-maintainers@digitalocean.com>
 ondigitalocean.app
 
+// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/
+// Submitted by Robin H. Johnson <psl-maintainers@digitalocean.com>
+*.digitaloceanspaces.com
+
 // dnstrace.pro : https://dnstrace.pro/
 // Submitted by Chris Partridge <chris@partridge.tech>
 bci.dnstrace.pro
@@ -11677,10 +11676,6 @@ tuleap-partners.com
 onred.one
 staging.onred.one
 
-// One.com: https://www.one.com/
-// Submitted by Jacob Bunk Nielsen <jbn@one.com>
-service.one
-
 // EU.org https://eu.org/
 // Submitted by Pierre Beyssac <hostmaster@eu.org>
 eu.org
@@ -12079,6 +12074,7 @@ withyoutube.com
 *.gateway.dev
 cloud.goog
 translate.goog
+*.usercontent.goog
 cloudfunctions.net
 blogspot.ae
 blogspot.al
@@ -12521,6 +12517,7 @@ linkyard-cloud.ch
 members.linode.com
 *.nodebalancer.linode.com
 *.linodeobjects.com
+ip.linodeusercontent.com
 
 // LiquidNet Ltd : http://www.liquidnetlimited.com/
 // Submitted by Victor Velchev <admin@liquidnetlimited.com>
@@ -12730,10 +12727,6 @@ that.win
 from.work
 to.work
 
-// NCTU.ME : https://nctu.me/
-// Submitted by Tocknicsu <admin@nctu.me>
-nctu.me
-
 // Netlify : https://www.netlify.com
 // Submitted by Jessica Parsons <jessica@netlify.com>
 netlify.app
@@ -12926,6 +12919,10 @@ cloudycluster.net
 // Submitted by Vicary Archangel <vicary@omniwe.com>
 omniwe.site
 
+// One.com: https://www.one.com/
+// Submitted by Jacob Bunk Nielsen <jbn@one.com>
+service.one
+
 // One Fold Media : http://www.onefoldmedia.com/
 // Submitted by Eddie Jones <eddie@onefoldmedia.com>
 nid.io
@@ -13066,6 +13063,10 @@ pstmn.io
 mock.pstmn.io
 httpbin.org
 
+//prequalifyme.today : https://prequalifyme.today
+//Submitted by DeepakTiwari deepak@ivylead.io
+prequalifyme.today
+
 // prgmr.com : https://prgmr.com/
 // Submitted by Sarah Newman <owner@prgmr.com>
 xen.prgmr.com
@@ -13116,6 +13117,10 @@ qbuser.com
 // Submitted by Scott Claeys <s.claeys@radwebhosting.com>
 cloudsite.builders
 
+// Redgate Software: https://red-gate.com
+// Submitted by Andrew Farries <andrew.farries@red-gate.com>
+instances.spawn.cc
+
 // Redstar Consultants : https://www.redstarconsultants.com/
 // Submitted by Jons Slemmer <jons@redstarconsultants.com>
 instantcloud.cn
@@ -13472,6 +13477,11 @@ tabitorder.co.il
 // Submitted by Bjoern Henke <dev-server@taifun-software.de>
 taifun-dns.de
 
+// Tailscale Inc. : https://www.tailscale.com
+// Submitted by David Anderson <danderson@tailscale.com>
+beta.tailscale.net
+ts.net
+
 // TASK geographical domains (www.task.gda.pl/uslugi/dns)
 gda.pl
 gdansk.pl
@@ -13507,6 +13517,10 @@ reservd.dev.thingdust.io
 reservd.disrec.thingdust.io
 reservd.testing.thingdust.io
 
+// ticket i/O GmbH : https://ticket.io
+// Submitted by Christian Franke <it@ticket.io>
+tickets.io
+
 // Tlon.io : https://tlon.io
 // Submitted by Mark Staarink <mark@tlon.io>
 arvo.network
@@ -13592,6 +13606,10 @@ inc.hk
 virtualuser.de
 virtual-user.de
 
+// Upli : https://upli.io
+// Submitted by Lenny Bakkalian <lenny.bakkalian@gmail.com>
+upli.io
+
 // urown.net : https://urown.net
 // Submitted by Hostmaster <hostmaster@urown.net>
 urown.cloud
@@ -13740,7 +13758,7 @@ wpenginepowered.com
 js.wpenginepowered.com
 
 // Wix.com, Inc. : https://www.wix.com
-// Submitted by Shahar Talmi <shahart@wix.com>
+// Submitted by Shahar Talmi <shahar@wix.com>
 wixsite.com
 editorx.io
 
diff --git a/etc/refcards/README b/etc/refcards/README
index 30c82bc714..4102c85ba1 100644
--- a/etc/refcards/README
+++ b/etc/refcards/README
@@ -5,7 +5,7 @@ See the end of the file for license conditions.
 REFERENCE CARDS FOR GNU EMACS
 
 To generate these refcards, you need to install the TeX document
-production system.  For example, <http://www.tug.org/texlive/>.
+production system.  For example, <https://www.tug.org/texlive/>.
 
 All modern GNU/Linux distributions provide TeX packages, so the
 easiest way is just to install those.  Your distribution may have
@@ -23,6 +23,51 @@ PDF and PS copies of these cards are also available at
 <https://www.gnu.org/software/emacs/refcards>.  The FSF online
 store <https://shop.fsf.org/> sometimes has printed copies for sale.
 
+List of generated cards:
+
+    calccard.pdf           Calc Reference Card
+    dired-ref.pdf          Dired Reference Card
+    gnus-booklet.pdf       Gnus Reference Booklet
+    gnus-refcard.pdf       Gnus Reference Card
+    orgcard.pdf            Org-Mode Reference Card
+    refcard.pdf            Emacs Reference Card
+    survival.pdf           Emacs Survival Card
+    vipcard.pdf            VIP Quick Reference Card
+    viperCard.pdf          ViperCard: Viper Reference Pal
+
+Brazilian Portuguese
+
+    pt-br-refcard.pdf      Reference Card (pt-br)
+
+Czech
+
+    cs-dired-ref.pdf       Dired Reference Card (cs)
+    cs-refcard.pdf         Emacs Reference Card (cs)
+    cs-survival.pdf        Emacs Survival Card (cs)
+
+French
+
+    fr-dired-ref.pdf       Dired Reference Card (fr)
+    fr-refcard.pdf         Emacs Reference Card (fr)
+    fr-survival.pdf        Emacs Survival Card (fr)
+
+German
+
+    de-refcard.pdf         Emacs Reference Card (de)
+
+Polish
+
+    pl-refcard.pdf         Emacs Reference Card (pl)
+
+Russian
+
+    ru-refcard.pdf         Emacs Reference Card (ru)
+
+Slovak
+
+    sk-dired-ref.pdf       Dired Reference Card (sk)
+    sk-refcard.pdf         Emacs Reference Card (sk)
+    sk-survival.pdf        Emacs Survival Card (sk)
 
 
 COPYRIGHT AND LICENSE INFORMATION FOR IMAGE FILES
diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex
index dc28587b47..d3715948d6 100644
--- a/etc/refcards/orgcard.tex
+++ b/etc/refcards/orgcard.tex
@@ -1,6 +1,6 @@
 % Reference Card for Org Mode
-\def\orgversionnumber{9.4.2}
-\def\versionyear{2019}          % latest update
+\def\orgversionnumber{9.5}
+\def\versionyear{2021}          % latest update
 \input emacsver.tex
 
 %**start of header
diff --git a/etc/refcards/ru-refcard.tex b/etc/refcards/ru-refcard.tex
index 179be0af88..018be36eb4 100644
--- a/etc/refcards/ru-refcard.tex
+++ b/etc/refcards/ru-refcard.tex
@@ -40,7 +40,7 @@
 \newlength{\ColThreeWidth}
 \setlength{\ColThreeWidth}{25mm}
 
-\newcommand{\versionemacs}[0]{28} % version of Emacs this is for
+\newcommand{\versionemacs}[0]{29} % version of Emacs this is for
 \newcommand{\cyear}[0]{2021}       % copyright year
 
 \newcommand\shortcopyrightnotice[0]{\vskip 1ex plus 2 fill
diff --git a/etc/themes/adwaita-theme.el b/etc/themes/adwaita-theme.el
index c98bec6cfa..7d297df526 100644
--- a/etc/themes/adwaita-theme.el
+++ b/etc/themes/adwaita-theme.el
@@ -96,6 +96,9 @@ default look of the Gnome 3 desktop.")
    `(gnus-cite-1 ((,class (:foreground "#00578E"))))
    `(gnus-cite-2 ((,class (:foreground "#0084C8"))))
 
+   `(image-dired-thumb-mark ((,class (:background "#CE5C00"))))
+   `(image-dired-thumb-flagged ((,class (:background "#B50000"))))
+
    `(diff-added ((,class (:bold t :foreground "#4E9A06"))))
    `(diff-removed ((,class (:bold t :foreground "#F5666D"))))))
 
diff --git a/etc/themes/deeper-blue-theme.el b/etc/themes/deeper-blue-theme.el
index cfe8a5bfb2..5895693386 100644
--- a/etc/themes/deeper-blue-theme.el
+++ b/etc/themes/deeper-blue-theme.el
@@ -82,6 +82,8 @@
    `(ido-first-match ((,class (:weight normal :foreground "orange"))))
    `(ido-only-match ((,class (:foreground "green"))))
    `(ido-subdir ((,class (:foreground nil :inherit font-lock-keyword-face))))
+   `(image-dired-thumb-flagged ((,class (:background "Red1"))))
+   `(image-dired-thumb-mark ((,class (:background "dodgerblue3"))))
    `(info-header-node ((,class (:foreground "DeepSkyBlue1"))))
    `(info-header-xref ((,class (:foreground "SeaGreen2"))))
    `(info-menu-header ((,class (:family "helv" :weight bold))))
diff --git a/etc/themes/dichromacy-theme.el b/etc/themes/dichromacy-theme.el
index 09f4454f9b..148ebd434c 100644
--- a/etc/themes/dichromacy-theme.el
+++ b/etc/themes/dichromacy-theme.el
@@ -101,6 +101,9 @@ Ansi-Color faces are included.")
    `(gnus-header-subject ((,class (:foreground ,orange))))
    `(gnus-header-name ((,class (:foreground ,skyblue))))
    `(gnus-header-newsgroups ((,class (:foreground ,vermillion))))
+   ;; Image-Dired
+   `(image-dired-thumb-flagged ((,class (:background ,vermillion))))
+   `(image-dired-thumb-mark ((,class (:background ,orange))))
    ;; Message faces
    `(message-header-name ((,class (:foreground ,skyblue))))
    `(message-header-cc ((,class (:foreground ,vermillion))))
@@ -113,12 +116,34 @@ Ansi-Color faces are included.")
    `(flyspell-duplicate ((,class (:weight unspecified :foreground unspecified
                                  :slant unspecified :underline ,orange))))
    `(flyspell-incorrect ((,class (:weight unspecified :foreground unspecified
-                                 :slant unspecified :underline ,redpurple)))))
-
-  (custom-theme-set-variables
-   'dichromacy
-   `(ansi-color-names-vector ["black" ,vermillion ,bluegreen ,yellow
-                             ,blue ,redpurple ,skyblue "white"])))
+                                 :slant unspecified :underline ,redpurple))))
+   ;; ANSI color
+   `(ansi-color-black ((,class (:background "black" :foreground "black"))))
+   `(ansi-color-red ((,class (:background ,vermillion
+                             :foreground ,vermillion))))
+   `(ansi-color-green ((,class (:background ,bluegreen
+                               :foreground ,bluegreen))))
+   `(ansi-color-yellow ((,class (:background ,yellow :foreground ,yellow))))
+   `(ansi-color-blue ((,class (:background ,blue :foreground ,blue))))
+   `(ansi-color-magenta ((,class (:background ,redpurple
+                                 :foreground ,redpurple))))
+   `(ansi-color-cyan ((,class (:background ,skyblue :foreground ,skyblue))))
+   `(ansi-color-white ((,class (:background "gray90" :foreground "gray90"))))
+   `(ansi-color-bright-black ((,class (:background "black"
+                                      :foreground "black"))))
+   `(ansi-color-bright-red ((,class (:background ,vermillion
+                                    :foreground ,vermillion))))
+   `(ansi-color-bright-green ((,class (:background ,bluegreen
+                                      :foreground ,bluegreen))))
+   `(ansi-color-bright-yellow ((,class (:background ,yellow
+                                       :foreground ,yellow))))
+   `(ansi-color-bright-blue ((,class (:background ,blue :foreground ,blue))))
+   `(ansi-color-bright-magenta ((,class (:background ,redpurple
+                                        :foreground ,redpurple))))
+   `(ansi-color-bright-cyan ((,class (:background ,skyblue
+                                     :foreground ,skyblue))))
+   `(ansi-color-bright-white ((,class (:background "gray90"
+                                      :foreground "gray90"))))))
 
 (provide-theme 'dichromacy)
 
diff --git a/etc/themes/leuven-theme.el b/etc/themes/leuven-theme.el
index f643dd560c..514384ca2a 100644
--- a/etc/themes/leuven-theme.el
+++ b/etc/themes/leuven-theme.el
@@ -287,6 +287,25 @@ more...")
    `(message-header-xheader ((,class ,mail-header-other)))
    `(message-mml ((,class (:foreground "forest green"))))
 
+   ;; ANSI colors.
+   `(ansi-color-bold ((,class (:weight bold))))
+   `(ansi-color-black ((,class (:foreground "black" :background "black"))))
+   `(ansi-color-red ((,class (:foreground "red3" :background "red3"))))
+   `(ansi-color-green ((,class (:foreground "forest green" :background "forest 
green"))))
+   `(ansi-color-yellow ((,class (:foreground "yellow3" :background 
"yellow3"))))
+   `(ansi-color-blue ((,class (:foreground "blue" :background "blue"))))
+   `(ansi-color-magenta ((,class (:foreground "magenta3" :background 
"magenta3"))))
+   `(ansi-color-cyan ((,class (:foreground "deep sky blue" :background "deep 
sky blue"))))
+   `(ansi-color-white ((,class (:foreground "gray60" :background "gray60"))))
+   `(ansi-color-bright-black ((,class (:foreground "gray30" :background 
"gray30"))))
+   `(ansi-color-bright-red ((,class (:foreground "red1" :background "red1"))))
+   `(ansi-color-bright-green ((,class (:foreground "lime green" :background 
"lime green"))))
+   `(ansi-color-bright-yellow ((,class (:foreground "yellow2" :background 
"yellow2"))))
+   `(ansi-color-bright-blue ((,class (:foreground "dodger blue" :background 
"dodger blue"))))
+   `(ansi-color-bright-magenta ((,class (:foreground "magenta" :background 
"magenta"))))
+   `(ansi-color-bright-cyan ((,class (:foreground "sky blue" :background "sky 
blue"))))
+   `(ansi-color-bright-white ((,class (:foreground "gray80" :background 
"gray80"))))
+
    ;; Diff.
    `(diff-added ((,class ,diff-added)))
    `(diff-changed ((,class ,diff-changed)))
@@ -613,6 +632,8 @@ more...")
    `(ilog-echo-face ((,class (:height 2.0 :foreground "#006FE0"))))
    `(ilog-load-face ((,class (:foreground "#BA36A5"))))
    `(ilog-message-face ((,class (:foreground "#808080"))))
+   `(image-dired-thumb-flagged ((,class (:background "red"))))
+   `(image-dired-thumb-mark ((,class :background "#FFAAAA")))
    `(indent-guide-face ((,class (:foreground "#D3D3D3"))))
    `(info-file ((,class (:family "Sans Serif" :height 1.8 :weight bold :box 
(:line-width 1 :color "#0000CC") :foreground "cornflower blue" :background 
"LightSteelBlue1"))))
    `(info-header-node ((,class (:underline t :foreground "orange")))) ; nodes 
in header
@@ -1035,12 +1056,6 @@ more...")
   ;; highlight-sexp-mode.
   '(hl-sexp-background-color "#efebe9")
 
-  '(ansi-color-faces-vector
-    [default default default italic underline success warning error])
-
-  ;; Colors used in Shell mode.
-  '(ansi-color-names-vector
-    ["black" "red3" "ForestGreen" "yellow3" "blue" "magenta3" "DeepSkyBlue" 
"gray50"])
  )
 
 ;;;###autoload
diff --git a/etc/themes/light-blue-theme.el b/etc/themes/light-blue-theme.el
index 62528856da..547d2df04c 100644
--- a/etc/themes/light-blue-theme.el
+++ b/etc/themes/light-blue-theme.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
 ;; Author: Drew Adams <drew.adams@oracle.com>
+;; Maintainer: emacs-devel@gnu.org
 
 ;; This file is part of GNU Emacs.
 
@@ -28,6 +29,8 @@
 (deftheme light-blue
   "Face colors utilizing a light blue background.")
 
+(make-obsolete 'light-blue nil "29.1")
+
 (let ((class '((class color) (min-colors 89))))
   (custom-theme-set-faces
    'light-blue
diff --git a/etc/themes/manoj-dark-theme.el b/etc/themes/manoj-dark-theme.el
index 0e5fb39119..f10b88507e 100644
--- a/etc/themes/manoj-dark-theme.el
+++ b/etc/themes/manoj-dark-theme.el
@@ -221,6 +221,9 @@ jarring angry fruit salad look to reduce eye fatigue.")
  '(gnus-group-news-low-empty ((t (:foreground "DarkTurquoise"))))
  '(gnus-group-news-low-empty-face ((t (:foreground "DarkTurquoise"))))
 
+ ;; '(image-dired-thumb-flagged ((t (:background "red"))))
+ ;; '(image-dired-thumb-mark ((t (:background "Pink"))))
+
  ;;message faces
  '(message-cited-text ((t (:foreground "red3"))))
  '(message-header-cc ((t (:bold t :foreground "chartreuse1" :weight bold))))
diff --git a/etc/themes/misterioso-theme.el b/etc/themes/misterioso-theme.el
index e7a66c5650..26a5946d30 100644
--- a/etc/themes/misterioso-theme.el
+++ b/etc/themes/misterioso-theme.el
@@ -101,12 +101,33 @@
    `(message-header-subject ((,class (:foreground "#dbdb95"))))
    `(message-header-to ((,class (:foreground "#00ede1"))))
    `(message-cited-text ((,class (:foreground "#74af68"))))
-   `(message-separator ((,class (:foreground "#23d7d7"))))))
-
-(custom-theme-set-variables
- 'misterioso
- '(ansi-color-names-vector ["#2d3743" "#ff4242" "#74af68" "#dbdb95"
-                           "#34cae2" "#008b8b" "#00ede1" "#e1e1e0"]))
+   `(message-separator ((,class (:foreground "#23d7d7"))))
+   ;; ANSI colors
+   `(ansi-color-black ((,class (:background "#2d3743" :foreground "#2d3743"))))
+   `(ansi-color-red ((,class (:background "#da3938" :foreground "#da3938"))))
+   `(ansi-color-green ((,class (:background "#74af68" :foreground "#74af68"))))
+   `(ansi-color-yellow ((,class (:background "#dbdb95" :foreground 
"#dbdb95"))))
+   `(ansi-color-blue ((,class (:background "#34cae2" :foreground "#34cae2"))))
+   `(ansi-color-magenta ((,class (:background "#b33c97"
+                                 :foreground "#b33c97"))))
+   `(ansi-color-cyan ((,class (:background "#008b8b" :foreground "#008b8b"))))
+   `(ansi-color-white ((,class (:background "#e1e1e0" :foreground "#e1e1e0"))))
+   `(ansi-color-bright-black ((,class (:background "#415160"
+                                       :foreground "#415160"))))
+   `(ansi-color-bright-red ((,class (:background "#ff4242"
+                                     :foreground "#ff4242"))))
+   `(ansi-color-bright-green ((,class (:background "#74cd65"
+                                       :foreground "#74cd65"))))
+   `(ansi-color-bright-yellow ((,class (:background "#ffad29"
+                                        :foreground "#ffad29"))))
+   `(ansi-color-bright-blue ((,class (:background "#59e9ff"
+                                      :foreground "#59e9ff"))))
+   `(ansi-color-bright-magenta ((,class (:background "#ed74cd"
+                                         :foreground "#ed74cd"))))
+   `(ansi-color-bright-cyan ((,class (:background "#00ede1"
+                                      :foreground "#00ede1"))))
+   `(ansi-color-bright-white ((,class (:background "#eeeeec"
+                                       :foreground "#eeeeec"))))))
 
 (provide-theme 'misterioso)
 
diff --git a/etc/themes/modus-operandi-theme.el 
b/etc/themes/modus-operandi-theme.el
index a946d747e8..350524779d 100644
--- a/etc/themes/modus-operandi-theme.el
+++ b/etc/themes/modus-operandi-theme.el
@@ -4,7 +4,7 @@
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
 ;; URL: https://gitlab.com/protesilaos/modus-themes
-;; Version: 1.5.0
+;; Version: 1.6.0
 ;; Package-Requires: ((emacs "26.1"))
 ;; Keywords: faces, theme, accessibility
 
diff --git a/etc/themes/modus-themes.el b/etc/themes/modus-themes.el
index b9fe4a3272..7ab985c077 100644
--- a/etc/themes/modus-themes.el
+++ b/etc/themes/modus-themes.el
@@ -4,9 +4,9 @@
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
 ;; URL: https://gitlab.com/protesilaos/modus-themes
-;; Version: 1.5.0
-;; Last-Modified: <2021-07-15 13:21:55 +0300>
-;; Package-Requires: ((emacs "26.1"))
+;; Version: 1.6.0
+;; Last-Modified: <2021-09-29 08:47:03 +0300>
+;; Package-Requires: ((emacs "27.1"))
 ;; Keywords: faces, theme, accessibility
 
 ;; This file is part of GNU Emacs.
@@ -35,30 +35,30 @@
 ;;
 ;; The themes share the following customization variables:
 ;;
+;;     modus-themes-headings                       (alist)
+;;     modus-themes-org-agenda                     (alist)
+;;     modus-themes-bold-constructs                (boolean)
 ;;     modus-themes-inhibit-reload                 (boolean)
 ;;     modus-themes-italic-constructs              (boolean)
-;;     modus-themes-bold-constructs                (boolean)
-;;     modus-themes-variable-pitch-headings        (boolean)
-;;     modus-themes-variable-pitch-ui              (boolean)
+;;     modus-themes-no-mixed-fonts                 (boolean)
 ;;     modus-themes-scale-headings                 (boolean)
 ;;     modus-themes-subtle-line-numbers            (boolean)
 ;;     modus-themes-success-deuteranopia           (boolean)
-;;     modus-themes-no-mixed-fonts                 (boolean)
-;;     modus-themes-headings                       (alist)
+;;     modus-themes-variable-pitch-headings        (boolean)
+;;     modus-themes-variable-pitch-ui              (boolean)
+;;     modus-themes-completions                    (choice)
+;;     modus-themes-diffs                          (choice)
 ;;     modus-themes-fringes                        (choice)
+;;     modus-themes-hl-line                        (choice)
 ;;     modus-themes-lang-checkers                  (choice)
-;;     modus-themes-org-agenda                     (alist)
-;;     modus-themes-org-blocks                     (choice)
-;;     modus-themes-prompts                        (choice)
+;;     modus-themes-links                          (choice)
+;;     modus-themes-mail-citations                 (choice)
 ;;     modus-themes-mode-line                      (choice)
-;;     modus-themes-diffs                          (choice)
-;;     modus-themes-syntax                         (choice)
-;;     modus-themes-hl-line                        (choice)
+;;     modus-themes-org-blocks                     (choice)
 ;;     modus-themes-paren-match                    (choice)
+;;     modus-themes-prompts                        (choice)
 ;;     modus-themes-region                         (choice)
-;;     modus-themes-links                          (choice)
-;;     modus-themes-completions                    (choice)
-;;     modus-themes-mail-citations                 (choice)
+;;     modus-themes-syntax                         (choice)
 ;;
 ;; The default scale for headings is as follows (it can be customized as
 ;; well---remember, no scaling takes place by default):
@@ -69,6 +69,11 @@
 ;;     modus-themes-scale-4                        1.2
 ;;     modus-themes-scale-title                    1.3
 ;;
+;; There is another scaling-related option, which however is reserved
+;; for special cases and is not used for headings:
+;;
+;;     modus-themes-scale-small                    0.9
+;;
 ;; There also exist two unique customization variables for overriding
 ;; color palette values.  The specifics are documented in the manual.
 ;; The symbols are:
@@ -86,6 +91,7 @@
 ;;     alert
 ;;     all-the-icons
 ;;     annotate
+;;     ansi-color
 ;;     anzu
 ;;     apropos
 ;;     apt-sources-list
@@ -125,6 +131,7 @@
 ;;     css-mode
 ;;     csv-mode
 ;;     ctrlf
+;;     cursor-flash
 ;;     custom (M-x customize)
 ;;     dap-mode
 ;;     dashboard (emacs-dashboard)
@@ -160,6 +167,7 @@
 ;;     eldoc-box
 ;;     elfeed
 ;;     elfeed-score
+;;     elpher
 ;;     embark
 ;;     emms
 ;;     enh-ruby-mode (enhanced-ruby-mode)
@@ -615,8 +623,10 @@ cover the blue-cyan-magenta side of the spectrum."
 
     (bg-tab-bar . "#d5d5d5")
     (bg-tab-active . "#f6f6f6")
-    (bg-tab-inactive . "#bdbdbd")
-    (bg-tab-inactive-alt . "#999999")
+    (bg-tab-inactive . "#b7b7b7")
+    (bg-tab-inactive-accent . "#a9b4f6")
+    (bg-tab-inactive-alt . "#9f9f9f")
+    (bg-tab-inactive-alt-accent . "#9fa6d0")
 
     (red-tab . "#680000")
     (green-tab . "#003900")
@@ -858,8 +868,10 @@ symbol and the latter as a string.")
 
     (bg-tab-bar . "#2c2c2c")
     (bg-tab-active . "#0e0e0e")
-    (bg-tab-inactive . "#3d3d3d")
+    (bg-tab-inactive . "#424242")
+    (bg-tab-inactive-accent . "#35398f")
     (bg-tab-inactive-alt . "#595959")
+    (bg-tab-inactive-alt-accent . "#505588")
 
     (red-tab . "#ffc0bf")
     (green-tab . "#88ef88")
@@ -1724,16 +1736,6 @@ For form, see `modus-themes-vivendi-colors'."
   (put 'modus-themes-vivendi-color-overrides
        'custom-options (copy-sequence colors)))
 
-(defcustom modus-themes-slanted-constructs nil
-  "Use slanted text in more code constructs (italics or oblique)."
-  :group 'modus-themes
-  :package-version '(modus-themes . "1.0.0")
-  :version "28.1"
-  :type 'boolean
-  :set #'modus-themes--set-option
-  :initialize #'custom-initialize-default
-  :link '(info-link "(modus-themes) Slanted constructs"))
-
 (define-obsolete-variable-alias
   'modus-themes-slanted-constructs
   'modus-themes-italic-constructs
@@ -1907,6 +1909,7 @@ combinations:
     (setq modus-themes-org-agenda
           '((header-block . (variable-pitch scale-title))
             (header-date . (grayscale workaholic bold-today))
+            (event . (accented scale-small))
             (scheduled . uniform)
             (habit . traffic-light)))
 
@@ -1945,6 +1948,11 @@ that can include any of the following properties:
 - `bold-today' to apply a bold typographic weight to the current
   date;
 - `bold-all' to render all date headings in a bold weight.
+- `scale-heading' increases the height of the date headings to
+  the value of `modus-themes-scale-1' (which is the first step in
+  the scale for regular headings).
+- `underline-today' applies an underline to the current date
+  while removing the background it has by default.
 
 For example:
 
@@ -1953,6 +1961,28 @@ For example:
     (header-date . (grayscale bold-all))
     (header-date . (grayscale workaholic))
     (header-date . (grayscale workaholic bold-today))
+    (header-date . (grayscale workaholic bold-today scale-heading))
+
+An `event' key covers events from the diary and other entries
+that derive from a symbolic expression or sexp (e.g. phases of
+the moon, holidays).  By default those have a gray
+foreground (the default is a nil value or an empty list).  This
+key accepts a list of properties.  Those are:
+
+- `scale-small' reduces the height of the entries to the value of
+  the user option `modus-themes-scale-small' (0.9 the height of
+  the main font size by default).
+- `accented' applies an accent value to the event's foreground,
+  replacing the original gray.
+- `italic' adds a slant to the font's forms (italic or oblique
+  forms, depending on the typeface)
+
+For example:
+
+    (event . nil)
+    (event . (scale-small))
+    (event . (scale-small accented))
+    (event . (scale-small accented italic))
 
 A `scheduled' key applies to tasks with a scheduled date.  By
 default (a nil value), these use varying shades of yellow to
@@ -2008,7 +2038,7 @@ For example:
     (habit . simplified)
     (habit . traffic-light)"
   :group 'modus-themes
-  :package-version '(modus-themes . "1.5.0")
+  :package-version '(modus-themes . "1.6.0")
   :version "28.1"
   :type '(set
           (cons :tag "Block header"
@@ -2027,7 +2057,15 @@ For example:
                      (const :tag "Use grayscale for date headers" grayscale)
                      (const :tag "Do not differentiate weekdays from weekends" 
workaholic)
                      (const :tag "Make today bold" bold-today)
-                     (const :tag "Make all dates bold" bold-all)))
+                     (const :tag "Make all dates bold" bold-all)
+                     (const :tag "Increase font size (`modus-themes-scale-1')" 
scale-heading)
+                     (const :tag "Make today underlined; remove the 
background" underline-today)))
+          (cons :tag "Event entry" :greedy t
+                (const event)
+                (set :tag "Text presentation" :greedy t
+                     (const :tag "Use smaller font size 
(`modus-themes-scale-small')" scale-small)
+                     (const :tag "Apply an accent color" accented)
+                     (const :tag "Italic font slant (oblique forms)" italic)))
           (cons :tag "Scheduled tasks"
                 (const scheduled)
                 (choice (const :tag "Yellow colors to distinguish current and 
future tasks (default)" nil)
@@ -2047,8 +2085,8 @@ For example:
   "Use font scaling for headings.
 
 For regular headings the scale is controlled by the variables
-`modus-themes-scale-1' (smallest) and its variants all the way up
-to `modus-themes-scale-4' (larger).
+`modus-themes-scale-1' (smallest increase) and its variants all
+the way up to `modus-themes-scale-4' (largest increase).
 
 While `modus-themes-scale-title' is reserved for special headings
 that nominally are the largest on the scale (though that is not a
@@ -2163,12 +2201,14 @@ accordance with it in cases where it changes, such as 
while using
   :initialize #'custom-initialize-default
   :link '(info-link "(modus-themes) Scaled heading sizes"))
 
-(defcustom modus-themes-scale-5 1.3
+(define-obsolete-variable-alias 'modus-themes-scale-5 
'modus-themes-scale-title "1.5.0")
+
+(defcustom modus-themes-scale-title 1.3
   "Font size slightly larger than `modus-themes-scale-4'.
 
 This size is only used for 'special' top level headings, such as
 Org's file title heading, denoted by the #+title key word, and
-the Org agenda structure headers.
+the Org agenda structure headers (see `modus-themes-org-agenda').
 
 The default value is a floating point that is interpreted as a
 multiple of the base font size.  It is recommended to use such a
@@ -2181,21 +2221,19 @@ This will ignore the base font size and, thus, will not 
scale in
 accordance with it in cases where it changes, such as while using
 `text-scale-adjust'."
   :group 'modus-themes
-  :package-version '(modus-themes . "1.2.0")
+  :package-version '(modus-themes . "1.5.0")
   :version "28.1"
   :type 'number
   :set #'modus-themes--set-option
   :initialize #'custom-initialize-default
   :link '(info-link "(modus-themes) Scaled heading sizes"))
 
-(define-obsolete-variable-alias 'modus-themes-scale-5 
'modus-themes-scale-title "1.5.0")
+(defcustom modus-themes-scale-small 0.9
+  "Font size smaller than the default value.
 
-(defcustom modus-themes-scale-title 1.3
-  "Font size slightly larger than `modus-themes-scale-4'.
-
-This size is only used for 'special' top level headings, such as
-Org's file title heading, denoted by the #+title key word, and
-the Org agenda structure headers (see `modus-themes-org-agenda').
+This size is only used in special contexts where users are
+presented with the option to have smaller text on display (see
+`modus-themes-org-agenda').
 
 The default value is a floating point that is interpreted as a
 multiple of the base font size.  It is recommended to use such a
@@ -2208,7 +2246,7 @@ This will ignore the base font size and, thus, will not 
scale in
 accordance with it in cases where it changes, such as while using
 `text-scale-adjust'."
   :group 'modus-themes
-  :package-version '(modus-themes . "1.5.0")
+  :package-version '(modus-themes . "1.6.0")
   :version "28.1"
   :type 'number
   :set #'modus-themes--set-option
@@ -2404,6 +2442,14 @@ the same as the background, effectively creating some 
padding.
 The `accented' property ensures that the active mode line uses a
 colored background instead of the standard shade of gray.
 
+The `padded' property increases the apparent height of the mode
+line.  This is done by applying box effects and combining them
+with an underline and overline.  To ensure that the underline is
+placed at the bottom, set `x-underline-at-descent-line' to
+non-nil.  The `padded' property has no effect when the `moody'
+property is also used, because Moody already applies its own
+padding.
+
 Combinations of any of those properties are expressed as a list,
 like in these examples:
 
@@ -2442,7 +2488,7 @@ Furthermore, because Moody expects an underline and 
overline
 instead of a box style, it is advised to set
 `x-underline-at-descent-line' to a non-nil value."
   :group 'modus-themes
-  :package-version '(modus-themes . "1.5.0")
+  :package-version '(modus-themes . "1.6.0")
   :version "28.1"
   :type '(set :tag "Properties" :greedy t
               (choice :tag "Overall style"
@@ -2450,7 +2496,8 @@ instead of a box style, it is advised to set
                       (const :tag "3d borders" 3d)
                       (const :tag "No box effects (Moody-compatible)" moody))
               (const :tag "Colored background" accented)
-              (const :tag "Without border color" borderless))
+              (const :tag "Without border color" borderless)
+              (const :tag "With extra padding" padded))
   :set #'modus-themes--set-option
   :initialize #'custom-initialize-default
   :link '(info-link "(modus-themes) Mode line"))
@@ -2905,6 +2952,18 @@ colored into a uniform shade of shade of gray."
   :initialize #'custom-initialize-default
   :link '(info-link "(modus-themes) Mail citations"))
 
+(defcustom modus-themes-tabs-accented nil
+  "Toggle accented tab backgrounds, instead of the default gray.
+This affects the built-in tab-bar mode and tab-line mode, as well
+as the Centaur tabs package."
+  :group 'modus-themes
+  :package-version '(modus-themes . "1.6.0")
+  :version "28.1"
+  :type 'boolean
+  :set #'modus-themes--set-option
+  :initialize #'custom-initialize-default
+  :link '(info-link "(modus-themes) Tab style"))
+
 
 
 ;;; Internal functions
@@ -3333,30 +3392,64 @@ FG is the foreground color to use."
           :height height
           :foreground fg)))
 
-(defun modus-themes--agenda-date (defaultfg grayscalefg &optional bold 
workaholicfg grayscaleworkaholicfg)
+(defun modus-themes--agenda-date (defaultfg grayscalefg &optional workaholicfg 
grayscaleworkaholicfg bg bold ul)
   "Control the style of date headings in Org agenda buffers.
 DEFAULTFG is the original accent color for the foreground.
-GRAYSCALEFG is a neutral color.  Optional BOLD applies a bold
-weight.  Optional WORKAHOLICFG and GRAYSCALEWORKAHOLICFG are
-alternative foreground colors."
-  (let* ((properties (modus-themes--key-cdr 'header-date 
modus-themes-org-agenda))
-         (weight (cond ((memq 'bold-all properties)
-                        'bold)
-                       ((and bold (memq 'bold-today properties))
-                        'bold)
-                       (t
-                        nil)))
-         (fg (cond ((and (memq 'grayscale properties)
-                         (memq 'workaholic properties))
-                    (or grayscaleworkaholicfg grayscalefg))
-                   ((memq 'grayscale properties)
-                    grayscalefg)
-                   ((memq 'workaholic properties)
-                    (or workaholicfg defaultfg))
-                   (t
-                    defaultfg))))
-    (list :inherit weight
-          :foreground fg)))
+GRAYSCALEFG is a neutral color.  Optional WORKAHOLICFG and
+GRAYSCALEWORKAHOLICFG are alternative foreground colors.
+Optional BG is a background color.  Optional BOLD applies a bold
+weight.  Optional UL applies an underline."
+  (let ((properties (modus-themes--key-cdr 'header-date 
modus-themes-org-agenda)))
+    (list :inherit
+          (cond
+           ((or (memq 'bold-all properties)
+                (and bold (memq 'bold-today properties)))
+            'bold)
+           (t
+            'unspecified))
+          :background
+          (unless (memq 'underline-today properties)
+            bg)
+          :foreground
+          (cond
+           ((and (memq 'grayscale properties)
+                 (memq 'workaholic properties))
+            (or grayscaleworkaholicfg grayscalefg))
+           ((memq 'grayscale properties)
+            grayscalefg)
+           ((memq 'workaholic properties)
+            (or workaholicfg defaultfg))
+           (t
+            defaultfg))
+          :height
+          (if (memq 'scale-heading properties)
+              modus-themes-scale-1
+            'unspecified)
+          :underline
+          (if (and ul (memq 'underline-today properties))
+              t
+            'unspecified))))
+
+(defun modus-themes--agenda-event (fg)
+  "Control the style of the Org agenda events.
+FG is the accent color to use."
+  (let ((properties (modus-themes--key-cdr 'event modus-themes-org-agenda)))
+    (list :height
+          (if (memq 'scale-small properties)
+              modus-themes-scale-small
+            'unspecified)
+          :foreground
+          (if (memq 'accented properties)
+              fg
+            'unspecified)
+          :inherit
+          (cond
+           ((and (memq 'accented properties)
+                 (memq 'italic properties))
+            'italic)
+           ((memq 'italic properties)
+            '(shadow italic))
+           ('shadow)))))
 
 (defun modus-themes--agenda-scheduled (defaultfg uniformfg rainbowfg)
   "Control the style of the Org agenda scheduled tasks.
@@ -3420,7 +3513,7 @@ set to `rainbow'."
     (_ (list :background bg :foreground fg))))
 
 (defun modus-themes--mode-line-attrs
-    (fg bg fg-alt bg-alt fg-accent bg-accent border border-3d &optional 
alt-style border-width fg-distant)
+    (fg bg fg-alt bg-alt fg-accent bg-accent border border-3d &optional 
alt-style fg-distant)
   "Color combinations for `modus-themes-mode-line'.
 
 FG and BG are the default colors.  FG-ALT and BG-ALT are meant to
@@ -3432,9 +3525,6 @@ three-dimensional effect, where BORDER-3D is used instead.
 Optional ALT-STYLE applies an appropriate style to the mode
 line's box property.
 
-Optional BORDER-WIDTH specifies an integer for the width of the
-rectangle that produces the box effect.
-
 Optional FG-DISTANT should be close to the main background
 values.  It is intended to be used as a distant-foreground
 property."
@@ -3463,20 +3553,39 @@ property."
                       ((cons fg bg))))
           (box (cond ((memq 'moody modus-themes-mode-line)
                       nil)
+                     ((and (memq '3d modus-themes-mode-line)
+                           (memq 'padded modus-themes-mode-line))
+                      (list :line-width 4
+                            :color
+                            (cond ((and (memq 'accented modus-themes-mode-line)
+                                        (memq 'borderless 
modus-themes-mode-line))
+                                   bg-accent)
+                                  ((or (memq 'accented modus-themes-mode-line)
+                                       (memq 'borderless 
modus-themes-mode-line))
+                                   bg)
+                                  (bg-alt))
+                            :style (when alt-style 'released-button)))
+                     ((and (memq 'accented modus-themes-mode-line)
+                           (memq 'padded modus-themes-mode-line))
+                      (list :line-width 6 :color bg-accent))
+                     ((memq 'padded modus-themes-mode-line)
+                      (list :line-width 6 :color bg))
                      ((memq '3d modus-themes-mode-line)
-                      (list :line-width (or border-width 1)
+                      (list :line-width 1
                             :color
                             (cond ((and (memq 'accented modus-themes-mode-line)
                                         (memq 'borderless 
modus-themes-mode-line))
                                    bg-accent)
                                   ((memq 'borderless modus-themes-mode-line) 
bg)
                                   (border-3d))
-                            :style (and alt-style 'released-button)))
-                     ((or (memq 'borderless modus-themes-mode-line)
-                          (memq 'moody modus-themes-mode-line))
+                            :style (when alt-style 'released-button)))
+                     ((memq 'borderless modus-themes-mode-line)
                       bg)
+                     ((memq 'padded modus-themes-mode-line)
+                      (list :line-width 6 :color bg))
                      (border)))
-          (line (cond ((not (memq 'moody modus-themes-mode-line))
+          (line (cond ((not (or (memq 'moody modus-themes-mode-line)
+                                (memq 'padded modus-themes-mode-line)))
                        nil)
                       ((and (memq 'borderless modus-themes-mode-line)
                             (memq 'accented modus-themes-mode-line))
@@ -3490,8 +3599,8 @@ property."
             :overline line
             :underline line
             :distant-foreground
-            (and (memq 'moody modus-themes-mode-line)
-                 fg-distant)))))
+            (when (memq 'moody modus-themes-mode-line)
+              fg-distant)))))
 
 (defun modus-themes--diff
     (fg-only-bg fg-only-fg mainbg mainfg altbg altfg &optional deuteranbg 
deuteranfg  bg-only-fg)
@@ -3759,6 +3868,30 @@ desaturated counterpart."
     ('desaturated (list :foreground subtlefg))
     (_ (list :foreground mainfg))))
 
+(defun modus-themes--tab (bg &optional bgaccent fg fgaccent box-p bold-p var-p)
+  "Helper function for tabs.
+BG is the default background, while BGACCENT is its more colorful
+alternative.  Optional FG is a foreground color that combines
+with BG.  Same principle FGACCENT.
+
+BOX-P and BOLD-P determine the use of a box property and the
+application of a bold weight, respectively.  VAR-P controls the
+application of a variable-pitch font."
+  (let ((background (if modus-themes-tabs-accented (or bgaccent bg) bg))
+        (foreground (if modus-themes-tabs-accented (or fgaccent fg) fg)))
+    (list
+     :inherit (cond
+               ((and bold-p var-p)
+                (if modus-themes-variable-pitch-ui
+                    '(variable-pitch bold)
+                  '(bold)))
+               (bold-p 'bold)
+               (var-p (when modus-themes-variable-pitch-ui 'variable-pitch))
+               ('unspecified))
+     :background background
+     :foreground (or foreground 'unspecified)
+     :box (if box-p (list :line-width 2 :color background) 'unspecified))))
+
 
 
 ;;;; Utilities for DIY users
@@ -4107,7 +4240,9 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                        bg-region blue-intense-bg
                                        fg-alt cyan-intense)
                                     :extend t)))
-    `(modus-themes-key-binding ((,class :inherit bold :foreground 
,blue-alt-other)))
+    `(modus-themes-key-binding ((,class ,@(if (facep 'help-key-binding) ; 
check emacs28 face
+                                              (list :inherit 'help-key-binding)
+                                            (list :inherit 'bold :foreground 
blue-alt-other)))))
     `(modus-themes-prompt ((,class ,@(modus-themes--prompt
                                       cyan-alt-other blue-alt-other fg-alt
                                       cyan-nuanced-bg blue-refine-bg fg-main
@@ -4233,6 +4368,25 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(annotate-annotation-secondary ((,class :inherit 
modus-themes-subtle-green)))
     `(annotate-highlight ((,class :background ,blue-nuanced-bg :underline 
,blue-intense)))
     `(annotate-highlight-secondary ((,class :background ,green-nuanced-bg 
:underline ,green-intense)))
+;;;;; ansi-color
+    ;; Those are in Emacs28.
+    `(ansi-color-black ((,class :background "black" :foreground "black")))
+    `(ansi-color-blue ((,class :background ,blue :foreground ,blue)))
+    `(ansi-color-bold ((,class :inherit bold)))
+    `(ansi-color-bright-black ((,class :background "gray35" :foreground 
"gray35")))
+    `(ansi-color-bright-blue ((,class :background ,blue-alt :foreground 
,blue-alt)))
+    `(ansi-color-bright-cyan ((,class :background ,cyan-alt-other :foreground 
,cyan-alt-other)))
+    `(ansi-color-bright-green ((,class :background ,green-alt-other 
:foreground ,green-alt-other)))
+    `(ansi-color-bright-magenta ((,class :background ,magenta-alt-other 
:foreground ,magenta-alt-other)))
+    `(ansi-color-bright-red ((,class :background ,red-alt :foreground 
,red-alt)))
+    `(ansi-color-bright-white ((,class :background "white" :foreground 
"white")))
+    `(ansi-color-bright-yellow ((,class :background ,yellow-alt :foreground 
,yellow-alt)))
+    `(ansi-color-cyan ((,class :background ,cyan :foreground ,cyan)))
+    `(ansi-color-green ((,class :background ,green :foreground ,green)))
+    `(ansi-color-magenta ((,class :background ,magenta :foreground ,magenta)))
+    `(ansi-color-red ((,class :background ,red :foreground ,red)))
+    `(ansi-color-white ((,class :background "gray65" :foreground "gray65")))
+    `(ansi-color-yellow ((,class :background ,yellow :foreground ,yellow)))
 ;;;;; anzu
     `(anzu-match-1 ((,class :inherit modus-themes-subtle-cyan)))
     `(anzu-match-2 ((,class :inherit modus-themes-search-success)))
@@ -4251,7 +4405,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(apropos-keybinding ((,class :inherit modus-themes-key-binding)))
     `(apropos-misc-button ((,class :inherit button
                                    ,@(modus-themes--link-color
-                                      cyan-alt-other cyan-alt-other-faint))))
+                                      green-alt-other green-alt-other-faint))))
     `(apropos-property ((,class :inherit modus-themes-bold :foreground 
,magenta-alt)))
     `(apropos-symbol ((,class :inherit modus-themes-pseudo-header)))
     `(apropos-user-option-button ((,class :inherit button
@@ -4275,7 +4429,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(font-latex-bold-face ((,class :inherit bold :foreground 
,fg-special-calm)))
     `(font-latex-doctex-documentation-face ((,class :inherit 
modus-themes-slant :foreground ,fg-special-cold)))
     `(font-latex-doctex-preprocessor-face ((,class :inherit modus-themes-bold 
:foreground ,red-alt-other)))
-    `(font-latex-italic-face ((,class :inherit italic :foreground 
,fg-special-calm)))
+    `(font-latex-italic-face ((,class :inherit italic)))
     `(font-latex-math-face ((,class :foreground ,cyan-alt-other)))
     `(font-latex-script-char-face ((,class :foreground ,cyan-alt-other)))
     `(font-latex-sectioning-0-face ((,class :inherit 
modus-themes-variable-pitch :foreground ,blue-nuanced-fg)))
@@ -4360,7 +4514,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(boon-modeline-off ((,class :inherit modus-themes-active-yellow)))
     `(boon-modeline-spc ((,class :inherit modus-themes-active-green)))
 ;;;;; bookmark
-    `(bookmark-face ((,class :inherit modus-themes-special-warm :extend t)))
+    `(bookmark-face ((,class :inherit modus-themes-fringe-cyan)))
+    `(bookmark-menu-bookmark ((,class :inherit bold)))
 ;;;;; breakpoint (built-in gdb-mi.el)
     `(breakpoint-disabled ((,class :inherit shadow)))
     `(breakpoint-enabled ((,class :inherit bold :foreground ,red)))
@@ -4406,11 +4561,11 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(centaur-tabs-close-unselected ((,class :inherit 
centaur-tabs-unselected)))
     `(centaur-tabs-modified-marker-selected ((,class :inherit 
centaur-tabs-selected)))
     `(centaur-tabs-modified-marker-unselected ((,class :inherit 
centaur-tabs-unselected)))
-    `(centaur-tabs-default ((,class :background ,bg-main :foreground 
,bg-main)))
-    `(centaur-tabs-selected ((,class :inherit bold :background ,bg-tab-active 
:foreground ,fg-main)))
-    `(centaur-tabs-selected-modified ((,class :inherit italic :background 
,bg-tab-active :foreground ,fg-main)))
-    `(centaur-tabs-unselected ((,class :background ,bg-tab-inactive 
:foreground ,fg-dim)))
-    `(centaur-tabs-unselected-modified ((,class :inherit italic :background 
,bg-tab-inactive :foreground ,fg-dim)))
+    `(centaur-tabs-default (( )))
+    `(centaur-tabs-selected ((,class ,@(modus-themes--tab bg-tab-active nil 
nil nil t t))))
+    `(centaur-tabs-selected-modified ((,class :inherit (italic 
centaur-tabs-selected))))
+    `(centaur-tabs-unselected ((,class ,@(modus-themes--tab bg-tab-inactive 
bg-tab-inactive-accent fg-dim nil t))))
+    `(centaur-tabs-unselected-modified ((,class :inherit (italic 
centaur-tabs-unselected))))
 ;;;;; cfrs
     `(cfrs-border-color ((,class :background ,fg-window-divider-inner)))
 ;;;;; change-log and log-view (`vc-print-log' and `vc-print-root-log')
@@ -4590,6 +4745,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(ctrlf-highlight-active ((,class :inherit (modus-themes-search-success 
bold))))
     `(ctrlf-highlight-line ((,class :inherit modus-themes-hl-line)))
     `(ctrlf-highlight-passive ((,class :inherit 
modus-themes-search-success-lazy)))
+;;;;; cursor-flash
+    `(cursor-flash-face ((,class :inherit modus-themes-intense-blue)))
 ;;;;; custom (M-x customize)
     `(custom-button ((,class :box (:line-width 2 :color nil :style 
released-button)
                              :background ,bg-active :foreground ,fg-main)))
@@ -4765,24 +4922,24 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(diredfl-autofile-name ((,class :inherit modus-themes-special-cold)))
     `(diredfl-compressed-file-name ((,class :foreground ,fg-special-warm)))
     `(diredfl-compressed-file-suffix ((,class :foreground ,red-alt)))
-    `(diredfl-date-time ((,class :foreground ,cyan-alt-other)))
+    `(diredfl-date-time ((,class :foreground ,cyan)))
     `(diredfl-deletion ((,class :inherit modus-themes-mark-del)))
     `(diredfl-deletion-file-name ((,class :inherit modus-themes-mark-del)))
     `(diredfl-dir-heading ((,class :inherit modus-themes-pseudo-header)))
     `(diredfl-dir-name ((,class :inherit dired-directory)))
     `(diredfl-dir-priv ((,class :foreground ,blue-alt)))
-    `(diredfl-exec-priv ((,class :foreground ,magenta)))
+    `(diredfl-exec-priv ((,class :foreground ,magenta-alt)))
     `(diredfl-executable-tag ((,class :foreground ,magenta-alt)))
     `(diredfl-file-name ((,class :foreground ,fg-main)))
-    `(diredfl-file-suffix ((,class :foreground ,cyan)))
+    `(diredfl-file-suffix ((,class :foreground ,magenta-alt-other)))
     `(diredfl-flag-mark ((,class :inherit modus-themes-mark-sel)))
     `(diredfl-flag-mark-line ((,class :inherit modus-themes-mark-sel)))
     `(diredfl-ignored-file-name ((,class :inherit shadow)))
     `(diredfl-link-priv ((,class :foreground ,blue-alt-other)))
-    `(diredfl-no-priv ((,class :inherit shadow)))
-    `(diredfl-number ((,class :foreground ,cyan-alt)))
+    `(diredfl-no-priv ((,class :foreground "gray50")))
+    `(diredfl-number ((,class :foreground ,cyan-alt-other-faint)))
     `(diredfl-other-priv ((,class :foreground ,yellow)))
-    `(diredfl-rare-priv ((,class :foreground ,red-alt)))
+    `(diredfl-rare-priv ((,class :foreground ,red)))
     `(diredfl-read-priv ((,class :foreground ,fg-main)))
     `(diredfl-symlink ((,class :inherit dired-symlink)))
     `(diredfl-tagged-autofile-name ((,class :inherit 
modus-themes-refine-magenta)))
@@ -4791,27 +4948,27 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(diredp-autofile-name ((,class :inherit modus-themes-special-cold)))
     `(diredp-compressed-file-name ((,class :foreground ,fg-special-warm)))
     `(diredp-compressed-file-suffix ((,class :foreground ,red-alt)))
-    `(diredp-date-time ((,class :foreground ,cyan-alt-other)))
+    `(diredp-date-time ((,class :foreground ,cyan)))
     `(diredp-deletion ((,class :inherit modus-themes-mark-del)))
     `(diredp-deletion-file-name ((,class :inherit modus-themes-mark-del)))
     `(diredp-dir-heading ((,class :inherit modus-themes-pseudo-header)))
     `(diredp-dir-name ((,class :inherit dired-directory)))
     `(diredp-dir-priv ((,class :foreground ,blue-alt)))
-    `(diredp-exec-priv ((,class :foreground ,magenta)))
+    `(diredp-exec-priv ((,class :foreground ,magenta-alt)))
     `(diredp-executable-tag ((,class :foreground ,magenta-alt)))
     `(diredp-file-name ((,class :foreground ,fg-main)))
-    `(diredp-file-suffix ((,class :foreground ,cyan)))
+    `(diredp-file-suffix ((,class :foreground ,magenta-alt-other)))
     `(diredp-flag-mark ((,class :inherit modus-themes-mark-sel)))
     `(diredp-flag-mark-line ((,class :inherit modus-themes-mark-sel)))
     `(diredp-ignored-file-name ((,class :inherit shadow)))
     `(diredp-link-priv ((,class :foreground ,blue-alt-other)))
     `(diredp-mode-line-flagged ((,class :foreground ,red-active)))
     `(diredp-mode-line-marked ((,class :foreground ,green-active)))
-    `(diredp-no-priv ((,class :inherit shadow)))
-    `(diredp-number ((,class :foreground ,cyan-alt)))
+    `(diredp-no-priv ((,class :foreground "gray50")))
+    `(diredp-number ((,class :foreground ,cyan-alt-other-faint)))
     `(diredp-omit-file-name ((,class :inherit shadow :strike-through t)))
     `(diredp-other-priv ((,class :foreground ,yellow)))
-    `(diredp-rare-priv ((,class :foreground ,red-alt)))
+    `(diredp-rare-priv ((,class :foreground ,red)))
     `(diredp-read-priv ((,class :foreground ,fg-main)))
     `(diredp-symlink ((,class :inherit dired-symlink)))
     `(diredp-tagged-autofile-name ((,class :inherit 
modus-themes-refine-magenta)))
@@ -4887,13 +5044,13 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(ebdb-phone-default ((,class :foreground ,cyan)))
     `(eieio-custom-slot-tag-face ((,class :foreground ,red-alt)))
 ;;;;; ediff
-    `(ediff-current-diff-A ((,class :inherit modus-themes-diff-focus-removed)))
+    `(ediff-current-diff-A ((,class :inherit modus-themes-diff-removed)))
     `(ediff-current-diff-Ancestor ((,class ,@(modus-themes--diff
                                               bg-alt fg-special-cold
                                               bg-special-cold fg-special-cold
                                               blue-nuanced-bg blue))))
-    `(ediff-current-diff-B ((,class :inherit modus-themes-diff-focus-added)))
-    `(ediff-current-diff-C ((,class :inherit modus-themes-diff-focus-changed)))
+    `(ediff-current-diff-B ((,class :inherit modus-themes-diff-added)))
+    `(ediff-current-diff-C ((,class :inherit modus-themes-diff-changed)))
     `(ediff-even-diff-A ((,class :background ,bg-alt)))
     `(ediff-even-diff-Ancestor ((,class :background ,bg-alt)))
     `(ediff-even-diff-B ((,class :background ,bg-alt)))
@@ -4939,9 +5096,19 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(elfeed-score-error-level-face ((,class :foreground ,red)))
     `(elfeed-score-info-level-face ((,class :foreground ,cyan)))
     `(elfeed-score-warn-level-face ((,class :foreground ,yellow)))
+;;;;; elpher
+    `(elpher-gemini-heading1 ((,class :inherit modus-themes-heading-1)))
+    `(elpher-gemini-heading2 ((,class :inherit modus-themes-heading-2)))
+    `(elpher-gemini-heading3 ((,class :inherit modus-themes-heading-3)))
 ;;;;; embark
     `(embark-keybinding ((,class :inherit modus-themes-key-binding)))
 ;;;;; emms
+    `(emms-browser-album-face ((,class :foreground ,magenta-alt-other 
,@(modus-themes--scale modus-themes-scale-2))))
+    `(emms-browser-artist-face ((,class :foreground ,cyan 
,@(modus-themes--scale modus-themes-scale-3))))
+    `(emms-browser-composer-face ((,class :foreground ,magenta-alt 
,@(modus-themes--scale modus-themes-scale-3))))
+    `(emms-browser-performer-face ((,class :inherit emms-browser-artist-face)))
+    `(emms-browser-track-face ((,class :inherit emms-playlist-track-face)))
+    `(emms-browser-year/genre-face ((,class :foreground ,cyan-alt-other 
,@(modus-themes--scale modus-themes-scale-4))))
     `(emms-playlist-track-face ((,class :foreground ,blue-alt)))
     `(emms-playlist-selected-face ((,class :inherit bold :foreground 
,blue-alt-other)))
     `(emms-metaplaylist-mode-current-face ((,class :inherit 
emms-playlist-selected-face)))
@@ -5659,6 +5826,10 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                      ,@(modus-themes--standard-completions
                                         magenta bg-alt
                                         bg-active fg-main))))
+    `(icomplete-selected-match ((,class :inherit bold :foreground ,fg-main
+                                        :background ,@(pcase 
modus-themes-completions
+                                                        ('opinionated (list 
bg-active))
+                                                        (_ (list 
bg-inactive))))))
 ;;;;; icomplete-vertical
     `(icomplete-vertical-separator ((,class :inherit shadow)))
 ;;;;; ido-mode
@@ -6074,27 +6245,41 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(Man-reverse ((,class :inherit modus-themes-subtle-magenta)))
     `(Man-underline ((,class :foreground ,cyan :underline t)))
 ;;;;; marginalia
-    `(marginalia-archive ((,class :foreground ,green-nuanced-fg)))
-    `(marginalia-date ((,class :foreground ,blue-nuanced-fg)))
-    `(marginalia-char ((,class :foreground ,red-active)))
-    `(marginalia-documentation ((,class :foreground ,fg-special-cold :inherit 
modus-themes-slant)))
-    `(marginalia-file-modes ((,class :inherit shadow)))
-    `(marginalia-file-name ((,class :foreground ,fg-special-mild)))
-    `(marginalia-file-owner ((,class :foreground ,red-nuanced-fg)))
+    `(marginalia-archive ((,class :foreground ,cyan-alt-other)))
+    `(marginalia-char ((,class :foreground ,magenta)))
+    `(marginalia-date ((,class :foreground ,cyan)))
+    `(marginalia-documentation ((,class :inherit modus-themes-slant 
:foreground ,fg-docstring)))
+    `(marginalia-file-name ((,class :foreground ,blue-faint)))
+    `(marginalia-file-owner ((,class :foreground ,red-faint)))
+    `(marginalia-file-priv-dir ((,class :foreground ,blue-alt)))
+    `(marginalia-file-priv-exec ((,class :foreground ,magenta-alt)))
+    `(marginalia-file-priv-link ((,class :foreground ,blue-alt-other)))
+    `(marginalia-file-priv-no ((,class :foreground "gray50")))
+    `(marginalia-file-priv-other ((,class :foreground ,yellow)))
+    `(marginalia-file-priv-rare ((,class :foreground ,red)))
+    `(marginalia-file-priv-read ((,class :foreground ,fg-main)))
+    `(marginalia-file-priv-write ((,class :foreground ,cyan)))
     ;; Here we make an exception of not applying the bespoke
     ;; `modus-themes-key-binding' for two reasons: (1) completion
     ;; highlights can be fairly intense, so we do not want more
     ;; components to compete with them for attention, (2) the
     ;; `marginalia-key' may not be used for key bindings specifically,
     ;; so we might end up applying styles in places we should not.
-    `(marginalia-key ((,class :foreground ,magenta-active)))
-    `(marginalia-mode ((,class :foreground ,cyan-active)))
-    `(marginalia-modified ((,class :foreground ,yellow-active)))
-    `(marginalia-number ((,class :foreground ,blue-active)))
-    `(marginalia-size ((,class :foreground ,green-active)))
-    `(marginalia-type ((,class :foreground ,fg-special-warm)))
-    `(marginalia-variable ((,class :foreground ,yellow-nuanced-fg)))
-    `(marginalia-version ((,class :foreground ,cyan-active)))
+    `(marginalia-function ((,class :foreground ,magenta-alt-faint)))
+    `(marginalia-key ((,class :foreground ,magenta-alt-other)))
+    `(marginalia-lighter ((,class :foreground ,blue-alt)))
+    `(marginalia-list ((,class :foreground ,magenta-alt-other-faint)))
+    `(marginalia-mode ((,class :foreground ,cyan)))
+    `(marginalia-modified ((,class :foreground ,magenta-alt-faint)))
+    `(marginalia-null ((,class :inherit shadow)))
+    `(marginalia-number ((,class :foreground ,cyan)))
+    `(marginalia-size ((,class :foreground ,cyan-alt-other-faint)))
+    `(marginalia-string ((,class :foreground ,blue-alt)))
+    `(marginalia-symbol ((,class :foreground ,blue-alt-other-faint)))
+    `(marginalia-true ((,class :foreground ,fg-main)))
+    `(marginalia-type ((,class :foreground ,cyan-alt-other)))
+    `(marginalia-value ((,class :foreground ,cyan)))
+    `(marginalia-version ((,class :foreground ,cyan)))
 ;;;;; markdown-mode
     `(markdown-blockquote-face ((,class :inherit modus-themes-slant 
:foreground ,fg-special-cold)))
     `(markdown-bold-face ((,class :inherit bold)))
@@ -6125,7 +6310,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                            :foreground ,magenta-alt)))
     `(markdown-inline-code-face ((,class :inherit modus-themes-fixed-pitch
                                          :background ,bg-alt :foreground 
,fg-special-calm)))
-    `(markdown-italic-face ((,class :inherit italic :foreground 
,fg-special-cold)))
+    `(markdown-italic-face ((,class :inherit italic)))
     `(markdown-language-info-face ((,class :inherit modus-themes-fixed-pitch
                                            :foreground ,fg-special-cold)))
     `(markdown-language-keyword-face ((,class :inherit modus-themes-fixed-pitch
@@ -6159,7 +6344,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(markup-error-face ((,class :inherit error)))
     `(markup-gen-face ((,class :foreground ,magenta-alt)))
     `(markup-internal-reference-face ((,class :foreground ,fg-alt :underline 
,bg-region)))
-    `(markup-italic-face ((,class :inherit italic :foreground 
,fg-special-cold)))
+    `(markup-italic-face ((,class :inherit italic)))
     `(markup-list-face ((,class :inherit modus-themes-special-cold)))
     `(markup-meta-face ((,class :inherit shadow)))
     `(markup-meta-hide-face ((,class :foreground "gray50")))
@@ -6236,7 +6421,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                             fg-dim bg-active
                             fg-main bg-active-accent
                             fg-alt bg-active
-                            'alt-style nil bg-main))))
+                            'alt-style bg-main))))
     `(mode-line-buffer-id ((,class :inherit bold)))
     `(mode-line-emphasis ((,class :inherit bold :foreground ,blue-active)))
     `(mode-line-highlight ((,class :inherit modus-themes-active-blue :box 
(:line-width -1 :style pressed-button))))
@@ -6273,7 +6458,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(mu4e-contact-face ((,class :inherit message-header-to)))
     `(mu4e-context-face ((,class :foreground ,blue-active)))
     `(mu4e-draft-face ((,class :foreground ,magenta-alt)))
-    `(mu4e-flagged-face ((,class :foreground ,red-alt)))
+    `(mu4e-flagged-face ((,class :foreground ,red-alt-other)))
     `(mu4e-footer-face ((,class :inherit modus-themes-slant :foreground 
,fg-special-cold)))
     `(mu4e-forwarded-face ((,class :foreground ,magenta-alt-other)))
     `(mu4e-header-face ((,class :inherit shadow)))
@@ -6343,10 +6528,11 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(notmuch-crypto-signature-good-key ((,class :inherit bold :foreground 
,cyan)))
     `(notmuch-crypto-signature-unknown ((,class :inherit warning)))
     `(notmuch-hello-logo-background ((,class :background "gray50")))
+    `(notmuch-jump-key ((,class :inherit modus-themes-key-binding)))
     `(notmuch-message-summary-face ((,class :inherit (bold 
modus-themes-nuanced-cyan))))
     `(notmuch-search-count ((,class :inherit shadow)))
     `(notmuch-search-date ((,class :foreground ,cyan)))
-    `(notmuch-search-flagged-face ((,class :foreground ,red-alt)))
+    `(notmuch-search-flagged-face ((,class :foreground ,red-alt-other)))
     `(notmuch-search-matching-authors ((,class :foreground ,fg-special-cold)))
     `(notmuch-search-non-matching-authors ((,class :inherit shadow)))
     `(notmuch-search-subject ((,class :foreground ,fg-main)))
@@ -6414,16 +6600,18 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
                                          yellow yellow-nuanced-bg
                                          yellow-refine-bg yellow-refine-fg))))
 ;;;;; org
-    `(org-agenda-calendar-event ((,class :inherit shadow)))
-    `(org-agenda-calendar-sexp ((,class :inherit (modus-themes-slant shadow))))
+    `(org-agenda-calendar-event ((,class ,@(modus-themes--agenda-event 
blue-alt))))
+    `(org-agenda-calendar-sexp ((,class :inherit org-agenda-calendar-event)))
     `(org-agenda-clocking ((,class :inherit modus-themes-special-cold :extend 
t)))
     `(org-agenda-column-dateline ((,class :background ,bg-alt)))
     `(org-agenda-current-time ((,class :foreground ,blue-alt-other-faint)))
-    `(org-agenda-date ((,class ,@(modus-themes--agenda-date cyan fg-main 
nil))))
-    `(org-agenda-date-today ((,class :background ,bg-active
-                                     ,@(modus-themes--agenda-date blue-active 
fg-main t cyan-active))))
-    `(org-agenda-date-weekend ((,class ,@(modus-themes--agenda-date 
cyan-alt-other fg-alt nil cyan fg-main))))
-    `(org-agenda-diary ((,class :inherit shadow)))
+    `(org-agenda-date ((,class ,@(modus-themes--agenda-date cyan fg-main))))
+    `(org-agenda-date-today ((,class ,@(modus-themes--agenda-date blue-active 
fg-main
+                                                                  cyan-active 
fg-main
+                                                                  bg-active t 
t))))
+    `(org-agenda-date-weekend ((,class ,@(modus-themes--agenda-date 
cyan-alt-other fg-alt
+                                                                    cyan 
fg-main))))
+    `(org-agenda-diary ((,class :inherit org-agenda-calendar-event)))
     `(org-agenda-dimmed-todo-face ((,class :inherit shadow)))
     `(org-agenda-done ((,class :foreground ,@(modus-themes--success-deuteran
                                               blue-nuanced-fg
@@ -6448,7 +6636,8 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(org-checkbox-statistics-todo ((,class :inherit org-todo)))
     `(org-clock-overlay ((,class :inherit modus-themes-special-cold)))
     `(org-code ((,class :inherit modus-themes-fixed-pitch
-                        :background ,bg-alt :foreground ,fg-special-mild)))
+                        :background ,bg-alt :foreground ,fg-special-mild
+                        :extend t)))
     `(org-column ((,class :background ,bg-alt)))
     `(org-column-title ((,class :inherit bold :underline t :background 
,bg-alt)))
     `(org-date ((,class :inherit ,(if modus-themes-no-mixed-fonts
@@ -6708,9 +6897,9 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(proced-marked ((,class :inherit modus-themes-mark-alt)))
     `(proced-sort-header ((,class :inherit bold :foreground ,fg-special-calm 
:underline t)))
 ;;;;; prodigy
-    `(prodigy-green-face ((,class :foreground ,green)))
-    `(prodigy-red-face ((,class :foreground ,red)))
-    `(prodigy-yellow-face ((,class :foreground ,yellow)))
+    `(prodigy-green-face ((,class :inherit success)))
+    `(prodigy-red-face ((,class :inherit error)))
+    `(prodigy-yellow-face ((,class :inherit warning)))
 ;;;;; pulse
     `(pulse-highlight-start-face ((,class :background ,bg-active-accent 
:extend t)))
 ;;;;; quick-peek
@@ -7018,7 +7207,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(spray-accent-face ((,class :foreground ,red-intense)))
     `(spray-base-face ((,class :inherit default :foreground ,fg-special-cold)))
 ;;;;; stripes
-    `(stripes ((,class :inherit modus-themes-hl-line)))
+    `(stripes ((,class :background ,bg-alt)))
 ;;;;; success
     `(suggest-heading ((,class :inherit bold :foreground ,yellow-alt-other)))
 ;;;;; switch-window
@@ -7100,24 +7289,24 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(tab-bar-groups-tab-7 ((,class ,@(modus-themes--variable-pitch-ui) 
:foreground ,yellow-tab)))
     `(tab-bar-groups-tab-8 ((,class ,@(modus-themes--variable-pitch-ui) 
:foreground ,magenta-tab)))
 ;;;;; tab-bar-mode
-    `(tab-bar ((,class ,@(modus-themes--variable-pitch-ui)
-                       :background ,bg-tab-bar :foreground ,fg-main)))
-    `(tab-bar-tab ((,class :inherit bold :box (:line-width 2 :color 
,bg-tab-active)
-                           :background ,bg-tab-active :foreground ,fg-main)))
-    `(tab-bar-tab-inactive ((,class :box (:line-width 2 :color 
,bg-tab-inactive)
-                                    :background ,bg-tab-inactive :foreground 
,fg-dim)))
+    `(tab-bar ((,class ,@(modus-themes--tab bg-active bg-active-accent nil nil 
nil nil t))))
+    `(tab-bar-tab-group-current ((,class ,@(modus-themes--tab bg-tab-active)
+                                         :box (:line-width (2 . -2) :color 
"gray50"))))
+    `(tab-bar-tab-group-inactive ((,class ,@(modus-themes--tab bg-tab-inactive 
bg-tab-inactive-accent fg-dim)
+                                          :box (:line-width (2 . -2) :color 
"gray50"))))
+    `(tab-bar-tab ((,class ,@(modus-themes--tab bg-tab-active nil nil nil t 
t))))
+    `(tab-bar-tab-inactive ((,class ,@(modus-themes--tab bg-tab-inactive 
bg-tab-inactive-accent fg-dim nil t))))
 ;;;;; tab-line-mode
-    `(tab-line ((,class ,@(modus-themes--variable-pitch-ui)
-                        :height 0.95 :background ,bg-tab-bar :foreground 
,fg-main)))
+    `(tab-line ((,class ,@(modus-themes--tab bg-active bg-active-accent nil 
nil nil nil t)
+                        :height 0.95)))
     `(tab-line-close-highlight ((,class :foreground ,red)))
-    `(tab-line-highlight ((,class :background ,blue-subtle-bg :foreground 
,fg-dim)))
-    `(tab-line-tab ((,class :inherit bold :box (:line-width 2 :color 
,bg-tab-active)
-                            :background ,bg-tab-active :foreground ,fg-main)))
+    `(tab-line-highlight ((,class :inherit modus-themes-active-blue)))
+    `(tab-line-tab ((,class ,@(modus-themes--tab bg-tab-active nil nil nil t 
t))))
     `(tab-line-tab-current ((,class :inherit tab-line-tab)))
-    `(tab-line-tab-inactive ((,class :box (:line-width 2 :color 
,bg-tab-inactive)
-                                     :background ,bg-tab-inactive :foreground 
,fg-dim)))
-    `(tab-line-tab-inactive-alternate ((,class :box (:line-width 2 :color 
,bg-tab-inactive-alt)
-                                               :background 
,bg-tab-inactive-alt :foreground ,fg-main)))
+    `(tab-line-tab-inactive ((,class ,@(modus-themes--tab bg-tab-inactive 
bg-tab-inactive-accent fg-dim nil t))))
+    `(tab-line-tab-inactive-alternate ((,class ,@(modus-themes--tab 
bg-tab-inactive-alt
+                                                                    
bg-tab-inactive-alt-accent fg-main nil t))))
+    `(tab-line-tab-modified ((,class :foreground ,red-alt-other-faint)))
 ;;;;; table (built-in table.el)
     `(table-cell ((,class :background ,blue-nuanced-bg)))
 ;;;;; telega
@@ -7194,7 +7383,10 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(transient-heading ((,class :inherit bold :foreground ,fg-main)))
     `(transient-inactive-argument ((,class :inherit shadow)))
     `(transient-inactive-value ((,class :inherit shadow)))
-    `(transient-key ((,class :inherit modus-themes-key-binding)))
+    ;; FIXME 2021-08-28: using `modus-themes-key-binding' leads to
+    ;; misalignments because of the added box property.
+    ;; `(transient-key ((,class :inherit modus-themes-key-binding)))
+    `(transient-key ((,class :inherit bold :foreground ,blue-alt-other)))
     `(transient-mismatched-key ((,class :underline t)))
     `(transient-nonstandard-key ((,class :underline t)))
     `(transient-pink ((,class :inherit bold :foreground ,magenta-alt-faint)))
@@ -7397,7 +7589,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
     `(web-mode-jsx-depth-3-face ((,class :background ,bg-special-cold 
:foreground ,fg-special-cold)))
     `(web-mode-jsx-depth-4-face ((,class :background ,bg-alt :foreground 
,blue-refine-fg)))
     `(web-mode-jsx-depth-5-face ((,class :background ,bg-alt :foreground 
,blue-nuanced-fg)))
-    `(web-mode-keyword-face ((,class :inherit :inherit 
font-lock-keyword-face)))
+    `(web-mode-keyword-face ((,class :inherit font-lock-keyword-face)))
     `(web-mode-param-name-face ((,class :inherit 
font-lock-function-name-face)))
     `(web-mode-part-comment-face ((,class :inherit web-mode-comment-face)))
     `(web-mode-part-face ((,class :inherit web-mode-block-face)))
@@ -7590,9 +7782,7 @@ by virtue of calling either of 
`modus-themes-load-operandi' and
 (provide 'modus-themes)
 
 ;; Local Variables:
-;; time-stamp-start: "Last-Modified:[ \t]+\\\\?[\"<]"
-;; time-stamp-end: "\\\\?[\">]"
-;; time-stamp-format: "%Y-%02m-%02d %02H:%02M:%02S %5z"
+;; time-stamp-pattern: "Last-Modified: <%Y-%02m-%02d %02H:%02M:%02S %5z>"
 ;; End:
 
 ;;; modus-themes.el ends here
diff --git a/etc/themes/modus-vivendi-theme.el 
b/etc/themes/modus-vivendi-theme.el
index 6ff359d341..919009278b 100644
--- a/etc/themes/modus-vivendi-theme.el
+++ b/etc/themes/modus-vivendi-theme.el
@@ -4,7 +4,7 @@
 
 ;; Author: Protesilaos Stavrou <info@protesilaos.com>
 ;; URL: https://gitlab.com/protesilaos/modus-themes
-;; Version: 1.5.0
+;; Version: 1.6.0
 ;; Package-Requires: ((emacs "26.1"))
 ;; Keywords: faces, theme, accessibility
 
diff --git a/etc/themes/tango-dark-theme.el b/etc/themes/tango-dark-theme.el
index 1a33676eba..fe4a24746e 100644
--- a/etc/themes/tango-dark-theme.el
+++ b/etc/themes/tango-dark-theme.el
@@ -45,7 +45,9 @@ Semantic, and Ansi-Color faces are included.")
       (alum-4 "#888a85") (alum-5 "#555753") (alum-6 "#2e3436")
       ;; Not in Tango palette; used for better contrast.
       (cham-0 "#b4fa70") (blue-0 "#8cc4ff") (plum-0 "#e9b2e3")
-      (red-0 "#ff4b4b")  (alum-5.5 "#41423f") (alum-7 "#212526"))
+      (red-0 "#ff4b4b")  (alum-5.5 "#41423f") (alum-7 "#212526")
+      ;; Not in Tango palette; used for ANSI cyan.
+      (cyan-1 "#34e2e2") (cyan-2 "#06989a"))
 
   (custom-theme-set-faces
    'tango-dark
@@ -162,12 +164,31 @@ Semantic, and Ansi-Color faces are included.")
    `(semantic-decoration-on-unparsed-includes
      ((,class (:background ,alum-5.5))))
    `(semantic-tag-boundary-face ((,class (:overline ,blue-1))))
-   `(semantic-unmatched-syntax-face ((,class (:underline ,red-1)))))
-
-  (custom-theme-set-variables
-   'tango-dark
-   `(ansi-color-names-vector [,alum-7 ,red-0 ,cham-0 ,butter-1
-                             ,blue-1 ,plum-1 ,blue-0 ,alum-1])))
+   `(semantic-unmatched-syntax-face ((,class (:underline ,red-1))))
+   ;; ANSI colors
+   `(ansi-color-black ((,class (:background ,alum-7 :foreground ,alum-7))))
+   `(ansi-color-red ((,class (:background ,red-1 :foreground ,red-1))))
+   `(ansi-color-green ((,class (:background ,cham-2 :foreground ,cham-2))))
+   `(ansi-color-yellow ((,class (:background ,butter-2 :foreground 
,butter-2))))
+   `(ansi-color-blue ((,class (:background ,blue-2 :foreground ,blue-2))))
+   `(ansi-color-magenta ((,class (:background ,plum-1 :foreground ,plum-1))))
+   `(ansi-color-cyan ((,class (:background ,cyan-2 :foreground ,cyan-2))))
+   `(ansi-color-white ((,class (:background ,alum-2 :foreground ,alum-2))))
+   `(ansi-color-bright-black ((,class (:background ,alum-5
+                                      :foreground ,alum-5))))
+   `(ansi-color-bright-red ((,class (:background ,red-0 :foreground ,red-0))))
+   `(ansi-color-bright-green ((,class (:background ,cham-1
+                                      :foreground ,cham-1))))
+   `(ansi-color-bright-yellow ((,class (:background ,butter-1
+                                       :foreground ,butter-1))))
+   `(ansi-color-bright-blue ((,class (:background ,blue-0
+                                     :foreground ,blue-0))))
+   `(ansi-color-bright-magenta ((,class (:background ,plum-0
+                                        :foreground ,plum-0))))
+   `(ansi-color-bright-cyan ((,class (:background ,cyan-1
+                                     :foreground ,cyan-1))))
+   `(ansi-color-bright-white ((,class (:background ,alum-1
+                                      :foreground ,alum-1))))))
 
 (provide-theme 'tango-dark)
 
diff --git a/etc/themes/tango-theme.el b/etc/themes/tango-theme.el
index 9ee2619ce2..5c429b0b70 100644
--- a/etc/themes/tango-theme.el
+++ b/etc/themes/tango-theme.el
@@ -44,7 +44,9 @@ Semantic, and Ansi-Color faces are included.")
       (alum-1 "#eeeeec") (alum-2 "#d3d7cf") (alum-3 "#babdb6")
       (alum-4 "#888a85") (alum-5 "#5f615c") (alum-6 "#2e3436")
       ;; Not in Tango palette; used for better contrast.
-      (cham-4 "#346604") (blue-0 "#8cc4ff") (orange-4 "#b35000"))
+      (cham-4 "#346604") (blue-0 "#8cc4ff") (orange-4 "#b35000")
+      ;; Not in Tango palette; used for ANSI cyan.
+      (cyan-1 "#34e2e2") (cyan-2 "#06989a"))
 
   (custom-theme-set-faces
    'tango
@@ -145,12 +147,31 @@ Semantic, and Ansi-Color faces are included.")
    `(semantic-decoration-on-unparsed-includes
      ((,class (:underline  ,orange-3))))
    `(semantic-tag-boundary-face ((,class (:overline   ,blue-1))))
-   `(semantic-unmatched-syntax-face ((,class (:underline  ,red-1)))))
-
-  (custom-theme-set-variables
-   'tango
-   `(ansi-color-names-vector [,alum-6 ,red-3 ,cham-3 ,butter-3
-                                     ,blue-3 ,plum-3 ,blue-1 ,alum-1])))
+   `(semantic-unmatched-syntax-face ((,class (:underline  ,red-1))))
+   ;; ANSI colors
+   `(ansi-color-black ((,class (:background ,alum-6 :foreground ,alum-6))))
+   `(ansi-color-red ((,class (:background ,red-2 :foreground ,red-2))))
+   `(ansi-color-green ((,class (:background ,cham-3 :foreground ,cham-3))))
+   `(ansi-color-yellow ((,class (:background ,butter-3 :foreground 
,butter-3))))
+   `(ansi-color-blue ((,class (:background ,blue-2 :foreground ,blue-2))))
+   `(ansi-color-magenta ((,class (:background ,plum-2 :foreground ,plum-2))))
+   `(ansi-color-cyan ((,class (:background ,cyan-2 :foreground ,cyan-2))))
+   `(ansi-color-white ((,class (:background ,alum-2 :foreground ,alum-2))))
+   `(ansi-color-bright-black ((,class (:background ,alum-5
+                                      :foreground ,alum-5))))
+   `(ansi-color-bright-red ((,class (:background ,red-1 :foreground ,red-1))))
+   `(ansi-color-bright-green ((,class (:background ,cham-1
+                                      :foreground ,cham-1))))
+   `(ansi-color-bright-yellow ((,class (:background ,butter-1
+                                       :foreground ,butter-1))))
+   `(ansi-color-bright-blue ((,class (:background ,blue-1
+                                     :foreground ,blue-1))))
+   `(ansi-color-bright-magenta ((,class (:background ,plum-1
+                                        :foreground ,plum-1))))
+   `(ansi-color-bright-cyan ((,class (:background ,cyan-1
+                                     :foreground ,cyan-1))))
+   `(ansi-color-bright-white ((,class (:background ,alum-1
+                                      :foreground ,alum-1))))))
 
 (provide-theme 'tango)
 
diff --git a/etc/themes/whiteboard-theme.el b/etc/themes/whiteboard-theme.el
index 729c082a33..9cf8e7dfc9 100644
--- a/etc/themes/whiteboard-theme.el
+++ b/etc/themes/whiteboard-theme.el
@@ -63,6 +63,8 @@
    `(ido-first-match ((,class (:weight normal :foreground "DarkOrange3"))))
    `(ido-only-match ((,class (:foreground "SeaGreen4"))))
    `(ido-subdir ((,class (:foreground nil :inherit font-lock-keyword-face))))
+   `(image-dired-thumb-flagged ((,class :background "Red1")))
+   `(image-dired-thumb-mark ((,class :background "dodgerblue3")))
    `(info-header-node ((,class (:foreground "DeepSkyBlue1"))))
    `(info-header-xref ((,class (:foreground "SeaGreen2"))))
    `(info-menu-header ((,class (:family "helv" :weight bold))))
diff --git a/etc/themes/wombat-theme.el b/etc/themes/wombat-theme.el
index 922114fb64..d769c33721 100644
--- a/etc/themes/wombat-theme.el
+++ b/etc/themes/wombat-theme.el
@@ -95,12 +95,24 @@ are included.")
    `(message-header-subject ((,class (:foreground "#cae682"))))
    `(message-header-to ((,class (:foreground "#cae682"))))
    `(message-cited-text ((,class (:foreground "#99968b"))))
-   `(message-separator ((,class (:foreground "#e5786d" :weight bold))))))
-
-(custom-theme-set-variables
- 'wombat
- '(ansi-color-names-vector ["#242424" "#e5786d" "#95e454" "#cae682"
-                           "#8ac6f2" "#333366" "#ccaa8f" "#f6f3e8"]))
+   `(message-separator ((,class (:foreground "#e5786d" :weight bold))))
+   ;; ANSI colors
+   `(ansi-color-black ((,class (:background "#242424" :foreground "#242424"))))
+   `(ansi-color-red ((,class (:background "#b85149" :foreground "#b85149"))))
+   `(ansi-color-green ((,class (:background "#92a65e" :foreground "#92a65e"))))
+   `(ansi-color-yellow ((,class (:background "#ccaa8f" :foreground 
"#ccaa8f"))))
+   `(ansi-color-blue ((,class (:background "#5b98c2" :foreground "#5b98c2"))))
+   `(ansi-color-magenta ((,class (:background "#64619a" :foreground 
"#64619a"))))
+   `(ansi-color-cyan ((,class (:background "#3f9f9e" :foreground "#3f9f9e"))))
+   `(ansi-color-white ((,class (:background "#f6f3e8" :foreground "#f6f3e8"))))
+   `(ansi-color-bright-black ((,class (:background "#444444" :foreground 
"#444444"))))
+   `(ansi-color-bright-red ((,class (:background "#e5786d" :foreground 
"#e5786d"))))
+   `(ansi-color-bright-green ((,class (:background "#95e454" :foreground 
"#95e454"))))
+   `(ansi-color-bright-yellow ((,class (:background "#edc4a3" :foreground 
"#edc4a3"))))
+   `(ansi-color-bright-blue ((,class (:background "#8ac6f2" :foreground 
"#8ac6f2"))))
+   `(ansi-color-bright-magenta ((,class (:background "#a6a1de" :foreground 
"#a6a1de"))))
+   `(ansi-color-bright-cyan ((,class (:background "#70cecc" :foreground 
"#70cecc"))))
+   `(ansi-color-bright-white ((,class (:background "#ffffff" :foreground 
"#ffffff"))))))
 
 (provide-theme 'wombat)
 
diff --git a/etc/tutorials/TUTORIAL.he b/etc/tutorials/TUTORIAL.he
index 2ee4f74c32..465768aa87 100644
--- a/etc/tutorials/TUTORIAL.he
+++ b/etc/tutorials/TUTORIAL.he
@@ -1,4 +1,4 @@
-שיעור ראשון בשימוש ב־‫Emacs‬. זכויות שימוש ראה בסוף המסמך.
+שיעור ראשון בשימוש ב־‪Emacs‬. זכויות שימוש ראה בסוף המסמך.
 
 פקודות רבות של Emacs משתמשות במקש CONTROL (בדרך־כלל מסומן ב־CTRL)
 או במקש META (בדרך־כלל מסומן ALT). במקום לציין את כל השמות האפשריים
@@ -24,7 +24,7 @@
 שימו לב לחפיפה של שתי שורות כאשר אתם עוברים ממסך למסך, מה שמבטיח רציפות
 מסוימת בעת קריאת הטקסט.
 
-הטקסט שלפניכם הינו עותק של שיעור בשימוש ב־‫Emacs‬ שהותאם קלות עבורכם.
+הטקסט שלפניכם הינו עותק של שיעור בשימוש ב־‪Emacs‬ שהותאם קלות עבורכם.
 בהמשך תקבלו הוראות לנסות פקודות שונות כדי לבצע שינויים בטקסט הזה. אם
 במקרה תשנו את הטקסט לפני שנבקש, אל דאגה: זוהי "עריכה" שהיא יעודו של
 Emacs.
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 018e81e422..0e800dd7e8 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -80,9 +80,6 @@ char *w32_getenv (const char *);
 #include <sys/stat.h>
 #include <unistd.h>
 
-#ifndef WINDOWSNT
-# include <acl.h>
-#endif
 #include <filename.h>
 #include <intprops.h>
 #include <min-max.h>
@@ -94,10 +91,6 @@ char *w32_getenv (const char *);
 # pragma GCC diagnostic ignored "-Wformat-truncation=2"
 #endif
 
-#if !defined O_PATH && !defined WINDOWSNT
-# define O_PATH O_SEARCH
-#endif
-
 
 /* Name used to invoke this program.  */
 static char const *progname;
@@ -123,6 +116,9 @@ static bool eval;
 /* True means open a new frame.  --create-frame etc.  */
 static bool create_frame;
 
+/* True means reuse a frame if it already exists.  */
+static bool reuse_frame;
+
 /* The display on which Emacs should work.  --display.  */
 static char const *display;
 
@@ -172,6 +168,7 @@ static struct option const longopts[] =
   { "tty",     no_argument,       NULL, 't' },
   { "nw",      no_argument,       NULL, 't' },
   { "create-frame", no_argument,   NULL, 'c' },
+  { "reuse-frame", no_argument,   NULL, 'r' },
   { "alternate-editor", required_argument, NULL, 'a' },
   { "frame-parameters", required_argument, NULL, 'F' },
 #ifdef SOCKETS_IN_FILE_SYSTEM
@@ -558,6 +555,11 @@ decode_options (int argc, char **argv)
          create_frame = true;
           break;
 
+       case 'r':
+         create_frame = true;
+         reuse_frame = true;
+         break;
+
        case 'p':
          parent_id = optarg;
          create_frame = true;
@@ -654,6 +656,8 @@ The following OPTIONS are accepted:\n\
 -nw, -t, --tty                 Open a new Emacs frame on the current 
terminal\n\
 -c, --create-frame     Create a new frame instead of trying to\n\
                        use the current Emacs frame\n\
+-r, --reuse-frame      Create a new frame if none exists, otherwise\n\
+                       use the current Emacs frame\n\
 ", "\
 -F ALIST, --frame-parameters=ALIST\n\
                        Set the parameters of a new frame\n\
@@ -1135,6 +1139,12 @@ process_grouping (void)
 
 #ifdef SOCKETS_IN_FILE_SYSTEM
 
+# include <acl.h>
+
+# ifndef O_PATH
+#  define O_PATH O_SEARCH
+# endif
+
 /* A local socket address.  The union avoids the need to cast.  */
 union local_sockaddr
 {
@@ -1942,7 +1952,7 @@ main (int argc, char **argv)
   if (nowait)
     send_to_emacs (emacs_socket, "-nowait ");
 
-  if (!create_frame)
+  if (!create_frame || reuse_frame)
     send_to_emacs (emacs_socket, "-current-frame ");
 
   if (display)
diff --git a/lib-src/ntlib.c b/lib-src/ntlib.c
index bcbc006431..c8bcf742fe 100644
--- a/lib-src/ntlib.c
+++ b/lib-src/ntlib.c
@@ -20,6 +20,9 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <windows.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -287,9 +290,6 @@ is_exec (const char * name)
         stricmp (p, ".cmd") == 0));
 }
 
-/* FIXME?  This is in configure.ac now - is this still needed?  */
-#define IS_DIRECTORY_SEP(x) ((x) == '/' || (x) == '\\')
-
 /* We need stat/fsfat below because nt/inc/sys/stat.h defines struct
    stat that is incompatible with the MS run-time libraries.  */
 int
diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c
index d378e0b027..e7496053a8 100644
--- a/lib-src/seccomp-filter.c
+++ b/lib-src/seccomp-filter.c
@@ -351,6 +351,8 @@ main (int argc, char **argv)
      calls at startup time to set up thread-local storage.  */
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (execve));
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (set_tid_address));
+  RULE (SCMP_ACT_ERRNO (EINVAL), SCMP_SYS (prctl),
+       SCMP_A0_32 (SCMP_CMP_EQ, PR_CAPBSET_READ));
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (arch_prctl),
         SCMP_A0_32 (SCMP_CMP_EQ, ARCH_SET_FS));
   RULE (SCMP_ACT_ERRNO (EINVAL), SCMP_SYS (arch_prctl),
diff --git a/lib/_Noreturn.h b/lib/_Noreturn.h
index fb718bc069..6fed3c7971 100644
--- a/lib/_Noreturn.h
+++ b/lib/_Noreturn.h
@@ -2,16 +2,16 @@
    Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
+   under the terms of the GNU Lesser General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _Noreturn
@@ -29,7 +29,7 @@
 # elif ((!defined __cplusplus || defined __clang__) \
         && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
             || (!defined __STRICT_ANSI__ \
-                && (__4 < __GNUC__ + (7 <= __GNUC_MINOR__) \
+                && (4 < __GNUC__ + (7 <= __GNUC_MINOR__) \
                     || (defined __apple_build_version__ \
                         ? 6000000 <= __apple_build_version__ \
                         : 3 < __clang_major__ + (5 <= __clang_minor__))))))
diff --git a/lib/af_alg.h b/lib/af_alg.h
index 4c5854cc99..f0fe7fc055 100644
--- a/lib/af_alg.h
+++ b/lib/af_alg.h
@@ -1,18 +1,18 @@
 /* af_alg.h - Compute message digests from file streams and buffers.
-   Copyright (C) 2018-2020 Free Software Foundation, Inc.
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2, or (at your option) any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Matteo Croce <mcroce@redhat.com>, 2018.
    Documentation by Bruno Haible <bruno@clisp.org>, 2018.  */
diff --git a/lib/alloca.in.h b/lib/alloca.in.h
index 0a6137e037..65c2d4d939 100644
--- a/lib/alloca.in.h
+++ b/lib/alloca.in.h
@@ -3,20 +3,18 @@
    Copyright (C) 1995, 1999, 2001-2004, 2006-2021 Free Software Foundation,
    Inc.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with this program; if not, see
-   <https://www.gnu.org/licenses/>.
-  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
    means there is a real alloca function.  */
diff --git a/lib/allocator.c b/lib/allocator.c
index 2c1a3da03a..2262de9ff3 100644
--- a/lib/allocator.c
+++ b/lib/allocator.c
@@ -1,3 +1,20 @@
+/* Memory allocators such as malloc+free.
+
+   Copyright (C) 2011-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #define _GL_USE_STDLIB_ALLOC 1
 #include <config.h>
 #include "allocator.h"
diff --git a/lib/allocator.h b/lib/allocator.h
index cfa0535774..f0e8f34896 100644
--- a/lib/allocator.h
+++ b/lib/allocator.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/arg-nonnull.h b/lib/arg-nonnull.h
index 5b81b50a87..b4de241e90 100644
--- a/lib/arg-nonnull.h
+++ b/lib/arg-nonnull.h
@@ -2,16 +2,16 @@
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
+   under the terms of the GNU Lesser General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
diff --git a/lib/attribute.h b/lib/attribute.h
index 82245279eb..eb36188d48 100644
--- a/lib/attribute.h
+++ b/lib/attribute.h
@@ -2,17 +2,17 @@
 
    Copyright 2020-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
@@ -32,7 +32,7 @@
 
 
 /* This file defines two types of attributes:
-   * C2X standard attributes.  These have macro names that do not begin with
+   * C2x standard attributes.  These have macro names that do not begin with
      'ATTRIBUTE_'.
    * Selected GCC attributes; see:
      https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
@@ -76,6 +76,14 @@
 /* Applies to: function, pointer to function, function types.  */
 #define ATTRIBUTE_ALLOC_SIZE(args) _GL_ATTRIBUTE_ALLOC_SIZE (args)
 
+/* ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
+   that can be freed by passing them as the Ith argument to the
+   function F.
+   ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that
+   can be freed via 'free'; it can be used only after declaring 'free'.  */
+/* Applies to: functions.  Cannot be used on inline functions.  */
+#define ATTRIBUTE_DEALLOC(f, i) _GL_ATTRIBUTE_DEALLOC(f, i)
+#define ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC_FREE
 
 /* Attributes for variadic functions.  */
 
diff --git a/lib/binary-io.c b/lib/binary-io.c
index f2678972ef..adc0ae2b0c 100644
--- a/lib/binary-io.c
+++ b/lib/binary-io.c
@@ -1,17 +1,17 @@
 /* Binary mode I/O.
    Copyright 2017-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/binary-io.h b/lib/binary-io.h
index 8654fd2d39..642f08b1ba 100644
--- a/lib/binary-io.h
+++ b/lib/binary-io.h
@@ -1,17 +1,17 @@
 /* Binary mode I/O.
    Copyright (C) 2001, 2003, 2005, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _BINARY_H
@@ -47,7 +47,7 @@ _GL_INLINE_HEADER_BEGIN
   /* Use a function rather than a macro, to avoid gcc warnings
      "warning: statement with no effect".  */
 BINARY_IO_INLINE int
-__gl_setmode (int fd _GL_UNUSED, int mode _GL_UNUSED)
+__gl_setmode (_GL_UNUSED int fd, _GL_UNUSED int mode)
 {
   return O_BINARY;
 }
diff --git a/lib/byteswap.in.h b/lib/byteswap.in.h
index 2b7d5abe1b..113f878027 100644
--- a/lib/byteswap.in.h
+++ b/lib/byteswap.in.h
@@ -2,17 +2,17 @@
    Copyright (C) 2005, 2007, 2009-2021 Free Software Foundation, Inc.
    Written by Oskar Liljeblad <oskar@osk.mine.nu>, 2005.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _GL_BYTESWAP_H
diff --git a/lib/c++defs.h b/lib/c++defs.h
index 39df1bc76b..a47b61a009 100644
--- a/lib/c++defs.h
+++ b/lib/c++defs.h
@@ -2,16 +2,16 @@
    Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
+   under the terms of the GNU Lesser General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _GL_CXXDEFS_H
diff --git a/lib/c-ctype.c b/lib/c-ctype.c
index 5d9d4d87a6..300f97c292 100644
--- a/lib/c-ctype.c
+++ b/lib/c-ctype.c
@@ -1,3 +1,21 @@
+/* Character handling in C locale.
+
+   Copyright (C) 2003-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define C_CTYPE_INLINE _GL_EXTERN_INLINE
 #include "c-ctype.h"
diff --git a/lib/c-ctype.h b/lib/c-ctype.h
index bf24a88310..3a652ac1f2 100644
--- a/lib/c-ctype.h
+++ b/lib/c-ctype.h
@@ -7,18 +7,18 @@
 
    Copyright (C) 2000-2003, 2006, 2008-2021 Free Software Foundation, Inc.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef C_CTYPE_H
 #define C_CTYPE_H
diff --git a/lib/c-strcase.h b/lib/c-strcase.h
index 089edfe7eb..82f99bb06b 100644
--- a/lib/c-strcase.h
+++ b/lib/c-strcase.h
@@ -2,18 +2,18 @@
    Copyright (C) 1995-1996, 2001, 2003, 2005, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef C_STRCASE_H
 #define C_STRCASE_H
diff --git a/lib/c-strcasecmp.c b/lib/c-strcasecmp.c
index 55479d6a33..3c22455082 100644
--- a/lib/c-strcasecmp.c
+++ b/lib/c-strcasecmp.c
@@ -1,18 +1,18 @@
 /* c-strcasecmp.c -- case insensitive string comparator in C locale
    Copyright (C) 1998-1999, 2005-2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/lib/c-strncasecmp.c b/lib/c-strncasecmp.c
index 02bc0f2ecd..f3ca786cb3 100644
--- a/lib/c-strncasecmp.c
+++ b/lib/c-strncasecmp.c
@@ -1,18 +1,18 @@
 /* c-strncasecmp.c -- case insensitive string comparator in C locale
    Copyright (C) 1998-1999, 2005-2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index b7dba08994..92e9639720 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -21,7 +21,6 @@
    optimizes away the name == NULL test below.  */
 # define _GL_ARG_NONNULL(params)
 
-# define _GL_USE_STDLIB_ALLOC 1
 # include <libc-config.h>
 #endif
 
@@ -75,7 +74,12 @@
 # define __pathconf pathconf
 # define __rawmemchr rawmemchr
 # define __readlink readlink
-# define __stat stat
+# if IN_RELOCWRAPPER
+    /* When building the relocatable program wrapper, use the system's memmove
+       function, not the gnulib override, otherwise we would get a link error.
+     */
+#  undef memmove
+# endif
 #endif
 
 /* Suppress bogus GCC -Wmaybe-uninitialized warnings.  */
@@ -100,7 +104,7 @@ file_accessible (char const *file)
   return __faccessat (AT_FDCWD, file, F_OK, AT_EACCESS) == 0;
 # else
   struct stat st;
-  return __stat (file, &st) == 0 || errno == EOVERFLOW;
+  return stat (file, &st) == 0 || errno == EOVERFLOW;
 # endif
 }
 
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c
index 18cfc114b6..9d0c125ecb 100644
--- a/lib/careadlinkat.c
+++ b/lib/careadlinkat.c
@@ -3,17 +3,17 @@
    Copyright (C) 2001, 2003-2004, 2007, 2009-2021 Free Software Foundation,
    Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert, Bruno Haible, and Jim Meyering.  */
@@ -22,6 +22,9 @@
 
 #include "careadlinkat.h"
 
+#include "idx.h"
+#include "minmax.h"
+
 #include <errno.h>
 #include <limits.h>
 #include <string.h>
@@ -65,11 +68,6 @@ readlink_stk (int fd, char const *filename,
               ssize_t (*preadlinkat) (int, char const *, char *, size_t),
               char stack_buf[STACK_BUF_SIZE])
 {
-  char *buf;
-  size_t buf_size;
-  size_t buf_size_max =
-    SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
-
   if (! alloc)
     alloc = &stdlib_allocator;
 
@@ -79,14 +77,14 @@ readlink_stk (int fd, char const *filename,
       buffer_size = STACK_BUF_SIZE;
     }
 
-  buf = buffer;
-  buf_size = buffer_size;
+  char *buf = buffer;
+  idx_t buf_size_max = MIN (IDX_MAX, MIN (SSIZE_MAX, SIZE_MAX));
+  idx_t buf_size = MIN (buffer_size, buf_size_max);
 
   while (buf)
     {
       /* Attempt to read the link into the current buffer.  */
-      ssize_t link_length = preadlinkat (fd, filename, buf, buf_size);
-      size_t link_size;
+      idx_t link_length = preadlinkat (fd, filename, buf, buf_size);
       if (link_length < 0)
         {
           if (buf != buffer)
@@ -98,7 +96,7 @@ readlink_stk (int fd, char const *filename,
           return NULL;
         }
 
-      link_size = link_length;
+      idx_t link_size = link_length;
 
       if (link_size < buf_size)
         {
@@ -127,17 +125,13 @@ readlink_stk (int fd, char const *filename,
       if (buf != buffer)
         alloc->free (buf);
 
-      if (buf_size < buf_size_max / 2)
-        buf_size = 2 * buf_size + 1;
-      else if (buf_size < buf_size_max)
-        buf_size = buf_size_max;
-      else if (buf_size_max < SIZE_MAX)
+      if (buf_size_max / 2 <= buf_size)
         {
           errno = ENAMETOOLONG;
           return NULL;
         }
-      else
-        break;
+
+      buf_size = 2 * buf_size + 1;
       buf = alloc->allocate (buf_size);
     }
 
diff --git a/lib/careadlinkat.h b/lib/careadlinkat.h
index c506fac3cb..a3517b827a 100644
--- a/lib/careadlinkat.h
+++ b/lib/careadlinkat.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert, Bruno Haible, and Jim Meyering.  */
diff --git a/lib/cdefs.h b/lib/cdefs.h
index 17a0919cd8..4dac9d264d 100644
--- a/lib/cdefs.h
+++ b/lib/cdefs.h
@@ -2,16 +2,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -259,9 +259,7 @@
 # define __attribute_const__ /* Ignore */
 #endif
 
-#if defined __STDC_VERSION__ && 201710L < __STDC_VERSION__
-# define __attribute_maybe_unused__ [[__maybe_unused__]]
-#elif __GNUC_PREREQ (2,7) || __glibc_has_attribute (__unused__)
+#if __GNUC_PREREQ (2,7) || __glibc_has_attribute (__unused__)
 # define __attribute_maybe_unused__ __attribute__ ((__unused__))
 #else
 # define __attribute_maybe_unused__ /* Ignore */
@@ -320,16 +318,28 @@
 #endif
 
 /* The nonnull function attribute marks pointer parameters that
-   must not be NULL.  */
-#ifndef __nonnull
+   must not be NULL.  This has the name __nonnull in glibc,
+   and __attribute_nonnull__ in files shared with Gnulib to avoid
+   collision with a different __nonnull in DragonFlyBSD 5.9.  */
+#ifndef __attribute_nonnull__
 # if __GNUC_PREREQ (3,3) || __glibc_has_attribute (__nonnull__)
-#  define __nonnull(params) __attribute__ ((__nonnull__ params))
+#  define __attribute_nonnull__(params) __attribute__ ((__nonnull__ params))
+# else
+#  define __attribute_nonnull__(params)
+# endif
+#endif
+#ifndef __nonnull
+# define __nonnull(params) __attribute_nonnull__ (params)
+#endif
+
+/* The returns_nonnull function attribute marks the return type of the function
+   as always being non-null.  */
+#ifndef __returns_nonnull
+# if __GNUC_PREREQ (4, 9) || __glibc_has_attribute (__returns_nonnull__)
+# define __returns_nonnull __attribute__ ((__returns_nonnull__))
 # else
-#  define __nonnull(params)
+# define __returns_nonnull
 # endif
-#elif !defined __GLIBC__
-# undef __nonnull
-# define __nonnull(params) _GL_ATTRIBUTE_NONNULL (params)
 #endif
 
 /* If fortification mode, we warn about unused results of certain
@@ -485,9 +495,9 @@
       [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]
 #endif
 
-/* The #ifndef lets Gnulib avoid including these on non-glibc
-   platforms, where the includes typically do not exist.  */
-#ifndef __WORDSIZE
+/* Gnulib avoids including these, as they don't work on non-glibc or
+   older glibc platforms.  */
+#ifndef __GNULIB_CDEFS
 # include <bits/wordsize.h>
 # include <bits/long-double.h>
 #endif
@@ -594,9 +604,26 @@ _Static_assert (0, "IEEE 128-bits long double requires 
redirection on this platf
    array according to access mode, or at least one element when
    size-index is not provided:
      access (access-mode, <ref-index> [, <size-index>])  */
-#define __attr_access(x) __attribute__ ((__access__ x))
+#  define __attr_access(x) __attribute__ ((__access__ x))
+#  if __GNUC_PREREQ (11, 0)
+#    define __attr_access_none(argno) __attribute__ ((__access__ (__none__, 
argno)))
+#  else
+#    define __attr_access_none(argno)
+#  endif
 #else
 #  define __attr_access(x)
+#  define __attr_access_none(argno)
+#endif
+
+#if __GNUC_PREREQ (11, 0)
+/* Designates dealloc as a function to call to deallocate objects
+   allocated by the declared function.  */
+# define __attr_dealloc(dealloc, argno) \
+    __attribute__ ((__malloc__ (dealloc, argno)))
+# define __attr_dealloc_free __attr_dealloc (__builtin_free, 1)
+#else
+# define __attr_dealloc(dealloc, argno)
+# define __attr_dealloc_free
 #endif
 
 /* Specify that a function such as setjmp or vfork may return
diff --git a/lib/cloexec.c b/lib/cloexec.c
index 8363ddaa60..7defa93446 100644
--- a/lib/cloexec.c
+++ b/lib/cloexec.c
@@ -2,20 +2,20 @@
 
    Copyright (C) 1991, 2004-2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-   The code is taken from glibc/manual/llio.texi  */
+/* The code is taken from glibc/manual/llio.texi  */
 
 #include <config.h>
 
diff --git a/lib/cloexec.h b/lib/cloexec.h
index 5ca0e6413e..97a3659efb 100644
--- a/lib/cloexec.h
+++ b/lib/cloexec.h
@@ -2,20 +2,18 @@
 
    Copyright (C) 2004, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-*/
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <stdbool.h>
 
diff --git a/lib/close-stream.h b/lib/close-stream.h
index be3d4196b0..8a58a48e61 100644
--- a/lib/close-stream.h
+++ b/lib/close-stream.h
@@ -1,2 +1,20 @@
+/* Close a stream, with nicer error checking than fclose's.
+
+   Copyright (C) 2006-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <stdio.h>
+
 int close_stream (FILE *stream);
diff --git a/lib/copy-file-range.c b/lib/copy-file-range.c
index e73c78b5aa..17df577055 100644
--- a/lib/copy-file-range.c
+++ b/lib/copy-file-range.c
@@ -1,17 +1,17 @@
 /* Stub for copy_file_range
    Copyright 2019-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/count-leading-zeros.c b/lib/count-leading-zeros.c
index d0c0704f58..7cf1ac2ff0 100644
--- a/lib/count-leading-zeros.c
+++ b/lib/count-leading-zeros.c
@@ -1,3 +1,21 @@
+/* Count the number of leading 0 bits in a word.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define COUNT_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE
 #include "count-leading-zeros.h"
diff --git a/lib/count-leading-zeros.h b/lib/count-leading-zeros.h
index 575ec3b4d0..cef529ac13 100644
--- a/lib/count-leading-zeros.h
+++ b/lib/count-leading-zeros.h
@@ -1,17 +1,17 @@
 /* count-leading-zeros.h -- counts the number of leading 0 bits in a word.
    Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Eric Blake.  */
diff --git a/lib/count-one-bits.c b/lib/count-one-bits.c
index 66341d77cd..d9b4f5e848 100644
--- a/lib/count-one-bits.c
+++ b/lib/count-one-bits.c
@@ -1,4 +1,22 @@
+/* Count the number of 1-bits in a word.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define COUNT_ONE_BITS_INLINE _GL_EXTERN_INLINE
 #include "count-one-bits.h"
 
diff --git a/lib/count-one-bits.h b/lib/count-one-bits.h
index 1a14f11f15..5e87a572b0 100644
--- a/lib/count-one-bits.h
+++ b/lib/count-one-bits.h
@@ -1,17 +1,17 @@
 /* count-one-bits.h -- counts the number of 1-bits in a word.
    Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Ben Pfaff.  */
diff --git a/lib/count-trailing-zeros.c b/lib/count-trailing-zeros.c
index f3da886742..538b01dc02 100644
--- a/lib/count-trailing-zeros.c
+++ b/lib/count-trailing-zeros.c
@@ -1,3 +1,21 @@
+/* Count the number of trailing 0 bits in a word.
+
+   Copyright 2013-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define COUNT_TRAILING_ZEROS_INLINE _GL_EXTERN_INLINE
 #include "count-trailing-zeros.h"
diff --git a/lib/count-trailing-zeros.h b/lib/count-trailing-zeros.h
index 5a8ef563ea..f81674c571 100644
--- a/lib/count-trailing-zeros.h
+++ b/lib/count-trailing-zeros.h
@@ -1,17 +1,17 @@
 /* count-trailing-zeros.h -- counts the number of trailing 0 bits in a word.
    Copyright 2013-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/dirent.in.h b/lib/dirent.in.h
index 4666972b15..4deb0cb466 100644
--- a/lib/dirent.in.h
+++ b/lib/dirent.in.h
@@ -1,17 +1,17 @@
 /* A GNU-like <dirent.h>.
    Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _@GUARD_PREFIX@_DIRENT_H
@@ -55,6 +55,28 @@ typedef struct gl_directory DIR;
 # endif
 #endif
 
+/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
+   that can be freed by passing them as the Ith argument to the
+   function F.  */
+#ifndef _GL_ATTRIBUTE_DEALLOC
+# if __GNUC__ >= 11
+#  define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
+# else
+#  define _GL_ATTRIBUTE_DEALLOC(f, i)
+# endif
+#endif
+
+/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly
+   allocated memory.  */
+/* Applies to: functions.  */
+#ifndef _GL_ATTRIBUTE_MALLOC
+# if __GNUC__ >= 3 || defined __clang__
+#  define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+#  define _GL_ATTRIBUTE_MALLOC
+# endif
+#endif
+
 /* The __attribute__ feature is available in gcc versions 2.5 and later.
    The attribute __pure__ was added in gcc 2.96.  */
 #ifndef _GL_ATTRIBUTE_PURE
@@ -74,6 +96,30 @@ typedef struct gl_directory DIR;
 
 /* Declare overridden functions.  */
 
+#if @GNULIB_CLOSEDIR@
+# if @REPLACE_CLOSEDIR@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef closedir
+#   define closedir rpl_closedir
+#   define GNULIB_defined_closedir 1
+#  endif
+_GL_FUNCDECL_RPL (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (closedir, int, (DIR *dirp));
+# else
+#  if !@HAVE_CLOSEDIR@
+_GL_FUNCDECL_SYS (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (closedir, int, (DIR *dirp));
+# endif
+_GL_CXXALIASWARN (closedir);
+#elif defined GNULIB_POSIXCHECK
+# undef closedir
+# if HAVE_RAW_DECL_CLOSEDIR
+_GL_WARN_ON_USE (closedir, "closedir is not portable - "
+                 "use gnulib module closedir for portability");
+# endif
+#endif
+
 #if @GNULIB_OPENDIR@
 # if @REPLACE_OPENDIR@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -81,20 +127,36 @@ typedef struct gl_directory DIR;
 #   define opendir rpl_opendir
 #   define GNULIB_defined_opendir 1
 #  endif
-_GL_FUNCDECL_RPL (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL 
((1)));
+_GL_FUNCDECL_RPL (opendir, DIR *,
+                  (const char *dir_name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
 _GL_CXXALIAS_RPL (opendir, DIR *, (const char *dir_name));
 # else
-#  if !@HAVE_OPENDIR@
-_GL_FUNCDECL_SYS (opendir, DIR *, (const char *dir_name) _GL_ARG_NONNULL 
((1)));
+#  if !@HAVE_OPENDIR@ || __GNUC__ >= 11
+_GL_FUNCDECL_SYS (opendir, DIR *,
+                  (const char *dir_name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
 #  endif
 _GL_CXXALIAS_SYS (opendir, DIR *, (const char *dir_name));
 # endif
 _GL_CXXALIASWARN (opendir);
-#elif defined GNULIB_POSIXCHECK
-# undef opendir
-# if HAVE_RAW_DECL_OPENDIR
+#else
+# if @GNULIB_CLOSEDIR@ && __GNUC__ >= 11 && !defined opendir
+/* For -Wmismatched-dealloc: Associate opendir with closedir or
+   rpl_closedir.  */
+_GL_FUNCDECL_SYS (opendir, DIR *,
+                  (const char *dir_name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef opendir
+#  if HAVE_RAW_DECL_OPENDIR
 _GL_WARN_ON_USE (opendir, "opendir is not portable - "
                  "use gnulib module opendir for portability");
+#  endif
 # endif
 #endif
 
@@ -126,30 +188,6 @@ _GL_WARN_ON_USE (rewinddir, "rewinddir is not portable - "
 # endif
 #endif
 
-#if @GNULIB_CLOSEDIR@
-# if @REPLACE_CLOSEDIR@
-#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#   undef closedir
-#   define closedir rpl_closedir
-#   define GNULIB_defined_closedir 1
-#  endif
-_GL_FUNCDECL_RPL (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
-_GL_CXXALIAS_RPL (closedir, int, (DIR *dirp));
-# else
-#  if !@HAVE_CLOSEDIR@
-_GL_FUNCDECL_SYS (closedir, int, (DIR *dirp) _GL_ARG_NONNULL ((1)));
-#  endif
-_GL_CXXALIAS_SYS (closedir, int, (DIR *dirp));
-# endif
-_GL_CXXALIASWARN (closedir);
-#elif defined GNULIB_POSIXCHECK
-# undef closedir
-# if HAVE_RAW_DECL_CLOSEDIR
-_GL_WARN_ON_USE (closedir, "closedir is not portable - "
-                 "use gnulib module closedir for portability");
-# endif
-#endif
-
 #if @GNULIB_DIRFD@
 /* Return the file descriptor associated with the given directory stream,
    or -1 if none exists.  */
@@ -200,20 +238,33 @@ _GL_WARN_ON_USE (dirfd, "dirfd is unportable - "
 #   undef fdopendir
 #   define fdopendir rpl_fdopendir
 #  endif
-_GL_FUNCDECL_RPL (fdopendir, DIR *, (int fd));
+_GL_FUNCDECL_RPL (fdopendir, DIR *,
+                  (int fd)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
 _GL_CXXALIAS_RPL (fdopendir, DIR *, (int fd));
 # else
-#  if !@HAVE_FDOPENDIR@ || !@HAVE_DECL_FDOPENDIR@
-_GL_FUNCDECL_SYS (fdopendir, DIR *, (int fd));
+#  if !@HAVE_FDOPENDIR@ || !@HAVE_DECL_FDOPENDIR@ || __GNUC__ >= 11
+_GL_FUNCDECL_SYS (fdopendir, DIR *,
+                  (int fd)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
 #  endif
 _GL_CXXALIAS_SYS (fdopendir, DIR *, (int fd));
 # endif
 _GL_CXXALIASWARN (fdopendir);
-#elif defined GNULIB_POSIXCHECK
-# undef fdopendir
-# if HAVE_RAW_DECL_FDOPENDIR
+#else
+# if @GNULIB_CLOSEDIR@ && __GNUC__ >= 11 && !defined fdopendir
+/* For -Wmismatched-dealloc: Associate fdopendir with closedir or
+   rpl_closedir.  */
+_GL_FUNCDECL_SYS (fdopendir, DIR *,
+                  (int fd)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (closedir, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef fdopendir
+#  if HAVE_RAW_DECL_FDOPENDIR
 _GL_WARN_ON_USE (fdopendir, "fdopendir is unportable - "
                  "use gnulib module fdopendir for portability");
+#  endif
 # endif
 #endif
 
diff --git a/lib/dirfd.c b/lib/dirfd.c
index ced7531c5e..640cb4ff13 100644
--- a/lib/dirfd.c
+++ b/lib/dirfd.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 2001, 2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Jim Meyering. */
diff --git a/lib/dtoastr.c b/lib/dtoastr.c
index aed181d66b..5baba92922 100644
--- a/lib/dtoastr.c
+++ b/lib/dtoastr.c
@@ -1,2 +1,19 @@
+/* Convert 'double' to accurate string.
+
+   Copyright (C) 2010-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #define LENGTH 2
 #include "ftoastr.c"
diff --git a/lib/dup2.c b/lib/dup2.c
index c4a0a29fbd..53e5552132 100644
--- a/lib/dup2.c
+++ b/lib/dup2.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 1999, 2004-2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Paul Eggert */
diff --git a/lib/dynarray.h b/lib/dynarray.h
index 6da3e87e55..ec64273b3a 100644
--- a/lib/dynarray.h
+++ b/lib/dynarray.h
@@ -1,31 +1,284 @@
 /* Type-safe arrays which grow dynamically.
    Copyright 2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-/* Written by Paul Eggert, 2021.  */
+/* Written by Paul Eggert and Bruno Haible, 2021.  */
 
 #ifndef _GL_DYNARRAY_H
 #define _GL_DYNARRAY_H
 
-#include <libc-config.h>
+/* Before including this file, you need to define:
 
+   DYNARRAY_STRUCT
+      The struct tag of dynamic array to be defined.
+
+   DYNARRAY_ELEMENT
+      The type name of the element type.  Elements are copied
+      as if by memcpy, and can change address as the dynamic
+      array grows.
+
+   DYNARRAY_PREFIX
+      The prefix of the functions which are defined.
+
+   The following parameters are optional:
+
+   DYNARRAY_ELEMENT_FREE
+      DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the
+      contents of elements. E is of type  DYNARRAY_ELEMENT *.
+
+   DYNARRAY_ELEMENT_INIT
+      DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new
+      element.  E is of type  DYNARRAY_ELEMENT *.
+      If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is
+      defined, new elements are automatically zero-initialized.
+      Otherwise, new elements have undefined contents.
+
+   DYNARRAY_INITIAL_SIZE
+      The size of the statically allocated array (default:
+      at least 2, more elements if they fit into 128 bytes).
+      Must be a preprocessor constant.  If DYNARRAY_INITIAL_SIZE is 0,
+      there is no statically allocated array at, and all non-empty
+      arrays are heap-allocated.
+
+   DYNARRAY_FINAL_TYPE
+      The name of the type which holds the final array.  If not
+      defined, is PREFIX##finalize not provided.  DYNARRAY_FINAL_TYPE
+      must be a struct type, with members of type DYNARRAY_ELEMENT and
+      size_t at the start (in this order).
+
+   These macros are undefined after this header file has been
+   included.
+
+   The following types are provided (their members are private to the
+   dynarray implementation):
+
+     struct DYNARRAY_STRUCT
+
+   The following functions are provided:
+ */
+
+/* Initialize a dynamic array object.  This must be called before any
+   use of the object.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Deallocate the dynamic array and its elements.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Return true if the dynamic array is in an error state.  */
+#if 0
+static bool
+       DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Mark the dynamic array as failed.  All elements are deallocated as
+   a side effect.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Return the number of elements which have been added to the dynamic
+   array.  */
+#if 0
+static size_t
+       DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Return a pointer to the first array element, if any.  For a
+   zero-length array, the pointer can be NULL even though the dynamic
+   array has not entered the failure state.  */
+#if 0
+static DYNARRAY_ELEMENT *
+       DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Return a pointer one element past the last array element.  For a
+   zero-length array, the pointer can be NULL even though the dynamic
+   array has not entered the failure state.  */
+#if 0
+static DYNARRAY_ELEMENT *
+       DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Return a pointer to the array element at INDEX.  Terminate the
+   process if INDEX is out of bounds.  */
+#if 0
+static DYNARRAY_ELEMENT *
+       DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *list, size_t index);
+#endif
+
+/* Add ITEM at the end of the array, enlarging it by one element.
+   Mark *LIST as failed if the dynamic array allocation size cannot be
+   increased.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *list,
+                             DYNARRAY_ELEMENT item);
+#endif
+
+/* Allocate a place for a new element in *LIST and return a pointer to
+   it.  The pointer can be NULL if the dynamic array cannot be
+   enlarged due to a memory allocation failure.  */
+#if 0
+static DYNARRAY_ELEMENT *
+       DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Change the size of *LIST to SIZE.  If SIZE is larger than the
+   existing size, new elements are added (which can be initialized).
+   Otherwise, the list is truncated, and elements are freed.  Return
+   false on memory allocation failure (and mark *LIST as failed).  */
+#if 0
+static bool
+       DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *list, size_t size);
+#endif
+
+/* Remove the last element of LIST if it is present.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *list);
+#endif
+
+/* Remove all elements from the list.  The elements are freed, but the
+   list itself is not.  */
+#if 0
+static void
+       DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *list);
+#endif
+
+#if defined DYNARRAY_FINAL_TYPE
+/* Transfer the dynamic array to a permanent location at *RESULT.
+   Returns true on success on false on allocation failure.  In either
+   case, *LIST is re-initialized and can be reused.  A NULL pointer is
+   stored in *RESULT if LIST refers to an empty list.  On success, the
+   pointer in *RESULT is heap-allocated and must be deallocated using
+   free.  */
+#if 0
+static bool
+       DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list,
+                                  DYNARRAY_FINAL_TYPE *result);
+#endif
+#else /* !defined DYNARRAY_FINAL_TYPE */
+/* Transfer the dynamic array to a heap-allocated array and return a
+   pointer to it.  The pointer is NULL if memory allocation fails, or
+   if the array is empty, so this function should be used only for
+   arrays which are known not be empty (usually because they always
+   have a sentinel at the end).  If LENGTHP is not NULL, the array
+   length is written to *LENGTHP.  *LIST is re-initialized and can be
+   reused.  */
+#if 0
+static DYNARRAY_ELEMENT *
+       DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *list,
+                                  size_t *lengthp);
+#endif
+#endif
+
+/* A minimal example which provides a growing list of integers can be
+   defined like this:
+
+     struct int_array
+     {
+       // Pointer to result array followed by its length,
+       // as required by DYNARRAY_FINAL_TYPE.
+       int *array;
+       size_t length;
+     };
+
+     #define DYNARRAY_STRUCT dynarray_int
+     #define DYNARRAY_ELEMENT int
+     #define DYNARRAY_PREFIX dynarray_int_
+     #define DYNARRAY_FINAL_TYPE struct int_array
+     #include <malloc/dynarray-skeleton.c>
+
+   To create a three-element array with elements 1, 2, 3, use this
+   code:
+
+     struct dynarray_int dyn;
+     dynarray_int_init (&dyn);
+     for (int i = 1; i <= 3; ++i)
+       {
+         int *place = dynarray_int_emplace (&dyn);
+         assert (place != NULL);
+         *place = i;
+       }
+     struct int_array result;
+     bool ok = dynarray_int_finalize (&dyn, &result);
+     assert (ok);
+     assert (result.length == 3);
+     assert (result.array[0] == 1);
+     assert (result.array[1] == 2);
+     assert (result.array[2] == 3);
+     free (result.array);
+
+   If the elements contain resources which must be freed, define
+   DYNARRAY_ELEMENT_FREE appropriately, like this:
+
+     struct str_array
+     {
+       char **array;
+       size_t length;
+     };
+
+     #define DYNARRAY_STRUCT dynarray_str
+     #define DYNARRAY_ELEMENT char *
+     #define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
+     #define DYNARRAY_PREFIX dynarray_str_
+     #define DYNARRAY_FINAL_TYPE struct str_array
+     #include <malloc/dynarray-skeleton.c>
+ */
+
+
+/* The implementation is imported from glibc.  */
+
+/* Avoid possible conflicts with symbols exported by the GNU libc.  */
 #define __libc_dynarray_at_failure gl_dynarray_at_failure
 #define __libc_dynarray_emplace_enlarge gl_dynarray_emplace_enlarge
 #define __libc_dynarray_finalize gl_dynarray_finalize
 #define __libc_dynarray_resize_clear gl_dynarray_resize_clear
 #define __libc_dynarray_resize gl_dynarray_resize
-#include <malloc/dynarray.h>
+
+#if defined DYNARRAY_STRUCT || defined DYNARRAY_ELEMENT || defined 
DYNARRAY_PREFIX
+
+# ifndef _GL_LIKELY
+/* Rely on __builtin_expect, as provided by the module 'builtin-expect'.  */
+#  define _GL_LIKELY(cond) __builtin_expect ((cond), 1)
+#  define _GL_UNLIKELY(cond) __builtin_expect ((cond), 0)
+# endif
+
+/* Define auxiliary structs and declare auxiliary functions, common to all
+   instantiations of dynarray.  */
+# include <malloc/dynarray.gl.h>
+
+/* Define the instantiation, specified through
+     DYNARRAY_STRUCT
+     DYNARRAY_ELEMENT
+     DYNARRAY_PREFIX
+   etc.  */
+# include <malloc/dynarray-skeleton.gl.h>
+
+#else
+
+/* This file is being included from one of the malloc/dynarray_*.c files.  */
+# include <malloc/dynarray.h>
+
+#endif
 
 #endif /* _GL_DYNARRAY_H */
diff --git a/lib/eloop-threshold.h b/lib/eloop-threshold.h
index 27d07a7296..fcd30ab1e6 100644
--- a/lib/eloop-threshold.h
+++ b/lib/eloop-threshold.h
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/errno.in.h b/lib/errno.in.h
index c6ab4e88e1..3cad9e2d62 100644
--- a/lib/errno.in.h
+++ b/lib/errno.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _@GUARD_PREFIX@_ERRNO_H
 
diff --git a/lib/euidaccess.c b/lib/euidaccess.c
index ef65961d81..a86cebd179 100644
--- a/lib/euidaccess.c
+++ b/lib/euidaccess.c
@@ -5,17 +5,17 @@
 
    This file is part of the GNU C Library.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by David MacKenzie and Torbjorn Granlund.
diff --git a/lib/execinfo.c b/lib/execinfo.c
index 0bcd9f078b..18a1051b25 100644
--- a/lib/execinfo.c
+++ b/lib/execinfo.c
@@ -1,3 +1,21 @@
+/* Information about executables.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define _GL_EXECINFO_INLINE _GL_EXTERN_INLINE
 #include "execinfo.h"
diff --git a/lib/execinfo.in.h b/lib/execinfo.in.h
index 790bec087e..98bb8039b7 100644
--- a/lib/execinfo.in.h
+++ b/lib/execinfo.in.h
@@ -3,16 +3,16 @@
    Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c
index f50ed0875d..2906c04d0f 100644
--- a/lib/explicit_bzero.c
+++ b/lib/explicit_bzero.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/fcntl.c b/lib/fcntl.c
index 9d6b10fa30..c744eb91e6 100644
--- a/lib/fcntl.c
+++ b/lib/fcntl.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Eric Blake <ebb9@byu.net>.  */
diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h
index 0b14467c54..26dedc3041 100644
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Paul Eggert */
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
index c667ae9d24..800af227cc 100644
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -1,6 +1,6 @@
 /* Test whether a file has a nontrivial ACL.  -*- coding: utf-8 -*-
 
-   Copyright (C) 2002-2003, 2005-2020 Free Software Foundation, Inc.
+   Copyright (C) 2002-2003, 2005-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -206,9 +206,7 @@ file_has_acl (char const *name, struct stat const *sb)
               ;
             else
               {
-                int saved_errno = errno;
                 free (malloced);
-                errno = saved_errno;
                 return -1;
               }
           }
@@ -281,9 +279,7 @@ file_has_acl (char const *name, struct stat const *sb)
               ;
             else
               {
-                int saved_errno = errno;
                 free (malloced);
-                errno = saved_errno;
                 return -1;
               }
           }
@@ -353,7 +349,7 @@ file_has_acl (char const *name, struct stat const *sb)
             {
               struct stat statbuf;
 
-              if (stat (name, &statbuf) < 0)
+              if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
                 return -1;
 
               return acl_nontrivial (count, entries);
@@ -418,11 +414,7 @@ file_has_acl (char const *name, struct stat const *sb)
           if (errno != ENOSPC)
             {
               if (acl != aclbuf)
-                {
-                  int saved_errno = errno;
-                  free (acl);
-                  errno = saved_errno;
-                }
+                free (acl);
               return -1;
             }
           aclsize = 2 * aclsize;
diff --git a/lib/filename.h b/lib/filename.h
index 541ffec0d5..dafe3dfddb 100644
--- a/lib/filename.h
+++ b/lib/filename.h
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/filevercmp.c b/lib/filevercmp.c
index 6b7226de6c..fca23ec4fc 100644
--- a/lib/filevercmp.c
+++ b/lib/filevercmp.c
@@ -3,18 +3,18 @@
    Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au>
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>. */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include "filevercmp.h"
diff --git a/lib/filevercmp.h b/lib/filevercmp.h
index 5de212f436..c210452938 100644
--- a/lib/filevercmp.h
+++ b/lib/filevercmp.h
@@ -3,18 +3,18 @@
    Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au>
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>. */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef FILEVERCMP_H
 #define FILEVERCMP_H
diff --git a/lib/flexmember.h b/lib/flexmember.h
index 9f6e1bf110..1b19a2bfd9 100644
--- a/lib/flexmember.h
+++ b/lib/flexmember.h
@@ -5,16 +5,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.
 
diff --git a/lib/free.c b/lib/free.c
index 5c89787aba..780f03dd11 100644
--- a/lib/free.c
+++ b/lib/free.c
@@ -2,32 +2,36 @@
 
    Copyright (C) 2003, 2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Paul Eggert */
 
 #include <config.h>
 
+/* Specification.  */
 #include <stdlib.h>
 
-#include <errno.h>
+/* A function definition is only needed if HAVE_FREE_POSIX is not defined.  */
+#if !HAVE_FREE_POSIX
+
+# include <errno.h>
 
 void
 rpl_free (void *p)
-#undef free
+# undef free
 {
-#if defined __GNUC__ && !defined __clang__
+# if defined __GNUC__ && !defined __clang__
   /* An invalid GCC optimization
      <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98396>
      would optimize away the assignments in the code below, when link-time
@@ -39,9 +43,11 @@ rpl_free (void *p)
   errno = 0;
   free (p);
   errno = err[errno == 0];
-#else
+# else
   int err = errno;
   free (p);
   errno = err;
-#endif
+# endif
 }
+
+#endif
diff --git a/lib/fsusage.c b/lib/fsusage.c
index 35de136cd8..740cdc219a 100644
--- a/lib/fsusage.c
+++ b/lib/fsusage.c
@@ -3,17 +3,17 @@
    Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/fsusage.h b/lib/fsusage.h
index e0657b3651..b3f58d9994 100644
--- a/lib/fsusage.h
+++ b/lib/fsusage.h
@@ -3,17 +3,17 @@
    Copyright (C) 1991-1992, 1997, 2003-2006, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Space usage statistics for a file system.  Blocks are 512-byte. */
diff --git a/lib/fsync.c b/lib/fsync.c
index a5280f281c..99a932d770 100644
--- a/lib/fsync.c
+++ b/lib/fsync.c
@@ -9,17 +9,17 @@
 
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This library is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/futimens.c b/lib/futimens.c
index 99eaba95df..273cc87187 100644
--- a/lib/futimens.c
+++ b/lib/futimens.c
@@ -1,17 +1,17 @@
 /* Set the access and modification time of an open fd.
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Eric Blake */
diff --git a/lib/getdtablesize.c b/lib/getdtablesize.c
index 56eaf5d32c..5006c2d5c5 100644
--- a/lib/getdtablesize.c
+++ b/lib/getdtablesize.c
@@ -2,17 +2,17 @@
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2008.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/getgroups.c b/lib/getgroups.c
index af602a74d3..96665257f2 100644
--- a/lib/getgroups.c
+++ b/lib/getgroups.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 1996, 1999, 2003, 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Jim Meyering */
@@ -30,7 +30,7 @@
 /* Provide a stub that fails with ENOSYS, since there is no group
    information available on mingw.  */
 int
-getgroups (int n _GL_UNUSED, GETGROUPS_T *groups _GL_UNUSED)
+getgroups (_GL_UNUSED int n, _GL_UNUSED GETGROUPS_T *groups)
 {
   errno = ENOSYS;
   return -1;
@@ -70,7 +70,6 @@ rpl_getgroups (int n, gid_t *group)
 {
   int n_groups;
   GETGROUPS_T *gbuf;
-  int saved_errno;
 
   if (n < 0)
     {
@@ -99,9 +98,7 @@ rpl_getgroups (int n, gid_t *group)
           while (n--)
             group[n] = gbuf[n];
         }
-      saved_errno = errno;
       free (gbuf);
-      errno = saved_errno;
       return result;
     }
 
@@ -121,10 +118,7 @@ rpl_getgroups (int n, gid_t *group)
       n *= 2;
     }
 
-  saved_errno = errno;
   free (gbuf);
-  errno = saved_errno;
-
   return n_groups;
 }
 
diff --git a/lib/getopt-cdefs.in.h b/lib/getopt-cdefs.in.h
index 11fe536ff2..33e3d4b3d8 100644
--- a/lib/getopt-cdefs.in.h
+++ b/lib/getopt-cdefs.in.h
@@ -4,19 +4,18 @@
    Unlike most of the getopt implementation, it is NOT shared
    with the GNU C Library.
 
-   This file is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 3 of
-   the License, or (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This file is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with gnulib; if not, see
-   <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _GETOPT_CDEFS_H
 #define _GETOPT_CDEFS_H 1
diff --git a/lib/getopt-core.h b/lib/getopt-core.h
index 05d16b0740..ceb14d0597 100644
--- a/lib/getopt-core.h
+++ b/lib/getopt-core.h
@@ -4,16 +4,16 @@
    Patches to this file should be submitted to both projects.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/getopt-ext.h b/lib/getopt-ext.h
index 9b11b47f0f..f82a8c6129 100644
--- a/lib/getopt-ext.h
+++ b/lib/getopt-ext.h
@@ -4,16 +4,16 @@
    Patches to this file should be submitted to both projects.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/getopt-pfx-core.h b/lib/getopt-pfx-core.h
index 78990a345a..b1733a3497 100644
--- a/lib/getopt-pfx-core.h
+++ b/lib/getopt-pfx-core.h
@@ -4,19 +4,18 @@
    Unlike most of the getopt implementation, it is NOT shared
    with the GNU C Library.
 
-   This file is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 3 of
-   the License, or (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This file is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with gnulib; if not, see
-   <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _GETOPT_PFX_CORE_H
 #define _GETOPT_PFX_CORE_H 1
diff --git a/lib/getopt-pfx-ext.h b/lib/getopt-pfx-ext.h
index 61ea8d2b1d..b9a14ba05a 100644
--- a/lib/getopt-pfx-ext.h
+++ b/lib/getopt-pfx-ext.h
@@ -4,19 +4,18 @@
    Unlike most of the getopt implementation, it is NOT shared
    with the GNU C Library.
 
-   This file is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 3 of
-   the License, or (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This file is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with gnulib; if not, see
-   <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _GETOPT_PFX_EXT_H
 #define _GETOPT_PFX_EXT_H 1
diff --git a/lib/getopt.c b/lib/getopt.c
index dd96c18407..7f3aa5aa3d 100644
--- a/lib/getopt.c
+++ b/lib/getopt.c
@@ -4,16 +4,16 @@
    Patches to this file should be submitted to both projects.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -378,8 +378,8 @@ process_long_option (int argc, char **argv, const char 
*optstring,
 /* Initialize internal data upon the first call to getopt.  */
 
 static const char *
-_getopt_initialize (int argc _GL_UNUSED,
-                   char **argv _GL_UNUSED, const char *optstring,
+_getopt_initialize (_GL_UNUSED int argc,
+                   _GL_UNUSED char **argv, const char *optstring,
                    struct _getopt_data *d, int posixly_correct)
 {
   /* Start processing options with ARGV-element 1 (since ARGV-element 0
diff --git a/lib/getopt.in.h b/lib/getopt.in.h
index 541fb9da2e..bf884f0322 100644
--- a/lib/getopt.in.h
+++ b/lib/getopt.in.h
@@ -5,18 +5,18 @@
    with the GNU C Library, which supplies a different version of
    this file.
 
-   This file is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 3 of
-   the License, or (at your option) any later version.
-
-   This file is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public
-   License along with gnulib; if not, see <https://www.gnu.org/licenses/>.  */
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _@GUARD_PREFIX@_GETOPT_H
 
diff --git a/lib/getopt1.c b/lib/getopt1.c
index ca24eb811f..5a928062fd 100644
--- a/lib/getopt1.c
+++ b/lib/getopt1.c
@@ -4,16 +4,16 @@
    Patches to this file should be submitted to both projects.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/getopt_int.h b/lib/getopt_int.h
index b70ff5badf..91254e487d 100644
--- a/lib/getopt_int.h
+++ b/lib/getopt_int.h
@@ -4,16 +4,16 @@
    Patches to this file should be submitted to both projects.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/getrandom.c b/lib/getrandom.c
index 41212fb329..a186c4d3bd 100644
--- a/lib/getrandom.c
+++ b/lib/getrandom.c
@@ -2,17 +2,17 @@
 
    Copyright 2020-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
@@ -178,7 +178,11 @@ getrandom (void *buffer, size_t length, unsigned int flags)
                     + (flags & GRND_NONBLOCK ? O_NONBLOCK : 0));
       fd = open (randdevice[devrandom], oflags);
       if (fd < 0)
-        return fd;
+        {
+          if (errno == ENOENT || errno == ENOTDIR)
+            errno = ENOSYS;
+          return -1;
+        }
       randfd[devrandom] = fd;
     }
 
diff --git a/lib/gettext.h b/lib/gettext.h
index 3552157efd..f1c7a24075 100644
--- a/lib/gettext.h
+++ b/lib/gettext.h
@@ -2,18 +2,18 @@
    Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _LIBGETTEXT_H
 #define _LIBGETTEXT_H 1
diff --git a/lib/gettime.c b/lib/gettime.c
index fb721b2cda..8f28a32df1 100644
--- a/lib/gettime.c
+++ b/lib/gettime.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 2002, 2004-2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c
index b1c93e1c3a..2a222fc5b7 100644
--- a/lib/gettimeofday.c
+++ b/lib/gettimeofday.c
@@ -2,18 +2,18 @@
 
    Copyright (C) 2001-2003, 2005-2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Jim Meyering */
 
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 0b9aaf6d9e..c7c7eb455b 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -36,12 +36,12 @@
 #  --no-vc-files \
 #  --avoid=btowc \
 #  --avoid=close \
+#  --avoid=crypto/af_alg \
 #  --avoid=dup \
 #  --avoid=fchdir \
 #  --avoid=fstat \
 #  --avoid=langinfo \
 #  --avoid=lock \
-#  --avoid=malloc-posix \
 #  --avoid=mbrtowc \
 #  --avoid=mbsinit \
 #  --avoid=memchr \
@@ -80,6 +80,7 @@
 #  count-leading-zeros \
 #  count-one-bits \
 #  count-trailing-zeros \
+#  crypto/md5 \
 #  crypto/md5-buffer \
 #  crypto/sha1-buffer \
 #  crypto/sha256-buffer \
@@ -128,6 +129,7 @@
 #  minmax \
 #  mkostemp \
 #  mktime \
+#  nproc \
 #  nstrftime \
 #  pathmax \
 #  pipe2 \
@@ -172,9 +174,7 @@ ALLOCA = @ALLOCA@
 ALLOCA_H = @ALLOCA_H@
 ALSA_CFLAGS = @ALSA_CFLAGS@
 ALSA_LIBS = @ALSA_LIBS@
-AM_DEFAULT_V = @AM_DEFAULT_V@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AM_V = @AM_V@
 APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
 AR = @AR@
 ARFLAGS = @ARFLAGS@
@@ -213,6 +213,7 @@ DEFS = @DEFS@
 DESLIB = @DESLIB@
 DOCMISC_W32 = @DOCMISC_W32@
 DUMPING = @DUMPING@
+DYNLIB_OBJ = @DYNLIB_OBJ@
 ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
@@ -255,297 +256,300 @@ GL_GENERATE_MINI_GMP_H = @GL_GENERATE_MINI_GMP_H@
 GL_GENERATE_STDALIGN_H = @GL_GENERATE_STDALIGN_H@
 GL_GENERATE_STDDEF_H = @GL_GENERATE_STDDEF_H@
 GL_GENERATE_STDINT_H = @GL_GENERATE_STDINT_H@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ALPHASORT = @GL_GNULIB_ALPHASORT@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CLOSEDIR = @GL_GNULIB_CLOSEDIR@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DIRFD = @GL_GNULIB_DIRFD@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FDOPENDIR = @GL_GNULIB_FDOPENDIR@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETRANDOM = @GL_GNULIB_GETRANDOM@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OPENDIR = @GL_GNULIB_OPENDIR@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PSELECT = @GL_GNULIB_PSELECT@
+GL_GNULIB_PTHREAD_SIGMASK = @GL_GNULIB_PTHREAD_SIGMASK@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RAISE = @GL_GNULIB_RAISE@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READDIR = @GL_GNULIB_READDIR@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_REWINDDIR = @GL_GNULIB_REWINDDIR@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANDIR = @GL_GNULIB_SCANDIR@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SELECT = @GL_GNULIB_SELECT@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGACTION = @GL_GNULIB_SIGACTION@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@
+GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
 GMALLOC_OBJ = @GMALLOC_OBJ@
 GMP_H = @GMP_H@
-GNULIB_ACCESS = @GNULIB_ACCESS@
-GNULIB_ALIGNED_ALLOC = @GNULIB_ALIGNED_ALLOC@
-GNULIB_ALPHASORT = @GNULIB_ALPHASORT@
-GNULIB_ATOLL = @GNULIB_ATOLL@
-GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
-GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@
-GNULIB_CHDIR = @GNULIB_CHDIR@
-GNULIB_CHOWN = @GNULIB_CHOWN@
-GNULIB_CLOSE = @GNULIB_CLOSE@
-GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@
-GNULIB_COPY_FILE_RANGE = @GNULIB_COPY_FILE_RANGE@
-GNULIB_CREAT = @GNULIB_CREAT@
-GNULIB_CTIME = @GNULIB_CTIME@
-GNULIB_DIRFD = @GNULIB_DIRFD@
-GNULIB_DPRINTF = @GNULIB_DPRINTF@
-GNULIB_DUP = @GNULIB_DUP@
-GNULIB_DUP2 = @GNULIB_DUP2@
-GNULIB_DUP3 = @GNULIB_DUP3@
-GNULIB_ENVIRON = @GNULIB_ENVIRON@
-GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@
-GNULIB_EXECL = @GNULIB_EXECL@
-GNULIB_EXECLE = @GNULIB_EXECLE@
-GNULIB_EXECLP = @GNULIB_EXECLP@
-GNULIB_EXECV = @GNULIB_EXECV@
-GNULIB_EXECVE = @GNULIB_EXECVE@
-GNULIB_EXECVP = @GNULIB_EXECVP@
-GNULIB_EXECVPE = @GNULIB_EXECVPE@
-GNULIB_EXPLICIT_BZERO = @GNULIB_EXPLICIT_BZERO@
-GNULIB_FACCESSAT = @GNULIB_FACCESSAT@
-GNULIB_FCHDIR = @GNULIB_FCHDIR@
-GNULIB_FCHMODAT = @GNULIB_FCHMODAT@
-GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@
-GNULIB_FCLOSE = @GNULIB_FCLOSE@
-GNULIB_FCNTL = @GNULIB_FCNTL@
-GNULIB_FDATASYNC = @GNULIB_FDATASYNC@
-GNULIB_FDOPEN = @GNULIB_FDOPEN@
-GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@
-GNULIB_FFLUSH = @GNULIB_FFLUSH@
-GNULIB_FFSL = @GNULIB_FFSL@
-GNULIB_FFSLL = @GNULIB_FFSLL@
-GNULIB_FGETC = @GNULIB_FGETC@
-GNULIB_FGETS = @GNULIB_FGETS@
-GNULIB_FOPEN = @GNULIB_FOPEN@
-GNULIB_FPRINTF = @GNULIB_FPRINTF@
-GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
-GNULIB_FPURGE = @GNULIB_FPURGE@
-GNULIB_FPUTC = @GNULIB_FPUTC@
-GNULIB_FPUTS = @GNULIB_FPUTS@
-GNULIB_FREAD = @GNULIB_FREAD@
-GNULIB_FREE_POSIX = @GNULIB_FREE_POSIX@
-GNULIB_FREOPEN = @GNULIB_FREOPEN@
-GNULIB_FSCANF = @GNULIB_FSCANF@
-GNULIB_FSEEK = @GNULIB_FSEEK@
-GNULIB_FSEEKO = @GNULIB_FSEEKO@
-GNULIB_FSTAT = @GNULIB_FSTAT@
-GNULIB_FSTATAT = @GNULIB_FSTATAT@
-GNULIB_FSYNC = @GNULIB_FSYNC@
-GNULIB_FTELL = @GNULIB_FTELL@
-GNULIB_FTELLO = @GNULIB_FTELLO@
-GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
-GNULIB_FUTIMENS = @GNULIB_FUTIMENS@
-GNULIB_FWRITE = @GNULIB_FWRITE@
-GNULIB_GETC = @GNULIB_GETC@
-GNULIB_GETCHAR = @GNULIB_GETCHAR@
-GNULIB_GETCWD = @GNULIB_GETCWD@
-GNULIB_GETDELIM = @GNULIB_GETDELIM@
-GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@
-GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@
-GNULIB_GETENTROPY = @GNULIB_GETENTROPY@
-GNULIB_GETGROUPS = @GNULIB_GETGROUPS@
-GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@
-GNULIB_GETLINE = @GNULIB_GETLINE@
-GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@
-GNULIB_GETLOGIN = @GNULIB_GETLOGIN@
-GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
-GNULIB_GETOPT_POSIX = @GNULIB_GETOPT_POSIX@
-GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@
-GNULIB_GETPASS = @GNULIB_GETPASS@
-GNULIB_GETRANDOM = @GNULIB_GETRANDOM@
-GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
 GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
-GNULIB_GETUMASK = @GNULIB_GETUMASK@
-GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@
-GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@
-GNULIB_GRANTPT = @GNULIB_GRANTPT@
-GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@
-GNULIB_IMAXABS = @GNULIB_IMAXABS@
-GNULIB_IMAXDIV = @GNULIB_IMAXDIV@
-GNULIB_ISATTY = @GNULIB_ISATTY@
-GNULIB_LCHMOD = @GNULIB_LCHMOD@
-GNULIB_LCHOWN = @GNULIB_LCHOWN@
-GNULIB_LINK = @GNULIB_LINK@
-GNULIB_LINKAT = @GNULIB_LINKAT@
-GNULIB_LOCALTIME = @GNULIB_LOCALTIME@
-GNULIB_LSEEK = @GNULIB_LSEEK@
-GNULIB_LSTAT = @GNULIB_LSTAT@
-GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
-GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
-GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
-GNULIB_MBSCHR = @GNULIB_MBSCHR@
-GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
-GNULIB_MBSLEN = @GNULIB_MBSLEN@
-GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
-GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
-GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
-GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
-GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
-GNULIB_MBSSEP = @GNULIB_MBSSEP@
-GNULIB_MBSSPN = @GNULIB_MBSSPN@
-GNULIB_MBSSTR = @GNULIB_MBSSTR@
-GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
-GNULIB_MBTOWC = @GNULIB_MBTOWC@
-GNULIB_MDA_ACCESS = @GNULIB_MDA_ACCESS@
-GNULIB_MDA_CHDIR = @GNULIB_MDA_CHDIR@
-GNULIB_MDA_CHMOD = @GNULIB_MDA_CHMOD@
-GNULIB_MDA_CLOSE = @GNULIB_MDA_CLOSE@
-GNULIB_MDA_CREAT = @GNULIB_MDA_CREAT@
-GNULIB_MDA_DUP = @GNULIB_MDA_DUP@
-GNULIB_MDA_DUP2 = @GNULIB_MDA_DUP2@
-GNULIB_MDA_ECVT = @GNULIB_MDA_ECVT@
-GNULIB_MDA_EXECL = @GNULIB_MDA_EXECL@
-GNULIB_MDA_EXECLE = @GNULIB_MDA_EXECLE@
-GNULIB_MDA_EXECLP = @GNULIB_MDA_EXECLP@
-GNULIB_MDA_EXECV = @GNULIB_MDA_EXECV@
-GNULIB_MDA_EXECVE = @GNULIB_MDA_EXECVE@
-GNULIB_MDA_EXECVP = @GNULIB_MDA_EXECVP@
-GNULIB_MDA_EXECVPE = @GNULIB_MDA_EXECVPE@
-GNULIB_MDA_FCLOSEALL = @GNULIB_MDA_FCLOSEALL@
-GNULIB_MDA_FCVT = @GNULIB_MDA_FCVT@
-GNULIB_MDA_FDOPEN = @GNULIB_MDA_FDOPEN@
-GNULIB_MDA_FILENO = @GNULIB_MDA_FILENO@
-GNULIB_MDA_GCVT = @GNULIB_MDA_GCVT@
-GNULIB_MDA_GETCWD = @GNULIB_MDA_GETCWD@
-GNULIB_MDA_GETPID = @GNULIB_MDA_GETPID@
-GNULIB_MDA_GETW = @GNULIB_MDA_GETW@
-GNULIB_MDA_ISATTY = @GNULIB_MDA_ISATTY@
-GNULIB_MDA_LSEEK = @GNULIB_MDA_LSEEK@
-GNULIB_MDA_MEMCCPY = @GNULIB_MDA_MEMCCPY@
-GNULIB_MDA_MKDIR = @GNULIB_MDA_MKDIR@
-GNULIB_MDA_MKTEMP = @GNULIB_MDA_MKTEMP@
-GNULIB_MDA_OPEN = @GNULIB_MDA_OPEN@
-GNULIB_MDA_PUTENV = @GNULIB_MDA_PUTENV@
-GNULIB_MDA_PUTW = @GNULIB_MDA_PUTW@
-GNULIB_MDA_READ = @GNULIB_MDA_READ@
-GNULIB_MDA_RMDIR = @GNULIB_MDA_RMDIR@
-GNULIB_MDA_STRDUP = @GNULIB_MDA_STRDUP@
-GNULIB_MDA_SWAB = @GNULIB_MDA_SWAB@
-GNULIB_MDA_TEMPNAM = @GNULIB_MDA_TEMPNAM@
-GNULIB_MDA_TZSET = @GNULIB_MDA_TZSET@
-GNULIB_MDA_UMASK = @GNULIB_MDA_UMASK@
-GNULIB_MDA_UNLINK = @GNULIB_MDA_UNLINK@
-GNULIB_MDA_WRITE = @GNULIB_MDA_WRITE@
-GNULIB_MEMCHR = @GNULIB_MEMCHR@
-GNULIB_MEMMEM = @GNULIB_MEMMEM@
-GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
-GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
-GNULIB_MKDIR = @GNULIB_MKDIR@
-GNULIB_MKDIRAT = @GNULIB_MKDIRAT@
-GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
-GNULIB_MKFIFO = @GNULIB_MKFIFO@
-GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@
-GNULIB_MKNOD = @GNULIB_MKNOD@
-GNULIB_MKNODAT = @GNULIB_MKNODAT@
-GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@
-GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@
-GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
-GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@
-GNULIB_MKTIME = @GNULIB_MKTIME@
-GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@
-GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@
-GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@
-GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@
-GNULIB_OPEN = @GNULIB_OPEN@
-GNULIB_OPENAT = @GNULIB_OPENAT@
-GNULIB_OPENDIR = @GNULIB_OPENDIR@
-GNULIB_OVERRIDES_STRUCT_STAT = @GNULIB_OVERRIDES_STRUCT_STAT@
-GNULIB_OVERRIDES_WINT_T = @GNULIB_OVERRIDES_WINT_T@
-GNULIB_PCLOSE = @GNULIB_PCLOSE@
-GNULIB_PERROR = @GNULIB_PERROR@
-GNULIB_PIPE = @GNULIB_PIPE@
-GNULIB_PIPE2 = @GNULIB_PIPE2@
-GNULIB_POPEN = @GNULIB_POPEN@
-GNULIB_POSIX_MEMALIGN = @GNULIB_POSIX_MEMALIGN@
-GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@
-GNULIB_PREAD = @GNULIB_PREAD@
-GNULIB_PRINTF = @GNULIB_PRINTF@
-GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
-GNULIB_PSELECT = @GNULIB_PSELECT@
-GNULIB_PTHREAD_SIGMASK = @GNULIB_PTHREAD_SIGMASK@
-GNULIB_PTSNAME = @GNULIB_PTSNAME@
-GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@
-GNULIB_PUTC = @GNULIB_PUTC@
-GNULIB_PUTCHAR = @GNULIB_PUTCHAR@
-GNULIB_PUTENV = @GNULIB_PUTENV@
-GNULIB_PUTS = @GNULIB_PUTS@
-GNULIB_PWRITE = @GNULIB_PWRITE@
-GNULIB_QSORT_R = @GNULIB_QSORT_R@
-GNULIB_RAISE = @GNULIB_RAISE@
-GNULIB_RANDOM = @GNULIB_RANDOM@
-GNULIB_RANDOM_R = @GNULIB_RANDOM_R@
-GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@
-GNULIB_READ = @GNULIB_READ@
-GNULIB_READDIR = @GNULIB_READDIR@
-GNULIB_READLINK = @GNULIB_READLINK@
-GNULIB_READLINKAT = @GNULIB_READLINKAT@
-GNULIB_REALLOCARRAY = @GNULIB_REALLOCARRAY@
-GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
-GNULIB_REALPATH = @GNULIB_REALPATH@
-GNULIB_REMOVE = @GNULIB_REMOVE@
-GNULIB_RENAME = @GNULIB_RENAME@
-GNULIB_RENAMEAT = @GNULIB_RENAMEAT@
-GNULIB_REWINDDIR = @GNULIB_REWINDDIR@
-GNULIB_RMDIR = @GNULIB_RMDIR@
-GNULIB_RPMATCH = @GNULIB_RPMATCH@
-GNULIB_SCANDIR = @GNULIB_SCANDIR@
-GNULIB_SCANF = @GNULIB_SCANF@
-GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@
-GNULIB_SELECT = @GNULIB_SELECT@
-GNULIB_SETENV = @GNULIB_SETENV@
-GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@
-GNULIB_SIGABBREV_NP = @GNULIB_SIGABBREV_NP@
-GNULIB_SIGACTION = @GNULIB_SIGACTION@
-GNULIB_SIGDESCR_NP = @GNULIB_SIGDESCR_NP@
-GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@
-GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@
-GNULIB_SLEEP = @GNULIB_SLEEP@
-GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
-GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
-GNULIB_STAT = @GNULIB_STAT@
-GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@
-GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@
-GNULIB_STPCPY = @GNULIB_STPCPY@
-GNULIB_STPNCPY = @GNULIB_STPNCPY@
-GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
-GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
-GNULIB_STRDUP = @GNULIB_STRDUP@
-GNULIB_STRERROR = @GNULIB_STRERROR@
-GNULIB_STRERRORNAME_NP = @GNULIB_STRERRORNAME_NP@
-GNULIB_STRERROR_R = @GNULIB_STRERROR_R@
-GNULIB_STRFTIME = @GNULIB_STRFTIME@
-GNULIB_STRNCAT = @GNULIB_STRNCAT@
-GNULIB_STRNDUP = @GNULIB_STRNDUP@
-GNULIB_STRNLEN = @GNULIB_STRNLEN@
-GNULIB_STRPBRK = @GNULIB_STRPBRK@
-GNULIB_STRPTIME = @GNULIB_STRPTIME@
-GNULIB_STRSEP = @GNULIB_STRSEP@
-GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@
-GNULIB_STRSTR = @GNULIB_STRSTR@
-GNULIB_STRTOD = @GNULIB_STRTOD@
-GNULIB_STRTOIMAX = @GNULIB_STRTOIMAX@
-GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
-GNULIB_STRTOLD = @GNULIB_STRTOLD@
-GNULIB_STRTOLL = @GNULIB_STRTOLL@
-GNULIB_STRTOULL = @GNULIB_STRTOULL@
-GNULIB_STRTOUMAX = @GNULIB_STRTOUMAX@
-GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@
-GNULIB_SYMLINK = @GNULIB_SYMLINK@
-GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@
-GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@
-GNULIB_TIMEGM = @GNULIB_TIMEGM@
-GNULIB_TIMESPEC_GET = @GNULIB_TIMESPEC_GET@
-GNULIB_TIME_R = @GNULIB_TIME_R@
-GNULIB_TIME_RZ = @GNULIB_TIME_RZ@
-GNULIB_TMPFILE = @GNULIB_TMPFILE@
-GNULIB_TRUNCATE = @GNULIB_TRUNCATE@
-GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@
-GNULIB_TZSET = @GNULIB_TZSET@
-GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@
-GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@
-GNULIB_UNLINK = @GNULIB_UNLINK@
-GNULIB_UNLINKAT = @GNULIB_UNLINKAT@
-GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@
-GNULIB_UNSETENV = @GNULIB_UNSETENV@
-GNULIB_USLEEP = @GNULIB_USLEEP@
-GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@
-GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
-GNULIB_VDPRINTF = @GNULIB_VDPRINTF@
-GNULIB_VFPRINTF = @GNULIB_VFPRINTF@
-GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
-GNULIB_VFSCANF = @GNULIB_VFSCANF@
-GNULIB_VPRINTF = @GNULIB_VPRINTF@
-GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
-GNULIB_VSCANF = @GNULIB_VSCANF@
-GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
-GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
 GNULIB_WARN_CFLAGS = @GNULIB_WARN_CFLAGS@
-GNULIB_WCTOMB = @GNULIB_WCTOMB@
-GNULIB_WRITE = @GNULIB_WRITE@
-GNULIB__EXIT = @GNULIB__EXIT@
 GNUSTEP_CFLAGS = @GNUSTEP_CFLAGS@
 GNU_OBJC_CFLAGS = @GNU_OBJC_CFLAGS@
 GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
@@ -653,10 +657,11 @@ HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
 HAVE_LCHMOD = @HAVE_LCHMOD@
 HAVE_LCHOWN = @HAVE_LCHOWN@
 HAVE_LIBGMP = @HAVE_LIBGMP@
+HAVE_LIBSECCOMP = @HAVE_LIBSECCOMP@
 HAVE_LINK = @HAVE_LINK@
 HAVE_LINKAT = @HAVE_LINKAT@
 HAVE_LSTAT = @HAVE_LSTAT@
-HAVE_MAKEINFO = @HAVE_MAKEINFO@
+HAVE_MACPORTS = @HAVE_MACPORTS@
 HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
 HAVE_MBSLEN = @HAVE_MBSLEN@
 HAVE_MBTOWC = @HAVE_MBTOWC@
@@ -673,6 +678,7 @@ HAVE_MKSTEMP = @HAVE_MKSTEMP@
 HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
 HAVE_MODULES = @HAVE_MODULES@
 HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
 HAVE_OPENAT = @HAVE_OPENAT@
 HAVE_OPENDIR = @HAVE_OPENDIR@
 HAVE_OS_H = @HAVE_OS_H@
@@ -705,6 +711,7 @@ HAVE_RENAMEAT = @HAVE_RENAMEAT@
 HAVE_REWINDDIR = @HAVE_REWINDDIR@
 HAVE_RPMATCH = @HAVE_RPMATCH@
 HAVE_SCANDIR = @HAVE_SCANDIR@
+HAVE_SECCOMP = @HAVE_SECCOMP@
 HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
 HAVE_SETENV = @HAVE_SETENV@
 HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
@@ -729,8 +736,10 @@ HAVE_STRPBRK = @HAVE_STRPBRK@
 HAVE_STRPTIME = @HAVE_STRPTIME@
 HAVE_STRSEP = @HAVE_STRSEP@
 HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
 HAVE_STRTOLD = @HAVE_STRTOLD@
 HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
 HAVE_STRTOULL = @HAVE_STRTOULL@
 HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
 HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@
@@ -790,6 +799,8 @@ LD_SWITCH_SYSTEM = @LD_SWITCH_SYSTEM@
 LD_SWITCH_SYSTEM_TEMACS = @LD_SWITCH_SYSTEM_TEMACS@
 LD_SWITCH_X_SITE = @LD_SWITCH_X_SITE@
 LD_SWITCH_X_SITE_RPATH = @LD_SWITCH_X_SITE_RPATH@
+LIBGCCJIT_CFLAGS = @LIBGCCJIT_CFLAGS@
+LIBGCCJIT_LIBS = @LIBGCCJIT_LIBS@
 LIBGIF = @LIBGIF@
 LIBGMP = @LIBGMP@
 LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@
@@ -807,6 +818,8 @@ LIBOTF_LIBS = @LIBOTF_LIBS@
 LIBPNG = @LIBPNG@
 LIBRESOLV = @LIBRESOLV@
 LIBS = @LIBS@
+LIBSECCOMP_CFLAGS = @LIBSECCOMP_CFLAGS@
+LIBSECCOMP_LIBS = @LIBSECCOMP_LIBS@
 LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
 LIBSOUND = @LIBSOUND@
 LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@
@@ -832,6 +845,7 @@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
 LIB_EACCESS = @LIB_EACCESS@
 LIB_EXECINFO = @LIB_EXECINFO@
 LIB_GETRANDOM = @LIB_GETRANDOM@
+LIB_HAS_ACL = @LIB_HAS_ACL@
 LIB_MATH = @LIB_MATH@
 LIB_PTHREAD = @LIB_PTHREAD@
 LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
@@ -1023,6 +1037,7 @@ REPLACE_READ = @REPLACE_READ@
 REPLACE_READLINK = @REPLACE_READLINK@
 REPLACE_READLINKAT = @REPLACE_READLINKAT@
 REPLACE_REALLOC = @REPLACE_REALLOC@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
 REPLACE_REALPATH = @REPLACE_REALPATH@
 REPLACE_REMOVE = @REPLACE_REMOVE@
 REPLACE_RENAME = @REPLACE_RENAME@
@@ -1053,7 +1068,11 @@ REPLACE_STRSTR = @REPLACE_STRSTR@
 REPLACE_STRTOD = @REPLACE_STRTOD@
 REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
 REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
 REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
 REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
 REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@
 REPLACE_SYMLINK = @REPLACE_SYMLINK@
@@ -1104,6 +1123,7 @@ UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
 UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
 UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = 
@UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
 USE_ACL = @USE_ACL@
+USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@
 VMLIMIT_OBJ = @VMLIMIT_OBJ@
 W32_LIBS = @W32_LIBS@
 W32_OBJ = @W32_OBJ@
@@ -1172,17 +1192,19 @@ gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7 = 
@gl_GNULIB_ENABLED_03e0aaad
 gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b = 
@gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b@
 gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31 = 
@gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31@
 gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c = 
@gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c@
+gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4 = 
@gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4@
 gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec = 
@gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec@
 gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c = 
@gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c@
 gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1 = 
@gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1@
 gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36 = 
@gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36@
 gl_GNULIB_ENABLED_cloexec = @gl_GNULIB_ENABLED_cloexec@
+gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b = 
@gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b@
 gl_GNULIB_ENABLED_dirfd = @gl_GNULIB_ENABLED_dirfd@
 gl_GNULIB_ENABLED_dynarray = @gl_GNULIB_ENABLED_dynarray@
+gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866 = 
@gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866@
 gl_GNULIB_ENABLED_euidaccess = @gl_GNULIB_ENABLED_euidaccess@
 gl_GNULIB_ENABLED_getdtablesize = @gl_GNULIB_ENABLED_getdtablesize@
 gl_GNULIB_ENABLED_getgroups = @gl_GNULIB_ENABLED_getgroups@
-gl_GNULIB_ENABLED_idx = @gl_GNULIB_ENABLED_idx@
 gl_GNULIB_ENABLED_lchmod = @gl_GNULIB_ENABLED_lchmod@
 gl_GNULIB_ENABLED_open = @gl_GNULIB_ENABLED_open@
 gl_GNULIB_ENABLED_rawmemchr = @gl_GNULIB_ENABLED_rawmemchr@
@@ -1206,6 +1228,7 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 liblockfile = @liblockfile@
 lispdir = @lispdir@
+lispdirrel = @lispdirrel@
 lisppath = @lisppath@
 localedir = @localedir@
 locallisppath = @locallisppath@
@@ -1213,6 +1236,8 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 ns_appbindir = @ns_appbindir@
 ns_appdir = @ns_appdir@
+ns_applibdir = @ns_applibdir@
+ns_applibexecdir = @ns_applibexecdir@
 ns_appresdir = @ns_appresdir@
 ns_appsrc = @ns_appsrc@
 ns_check_file = @ns_check_file@
@@ -1222,6 +1247,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -1450,6 +1476,14 @@ EXTRA_DIST += count-trailing-zeros.h
 endif
 ## end   gnulib module count-trailing-zeros
 
+## begin gnulib module crypto/md5
+ifeq (,$(OMIT_GNULIB_MODULE_crypto/md5))
+
+libgnu_a_SOURCES += md5-stream.c
+
+endif
+## end   gnulib module crypto/md5
+
 ## begin gnulib module crypto/md5-buffer
 ifeq (,$(OMIT_GNULIB_MODULE_crypto/md5-buffer))
 
@@ -1514,14 +1548,14 @@ dirent.h: dirent.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_DIRENT_H''@|$(NEXT_DIRENT_H)|g' \
-             -e 's/@''GNULIB_OPENDIR''@/$(GNULIB_OPENDIR)/g' \
-             -e 's/@''GNULIB_READDIR''@/$(GNULIB_READDIR)/g' \
-             -e 's/@''GNULIB_REWINDDIR''@/$(GNULIB_REWINDDIR)/g' \
-             -e 's/@''GNULIB_CLOSEDIR''@/$(GNULIB_CLOSEDIR)/g' \
-             -e 's/@''GNULIB_DIRFD''@/$(GNULIB_DIRFD)/g' \
-             -e 's/@''GNULIB_FDOPENDIR''@/$(GNULIB_FDOPENDIR)/g' \
-             -e 's/@''GNULIB_SCANDIR''@/$(GNULIB_SCANDIR)/g' \
-             -e 's/@''GNULIB_ALPHASORT''@/$(GNULIB_ALPHASORT)/g' \
+             -e 's/@''GNULIB_OPENDIR''@/$(GL_GNULIB_OPENDIR)/g' \
+             -e 's/@''GNULIB_READDIR''@/$(GL_GNULIB_READDIR)/g' \
+             -e 's/@''GNULIB_REWINDDIR''@/$(GL_GNULIB_REWINDDIR)/g' \
+             -e 's/@''GNULIB_CLOSEDIR''@/$(GL_GNULIB_CLOSEDIR)/g' \
+             -e 's/@''GNULIB_DIRFD''@/$(GL_GNULIB_DIRFD)/g' \
+             -e 's/@''GNULIB_FDOPENDIR''@/$(GL_GNULIB_FDOPENDIR)/g' \
+             -e 's/@''GNULIB_SCANDIR''@/$(GL_GNULIB_SCANDIR)/g' \
+             -e 's/@''GNULIB_ALPHASORT''@/$(GL_GNULIB_ALPHASORT)/g' \
              -e 's/@''HAVE_OPENDIR''@/$(HAVE_OPENDIR)/g' \
              -e 's/@''HAVE_READDIR''@/$(HAVE_READDIR)/g' \
              -e 's/@''HAVE_REWINDDIR''@/$(HAVE_REWINDDIR)/g' \
@@ -1596,6 +1630,32 @@ endif
 ifeq (,$(OMIT_GNULIB_MODULE_dynarray))
 
 ifneq (,$(gl_GNULIB_ENABLED_dynarray))
+BUILT_SOURCES += malloc/dynarray.gl.h malloc/dynarray-skeleton.gl.h
+
+malloc/dynarray.gl.h: malloc/dynarray.h
+       $(AM_V_at)$(MKDIR_P) malloc
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e '/libc_hidden_proto/d' < $(srcdir)/malloc/dynarray.h; \
+       } > $@-t && \
+       mv $@-t $@
+MOSTLYCLEANFILES += malloc/dynarray.gl.h malloc/dynarray.gl.h-t
+
+malloc/dynarray-skeleton.gl.h: malloc/dynarray-skeleton.c
+       $(AM_V_at)$(MKDIR_P) malloc
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e 's|<malloc/dynarray\.h>|<malloc/dynarray.gl.h>|g' \
+             -e 's|__attribute_maybe_unused__|_GL_ATTRIBUTE_MAYBE_UNUSED|g' \
+             -e 's|__attribute_nonnull__|_GL_ATTRIBUTE_NONNULL|g' \
+             -e 's|__attribute_warn_unused_result__|_GL_ATTRIBUTE_NODISCARD|g' 
\
+             -e 's|__glibc_likely|_GL_LIKELY|g' \
+             -e 's|__glibc_unlikely|_GL_UNLIKELY|g' \
+             < $(srcdir)/malloc/dynarray-skeleton.c; \
+       } > $@-t && \
+       mv $@-t $@
+MOSTLYCLEANFILES += malloc/dynarray-skeleton.gl.h 
malloc/dynarray-skeleton.gl.h-t
+
 libgnu_a_SOURCES += malloc/dynarray_at_failure.c                 
malloc/dynarray_emplace_enlarge.c                 malloc/dynarray_finalize.c    
             malloc/dynarray_resize.c                 
malloc/dynarray_resize_clear.c
 
 endif
@@ -1752,13 +1812,13 @@ fcntl.h: fcntl.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H)
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_FCNTL_H''@|$(NEXT_FCNTL_H)|g' \
-             -e 's/@''GNULIB_CREAT''@/$(GNULIB_CREAT)/g' \
-             -e 's/@''GNULIB_FCNTL''@/$(GNULIB_FCNTL)/g' \
-             -e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \
-             -e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \
-             -e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \
-             -e 's/@''GNULIB_MDA_CREAT''@/$(GNULIB_MDA_CREAT)/g' \
-             -e 's/@''GNULIB_MDA_OPEN''@/$(GNULIB_MDA_OPEN)/g' \
+             -e 's/@''GNULIB_CREAT''@/$(GL_GNULIB_CREAT)/g' \
+             -e 's/@''GNULIB_FCNTL''@/$(GL_GNULIB_FCNTL)/g' \
+             -e 's/@''GNULIB_NONBLOCKING''@/$(GL_GNULIB_NONBLOCKING)/g' \
+             -e 's/@''GNULIB_OPEN''@/$(GL_GNULIB_OPEN)/g' \
+             -e 's/@''GNULIB_OPENAT''@/$(GL_GNULIB_OPENAT)/g' \
+             -e 's/@''GNULIB_MDA_CREAT''@/$(GL_GNULIB_MDA_CREAT)/g' \
+             -e 's/@''GNULIB_MDA_OPEN''@/$(GL_GNULIB_MDA_OPEN)/g' \
              -e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \
              -e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \
              -e 's|@''REPLACE_CREAT''@|$(REPLACE_CREAT)|g' \
@@ -2043,10 +2103,8 @@ endif
 ## begin gnulib module idx
 ifeq (,$(OMIT_GNULIB_MODULE_idx))
 
-ifneq (,$(gl_GNULIB_ENABLED_idx))
 libgnu_a_SOURCES += idx.h
 
-endif
 endif
 ## end   gnulib module idx
 
@@ -2111,10 +2169,10 @@ inttypes.h: inttypes.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(WARN_ON_U
              -e 's|@''NEXT_INTTYPES_H''@|$(NEXT_INTTYPES_H)|g' \
              -e 's/@''APPLE_UNIVERSAL_BUILD''@/$(APPLE_UNIVERSAL_BUILD)/g' \
              -e 's/@''PRIPTR_PREFIX''@/$(PRIPTR_PREFIX)/g' \
-             -e 's/@''GNULIB_IMAXABS''@/$(GNULIB_IMAXABS)/g' \
-             -e 's/@''GNULIB_IMAXDIV''@/$(GNULIB_IMAXDIV)/g' \
-             -e 's/@''GNULIB_STRTOIMAX''@/$(GNULIB_STRTOIMAX)/g' \
-             -e 's/@''GNULIB_STRTOUMAX''@/$(GNULIB_STRTOUMAX)/g' \
+             -e 's/@''GNULIB_IMAXABS''@/$(GL_GNULIB_IMAXABS)/g' \
+             -e 's/@''GNULIB_IMAXDIV''@/$(GL_GNULIB_IMAXDIV)/g' \
+             -e 's/@''GNULIB_STRTOIMAX''@/$(GL_GNULIB_STRTOIMAX)/g' \
+             -e 's/@''GNULIB_STRTOUMAX''@/$(GL_GNULIB_STRTOUMAX)/g' \
              -e 's/@''HAVE_DECL_IMAXABS''@/$(HAVE_DECL_IMAXABS)/g' \
              -e 's/@''HAVE_DECL_IMAXDIV''@/$(HAVE_DECL_IMAXDIV)/g' \
              -e 's/@''HAVE_DECL_STRTOIMAX''@/$(HAVE_DECL_STRTOIMAX)/g' \
@@ -2232,6 +2290,19 @@ EXTRA_libgnu_a_SOURCES += lstat.c
 endif
 ## end   gnulib module lstat
 
+## begin gnulib module malloc-posix
+ifeq (,$(OMIT_GNULIB_MODULE_malloc-posix))
+
+ifneq (,$(gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866))
+
+endif
+EXTRA_DIST += malloc.c
+
+EXTRA_libgnu_a_SOURCES += malloc.c
+
+endif
+## end   gnulib module malloc-posix
+
 ## begin gnulib module memmem-simple
 ifeq (,$(OMIT_GNULIB_MODULE_memmem-simple))
 
@@ -2308,6 +2379,16 @@ EXTRA_libgnu_a_SOURCES += mktime.c
 endif
 ## end   gnulib module mktime-internal
 
+## begin gnulib module nproc
+ifeq (,$(OMIT_GNULIB_MODULE_nproc))
+
+libgnu_a_SOURCES += nproc.c
+
+EXTRA_DIST += nproc.h
+
+endif
+## end   gnulib module nproc
+
 ## begin gnulib module nstrftime
 ifeq (,$(OMIT_GNULIB_MODULE_nstrftime))
 
@@ -2424,6 +2505,32 @@ EXTRA_libgnu_a_SOURCES += at-func.c readlinkat.c
 endif
 ## end   gnulib module readlinkat
 
+## begin gnulib module realloc-gnu
+ifeq (,$(OMIT_GNULIB_MODULE_realloc-gnu))
+
+ifneq (,$(gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b))
+
+endif
+EXTRA_DIST += realloc.c
+
+EXTRA_libgnu_a_SOURCES += realloc.c
+
+endif
+## end   gnulib module realloc-gnu
+
+## begin gnulib module realloc-posix
+ifeq (,$(OMIT_GNULIB_MODULE_realloc-posix))
+
+ifneq (,$(gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4))
+
+endif
+EXTRA_DIST += realloc.c
+
+EXTRA_libgnu_a_SOURCES += realloc.c
+
+endif
+## end   gnulib module realloc-posix
+
 ## begin gnulib module regex
 ifeq (,$(OMIT_GNULIB_MODULE_regex))
 
@@ -2450,6 +2557,21 @@ endif
 ifeq (,$(OMIT_GNULIB_MODULE_scratch_buffer))
 
 ifneq (,$(gl_GNULIB_ENABLED_scratch_buffer))
+BUILT_SOURCES += malloc/scratch_buffer.gl.h
+
+malloc/scratch_buffer.gl.h: malloc/scratch_buffer.h
+       $(AM_V_at)$(MKDIR_P) malloc
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e 's|__always_inline|inline _GL_ATTRIBUTE_ALWAYS_INLINE|g' \
+             -e 's|__glibc_likely|_GL_LIKELY|g' \
+             -e 's|__glibc_unlikely|_GL_UNLIKELY|g' \
+             -e '/libc_hidden_proto/d' \
+             < $(srcdir)/malloc/scratch_buffer.h; \
+       } > $@-t && \
+       mv $@-t $@
+MOSTLYCLEANFILES += malloc/scratch_buffer.gl.h malloc/scratch_buffer.gl.h-t
+
 libgnu_a_SOURCES += malloc/scratch_buffer_dupfree.c                 
malloc/scratch_buffer_grow.c                 
malloc/scratch_buffer_grow_preserve.c                 
malloc/scratch_buffer_set_array_size.c
 
 endif
@@ -2495,11 +2617,11 @@ signal.h: signal.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_SIGNAL_H''@|$(NEXT_SIGNAL_H)|g' \
-             -e 's/@''GNULIB_PTHREAD_SIGMASK''@/$(GNULIB_PTHREAD_SIGMASK)/g' \
-             -e 's/@''GNULIB_RAISE''@/$(GNULIB_RAISE)/g' \
-             -e 's/@''GNULIB_SIGNAL_H_SIGPIPE''@/$(GNULIB_SIGNAL_H_SIGPIPE)/g' 
\
-             -e 's/@''GNULIB_SIGPROCMASK''@/$(GNULIB_SIGPROCMASK)/g' \
-             -e 's/@''GNULIB_SIGACTION''@/$(GNULIB_SIGACTION)/g' \
+             -e 
's/@''GNULIB_PTHREAD_SIGMASK''@/$(GL_GNULIB_PTHREAD_SIGMASK)/g' \
+             -e 's/@''GNULIB_RAISE''@/$(GL_GNULIB_RAISE)/g' \
+             -e 
's/@''GNULIB_SIGNAL_H_SIGPIPE''@/$(GL_GNULIB_SIGNAL_H_SIGPIPE)/g' \
+             -e 's/@''GNULIB_SIGPROCMASK''@/$(GL_GNULIB_SIGPROCMASK)/g' \
+             -e 's/@''GNULIB_SIGACTION''@/$(GL_GNULIB_SIGACTION)/g' \
              -e 
's|@''HAVE_POSIX_SIGNALBLOCKING''@|$(HAVE_POSIX_SIGNALBLOCKING)|g' \
              -e 's|@''HAVE_PTHREAD_SIGMASK''@|$(HAVE_PTHREAD_SIGMASK)|g' \
              -e 's|@''HAVE_RAISE''@|$(HAVE_RAISE)|g' \
@@ -2685,7 +2807,7 @@ stdint.h: stdint.in.h $(top_builddir)/config.status
              -e 's/@''BITSIZEOF_WINT_T''@/$(BITSIZEOF_WINT_T)/g' \
              -e 's/@''HAVE_SIGNED_WINT_T''@/$(HAVE_SIGNED_WINT_T)/g' \
              -e 's/@''WINT_T_SUFFIX''@/$(WINT_T_SUFFIX)/g' \
-             -e 's/@''GNULIB_OVERRIDES_WINT_T''@/$(GNULIB_OVERRIDES_WINT_T)/g' 
\
+             -e 
's/@''GNULIBHEADERS_OVERRIDE_WINT_T''@/$(GNULIBHEADERS_OVERRIDE_WINT_T)/g' \
              < $(srcdir)/stdint.in.h; \
        } > $@-t && \
        mv $@-t $@
@@ -2715,65 +2837,65 @@ stdio.h: stdio.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H)
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_STDIO_H''@|$(NEXT_STDIO_H)|g' \
-             -e 's/@''GNULIB_DPRINTF''@/$(GNULIB_DPRINTF)/g' \
-             -e 's/@''GNULIB_FCLOSE''@/$(GNULIB_FCLOSE)/g' \
-             -e 's/@''GNULIB_FDOPEN''@/$(GNULIB_FDOPEN)/g' \
-             -e 's/@''GNULIB_FFLUSH''@/$(GNULIB_FFLUSH)/g' \
-             -e 's/@''GNULIB_FGETC''@/$(GNULIB_FGETC)/g' \
-             -e 's/@''GNULIB_FGETS''@/$(GNULIB_FGETS)/g' \
-             -e 's/@''GNULIB_FOPEN''@/$(GNULIB_FOPEN)/g' \
-             -e 's/@''GNULIB_FPRINTF''@/$(GNULIB_FPRINTF)/g' \
-             -e 's/@''GNULIB_FPRINTF_POSIX''@/$(GNULIB_FPRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_FPURGE''@/$(GNULIB_FPURGE)/g' \
-             -e 's/@''GNULIB_FPUTC''@/$(GNULIB_FPUTC)/g' \
-             -e 's/@''GNULIB_FPUTS''@/$(GNULIB_FPUTS)/g' \
-             -e 's/@''GNULIB_FREAD''@/$(GNULIB_FREAD)/g' \
-             -e 's/@''GNULIB_FREOPEN''@/$(GNULIB_FREOPEN)/g' \
-             -e 's/@''GNULIB_FSCANF''@/$(GNULIB_FSCANF)/g' \
-             -e 's/@''GNULIB_FSEEK''@/$(GNULIB_FSEEK)/g' \
-             -e 's/@''GNULIB_FSEEKO''@/$(GNULIB_FSEEKO)/g' \
-             -e 's/@''GNULIB_FTELL''@/$(GNULIB_FTELL)/g' \
-             -e 's/@''GNULIB_FTELLO''@/$(GNULIB_FTELLO)/g' \
-             -e 's/@''GNULIB_FWRITE''@/$(GNULIB_FWRITE)/g' \
-             -e 's/@''GNULIB_GETC''@/$(GNULIB_GETC)/g' \
-             -e 's/@''GNULIB_GETCHAR''@/$(GNULIB_GETCHAR)/g' \
-             -e 's/@''GNULIB_GETDELIM''@/$(GNULIB_GETDELIM)/g' \
-             -e 's/@''GNULIB_GETLINE''@/$(GNULIB_GETLINE)/g' \
-             -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GNULIB_OBSTACK_PRINTF)/g' \
-             -e 
's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GNULIB_OBSTACK_PRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_PCLOSE''@/$(GNULIB_PCLOSE)/g' \
-             -e 's/@''GNULIB_PERROR''@/$(GNULIB_PERROR)/g' \
-             -e 's/@''GNULIB_POPEN''@/$(GNULIB_POPEN)/g' \
-             -e 's/@''GNULIB_PRINTF''@/$(GNULIB_PRINTF)/g' \
-             -e 's/@''GNULIB_PRINTF_POSIX''@/$(GNULIB_PRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_PUTC''@/$(GNULIB_PUTC)/g' \
-             -e 's/@''GNULIB_PUTCHAR''@/$(GNULIB_PUTCHAR)/g' \
-             -e 's/@''GNULIB_PUTS''@/$(GNULIB_PUTS)/g' \
-             -e 's/@''GNULIB_REMOVE''@/$(GNULIB_REMOVE)/g' \
-             -e 's/@''GNULIB_RENAME''@/$(GNULIB_RENAME)/g' \
-             -e 's/@''GNULIB_RENAMEAT''@/$(GNULIB_RENAMEAT)/g' \
-             -e 's/@''GNULIB_SCANF''@/$(GNULIB_SCANF)/g' \
-             -e 's/@''GNULIB_SNPRINTF''@/$(GNULIB_SNPRINTF)/g' \
-             -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GNULIB_SPRINTF_POSIX)/g' \
-             -e 
's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GNULIB_STDIO_H_NONBLOCKING)/g' \
-             -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GNULIB_STDIO_H_SIGPIPE)/g' \
-             -e 's/@''GNULIB_TMPFILE''@/$(GNULIB_TMPFILE)/g' \
-             -e 's/@''GNULIB_VASPRINTF''@/$(GNULIB_VASPRINTF)/g' \
-             -e 's/@''GNULIB_VDPRINTF''@/$(GNULIB_VDPRINTF)/g' \
-             -e 's/@''GNULIB_VFPRINTF''@/$(GNULIB_VFPRINTF)/g' \
-             -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GNULIB_VFPRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_VFSCANF''@/$(GNULIB_VFSCANF)/g' \
-             -e 's/@''GNULIB_VSCANF''@/$(GNULIB_VSCANF)/g' \
-             -e 's/@''GNULIB_VPRINTF''@/$(GNULIB_VPRINTF)/g' \
-             -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GNULIB_VPRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
-             -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
-             -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
-             -e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
-             -e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
-             -e 's/@''GNULIB_MDA_GETW''@/$(GNULIB_MDA_GETW)/g' \
-             -e 's/@''GNULIB_MDA_PUTW''@/$(GNULIB_MDA_PUTW)/g' \
-             -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GNULIB_MDA_TEMPNAM)/g' \
+             -e 's/@''GNULIB_DPRINTF''@/$(GL_GNULIB_DPRINTF)/g' \
+             -e 's/@''GNULIB_FCLOSE''@/$(GL_GNULIB_FCLOSE)/g' \
+             -e 's/@''GNULIB_FDOPEN''@/$(GL_GNULIB_FDOPEN)/g' \
+             -e 's/@''GNULIB_FFLUSH''@/$(GL_GNULIB_FFLUSH)/g' \
+             -e 's/@''GNULIB_FGETC''@/$(GL_GNULIB_FGETC)/g' \
+             -e 's/@''GNULIB_FGETS''@/$(GL_GNULIB_FGETS)/g' \
+             -e 's/@''GNULIB_FOPEN''@/$(GL_GNULIB_FOPEN)/g' \
+             -e 's/@''GNULIB_FPRINTF''@/$(GL_GNULIB_FPRINTF)/g' \
+             -e 's/@''GNULIB_FPRINTF_POSIX''@/$(GL_GNULIB_FPRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_FPURGE''@/$(GL_GNULIB_FPURGE)/g' \
+             -e 's/@''GNULIB_FPUTC''@/$(GL_GNULIB_FPUTC)/g' \
+             -e 's/@''GNULIB_FPUTS''@/$(GL_GNULIB_FPUTS)/g' \
+             -e 's/@''GNULIB_FREAD''@/$(GL_GNULIB_FREAD)/g' \
+             -e 's/@''GNULIB_FREOPEN''@/$(GL_GNULIB_FREOPEN)/g' \
+             -e 's/@''GNULIB_FSCANF''@/$(GL_GNULIB_FSCANF)/g' \
+             -e 's/@''GNULIB_FSEEK''@/$(GL_GNULIB_FSEEK)/g' \
+             -e 's/@''GNULIB_FSEEKO''@/$(GL_GNULIB_FSEEKO)/g' \
+             -e 's/@''GNULIB_FTELL''@/$(GL_GNULIB_FTELL)/g' \
+             -e 's/@''GNULIB_FTELLO''@/$(GL_GNULIB_FTELLO)/g' \
+             -e 's/@''GNULIB_FWRITE''@/$(GL_GNULIB_FWRITE)/g' \
+             -e 's/@''GNULIB_GETC''@/$(GL_GNULIB_GETC)/g' \
+             -e 's/@''GNULIB_GETCHAR''@/$(GL_GNULIB_GETCHAR)/g' \
+             -e 's/@''GNULIB_GETDELIM''@/$(GL_GNULIB_GETDELIM)/g' \
+             -e 's/@''GNULIB_GETLINE''@/$(GL_GNULIB_GETLINE)/g' \
+             -e 's/@''GNULIB_OBSTACK_PRINTF''@/$(GL_GNULIB_OBSTACK_PRINTF)/g' \
+             -e 
's/@''GNULIB_OBSTACK_PRINTF_POSIX''@/$(GL_GNULIB_OBSTACK_PRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_PCLOSE''@/$(GL_GNULIB_PCLOSE)/g' \
+             -e 's/@''GNULIB_PERROR''@/$(GL_GNULIB_PERROR)/g' \
+             -e 's/@''GNULIB_POPEN''@/$(GL_GNULIB_POPEN)/g' \
+             -e 's/@''GNULIB_PRINTF''@/$(GL_GNULIB_PRINTF)/g' \
+             -e 's/@''GNULIB_PRINTF_POSIX''@/$(GL_GNULIB_PRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_PUTC''@/$(GL_GNULIB_PUTC)/g' \
+             -e 's/@''GNULIB_PUTCHAR''@/$(GL_GNULIB_PUTCHAR)/g' \
+             -e 's/@''GNULIB_PUTS''@/$(GL_GNULIB_PUTS)/g' \
+             -e 's/@''GNULIB_REMOVE''@/$(GL_GNULIB_REMOVE)/g' \
+             -e 's/@''GNULIB_RENAME''@/$(GL_GNULIB_RENAME)/g' \
+             -e 's/@''GNULIB_RENAMEAT''@/$(GL_GNULIB_RENAMEAT)/g' \
+             -e 's/@''GNULIB_SCANF''@/$(GL_GNULIB_SCANF)/g' \
+             -e 's/@''GNULIB_SNPRINTF''@/$(GL_GNULIB_SNPRINTF)/g' \
+             -e 's/@''GNULIB_SPRINTF_POSIX''@/$(GL_GNULIB_SPRINTF_POSIX)/g' \
+             -e 
's/@''GNULIB_STDIO_H_NONBLOCKING''@/$(GL_GNULIB_STDIO_H_NONBLOCKING)/g' \
+             -e 
's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GL_GNULIB_STDIO_H_SIGPIPE)/g' \
+             -e 's/@''GNULIB_TMPFILE''@/$(GL_GNULIB_TMPFILE)/g' \
+             -e 's/@''GNULIB_VASPRINTF''@/$(GL_GNULIB_VASPRINTF)/g' \
+             -e 's/@''GNULIB_VDPRINTF''@/$(GL_GNULIB_VDPRINTF)/g' \
+             -e 's/@''GNULIB_VFPRINTF''@/$(GL_GNULIB_VFPRINTF)/g' \
+             -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GL_GNULIB_VFPRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_VFSCANF''@/$(GL_GNULIB_VFSCANF)/g' \
+             -e 's/@''GNULIB_VSCANF''@/$(GL_GNULIB_VSCANF)/g' \
+             -e 's/@''GNULIB_VPRINTF''@/$(GL_GNULIB_VPRINTF)/g' \
+             -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GL_GNULIB_VPRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_VSNPRINTF''@/$(GL_GNULIB_VSNPRINTF)/g' \
+             -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GL_GNULIB_VSPRINTF_POSIX)/g' \
+             -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GL_GNULIB_MDA_FCLOSEALL)/g' \
+             -e 's/@''GNULIB_MDA_FDOPEN''@/$(GL_GNULIB_MDA_FDOPEN)/g' \
+             -e 's/@''GNULIB_MDA_FILENO''@/$(GL_GNULIB_MDA_FILENO)/g' \
+             -e 's/@''GNULIB_MDA_GETW''@/$(GL_GNULIB_MDA_GETW)/g' \
+             -e 's/@''GNULIB_MDA_PUTW''@/$(GL_GNULIB_MDA_PUTW)/g' \
+             -e 's/@''GNULIB_MDA_TEMPNAM''@/$(GL_GNULIB_MDA_TEMPNAM)/g' \
              < $(srcdir)/stdio.in.h | \
          sed -e 's|@''HAVE_DECL_FCLOSEALL''@|$(HAVE_DECL_FCLOSEALL)|g' \
              -e 's|@''HAVE_DECL_FPURGE''@|$(HAVE_DECL_FPURGE)|g' \
@@ -2853,49 +2975,51 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) \
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \
-             -e 's/@''GNULIB__EXIT''@/$(GNULIB__EXIT)/g' \
-             -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GNULIB_ALIGNED_ALLOC)/g' \
-             -e 's/@''GNULIB_ATOLL''@/$(GNULIB_ATOLL)/g' \
-             -e 's/@''GNULIB_CALLOC_POSIX''@/$(GNULIB_CALLOC_POSIX)/g' \
-             -e 
's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GNULIB_CANONICALIZE_FILE_NAME)/g' \
-             -e 's/@''GNULIB_FREE_POSIX''@/$(GNULIB_FREE_POSIX)/g' \
-             -e 's/@''GNULIB_GETLOADAVG''@/$(GNULIB_GETLOADAVG)/g' \
-             -e 's/@''GNULIB_GETSUBOPT''@/$(GNULIB_GETSUBOPT)/g' \
-             -e 's/@''GNULIB_GRANTPT''@/$(GNULIB_GRANTPT)/g' \
-             -e 's/@''GNULIB_MALLOC_POSIX''@/$(GNULIB_MALLOC_POSIX)/g' \
-             -e 's/@''GNULIB_MBTOWC''@/$(GNULIB_MBTOWC)/g' \
-             -e 's/@''GNULIB_MKDTEMP''@/$(GNULIB_MKDTEMP)/g' \
-             -e 's/@''GNULIB_MKOSTEMP''@/$(GNULIB_MKOSTEMP)/g' \
-             -e 's/@''GNULIB_MKOSTEMPS''@/$(GNULIB_MKOSTEMPS)/g' \
-             -e 's/@''GNULIB_MKSTEMP''@/$(GNULIB_MKSTEMP)/g' \
-             -e 's/@''GNULIB_MKSTEMPS''@/$(GNULIB_MKSTEMPS)/g' \
-             -e 's/@''GNULIB_POSIX_MEMALIGN''@/$(GNULIB_POSIX_MEMALIGN)/g' \
-             -e 's/@''GNULIB_POSIX_OPENPT''@/$(GNULIB_POSIX_OPENPT)/g' \
-             -e 's/@''GNULIB_PTSNAME''@/$(GNULIB_PTSNAME)/g' \
-             -e 's/@''GNULIB_PTSNAME_R''@/$(GNULIB_PTSNAME_R)/g' \
-             -e 's/@''GNULIB_PUTENV''@/$(GNULIB_PUTENV)/g' \
-             -e 's/@''GNULIB_QSORT_R''@/$(GNULIB_QSORT_R)/g' \
-             -e 's/@''GNULIB_RANDOM''@/$(GNULIB_RANDOM)/g' \
-             -e 's/@''GNULIB_RANDOM_R''@/$(GNULIB_RANDOM_R)/g' \
-             -e 's/@''GNULIB_REALLOC_POSIX''@/$(GNULIB_REALLOC_POSIX)/g' \
-             -e 's/@''GNULIB_REALLOCARRAY''@/$(GNULIB_REALLOCARRAY)/g' \
-             -e 's/@''GNULIB_REALPATH''@/$(GNULIB_REALPATH)/g' \
-             -e 's/@''GNULIB_RPMATCH''@/$(GNULIB_RPMATCH)/g' \
-             -e 's/@''GNULIB_SECURE_GETENV''@/$(GNULIB_SECURE_GETENV)/g' \
-             -e 's/@''GNULIB_SETENV''@/$(GNULIB_SETENV)/g' \
-             -e 's/@''GNULIB_STRTOD''@/$(GNULIB_STRTOD)/g' \
-             -e 's/@''GNULIB_STRTOLD''@/$(GNULIB_STRTOLD)/g' \
-             -e 's/@''GNULIB_STRTOLL''@/$(GNULIB_STRTOLL)/g' \
-             -e 's/@''GNULIB_STRTOULL''@/$(GNULIB_STRTOULL)/g' \
-             -e 's/@''GNULIB_SYSTEM_POSIX''@/$(GNULIB_SYSTEM_POSIX)/g' \
-             -e 's/@''GNULIB_UNLOCKPT''@/$(GNULIB_UNLOCKPT)/g' \
-             -e 's/@''GNULIB_UNSETENV''@/$(GNULIB_UNSETENV)/g' \
-             -e 's/@''GNULIB_WCTOMB''@/$(GNULIB_WCTOMB)/g' \
-             -e 's/@''GNULIB_MDA_ECVT''@/$(GNULIB_MDA_ECVT)/g' \
-             -e 's/@''GNULIB_MDA_FCVT''@/$(GNULIB_MDA_FCVT)/g' \
-             -e 's/@''GNULIB_MDA_GCVT''@/$(GNULIB_MDA_GCVT)/g' \
-             -e 's/@''GNULIB_MDA_MKTEMP''@/$(GNULIB_MDA_MKTEMP)/g' \
-             -e 's/@''GNULIB_MDA_PUTENV''@/$(GNULIB_MDA_PUTENV)/g' \
+             -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \
+             -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \
+             -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \
+             -e 's/@''GNULIB_CALLOC_POSIX''@/$(GL_GNULIB_CALLOC_POSIX)/g' \
+             -e 
's/@''GNULIB_CANONICALIZE_FILE_NAME''@/$(GL_GNULIB_CANONICALIZE_FILE_NAME)/g' \
+             -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \
+             -e 's/@''GNULIB_GETLOADAVG''@/$(GL_GNULIB_GETLOADAVG)/g' \
+             -e 's/@''GNULIB_GETSUBOPT''@/$(GL_GNULIB_GETSUBOPT)/g' \
+             -e 's/@''GNULIB_GRANTPT''@/$(GL_GNULIB_GRANTPT)/g' \
+             -e 's/@''GNULIB_MALLOC_POSIX''@/$(GL_GNULIB_MALLOC_POSIX)/g' \
+             -e 's/@''GNULIB_MBTOWC''@/$(GL_GNULIB_MBTOWC)/g' \
+             -e 's/@''GNULIB_MKDTEMP''@/$(GL_GNULIB_MKDTEMP)/g' \
+             -e 's/@''GNULIB_MKOSTEMP''@/$(GL_GNULIB_MKOSTEMP)/g' \
+             -e 's/@''GNULIB_MKOSTEMPS''@/$(GL_GNULIB_MKOSTEMPS)/g' \
+             -e 's/@''GNULIB_MKSTEMP''@/$(GL_GNULIB_MKSTEMP)/g' \
+             -e 's/@''GNULIB_MKSTEMPS''@/$(GL_GNULIB_MKSTEMPS)/g' \
+             -e 's/@''GNULIB_POSIX_MEMALIGN''@/$(GL_GNULIB_POSIX_MEMALIGN)/g' \
+             -e 's/@''GNULIB_POSIX_OPENPT''@/$(GL_GNULIB_POSIX_OPENPT)/g' \
+             -e 's/@''GNULIB_PTSNAME''@/$(GL_GNULIB_PTSNAME)/g' \
+             -e 's/@''GNULIB_PTSNAME_R''@/$(GL_GNULIB_PTSNAME_R)/g' \
+             -e 's/@''GNULIB_PUTENV''@/$(GL_GNULIB_PUTENV)/g' \
+             -e 's/@''GNULIB_QSORT_R''@/$(GL_GNULIB_QSORT_R)/g' \
+             -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \
+             -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \
+             -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \
+             -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \
+             -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \
+             -e 's/@''GNULIB_RPMATCH''@/$(GL_GNULIB_RPMATCH)/g' \
+             -e 's/@''GNULIB_SECURE_GETENV''@/$(GL_GNULIB_SECURE_GETENV)/g' \
+             -e 's/@''GNULIB_SETENV''@/$(GL_GNULIB_SETENV)/g' \
+             -e 's/@''GNULIB_STRTOD''@/$(GL_GNULIB_STRTOD)/g' \
+             -e 's/@''GNULIB_STRTOL''@/$(GL_GNULIB_STRTOL)/g' \
+             -e 's/@''GNULIB_STRTOLD''@/$(GL_GNULIB_STRTOLD)/g' \
+             -e 's/@''GNULIB_STRTOLL''@/$(GL_GNULIB_STRTOLL)/g' \
+             -e 's/@''GNULIB_STRTOUL''@/$(GL_GNULIB_STRTOUL)/g' \
+             -e 's/@''GNULIB_STRTOULL''@/$(GL_GNULIB_STRTOULL)/g' \
+             -e 's/@''GNULIB_SYSTEM_POSIX''@/$(GL_GNULIB_SYSTEM_POSIX)/g' \
+             -e 's/@''GNULIB_UNLOCKPT''@/$(GL_GNULIB_UNLOCKPT)/g' \
+             -e 's/@''GNULIB_UNSETENV''@/$(GL_GNULIB_UNSETENV)/g' \
+             -e 's/@''GNULIB_WCTOMB''@/$(GL_GNULIB_WCTOMB)/g' \
+             -e 's/@''GNULIB_MDA_ECVT''@/$(GL_GNULIB_MDA_ECVT)/g' \
+             -e 's/@''GNULIB_MDA_FCVT''@/$(GL_GNULIB_MDA_FCVT)/g' \
+             -e 's/@''GNULIB_MDA_GCVT''@/$(GL_GNULIB_MDA_GCVT)/g' \
+             -e 's/@''GNULIB_MDA_MKTEMP''@/$(GL_GNULIB_MDA_MKTEMP)/g' \
+             -e 's/@''GNULIB_MDA_PUTENV''@/$(GL_GNULIB_MDA_PUTENV)/g' \
              < $(srcdir)/stdlib.in.h | \
          sed -e 's|@''HAVE__EXIT''@|$(HAVE__EXIT)|g' \
              -e 's|@''HAVE_ALIGNED_ALLOC''@|$(HAVE_ALIGNED_ALLOC)|g' \
@@ -2931,8 +3055,10 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) \
              -e 's|@''HAVE_SETSTATE''@|$(HAVE_SETSTATE)|g' \
              -e 's|@''HAVE_DECL_SETSTATE''@|$(HAVE_DECL_SETSTATE)|g' \
              -e 's|@''HAVE_STRTOD''@|$(HAVE_STRTOD)|g' \
+             -e 's|@''HAVE_STRTOL''@|$(HAVE_STRTOL)|g' \
              -e 's|@''HAVE_STRTOLD''@|$(HAVE_STRTOLD)|g' \
              -e 's|@''HAVE_STRTOLL''@|$(HAVE_STRTOLL)|g' \
+             -e 's|@''HAVE_STRTOUL''@|$(HAVE_STRTOUL)|g' \
              -e 's|@''HAVE_STRTOULL''@|$(HAVE_STRTOULL)|g' \
              -e 's|@''HAVE_STRUCT_RANDOM_DATA''@|$(HAVE_STRUCT_RANDOM_DATA)|g' 
\
              -e 's|@''HAVE_SYS_LOADAVG_H''@|$(HAVE_SYS_LOADAVG_H)|g' \
@@ -2954,11 +3080,16 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) \
              -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \
              -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \
              -e 's|@''REPLACE_REALLOC''@|$(REPLACE_REALLOC)|g' \
+             -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \
              -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \
              -e 's|@''REPLACE_SETENV''@|$(REPLACE_SETENV)|g' \
              -e 's|@''REPLACE_SETSTATE''@|$(REPLACE_SETSTATE)|g' \
              -e 's|@''REPLACE_STRTOD''@|$(REPLACE_STRTOD)|g' \
+             -e 's|@''REPLACE_STRTOL''@|$(REPLACE_STRTOL)|g' \
              -e 's|@''REPLACE_STRTOLD''@|$(REPLACE_STRTOLD)|g' \
+             -e 's|@''REPLACE_STRTOLL''@|$(REPLACE_STRTOLL)|g' \
+             -e 's|@''REPLACE_STRTOUL''@|$(REPLACE_STRTOUL)|g' \
+             -e 's|@''REPLACE_STRTOULL''@|$(REPLACE_STRTOULL)|g' \
              -e 's|@''REPLACE_UNSETENV''@|$(REPLACE_UNSETENV)|g' \
              -e 's|@''REPLACE_WCTOMB''@|$(REPLACE_WCTOMB)|g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
@@ -3000,49 +3131,50 @@ string.h: string.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_STRING_H''@|$(NEXT_STRING_H)|g' \
-             -e 's/@''GNULIB_EXPLICIT_BZERO''@/$(GNULIB_EXPLICIT_BZERO)/g' \
-             -e 's/@''GNULIB_FFSL''@/$(GNULIB_FFSL)/g' \
-             -e 's/@''GNULIB_FFSLL''@/$(GNULIB_FFSLL)/g' \
-             -e 's/@''GNULIB_MBSLEN''@/$(GNULIB_MBSLEN)/g' \
-             -e 's/@''GNULIB_MBSNLEN''@/$(GNULIB_MBSNLEN)/g' \
-             -e 's/@''GNULIB_MBSCHR''@/$(GNULIB_MBSCHR)/g' \
-             -e 's/@''GNULIB_MBSRCHR''@/$(GNULIB_MBSRCHR)/g' \
-             -e 's/@''GNULIB_MBSSTR''@/$(GNULIB_MBSSTR)/g' \
-             -e 's/@''GNULIB_MBSCASECMP''@/$(GNULIB_MBSCASECMP)/g' \
-             -e 's/@''GNULIB_MBSNCASECMP''@/$(GNULIB_MBSNCASECMP)/g' \
-             -e 's/@''GNULIB_MBSPCASECMP''@/$(GNULIB_MBSPCASECMP)/g' \
-             -e 's/@''GNULIB_MBSCASESTR''@/$(GNULIB_MBSCASESTR)/g' \
-             -e 's/@''GNULIB_MBSCSPN''@/$(GNULIB_MBSCSPN)/g' \
-             -e 's/@''GNULIB_MBSPBRK''@/$(GNULIB_MBSPBRK)/g' \
-             -e 's/@''GNULIB_MBSSPN''@/$(GNULIB_MBSSPN)/g' \
-             -e 's/@''GNULIB_MBSSEP''@/$(GNULIB_MBSSEP)/g' \
-             -e 's/@''GNULIB_MBSTOK_R''@/$(GNULIB_MBSTOK_R)/g' \
-             -e 's/@''GNULIB_MEMCHR''@/$(GNULIB_MEMCHR)/g' \
-             -e 's/@''GNULIB_MEMMEM''@/$(GNULIB_MEMMEM)/g' \
-             -e 's/@''GNULIB_MEMPCPY''@/$(GNULIB_MEMPCPY)/g' \
-             -e 's/@''GNULIB_MEMRCHR''@/$(GNULIB_MEMRCHR)/g' \
-             -e 's/@''GNULIB_RAWMEMCHR''@/$(GNULIB_RAWMEMCHR)/g' \
-             -e 's/@''GNULIB_STPCPY''@/$(GNULIB_STPCPY)/g' \
-             -e 's/@''GNULIB_STPNCPY''@/$(GNULIB_STPNCPY)/g' \
-             -e 's/@''GNULIB_STRCHRNUL''@/$(GNULIB_STRCHRNUL)/g' \
-             -e 's/@''GNULIB_STRDUP''@/$(GNULIB_STRDUP)/g' \
-             -e 's/@''GNULIB_STRNCAT''@/$(GNULIB_STRNCAT)/g' \
-             -e 's/@''GNULIB_STRNDUP''@/$(GNULIB_STRNDUP)/g' \
-             -e 's/@''GNULIB_STRNLEN''@/$(GNULIB_STRNLEN)/g' \
-             -e 's/@''GNULIB_STRPBRK''@/$(GNULIB_STRPBRK)/g' \
-             -e 's/@''GNULIB_STRSEP''@/$(GNULIB_STRSEP)/g' \
-             -e 's/@''GNULIB_STRSTR''@/$(GNULIB_STRSTR)/g' \
-             -e 's/@''GNULIB_STRCASESTR''@/$(GNULIB_STRCASESTR)/g' \
-             -e 's/@''GNULIB_STRTOK_R''@/$(GNULIB_STRTOK_R)/g' \
-             -e 's/@''GNULIB_STRERROR''@/$(GNULIB_STRERROR)/g' \
-             -e 's/@''GNULIB_STRERROR_R''@/$(GNULIB_STRERROR_R)/g' \
-             -e 's/@''GNULIB_STRERRORNAME_NP''@/$(GNULIB_STRERRORNAME_NP)/g' \
-             -e 's/@''GNULIB_SIGABBREV_NP''@/$(GNULIB_SIGABBREV_NP)/g' \
-             -e 's/@''GNULIB_SIGDESCR_NP''@/$(GNULIB_SIGDESCR_NP)/g' \
-             -e 's/@''GNULIB_STRSIGNAL''@/$(GNULIB_STRSIGNAL)/g' \
-             -e 's/@''GNULIB_STRVERSCMP''@/$(GNULIB_STRVERSCMP)/g' \
-             -e 's/@''GNULIB_MDA_MEMCCPY''@/$(GNULIB_MDA_MEMCCPY)/g' \
-             -e 's/@''GNULIB_MDA_STRDUP''@/$(GNULIB_MDA_STRDUP)/g' \
+             -e 's/@''GNULIB_EXPLICIT_BZERO''@/$(GL_GNULIB_EXPLICIT_BZERO)/g' \
+             -e 's/@''GNULIB_FFSL''@/$(GL_GNULIB_FFSL)/g' \
+             -e 's/@''GNULIB_FFSLL''@/$(GL_GNULIB_FFSLL)/g' \
+             -e 's/@''GNULIB_MBSLEN''@/$(GL_GNULIB_MBSLEN)/g' \
+             -e 's/@''GNULIB_MBSNLEN''@/$(GL_GNULIB_MBSNLEN)/g' \
+             -e 's/@''GNULIB_MBSCHR''@/$(GL_GNULIB_MBSCHR)/g' \
+             -e 's/@''GNULIB_MBSRCHR''@/$(GL_GNULIB_MBSRCHR)/g' \
+             -e 's/@''GNULIB_MBSSTR''@/$(GL_GNULIB_MBSSTR)/g' \
+             -e 's/@''GNULIB_MBSCASECMP''@/$(GL_GNULIB_MBSCASECMP)/g' \
+             -e 's/@''GNULIB_MBSNCASECMP''@/$(GL_GNULIB_MBSNCASECMP)/g' \
+             -e 's/@''GNULIB_MBSPCASECMP''@/$(GL_GNULIB_MBSPCASECMP)/g' \
+             -e 's/@''GNULIB_MBSCASESTR''@/$(GL_GNULIB_MBSCASESTR)/g' \
+             -e 's/@''GNULIB_MBSCSPN''@/$(GL_GNULIB_MBSCSPN)/g' \
+             -e 's/@''GNULIB_MBSPBRK''@/$(GL_GNULIB_MBSPBRK)/g' \
+             -e 's/@''GNULIB_MBSSPN''@/$(GL_GNULIB_MBSSPN)/g' \
+             -e 's/@''GNULIB_MBSSEP''@/$(GL_GNULIB_MBSSEP)/g' \
+             -e 's/@''GNULIB_MBSTOK_R''@/$(GL_GNULIB_MBSTOK_R)/g' \
+             -e 's/@''GNULIB_MEMCHR''@/$(GL_GNULIB_MEMCHR)/g' \
+             -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \
+             -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \
+             -e 's/@''GNULIB_MEMRCHR''@/$(GL_GNULIB_MEMRCHR)/g' \
+             -e 's/@''GNULIB_RAWMEMCHR''@/$(GL_GNULIB_RAWMEMCHR)/g' \
+             -e 's/@''GNULIB_STPCPY''@/$(GL_GNULIB_STPCPY)/g' \
+             -e 's/@''GNULIB_STPNCPY''@/$(GL_GNULIB_STPNCPY)/g' \
+             -e 's/@''GNULIB_STRCHRNUL''@/$(GL_GNULIB_STRCHRNUL)/g' \
+             -e 's/@''GNULIB_STRDUP''@/$(GL_GNULIB_STRDUP)/g' \
+             -e 's/@''GNULIB_STRNCAT''@/$(GL_GNULIB_STRNCAT)/g' \
+             -e 's/@''GNULIB_STRNDUP''@/$(GL_GNULIB_STRNDUP)/g' \
+             -e 's/@''GNULIB_STRNLEN''@/$(GL_GNULIB_STRNLEN)/g' \
+             -e 's/@''GNULIB_STRPBRK''@/$(GL_GNULIB_STRPBRK)/g' \
+             -e 's/@''GNULIB_STRSEP''@/$(GL_GNULIB_STRSEP)/g' \
+             -e 's/@''GNULIB_STRSTR''@/$(GL_GNULIB_STRSTR)/g' \
+             -e 's/@''GNULIB_STRCASESTR''@/$(GL_GNULIB_STRCASESTR)/g' \
+             -e 's/@''GNULIB_STRTOK_R''@/$(GL_GNULIB_STRTOK_R)/g' \
+             -e 's/@''GNULIB_STRERROR''@/$(GL_GNULIB_STRERROR)/g' \
+             -e 's/@''GNULIB_STRERROR_R''@/$(GL_GNULIB_STRERROR_R)/g' \
+             -e 
's/@''GNULIB_STRERRORNAME_NP''@/$(GL_GNULIB_STRERRORNAME_NP)/g' \
+             -e 's/@''GNULIB_SIGABBREV_NP''@/$(GL_GNULIB_SIGABBREV_NP)/g' \
+             -e 's/@''GNULIB_SIGDESCR_NP''@/$(GL_GNULIB_SIGDESCR_NP)/g' \
+             -e 's/@''GNULIB_STRSIGNAL''@/$(GL_GNULIB_STRSIGNAL)/g' \
+             -e 's/@''GNULIB_STRVERSCMP''@/$(GL_GNULIB_STRVERSCMP)/g' \
+             -e 's/@''GNULIB_MDA_MEMCCPY''@/$(GL_GNULIB_MDA_MEMCCPY)/g' \
+             -e 's/@''GNULIB_MDA_STRDUP''@/$(GL_GNULIB_MDA_STRDUP)/g' \
+             -e 's/@''GNULIB_FREE_POSIX''@/$(GL_GNULIB_FREE_POSIX)/g' \
              < $(srcdir)/string.in.h | \
          sed -e 's|@''HAVE_EXPLICIT_BZERO''@|$(HAVE_EXPLICIT_BZERO)|g' \
              -e 's|@''HAVE_FFSL''@|$(HAVE_FFSL)|g' \
@@ -3071,6 +3203,7 @@ string.h: string.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''REPLACE_FFSLL''@|$(REPLACE_FFSLL)|g' \
              -e 's|@''REPLACE_MEMCHR''@|$(REPLACE_MEMCHR)|g' \
              -e 's|@''REPLACE_MEMMEM''@|$(REPLACE_MEMMEM)|g' \
+             -e 's|@''REPLACE_FREE''@|$(REPLACE_FREE)|g' \
              -e 's|@''REPLACE_STPNCPY''@|$(REPLACE_STPNCPY)|g' \
              -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \
              -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \
@@ -3161,7 +3294,7 @@ sys/random.h: sys_random.in.h 
$(top_builddir)/config.status $(CXXDEFS_H) $(ARG_N
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_SYS_RANDOM_H''@|$(NEXT_SYS_RANDOM_H)|g' \
              -e 's|@''HAVE_SYS_RANDOM_H''@|$(HAVE_SYS_RANDOM_H)|g' \
-             -e 's/@''GNULIB_GETRANDOM''@/$(GNULIB_GETRANDOM)/g' \
+             -e 's/@''GNULIB_GETRANDOM''@/$(GL_GNULIB_GETRANDOM)/g' \
              -e 's/@''HAVE_GETRANDOM''@/$(HAVE_GETRANDOM)/g' \
              -e 's/@''REPLACE_GETRANDOM''@/$(REPLACE_GETRANDOM)/g' \
              -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
@@ -3195,8 +3328,8 @@ sys/select.h: sys_select.in.h 
$(top_builddir)/config.status $(CXXDEFS_H) $(WARN_
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_SYS_SELECT_H''@|$(NEXT_SYS_SELECT_H)|g' \
              -e 's|@''HAVE_SYS_SELECT_H''@|$(HAVE_SYS_SELECT_H)|g' \
-             -e 's/@''GNULIB_PSELECT''@/$(GNULIB_PSELECT)/g' \
-             -e 's/@''GNULIB_SELECT''@/$(GNULIB_SELECT)/g' \
+             -e 's/@''GNULIB_PSELECT''@/$(GL_GNULIB_PSELECT)/g' \
+             -e 's/@''GNULIB_SELECT''@/$(GL_GNULIB_SELECT)/g' \
              -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \
              -e 's|@''HAVE_PSELECT''@|$(HAVE_PSELECT)|g' \
              -e 's|@''REPLACE_PSELECT''@|$(REPLACE_PSELECT)|g' \
@@ -3232,25 +3365,25 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNU
              -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \
              -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \
              -e 's|@''WINDOWS_STAT_TIMESPEC''@|$(WINDOWS_STAT_TIMESPEC)|g' \
-             -e 's/@''GNULIB_FCHMODAT''@/$(GNULIB_FCHMODAT)/g' \
-             -e 's/@''GNULIB_FSTAT''@/$(GNULIB_FSTAT)/g' \
-             -e 's/@''GNULIB_FSTATAT''@/$(GNULIB_FSTATAT)/g' \
-             -e 's/@''GNULIB_FUTIMENS''@/$(GNULIB_FUTIMENS)/g' \
-             -e 's/@''GNULIB_GETUMASK''@/$(GNULIB_GETUMASK)/g' \
-             -e 's/@''GNULIB_LCHMOD''@/$(GNULIB_LCHMOD)/g' \
-             -e 's/@''GNULIB_LSTAT''@/$(GNULIB_LSTAT)/g' \
-             -e 's/@''GNULIB_MKDIR''@/$(GNULIB_MKDIR)/g' \
-             -e 's/@''GNULIB_MKDIRAT''@/$(GNULIB_MKDIRAT)/g' \
-             -e 's/@''GNULIB_MKFIFO''@/$(GNULIB_MKFIFO)/g' \
-             -e 's/@''GNULIB_MKFIFOAT''@/$(GNULIB_MKFIFOAT)/g' \
-             -e 's/@''GNULIB_MKNOD''@/$(GNULIB_MKNOD)/g' \
-             -e 's/@''GNULIB_MKNODAT''@/$(GNULIB_MKNODAT)/g' \
-             -e 's/@''GNULIB_STAT''@/$(GNULIB_STAT)/g' \
-             -e 's/@''GNULIB_UTIMENSAT''@/$(GNULIB_UTIMENSAT)/g' \
-             -e 
's/@''GNULIB_OVERRIDES_STRUCT_STAT''@/$(GNULIB_OVERRIDES_STRUCT_STAT)/g' \
-             -e 's/@''GNULIB_MDA_CHMOD''@/$(GNULIB_MDA_CHMOD)/g' \
-             -e 's/@''GNULIB_MDA_MKDIR''@/$(GNULIB_MDA_MKDIR)/g' \
-             -e 's/@''GNULIB_MDA_UMASK''@/$(GNULIB_MDA_UMASK)/g' \
+             -e 's/@''GNULIB_FCHMODAT''@/$(GL_GNULIB_FCHMODAT)/g' \
+             -e 's/@''GNULIB_FSTAT''@/$(GL_GNULIB_FSTAT)/g' \
+             -e 's/@''GNULIB_FSTATAT''@/$(GL_GNULIB_FSTATAT)/g' \
+             -e 's/@''GNULIB_FUTIMENS''@/$(GL_GNULIB_FUTIMENS)/g' \
+             -e 's/@''GNULIB_GETUMASK''@/$(GL_GNULIB_GETUMASK)/g' \
+             -e 's/@''GNULIB_LCHMOD''@/$(GL_GNULIB_LCHMOD)/g' \
+             -e 's/@''GNULIB_LSTAT''@/$(GL_GNULIB_LSTAT)/g' \
+             -e 's/@''GNULIB_MKDIR''@/$(GL_GNULIB_MKDIR)/g' \
+             -e 's/@''GNULIB_MKDIRAT''@/$(GL_GNULIB_MKDIRAT)/g' \
+             -e 's/@''GNULIB_MKFIFO''@/$(GL_GNULIB_MKFIFO)/g' \
+             -e 's/@''GNULIB_MKFIFOAT''@/$(GL_GNULIB_MKFIFOAT)/g' \
+             -e 's/@''GNULIB_MKNOD''@/$(GL_GNULIB_MKNOD)/g' \
+             -e 's/@''GNULIB_MKNODAT''@/$(GL_GNULIB_MKNODAT)/g' \
+             -e 's/@''GNULIB_STAT''@/$(GL_GNULIB_STAT)/g' \
+             -e 's/@''GNULIB_UTIMENSAT''@/$(GL_GNULIB_UTIMENSAT)/g' \
+             -e 
's/@''GNULIB_OVERRIDES_STRUCT_STAT''@/$(GL_GNULIB_OVERRIDES_STRUCT_STAT)/g' \
+             -e 's/@''GNULIB_MDA_CHMOD''@/$(GL_GNULIB_MDA_CHMOD)/g' \
+             -e 's/@''GNULIB_MDA_MKDIR''@/$(GL_GNULIB_MDA_MKDIR)/g' \
+             -e 's/@''GNULIB_MDA_UMASK''@/$(GL_GNULIB_MDA_UMASK)/g' \
              -e 's|@''HAVE_FCHMODAT''@|$(HAVE_FCHMODAT)|g' \
              -e 's|@''HAVE_FSTATAT''@|$(HAVE_FSTATAT)|g' \
              -e 's|@''HAVE_FUTIMENS''@|$(HAVE_FUTIMENS)|g' \
@@ -3306,7 +3439,7 @@ sys/time.h: sys_time.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNU
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_SYS_TIME_H''@|$(NEXT_SYS_TIME_H)|g' \
-             -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GNULIB_GETTIMEOFDAY)/g' \
+             -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GL_GNULIB_GETTIMEOFDAY)/g' \
              -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \
              -e 's/@''HAVE_GETTIMEOFDAY''@/$(HAVE_GETTIMEOFDAY)/g' \
              -e 's/@''HAVE_STRUCT_TIMEVAL''@/$(HAVE_STRUCT_TIMEVAL)/g' \
@@ -3378,18 +3511,18 @@ time.h: time.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H) $(
              -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \
-             -e 's/@''GNULIB_CTIME''@/$(GNULIB_CTIME)/g' \
-             -e 's/@''GNULIB_LOCALTIME''@/$(GNULIB_LOCALTIME)/g' \
-             -e 's/@''GNULIB_MKTIME''@/$(GNULIB_MKTIME)/g' \
-             -e 's/@''GNULIB_NANOSLEEP''@/$(GNULIB_NANOSLEEP)/g' \
-             -e 's/@''GNULIB_STRFTIME''@/$(GNULIB_STRFTIME)/g' \
-             -e 's/@''GNULIB_STRPTIME''@/$(GNULIB_STRPTIME)/g' \
-             -e 's/@''GNULIB_TIMEGM''@/$(GNULIB_TIMEGM)/g' \
-             -e 's/@''GNULIB_TIMESPEC_GET''@/$(GNULIB_TIMESPEC_GET)/g' \
-             -e 's/@''GNULIB_TIME_R''@/$(GNULIB_TIME_R)/g' \
-             -e 's/@''GNULIB_TIME_RZ''@/$(GNULIB_TIME_RZ)/g' \
-             -e 's/@''GNULIB_TZSET''@/$(GNULIB_TZSET)/g' \
-             -e 's/@''GNULIB_MDA_TZSET''@/$(GNULIB_MDA_TZSET)/g' \
+             -e 's/@''GNULIB_CTIME''@/$(GL_GNULIB_CTIME)/g' \
+             -e 's/@''GNULIB_LOCALTIME''@/$(GL_GNULIB_LOCALTIME)/g' \
+             -e 's/@''GNULIB_MKTIME''@/$(GL_GNULIB_MKTIME)/g' \
+             -e 's/@''GNULIB_NANOSLEEP''@/$(GL_GNULIB_NANOSLEEP)/g' \
+             -e 's/@''GNULIB_STRFTIME''@/$(GL_GNULIB_STRFTIME)/g' \
+             -e 's/@''GNULIB_STRPTIME''@/$(GL_GNULIB_STRPTIME)/g' \
+             -e 's/@''GNULIB_TIMEGM''@/$(GL_GNULIB_TIMEGM)/g' \
+             -e 's/@''GNULIB_TIMESPEC_GET''@/$(GL_GNULIB_TIMESPEC_GET)/g' \
+             -e 's/@''GNULIB_TIME_R''@/$(GL_GNULIB_TIME_R)/g' \
+             -e 's/@''GNULIB_TIME_RZ''@/$(GL_GNULIB_TIME_RZ)/g' \
+             -e 's/@''GNULIB_TZSET''@/$(GL_GNULIB_TZSET)/g' \
+             -e 's/@''GNULIB_MDA_TZSET''@/$(GL_GNULIB_MDA_TZSET)/g' \
              -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \
              -e 's|@''HAVE_NANOSLEEP''@|$(HAVE_NANOSLEEP)|g' \
              -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \
@@ -3510,89 +3643,89 @@ unistd.h: unistd.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
              -e 's|@''NEXT_UNISTD_H''@|$(NEXT_UNISTD_H)|g' \
              -e 's|@''WINDOWS_64_BIT_OFF_T''@|$(WINDOWS_64_BIT_OFF_T)|g' \
-             -e 's/@''GNULIB_ACCESS''@/$(GNULIB_ACCESS)/g' \
-             -e 's/@''GNULIB_CHDIR''@/$(GNULIB_CHDIR)/g' \
-             -e 's/@''GNULIB_CHOWN''@/$(GNULIB_CHOWN)/g' \
-             -e 's/@''GNULIB_CLOSE''@/$(GNULIB_CLOSE)/g' \
-             -e 's/@''GNULIB_COPY_FILE_RANGE''@/$(GNULIB_COPY_FILE_RANGE)/g' \
-             -e 's/@''GNULIB_DUP''@/$(GNULIB_DUP)/g' \
-             -e 's/@''GNULIB_DUP2''@/$(GNULIB_DUP2)/g' \
-             -e 's/@''GNULIB_DUP3''@/$(GNULIB_DUP3)/g' \
-             -e 's/@''GNULIB_ENVIRON''@/$(GNULIB_ENVIRON)/g' \
-             -e 's/@''GNULIB_EUIDACCESS''@/$(GNULIB_EUIDACCESS)/g' \
-             -e 's/@''GNULIB_EXECL''@/$(GNULIB_EXECL)/g' \
-             -e 's/@''GNULIB_EXECLE''@/$(GNULIB_EXECLE)/g' \
-             -e 's/@''GNULIB_EXECLP''@/$(GNULIB_EXECLP)/g' \
-             -e 's/@''GNULIB_EXECV''@/$(GNULIB_EXECV)/g' \
-             -e 's/@''GNULIB_EXECVE''@/$(GNULIB_EXECVE)/g' \
-             -e 's/@''GNULIB_EXECVP''@/$(GNULIB_EXECVP)/g' \
-             -e 's/@''GNULIB_EXECVPE''@/$(GNULIB_EXECVPE)/g' \
-             -e 's/@''GNULIB_FACCESSAT''@/$(GNULIB_FACCESSAT)/g' \
-             -e 's/@''GNULIB_FCHDIR''@/$(GNULIB_FCHDIR)/g' \
-             -e 's/@''GNULIB_FCHOWNAT''@/$(GNULIB_FCHOWNAT)/g' \
-             -e 's/@''GNULIB_FDATASYNC''@/$(GNULIB_FDATASYNC)/g' \
-             -e 's/@''GNULIB_FSYNC''@/$(GNULIB_FSYNC)/g' \
-             -e 's/@''GNULIB_FTRUNCATE''@/$(GNULIB_FTRUNCATE)/g' \
-             -e 's/@''GNULIB_GETCWD''@/$(GNULIB_GETCWD)/g' \
-             -e 's/@''GNULIB_GETDOMAINNAME''@/$(GNULIB_GETDOMAINNAME)/g' \
-             -e 's/@''GNULIB_GETDTABLESIZE''@/$(GNULIB_GETDTABLESIZE)/g' \
-             -e 's/@''GNULIB_GETENTROPY''@/$(GNULIB_GETENTROPY)/g' \
-             -e 's/@''GNULIB_GETGROUPS''@/$(GNULIB_GETGROUPS)/g' \
-             -e 's/@''GNULIB_GETHOSTNAME''@/$(GNULIB_GETHOSTNAME)/g' \
-             -e 's/@''GNULIB_GETLOGIN''@/$(GNULIB_GETLOGIN)/g' \
-             -e 's/@''GNULIB_GETLOGIN_R''@/$(GNULIB_GETLOGIN_R)/g' \
-             -e 's/@''GNULIB_GETOPT_POSIX''@/$(GNULIB_GETOPT_POSIX)/g' \
-             -e 's/@''GNULIB_GETPAGESIZE''@/$(GNULIB_GETPAGESIZE)/g' \
-             -e 's/@''GNULIB_GETPASS''@/$(GNULIB_GETPASS)/g' \
-             -e 's/@''GNULIB_GETUSERSHELL''@/$(GNULIB_GETUSERSHELL)/g' \
-             -e 's/@''GNULIB_GROUP_MEMBER''@/$(GNULIB_GROUP_MEMBER)/g' \
-             -e 's/@''GNULIB_ISATTY''@/$(GNULIB_ISATTY)/g' \
-             -e 's/@''GNULIB_LCHOWN''@/$(GNULIB_LCHOWN)/g' \
-             -e 's/@''GNULIB_LINK''@/$(GNULIB_LINK)/g' \
-             -e 's/@''GNULIB_LINKAT''@/$(GNULIB_LINKAT)/g' \
-             -e 's/@''GNULIB_LSEEK''@/$(GNULIB_LSEEK)/g' \
-             -e 's/@''GNULIB_PIPE''@/$(GNULIB_PIPE)/g' \
-             -e 's/@''GNULIB_PIPE2''@/$(GNULIB_PIPE2)/g' \
-             -e 's/@''GNULIB_PREAD''@/$(GNULIB_PREAD)/g' \
-             -e 's/@''GNULIB_PWRITE''@/$(GNULIB_PWRITE)/g' \
-             -e 's/@''GNULIB_READ''@/$(GNULIB_READ)/g' \
-             -e 's/@''GNULIB_READLINK''@/$(GNULIB_READLINK)/g' \
-             -e 's/@''GNULIB_READLINKAT''@/$(GNULIB_READLINKAT)/g' \
-             -e 's/@''GNULIB_RMDIR''@/$(GNULIB_RMDIR)/g' \
-             -e 's/@''GNULIB_SETHOSTNAME''@/$(GNULIB_SETHOSTNAME)/g' \
-             -e 's/@''GNULIB_SLEEP''@/$(GNULIB_SLEEP)/g' \
-             -e 's/@''GNULIB_SYMLINK''@/$(GNULIB_SYMLINK)/g' \
-             -e 's/@''GNULIB_SYMLINKAT''@/$(GNULIB_SYMLINKAT)/g' \
-             -e 's/@''GNULIB_TRUNCATE''@/$(GNULIB_TRUNCATE)/g' \
-             -e 's/@''GNULIB_TTYNAME_R''@/$(GNULIB_TTYNAME_R)/g' \
-             -e 
's/@''GNULIB_UNISTD_H_GETOPT''@/0$(GNULIB_GL_UNISTD_H_GETOPT)/g' \
-             -e 
's/@''GNULIB_UNISTD_H_NONBLOCKING''@/$(GNULIB_UNISTD_H_NONBLOCKING)/g' \
-             -e 's/@''GNULIB_UNISTD_H_SIGPIPE''@/$(GNULIB_UNISTD_H_SIGPIPE)/g' 
\
-             -e 's/@''GNULIB_UNLINK''@/$(GNULIB_UNLINK)/g' \
-             -e 's/@''GNULIB_UNLINKAT''@/$(GNULIB_UNLINKAT)/g' \
-             -e 's/@''GNULIB_USLEEP''@/$(GNULIB_USLEEP)/g' \
-             -e 's/@''GNULIB_WRITE''@/$(GNULIB_WRITE)/g' \
-             -e 's/@''GNULIB_MDA_ACCESS''@/$(GNULIB_MDA_ACCESS)/g' \
-             -e 's/@''GNULIB_MDA_CHDIR''@/$(GNULIB_MDA_CHDIR)/g' \
-             -e 's/@''GNULIB_MDA_CLOSE''@/$(GNULIB_MDA_CLOSE)/g' \
-             -e 's/@''GNULIB_MDA_DUP''@/$(GNULIB_MDA_DUP)/g' \
-             -e 's/@''GNULIB_MDA_DUP2''@/$(GNULIB_MDA_DUP2)/g' \
-             -e 's/@''GNULIB_MDA_EXECL''@/$(GNULIB_MDA_EXECL)/g' \
-             -e 's/@''GNULIB_MDA_EXECLE''@/$(GNULIB_MDA_EXECLE)/g' \
-             -e 's/@''GNULIB_MDA_EXECLP''@/$(GNULIB_MDA_EXECLP)/g' \
-             -e 's/@''GNULIB_MDA_EXECV''@/$(GNULIB_MDA_EXECV)/g' \
-             -e 's/@''GNULIB_MDA_EXECVE''@/$(GNULIB_MDA_EXECVE)/g' \
-             -e 's/@''GNULIB_MDA_EXECVP''@/$(GNULIB_MDA_EXECVP)/g' \
-             -e 's/@''GNULIB_MDA_EXECVPE''@/$(GNULIB_MDA_EXECVPE)/g' \
-             -e 's/@''GNULIB_MDA_GETCWD''@/$(GNULIB_MDA_GETCWD)/g' \
-             -e 's/@''GNULIB_MDA_GETPID''@/$(GNULIB_MDA_GETPID)/g' \
-             -e 's/@''GNULIB_MDA_ISATTY''@/$(GNULIB_MDA_ISATTY)/g' \
-             -e 's/@''GNULIB_MDA_LSEEK''@/$(GNULIB_MDA_LSEEK)/g' \
-             -e 's/@''GNULIB_MDA_READ''@/$(GNULIB_MDA_READ)/g' \
-             -e 's/@''GNULIB_MDA_RMDIR''@/$(GNULIB_MDA_RMDIR)/g' \
-             -e 's/@''GNULIB_MDA_SWAB''@/$(GNULIB_MDA_SWAB)/g' \
-             -e 's/@''GNULIB_MDA_UNLINK''@/$(GNULIB_MDA_UNLINK)/g' \
-             -e 's/@''GNULIB_MDA_WRITE''@/$(GNULIB_MDA_WRITE)/g' \
+             -e 's/@''GNULIB_ACCESS''@/$(GL_GNULIB_ACCESS)/g' \
+             -e 's/@''GNULIB_CHDIR''@/$(GL_GNULIB_CHDIR)/g' \
+             -e 's/@''GNULIB_CHOWN''@/$(GL_GNULIB_CHOWN)/g' \
+             -e 's/@''GNULIB_CLOSE''@/$(GL_GNULIB_CLOSE)/g' \
+             -e 
's/@''GNULIB_COPY_FILE_RANGE''@/$(GL_GNULIB_COPY_FILE_RANGE)/g' \
+             -e 's/@''GNULIB_DUP''@/$(GL_GNULIB_DUP)/g' \
+             -e 's/@''GNULIB_DUP2''@/$(GL_GNULIB_DUP2)/g' \
+             -e 's/@''GNULIB_DUP3''@/$(GL_GNULIB_DUP3)/g' \
+             -e 's/@''GNULIB_ENVIRON''@/$(GL_GNULIB_ENVIRON)/g' \
+             -e 's/@''GNULIB_EUIDACCESS''@/$(GL_GNULIB_EUIDACCESS)/g' \
+             -e 's/@''GNULIB_EXECL''@/$(GL_GNULIB_EXECL)/g' \
+             -e 's/@''GNULIB_EXECLE''@/$(GL_GNULIB_EXECLE)/g' \
+             -e 's/@''GNULIB_EXECLP''@/$(GL_GNULIB_EXECLP)/g' \
+             -e 's/@''GNULIB_EXECV''@/$(GL_GNULIB_EXECV)/g' \
+             -e 's/@''GNULIB_EXECVE''@/$(GL_GNULIB_EXECVE)/g' \
+             -e 's/@''GNULIB_EXECVP''@/$(GL_GNULIB_EXECVP)/g' \
+             -e 's/@''GNULIB_EXECVPE''@/$(GL_GNULIB_EXECVPE)/g' \
+             -e 's/@''GNULIB_FACCESSAT''@/$(GL_GNULIB_FACCESSAT)/g' \
+             -e 's/@''GNULIB_FCHDIR''@/$(GL_GNULIB_FCHDIR)/g' \
+             -e 's/@''GNULIB_FCHOWNAT''@/$(GL_GNULIB_FCHOWNAT)/g' \
+             -e 's/@''GNULIB_FDATASYNC''@/$(GL_GNULIB_FDATASYNC)/g' \
+             -e 's/@''GNULIB_FSYNC''@/$(GL_GNULIB_FSYNC)/g' \
+             -e 's/@''GNULIB_FTRUNCATE''@/$(GL_GNULIB_FTRUNCATE)/g' \
+             -e 's/@''GNULIB_GETCWD''@/$(GL_GNULIB_GETCWD)/g' \
+             -e 's/@''GNULIB_GETDOMAINNAME''@/$(GL_GNULIB_GETDOMAINNAME)/g' \
+             -e 's/@''GNULIB_GETDTABLESIZE''@/$(GL_GNULIB_GETDTABLESIZE)/g' \
+             -e 's/@''GNULIB_GETENTROPY''@/$(GL_GNULIB_GETENTROPY)/g' \
+             -e 's/@''GNULIB_GETGROUPS''@/$(GL_GNULIB_GETGROUPS)/g' \
+             -e 's/@''GNULIB_GETHOSTNAME''@/$(GL_GNULIB_GETHOSTNAME)/g' \
+             -e 's/@''GNULIB_GETLOGIN''@/$(GL_GNULIB_GETLOGIN)/g' \
+             -e 's/@''GNULIB_GETLOGIN_R''@/$(GL_GNULIB_GETLOGIN_R)/g' \
+             -e 's/@''GNULIB_GETOPT_POSIX''@/$(GL_GNULIB_GETOPT_POSIX)/g' \
+             -e 's/@''GNULIB_GETPAGESIZE''@/$(GL_GNULIB_GETPAGESIZE)/g' \
+             -e 's/@''GNULIB_GETPASS''@/$(GL_GNULIB_GETPASS)/g' \
+             -e 's/@''GNULIB_GETUSERSHELL''@/$(GL_GNULIB_GETUSERSHELL)/g' \
+             -e 's/@''GNULIB_GROUP_MEMBER''@/$(GL_GNULIB_GROUP_MEMBER)/g' \
+             -e 's/@''GNULIB_ISATTY''@/$(GL_GNULIB_ISATTY)/g' \
+             -e 's/@''GNULIB_LCHOWN''@/$(GL_GNULIB_LCHOWN)/g' \
+             -e 's/@''GNULIB_LINK''@/$(GL_GNULIB_LINK)/g' \
+             -e 's/@''GNULIB_LINKAT''@/$(GL_GNULIB_LINKAT)/g' \
+             -e 's/@''GNULIB_LSEEK''@/$(GL_GNULIB_LSEEK)/g' \
+             -e 's/@''GNULIB_PIPE''@/$(GL_GNULIB_PIPE)/g' \
+             -e 's/@''GNULIB_PIPE2''@/$(GL_GNULIB_PIPE2)/g' \
+             -e 's/@''GNULIB_PREAD''@/$(GL_GNULIB_PREAD)/g' \
+             -e 's/@''GNULIB_PWRITE''@/$(GL_GNULIB_PWRITE)/g' \
+             -e 's/@''GNULIB_READ''@/$(GL_GNULIB_READ)/g' \
+             -e 's/@''GNULIB_READLINK''@/$(GL_GNULIB_READLINK)/g' \
+             -e 's/@''GNULIB_READLINKAT''@/$(GL_GNULIB_READLINKAT)/g' \
+             -e 's/@''GNULIB_RMDIR''@/$(GL_GNULIB_RMDIR)/g' \
+             -e 's/@''GNULIB_SETHOSTNAME''@/$(GL_GNULIB_SETHOSTNAME)/g' \
+             -e 's/@''GNULIB_SLEEP''@/$(GL_GNULIB_SLEEP)/g' \
+             -e 's/@''GNULIB_SYMLINK''@/$(GL_GNULIB_SYMLINK)/g' \
+             -e 's/@''GNULIB_SYMLINKAT''@/$(GL_GNULIB_SYMLINKAT)/g' \
+             -e 's/@''GNULIB_TRUNCATE''@/$(GL_GNULIB_TRUNCATE)/g' \
+             -e 's/@''GNULIB_TTYNAME_R''@/$(GL_GNULIB_TTYNAME_R)/g' \
+             -e 
's/@''GNULIB_UNISTD_H_GETOPT''@/0$(GL_GNULIB_UNISTD_H_GETOPT)/g' \
+             -e 
's/@''GNULIB_UNISTD_H_NONBLOCKING''@/$(GL_GNULIB_UNISTD_H_NONBLOCKING)/g' \
+             -e 
's/@''GNULIB_UNISTD_H_SIGPIPE''@/$(GL_GNULIB_UNISTD_H_SIGPIPE)/g' \
+             -e 's/@''GNULIB_UNLINK''@/$(GL_GNULIB_UNLINK)/g' \
+             -e 's/@''GNULIB_UNLINKAT''@/$(GL_GNULIB_UNLINKAT)/g' \
+             -e 's/@''GNULIB_USLEEP''@/$(GL_GNULIB_USLEEP)/g' \
+             -e 's/@''GNULIB_WRITE''@/$(GL_GNULIB_WRITE)/g' \
+             -e 's/@''GNULIB_MDA_ACCESS''@/$(GL_GNULIB_MDA_ACCESS)/g' \
+             -e 's/@''GNULIB_MDA_CHDIR''@/$(GL_GNULIB_MDA_CHDIR)/g' \
+             -e 's/@''GNULIB_MDA_CLOSE''@/$(GL_GNULIB_MDA_CLOSE)/g' \
+             -e 's/@''GNULIB_MDA_DUP''@/$(GL_GNULIB_MDA_DUP)/g' \
+             -e 's/@''GNULIB_MDA_DUP2''@/$(GL_GNULIB_MDA_DUP2)/g' \
+             -e 's/@''GNULIB_MDA_EXECL''@/$(GL_GNULIB_MDA_EXECL)/g' \
+             -e 's/@''GNULIB_MDA_EXECLE''@/$(GL_GNULIB_MDA_EXECLE)/g' \
+             -e 's/@''GNULIB_MDA_EXECLP''@/$(GL_GNULIB_MDA_EXECLP)/g' \
+             -e 's/@''GNULIB_MDA_EXECV''@/$(GL_GNULIB_MDA_EXECV)/g' \
+             -e 's/@''GNULIB_MDA_EXECVE''@/$(GL_GNULIB_MDA_EXECVE)/g' \
+             -e 's/@''GNULIB_MDA_EXECVP''@/$(GL_GNULIB_MDA_EXECVP)/g' \
+             -e 's/@''GNULIB_MDA_EXECVPE''@/$(GL_GNULIB_MDA_EXECVPE)/g' \
+             -e 's/@''GNULIB_MDA_GETCWD''@/$(GL_GNULIB_MDA_GETCWD)/g' \
+             -e 's/@''GNULIB_MDA_GETPID''@/$(GL_GNULIB_MDA_GETPID)/g' \
+             -e 's/@''GNULIB_MDA_ISATTY''@/$(GL_GNULIB_MDA_ISATTY)/g' \
+             -e 's/@''GNULIB_MDA_LSEEK''@/$(GL_GNULIB_MDA_LSEEK)/g' \
+             -e 's/@''GNULIB_MDA_READ''@/$(GL_GNULIB_MDA_READ)/g' \
+             -e 's/@''GNULIB_MDA_RMDIR''@/$(GL_GNULIB_MDA_RMDIR)/g' \
+             -e 's/@''GNULIB_MDA_SWAB''@/$(GL_GNULIB_MDA_SWAB)/g' \
+             -e 's/@''GNULIB_MDA_UNLINK''@/$(GL_GNULIB_MDA_UNLINK)/g' \
+             -e 's/@''GNULIB_MDA_WRITE''@/$(GL_GNULIB_MDA_WRITE)/g' \
              < $(srcdir)/unistd.in.h | \
          sed -e 's|@''HAVE_CHOWN''@|$(HAVE_CHOWN)|g' \
              -e 's|@''HAVE_COPY_FILE_RANGE''@|$(HAVE_COPY_FILE_RANGE)|g' \
@@ -3699,14 +3832,14 @@ EXTRA_DIST += unistd.in.h
 endif
 ## end   gnulib module unistd
 
-## begin gnulib module unlocked-io
-ifeq (,$(OMIT_GNULIB_MODULE_unlocked-io))
+## begin gnulib module unlocked-io-internal
+ifeq (,$(OMIT_GNULIB_MODULE_unlocked-io-internal))
 
 
 EXTRA_DIST += unlocked-io.h
 
 endif
-## end   gnulib module unlocked-io
+## end   gnulib module unlocked-io-internal
 
 ## begin gnulib module update-copyright
 ifeq (,$(OMIT_GNULIB_MODULE_update-copyright))
diff --git a/lib/group-member.c b/lib/group-member.c
index 52159016ea..24aea3599c 100644
--- a/lib/group-member.c
+++ b/lib/group-member.c
@@ -3,17 +3,17 @@
    Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
@@ -25,7 +25,7 @@
 #include <sys/types.h>
 #include <stdlib.h>
 
-#include "xalloc-oversized.h"
+#include "intprops.h"
 
 /* Most processes have no more than this many groups, and for these
    processes we can avoid using malloc.  */
@@ -53,10 +53,10 @@ get_group_info (struct group_info *gi)
   if (n_groups < 0)
     {
       int n_group_slots = getgroups (0, NULL);
-      if (0 <= n_group_slots
-          && ! xalloc_oversized (n_group_slots, sizeof *gi->group))
+      size_t nbytes;
+      if (! INT_MULTIPLY_WRAPV (n_group_slots, sizeof *gi->group, &nbytes))
         {
-          gi->group = malloc (n_group_slots * sizeof *gi->group);
+          gi->group = malloc (nbytes);
           if (gi->group)
             n_groups = getgroups (n_group_slots, gi->group);
         }
diff --git a/lib/idx.h b/lib/idx.h
index 681c8c90f1..54ad5d81fe 100644
--- a/lib/idx.h
+++ b/lib/idx.h
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -56,6 +56,26 @@
      * Because 'size_t' is an unsigned type, and a signed type is better.
        See above.
 
+   Why not use 'ssize_t'?
+
+     * 'ptrdiff_t' is more portable; it is standardized by ISO C
+       whereas 'ssize_t' is standardized only by POSIX.
+
+     * 'ssize_t' is not required to be as wide as 'size_t', and some
+       now-obsolete POSIX platforms had 'size_t' wider than 'ssize_t'.
+
+     * Conversely, some now-obsolete platforms had 'ptrdiff_t' wider
+       than 'size_t', which can be a win and conforms to POSIX.
+
+   Won't this cause a problem with objects larger than PTRDIFF_MAX?
+
+     * Typical modern or large platforms do not allocate such objects,
+       so this is not much of a problem in practice; for example, you
+       can safely write 'idx_t len = strlen (s);'.  To port to older
+       small platforms where allocations larger than PTRDIFF_MAX could
+       in theory be a problem, you can use Gnulib's ialloc module, or
+       functions like ximalloc in Gnulib's xalloc module.
+
    Why not use 'ptrdiff_t' directly?
 
      * Maintainability: When reading and modifying code, it helps to know that
diff --git a/lib/ieee754.in.h b/lib/ieee754.in.h
index ce13efc918..ce371cbcea 100644
--- a/lib/ieee754.in.h
+++ b/lib/ieee754.in.h
@@ -2,16 +2,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/ignore-value.h b/lib/ignore-value.h
index 0a3cf1e95b..6099abad97 100644
--- a/lib/ignore-value.h
+++ b/lib/ignore-value.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Jim Meyering, Eric Blake and Pádraig Brady.  */
diff --git a/lib/intprops.h b/lib/intprops.h
index 2a420ac831..3fe64e82e9 100644
--- a/lib/intprops.h
+++ b/lib/intprops.h
@@ -3,19 +3,18 @@
    Copyright (C) 2001-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
+   under the terms of the GNU Lesser General Public License as published
+   by the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-/* Written by Paul Eggert.  */
 
 #ifndef _GL_INTPROPS_H
 #define _GL_INTPROPS_H
@@ -133,7 +132,8 @@
    operators might not yield numerically correct answers due to
    arithmetic overflow.  They do not rely on undefined or
    implementation-defined behavior.  Their implementations are simple
-   and straightforward, but they are a bit harder to use than the
+   and straightforward, but they are harder to use and may be less
+   efficient than the INT_<op>_WRAPV, INT_<op>_OK, and
    INT_<op>_OVERFLOW macros described below.
 
    Example usage:
@@ -158,6 +158,9 @@
    must have minimum value MIN and maximum MAX.  Unsigned types should
    use a zero MIN of the proper type.
 
+   Because all arguments are subject to integer promotions, these
+   macros typically do not work on types narrower than 'int'.
+
    These macros are tuned for constant MIN and MAX.  For commutative
    operations such as A + B, they are also tuned for constant B.  */
 
@@ -339,9 +342,15 @@
    arguments should not have side effects.
 
    The WRAPV macros are not constant expressions.  They support only
-   +, binary -, and *.  Because the WRAPV macros convert the result,
-   they report overflow in different circumstances than the OVERFLOW
-   macros do.
+   +, binary -, and *.
+
+   Because the WRAPV macros convert the result, they report overflow
+   in different circumstances than the OVERFLOW macros do.  For
+   example, in the typical case with 16-bit 'short' and 32-bit 'int',
+   if A, B and R are all of type 'short' then INT_ADD_OVERFLOW (A, B)
+   returns false because the addition cannot overflow after A and B
+   are converted to 'int', whereas INT_ADD_WRAPV (A, B, &R) returns
+   true or false depending on whether the sum fits into 'short'.
 
    These macros are tuned for their last input argument being a constant.
 
diff --git a/lib/inttypes.in.h b/lib/inttypes.in.h
index e9ee500e3e..41cb4220ce 100644
--- a/lib/inttypes.in.h
+++ b/lib/inttypes.in.h
@@ -2,17 +2,17 @@
    Written by Paul Eggert, Bruno Haible, Derek Price.
    This file is part of gnulib.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /*
diff --git a/lib/libc-config.h b/lib/libc-config.h
index c0eac707cf..886c11f37f 100644
--- a/lib/libc-config.h
+++ b/lib/libc-config.h
@@ -3,16 +3,16 @@
    Copyright 2017-2021 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with this program; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -28,14 +28,17 @@
 
    When compiled as part of glibc this is a no-op; when compiled as
    part of Gnulib this includes Gnulib's <config.h> and defines macros
-   that glibc library code would normally assume.  */
+   that glibc library code would normally assume.
+
+   Note: This header file MUST NOT be included by public header files
+   of Gnulib.  */
 
 #include <config.h>
 
 /* On glibc this includes <features.h> and <sys/cdefs.h> and #defines
-   _FEATURES_H, __WORDSIZE, and __set_errno.  On FreeBSD 11 it
-   includes <sys/cdefs.h> which defines __nonnull.  Elsewhere it
-   is harmless.  */
+   _FEATURES_H, __WORDSIZE, and __set_errno.  On FreeBSD 11 and
+   DragonFlyBSD 5.9 it includes <sys/cdefs.h> which defines __nonnull.
+   Elsewhere it is harmless.  */
 #include <errno.h>
 
 /* From glibc <errno.h>.  */
@@ -71,7 +74,7 @@
 # endif
 #endif
 
-#ifndef __attribute_maybe_unused__
+#ifndef __attribute_nonnull__
 /* <sys/cdefs.h> either does not exist, or is too old for Gnulib.
    Prepare to include <cdefs.h>, which is Gnulib's version of a
    more-recent glibc <sys/cdefs.h>.  */
@@ -80,13 +83,9 @@
 # ifndef _FEATURES_H
 #  define _FEATURES_H 1
 # endif
-/* Define __WORDSIZE so that <cdefs.h> does not attempt to include
-   nonexistent files.  Make it a syntax error, since Gnulib does not
-   use __WORDSIZE now, and if Gnulib uses it later the syntax error
-   will let us know that __WORDSIZE needs configuring.  */
-# ifndef __WORDSIZE
-#  define __WORDSIZE %%%
-# endif
+/* Define __GNULIB_CDEFS so that <cdefs.h> does not attempt to include
+   nonexistent files.  */
+# define __GNULIB_CDEFS
 /* Undef the macros unconditionally defined by our copy of glibc
    <sys/cdefs.h>, so that they do not clash with any system-defined
    versions.  */
@@ -118,6 +117,9 @@
 # undef __THROW
 # undef __THROWNL
 # undef __attr_access
+# undef __attr_access_none
+# undef __attr_dealloc
+# undef __attr_dealloc_free
 # undef __attribute__
 # undef __attribute_alloc_size__
 # undef __attribute_artificial__
diff --git a/lib/limits.in.h b/lib/limits.in.h
index 076ab9ef54..2ecafebb00 100644
--- a/lib/limits.in.h
+++ b/lib/limits.in.h
@@ -2,18 +2,18 @@
 
    Copyright 2016-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   as published by the Free Software Foundation; either version 3, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
@@ -99,10 +99,11 @@
 # endif
 #endif
 
-/* Macros specified by ISO/IEC TS 18661-1:2014.  */
+/* Macros specified by C2x and by ISO/IEC TS 18661-1:2014.  */
 
 #if (! defined ULLONG_WIDTH                                             \
-     && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__))
+     && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__ \
+         || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__)))
 # define CHAR_WIDTH _GL_INTEGER_WIDTH (CHAR_MIN, CHAR_MAX)
 # define SCHAR_WIDTH _GL_INTEGER_WIDTH (SCHAR_MIN, SCHAR_MAX)
 # define UCHAR_WIDTH _GL_INTEGER_WIDTH (0, UCHAR_MAX)
@@ -114,7 +115,16 @@
 # define ULONG_WIDTH _GL_INTEGER_WIDTH (0, ULONG_MAX)
 # define LLONG_WIDTH _GL_INTEGER_WIDTH (LLONG_MIN, LLONG_MAX)
 # define ULLONG_WIDTH _GL_INTEGER_WIDTH (0, ULLONG_MAX)
-#endif /* !ULLONG_WIDTH && (_GNU_SOURCE || __STDC_WANT_IEC_60559_BFP_EXT__) */
+#endif
+
+/* Macros specified by C2x.  */
+
+#if (! defined BOOL_WIDTH \
+     && (defined _GNU_SOURCE \
+         || (defined __STDC_VERSION__ && 201710 < __STDC_VERSION__)))
+# define BOOL_MAX 1
+# define BOOL_WIDTH 1
+#endif
 
 #endif /* _@GUARD_PREFIX@_LIMITS_H */
 #endif /* _@GUARD_PREFIX@_LIMITS_H */
diff --git a/lib/lstat.c b/lib/lstat.c
index a584c6aa06..7de0bf1027 100644
--- a/lib/lstat.c
+++ b/lib/lstat.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 1997-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Jim Meyering */
diff --git a/lib/malloc.c b/lib/malloc.c
new file mode 100644
index 0000000000..0d8b3596ca
--- /dev/null
+++ b/lib/malloc.c
@@ -0,0 +1,51 @@
+/* malloc() function that is glibc compatible.
+
+   Copyright (C) 1997-1998, 2006-2007, 2009-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* written by Jim Meyering and Bruno Haible */
+
+#define _GL_USE_STDLIB_ALLOC 1
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <errno.h>
+
+#include "xalloc-oversized.h"
+
+/* Allocate an N-byte block of memory from the heap, even if N is 0.  */
+
+void *
+rpl_malloc (size_t n)
+{
+  if (n == 0)
+    n = 1;
+
+  if (xalloc_oversized (n, 1))
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+
+  void *result = malloc (n);
+
+#if !HAVE_MALLOC_POSIX
+  if (result == NULL)
+    errno = ENOMEM;
+#endif
+
+  return result;
+}
diff --git a/lib/malloc/dynarray-skeleton.c b/lib/malloc/dynarray-skeleton.c
index 4995fd1c04..48210e3252 100644
--- a/lib/malloc/dynarray-skeleton.c
+++ b/lib/malloc/dynarray-skeleton.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -192,7 +192,7 @@ DYNARRAY_NAME (free__array__) (struct DYNARRAY_STRUCT *list)
 
 /* Initialize a dynamic array object.  This must be called before any
    use of the object.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static void
 DYNARRAY_NAME (init) (struct DYNARRAY_STRUCT *list)
 {
@@ -202,7 +202,7 @@ DYNARRAY_NAME (init) (struct DYNARRAY_STRUCT *list)
 }
 
 /* Deallocate the dynamic array and its elements.  */
-__attribute_maybe_unused__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_nonnull__ ((1))
 static void
 DYNARRAY_FREE (struct DYNARRAY_STRUCT *list)
 {
@@ -213,7 +213,7 @@ DYNARRAY_FREE (struct DYNARRAY_STRUCT *list)
 }
 
 /* Return true if the dynamic array is in an error state.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline bool
 DYNARRAY_NAME (has_failed) (const struct DYNARRAY_STRUCT *list)
 {
@@ -222,7 +222,7 @@ DYNARRAY_NAME (has_failed) (const struct DYNARRAY_STRUCT 
*list)
 
 /* Mark the dynamic array as failed.  All elements are deallocated as
    a side effect.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static void
 DYNARRAY_NAME (mark_failed) (struct DYNARRAY_STRUCT *list)
 {
@@ -236,7 +236,7 @@ DYNARRAY_NAME (mark_failed) (struct DYNARRAY_STRUCT *list)
 
 /* Return the number of elements which have been added to the dynamic
    array.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline size_t
 DYNARRAY_NAME (size) (const struct DYNARRAY_STRUCT *list)
 {
@@ -245,7 +245,7 @@ DYNARRAY_NAME (size) (const struct DYNARRAY_STRUCT *list)
 
 /* Return a pointer to the array element at INDEX.  Terminate the
    process if INDEX is out of bounds.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline DYNARRAY_ELEMENT *
 DYNARRAY_NAME (at) (struct DYNARRAY_STRUCT *list, size_t index)
 {
@@ -257,7 +257,7 @@ DYNARRAY_NAME (at) (struct DYNARRAY_STRUCT *list, size_t 
index)
 /* Return a pointer to the first array element, if any.  For a
    zero-length array, the pointer can be NULL even though the dynamic
    array has not entered the failure state.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline DYNARRAY_ELEMENT *
 DYNARRAY_NAME (begin) (struct DYNARRAY_STRUCT *list)
 {
@@ -267,7 +267,7 @@ DYNARRAY_NAME (begin) (struct DYNARRAY_STRUCT *list)
 /* Return a pointer one element past the last array element.  For a
    zero-length array, the pointer can be NULL even though the dynamic
    array has not entered the failure state.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline DYNARRAY_ELEMENT *
 DYNARRAY_NAME (end) (struct DYNARRAY_STRUCT *list)
 {
@@ -294,7 +294,7 @@ DYNARRAY_NAME (add__) (struct DYNARRAY_STRUCT *list, 
DYNARRAY_ELEMENT item)
 /* Add ITEM at the end of the array, enlarging it by one element.
    Mark *LIST as failed if the dynamic array allocation size cannot be
    increased.  */
-__nonnull ((1))
+__attribute_nonnull__ ((1))
 static inline void
 DYNARRAY_NAME (add) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item)
 {
@@ -348,7 +348,8 @@ DYNARRAY_NAME (emplace__) (struct DYNARRAY_STRUCT *list)
 /* Allocate a place for a new element in *LIST and return a pointer to
    it.  The pointer can be NULL if the dynamic array cannot be
    enlarged due to a memory allocation failure.  */
-__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_warn_unused_result__
+__attribute_nonnull__ ((1))
 static
 /* Avoid inlining with the larger initialization code.  */
 #if !(defined (DYNARRAY_ELEMENT_INIT) || defined (DYNARRAY_ELEMENT_FREE))
@@ -372,7 +373,7 @@ DYNARRAY_NAME (emplace) (struct DYNARRAY_STRUCT *list)
    existing size, new elements are added (which can be initialized).
    Otherwise, the list is truncated, and elements are freed.  Return
    false on memory allocation failure (and mark *LIST as failed).  */
-__attribute_maybe_unused__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_nonnull__ ((1))
 static bool
 DYNARRAY_NAME (resize) (struct DYNARRAY_STRUCT *list, size_t size)
 {
@@ -417,7 +418,7 @@ DYNARRAY_NAME (resize) (struct DYNARRAY_STRUCT *list, 
size_t size)
 }
 
 /* Remove the last element of LIST if it is present.  */
-__attribute_maybe_unused__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_nonnull__ ((1))
 static void
 DYNARRAY_NAME (remove_last) (struct DYNARRAY_STRUCT *list)
 {
@@ -434,7 +435,7 @@ DYNARRAY_NAME (remove_last) (struct DYNARRAY_STRUCT *list)
 
 /* Remove all elements from the list.  The elements are freed, but the
    list itself is not.  */
-__attribute_maybe_unused__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_nonnull__ ((1))
 static void
 DYNARRAY_NAME (clear) (struct DYNARRAY_STRUCT *list)
 {
@@ -452,7 +453,8 @@ DYNARRAY_NAME (clear) (struct DYNARRAY_STRUCT *list)
    stored in *RESULT if LIST refers to an empty list.  On success, the
    pointer in *RESULT is heap-allocated and must be deallocated using
    free.  */
-__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1, 2))
+__attribute_maybe_unused__ __attribute_warn_unused_result__
+__attribute_nonnull__ ((1, 2))
 static bool
 DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list,
                           DYNARRAY_FINAL_TYPE *result)
@@ -483,7 +485,8 @@ DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list,
    have a sentinel at the end).  If LENGTHP is not NULL, the array
    length is written to *LENGTHP.  *LIST is re-initialized and can be
    reused.  */
-__attribute_maybe_unused__ __attribute_warn_unused_result__ __nonnull ((1))
+__attribute_maybe_unused__ __attribute_warn_unused_result__
+__attribute_nonnull__ ((1))
 static DYNARRAY_ELEMENT *
 DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list, size_t *lengthp)
 {
diff --git a/lib/malloc/dynarray.h b/lib/malloc/dynarray.h
index 84e4394bf3..638c33f986 100644
--- a/lib/malloc/dynarray.h
+++ b/lib/malloc/dynarray.h
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloc/dynarray_at_failure.c b/lib/malloc/dynarray_at_failure.c
index a442459374..8dd6850787 100644
--- a/lib/malloc/dynarray_at_failure.c
+++ b/lib/malloc/dynarray_at_failure.c
@@ -3,22 +3,26 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _LIBC
+# include <libc-config.h>
+# include <stdlib.h>
+#endif
+
 #include <dynarray.h>
 #include <stdio.h>
-#include <stdlib.h>
 
 void
 __libc_dynarray_at_failure (size_t size, size_t index)
@@ -28,6 +32,7 @@ __libc_dynarray_at_failure (size_t size, size_t index)
   __snprintf (buf, sizeof (buf), "Fatal glibc error: "
               "array index %zu not less than array length %zu\n",
               index, size);
+  __libc_fatal (buf);
 #else
  abort ();
 #endif
diff --git a/lib/malloc/dynarray_emplace_enlarge.c 
b/lib/malloc/dynarray_emplace_enlarge.c
index 7ac4b6db40..0f8baf94ad 100644
--- a/lib/malloc/dynarray_emplace_enlarge.c
+++ b/lib/malloc/dynarray_emplace_enlarge.c
@@ -3,19 +3,23 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _LIBC
+# include <libc-config.h>
+#endif
+
 #include <dynarray.h>
 #include <errno.h>
 #include <intprops.h>
diff --git a/lib/malloc/dynarray_finalize.c b/lib/malloc/dynarray_finalize.c
index be9441e313..c33da41389 100644
--- a/lib/malloc/dynarray_finalize.c
+++ b/lib/malloc/dynarray_finalize.c
@@ -3,19 +3,23 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _LIBC
+# include <libc-config.h>
+#endif
+
 #include <dynarray.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/lib/malloc/dynarray_resize.c b/lib/malloc/dynarray_resize.c
index 92bbddd446..5a57166a84 100644
--- a/lib/malloc/dynarray_resize.c
+++ b/lib/malloc/dynarray_resize.c
@@ -3,19 +3,23 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _LIBC
+# include <libc-config.h>
+#endif
+
 #include <dynarray.h>
 #include <errno.h>
 #include <intprops.h>
diff --git a/lib/malloc/dynarray_resize_clear.c 
b/lib/malloc/dynarray_resize_clear.c
index 99c2cc87c3..9c43b00c3a 100644
--- a/lib/malloc/dynarray_resize_clear.c
+++ b/lib/malloc/dynarray_resize_clear.c
@@ -3,19 +3,23 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#ifndef _LIBC
+# include <libc-config.h>
+#endif
+
 #include <dynarray.h>
 #include <string.h>
 
diff --git a/lib/malloc/scratch_buffer.h b/lib/malloc/scratch_buffer.h
index 26e306212d..36d0bef4bb 100644
--- a/lib/malloc/scratch_buffer.h
+++ b/lib/malloc/scratch_buffer.h
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloc/scratch_buffer_dupfree.c 
b/lib/malloc/scratch_buffer_dupfree.c
index 775bff5609..07363b9bc8 100644
--- a/lib/malloc/scratch_buffer_dupfree.c
+++ b/lib/malloc/scratch_buffer_dupfree.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloc/scratch_buffer_grow.c b/lib/malloc/scratch_buffer_grow.c
index e7606d81cd..22c8c7781e 100644
--- a/lib/malloc/scratch_buffer_grow.c
+++ b/lib/malloc/scratch_buffer_grow.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloc/scratch_buffer_grow_preserve.c 
b/lib/malloc/scratch_buffer_grow_preserve.c
index 59f8c71000..2b2b819289 100644
--- a/lib/malloc/scratch_buffer_grow_preserve.c
+++ b/lib/malloc/scratch_buffer_grow_preserve.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloc/scratch_buffer_set_array_size.c 
b/lib/malloc/scratch_buffer_set_array_size.c
index e2b9f31211..a47f9276a8 100644
--- a/lib/malloc/scratch_buffer_set_array_size.c
+++ b/lib/malloc/scratch_buffer_set_array_size.c
@@ -3,16 +3,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/malloca.c b/lib/malloca.c
deleted file mode 100644
index d68d233dcb..0000000000
--- a/lib/malloca.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/* Safe automatic memory allocation.
-   Copyright (C) 2003, 2006-2007, 2009-2021 Free Software Foundation,
-   Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2003, 2018.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
-
-#define _GL_USE_STDLIB_ALLOC 1
-#include <config.h>
-
-/* Specification.  */
-#include "malloca.h"
-
-#include "verify.h"
-
-/* The speed critical point in this file is freea() applied to an alloca()
-   result: it must be fast, to match the speed of alloca().  The speed of
-   mmalloca() and freea() in the other case are not critical, because they
-   are only invoked for big memory sizes.
-   Here we use a bit in the address as an indicator, an idea by Ondřej Bílka.
-   malloca() can return three types of pointers:
-     - Pointers ≡ 0 mod 2*sa_alignment_max come from stack allocation.
-     - Pointers ≡ sa_alignment_max mod 2*sa_alignment_max come from heap
-       allocation.
-     - NULL comes from a failed heap allocation.  */
-
-/* Type for holding very small pointer differences.  */
-typedef unsigned char small_t;
-/* Verify that it is wide enough.  */
-verify (2 * sa_alignment_max - 1 <= (small_t) -1);
-
-void *
-mmalloca (size_t n)
-{
-#if HAVE_ALLOCA
-  /* Allocate one more word, used to determine the address to pass to freea(),
-     and room for the alignment ≡ sa_alignment_max mod 2*sa_alignment_max.  */
-  size_t nplus = n + sizeof (small_t) + 2 * sa_alignment_max - 1;
-
-  if (nplus >= n)
-    {
-      char *mem = (char *) malloc (nplus);
-
-      if (mem != NULL)
-        {
-          char *p =
-            (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 
1)
-                      & ~(uintptr_t)(2 * sa_alignment_max - 1))
-                     + sa_alignment_max);
-          /* Here p >= mem + sizeof (small_t),
-             and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
-             hence p + n <= mem + nplus.
-             So, the memory range [p, p+n) lies in the allocated memory range
-             [mem, mem + nplus).  */
-          ((small_t *) p)[-1] = p - mem;
-          /* p ≡ sa_alignment_max mod 2*sa_alignment_max.  */
-          return p;
-        }
-    }
-  /* Out of memory.  */
-  return NULL;
-#else
-# if !MALLOC_0_IS_NONNULL
-  if (n == 0)
-    n = 1;
-# endif
-  return malloc (n);
-#endif
-}
-
-#if HAVE_ALLOCA
-void
-freea (void *p)
-{
-  /* Check argument.  */
-  if ((uintptr_t) p & (sa_alignment_max - 1))
-    {
-      /* p was not the result of a malloca() call.  Invalid argument.  */
-      abort ();
-    }
-  /* Determine whether p was a non-NULL pointer returned by mmalloca().  */
-  if ((uintptr_t) p & sa_alignment_max)
-    {
-      void *mem = (char *) p - ((small_t *) p)[-1];
-      free (mem);
-    }
-}
-#endif
-
-/*
- * Hey Emacs!
- * Local Variables:
- * coding: utf-8
- * End:
- */
diff --git a/lib/malloca.h b/lib/malloca.h
deleted file mode 100644
index a04e54593f..0000000000
--- a/lib/malloca.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Safe automatic memory allocation.
-   Copyright (C) 2003-2007, 2009-2021 Free Software Foundation, Inc.
-   Written by Bruno Haible <bruno@clisp.org>, 2003.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef _MALLOCA_H
-#define _MALLOCA_H
-
-#include <alloca.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "xalloc-oversized.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* safe_alloca(N) is equivalent to alloca(N) when it is safe to call
-   alloca(N); otherwise it returns NULL.  It either returns N bytes of
-   memory allocated on the stack, that lasts until the function returns,
-   or NULL.
-   Use of safe_alloca should be avoided:
-     - inside arguments of function calls - undefined behaviour,
-     - in inline functions - the allocation may actually last until the
-       calling function returns.
-*/
-#if HAVE_ALLOCA
-/* The OS usually guarantees only one guard page at the bottom of the stack,
-   and a page size can be as small as 4096 bytes.  So we cannot safely
-   allocate anything larger than 4096 bytes.  Also care for the possibility
-   of a few compiler-allocated temporary stack slots.
-   This must be a macro, not a function.  */
-# define safe_alloca(N) ((N) < 4032 ? alloca (N) : NULL)
-#else
-# define safe_alloca(N) ((void) (N), NULL)
-#endif
-
-/* malloca(N) is a safe variant of alloca(N).  It allocates N bytes of
-   memory allocated on the stack, that must be freed using freea() before
-   the function returns.  Upon failure, it returns NULL.  */
-#if HAVE_ALLOCA
-# define malloca(N) \
-  ((N) < 4032 - (2 * sa_alignment_max - 1)                                   \
-   ? (void *) (((uintptr_t) (char *) alloca ((N) + 2 * sa_alignment_max - 1) \
-                + (2 * sa_alignment_max - 1))                                \
-               & ~(uintptr_t)(2 * sa_alignment_max - 1))                     \
-   : mmalloca (N))
-#else
-# define malloca(N) \
-  mmalloca (N)
-#endif
-extern void * mmalloca (size_t n);
-
-/* Free a block of memory allocated through malloca().  */
-#if HAVE_ALLOCA
-extern void freea (void *p);
-#else
-# define freea free
-#endif
-
-/* nmalloca(N,S) is an overflow-safe variant of malloca (N * S).
-   It allocates an array of N objects, each with S bytes of memory,
-   on the stack.  S must be positive and N must be nonnegative.
-   The array must be freed using freea() before the function returns.  */
-#define nmalloca(n, s) (xalloc_oversized (n, s) ? NULL : malloca ((n) * (s)))
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-/* ------------------- Auxiliary, non-public definitions ------------------- */
-
-/* Determine the alignment of a type at compile time.  */
-#if defined __GNUC__ || defined __clang__ || defined __IBM__ALIGNOF__
-# define sa_alignof __alignof__
-#elif defined __cplusplus
-  template <class type> struct sa_alignof_helper { char __slot1; type __slot2; 
};
-# define sa_alignof(type) offsetof (sa_alignof_helper<type>, __slot2)
-#elif defined __hpux
-  /* Work around a HP-UX 10.20 cc bug with enums constants defined as offsetof
-     values.  */
-# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
-#elif defined _AIX
-  /* Work around an AIX 3.2.5 xlc bug with enums constants defined as offsetof
-     values.  */
-# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8)
-#else
-# define sa_alignof(type) offsetof (struct { char __slot1; type __slot2; }, 
__slot2)
-#endif
-
-enum
-{
-/* The desired alignment of memory allocations is the maximum alignment
-   among all elementary types.  */
-  sa_alignment_long = sa_alignof (long),
-  sa_alignment_double = sa_alignof (double),
-  sa_alignment_longlong = sa_alignof (long long),
-  sa_alignment_longdouble = sa_alignof (long double),
-  sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1)
-                      | (sa_alignment_longlong - 1)
-                      | (sa_alignment_longdouble - 1)
-                     ) + 1
-};
-
-#endif /* _MALLOCA_H */
diff --git a/lib/md5-stream.c b/lib/md5-stream.c
new file mode 100644
index 0000000000..fb483b7334
--- /dev/null
+++ b/lib/md5-stream.c
@@ -0,0 +1,141 @@
+/* Functions to compute MD5 message digest of files or memory blocks.
+   according to the definition of MD5 in RFC 1321 from April 1992.
+   Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2021 Free Software
+   Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+
+#include <config.h>
+
+/* Specification.  */
+#if HAVE_OPENSSL_MD5
+# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
+#endif
+#include "md5.h"
+
+#include <stdlib.h>
+
+#if USE_UNLOCKED_IO
+# include "unlocked-io.h"
+#endif
+
+#include "af_alg.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+   protected using leading __ .  */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_stream __md5_stream
+#endif
+
+#define BLOCKSIZE 32768
+#if BLOCKSIZE % 64 != 0
+# error "invalid BLOCKSIZE"
+#endif
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+md5_stream (FILE *stream, void *resblock)
+{
+  switch (afalg_stream (stream, "md5", resblock, MD5_DIGEST_SIZE))
+    {
+    case 0: return 0;
+    case -EIO: return 1;
+    }
+
+  char *buffer = malloc (BLOCKSIZE + 72);
+  if (!buffer)
+    return 1;
+
+  struct md5_ctx ctx;
+  md5_init_ctx (&ctx);
+  size_t sum;
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+         computation function processes the whole buffer so that with the
+         next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      while (1)
+        {
+          /* Either process a partial fread() from this loop,
+             or the fread() in afalg_stream may have gotten EOF.
+             We need to avoid a subsequent fread() as EOF may
+             not be sticky.  For details of such systems, see:
+             https://sourceware.org/bugzilla/show_bug.cgi?id=1190  */
+          if (feof (stream))
+            goto process_partial_block;
+
+          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+          sum += n;
+
+          if (sum == BLOCKSIZE)
+            break;
+
+          if (n == 0)
+            {
+              /* Check for the error flag IFF N == 0, so that we don't
+                 exit the loop after a partial read due to e.g., EAGAIN
+                 or EWOULDBLOCK.  */
+              if (ferror (stream))
+                {
+                  free (buffer);
+                  return 1;
+                }
+              goto process_partial_block;
+            }
+        }
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+         BLOCKSIZE % 64 == 0
+       */
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+process_partial_block:
+
+  /* Process any remaining bytes.  */
+  if (sum > 0)
+    md5_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx (&ctx, resblock);
+  free (buffer);
+  return 0;
+}
+
+/*
+ * Hey Emacs!
+ * Local Variables:
+ * coding: utf-8
+ * End:
+ */
diff --git a/lib/md5.c b/lib/md5.c
index e7eeeaab03..7955665ccd 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -4,23 +4,24 @@
    Foundation, Inc.
    This file is part of the GNU C Library.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3, or (at your option) any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
 
 #include <config.h>
 
+/* Specification.  */
 #if HAVE_OPENSSL_MD5
 # define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
 #endif
@@ -28,14 +29,9 @@
 
 #include <stdalign.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 
-#if USE_UNLOCKED_IO
-# include "unlocked-io.h"
-#endif
-
 #ifdef _LIBC
 # include <endian.h>
 # if __BYTE_ORDER == __BIG_ENDIAN
@@ -48,7 +44,6 @@
 # define md5_process_bytes __md5_process_bytes
 # define md5_finish_ctx __md5_finish_ctx
 # define md5_read_ctx __md5_read_ctx
-# define md5_stream __md5_stream
 # define md5_buffer __md5_buffer
 #endif
 
@@ -59,12 +54,8 @@
 # define SWAP(n) (n)
 #endif
 
-#define BLOCKSIZE 32768
-#if BLOCKSIZE % 64 != 0
-# error "invalid BLOCKSIZE"
-#endif
-
 #if ! HAVE_OPENSSL_MD5
+
 /* This array contains the bytes used to pad the buffer to the next
    64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
 static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
@@ -132,93 +123,7 @@ md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
 
   return md5_read_ctx (ctx, resbuf);
 }
-#endif
-
-#if defined _LIBC || defined GL_COMPILE_CRYPTO_STREAM
-
-#include "af_alg.h"
-
-/* Compute MD5 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 16 bytes
-   beginning at RESBLOCK.  */
-int
-md5_stream (FILE *stream, void *resblock)
-{
-  switch (afalg_stream (stream, "md5", resblock, MD5_DIGEST_SIZE))
-    {
-    case 0: return 0;
-    case -EIO: return 1;
-    }
-
-  char *buffer = malloc (BLOCKSIZE + 72);
-  if (!buffer)
-    return 1;
-
-  struct md5_ctx ctx;
-  md5_init_ctx (&ctx);
-  size_t sum;
-
-  /* Iterate over full file contents.  */
-  while (1)
-    {
-      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-         computation function processes the whole buffer so that with the
-         next round of the loop another block can be read.  */
-      size_t n;
-      sum = 0;
-
-      /* Read block.  Take care for partial reads.  */
-      while (1)
-        {
-          /* Either process a partial fread() from this loop,
-             or the fread() in afalg_stream may have gotten EOF.
-             We need to avoid a subsequent fread() as EOF may
-             not be sticky.  For details of such systems, see:
-             https://sourceware.org/bugzilla/show_bug.cgi?id=1190  */
-          if (feof (stream))
-            goto process_partial_block;
-
-          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-          sum += n;
-
-          if (sum == BLOCKSIZE)
-            break;
-
-          if (n == 0)
-            {
-              /* Check for the error flag IFF N == 0, so that we don't
-                 exit the loop after a partial read due to e.g., EAGAIN
-                 or EWOULDBLOCK.  */
-              if (ferror (stream))
-                {
-                  free (buffer);
-                  return 1;
-                }
-              goto process_partial_block;
-            }
-        }
-
-      /* Process buffer with BLOCKSIZE bytes.  Note that
-         BLOCKSIZE % 64 == 0
-       */
-      md5_process_block (buffer, BLOCKSIZE, &ctx);
-    }
-
-process_partial_block:
-
-  /* Process any remaining bytes.  */
-  if (sum > 0)
-    md5_process_bytes (buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  md5_finish_ctx (&ctx, resblock);
-  free (buffer);
-  return 0;
-}
-#endif
 
-#if ! HAVE_OPENSSL_MD5
 /* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
    result is always in little endian byte order, so that a byte-wise
    output yields to the wanted ASCII representation of the message
@@ -479,6 +384,7 @@ md5_process_block (const void *buffer, size_t len, struct 
md5_ctx *ctx)
   ctx->C = C;
   ctx->D = D;
 }
+
 #endif
 
 /*
diff --git a/lib/md5.h b/lib/md5.h
index aa4b0805d5..bae5960a8c 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -4,18 +4,18 @@
    Foundation, Inc.
    This file is part of the GNU C Library.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3, or (at your option) any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _MD5_H
 #define _MD5_H 1
@@ -124,6 +124,7 @@ extern void *__md5_buffer (const char *buffer, size_t len,
                            void *restrict resblock) __THROW;
 
 # endif
+
 /* Compute MD5 message digest for bytes read from STREAM.
    STREAM is an open file stream.  Regular files are handled more efficiently.
    The contents of STREAM from its current position to its end will be read.
diff --git a/lib/memmem.c b/lib/memmem.c
index 87266fa87a..142de576d9 100644
--- a/lib/memmem.c
+++ b/lib/memmem.c
@@ -2,18 +2,18 @@
    Foundation, Inc.
    This file is part of the GNU C Library.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* This particular implementation was written by Eric Blake, 2008.  */
 
diff --git a/lib/mempcpy.c b/lib/mempcpy.c
index fea618a9e5..cacacdbc62 100644
--- a/lib/mempcpy.c
+++ b/lib/mempcpy.c
@@ -1,24 +1,27 @@
 /* Copy memory area and return pointer after last written byte.
    Copyright (C) 2003, 2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
 /* Specification.  */
 #include <string.h>
 
+/* A function definition is only needed if HAVE_MEMPCPY is not defined.  */
+#if !HAVE_MEMPCPY
+
 /* Copy N bytes of SRC to DEST, return pointer to bytes after the
    last written byte.  */
 void *
@@ -26,3 +29,5 @@ mempcpy (void *dest, const void *src, size_t n)
 {
   return (char *) memcpy (dest, src, n) + n;
 }
+
+#endif
diff --git a/lib/memrchr.c b/lib/memrchr.c
index dcd24fafc6..e0d47d13d7 100644
--- a/lib/memrchr.c
+++ b/lib/memrchr.c
@@ -9,17 +9,17 @@
    adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
    and implemented by Roland McGrath (roland@ai.mit.edu).
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if defined _LIBC
diff --git a/lib/mini-gmp-gnulib.c b/lib/mini-gmp-gnulib.c
index d46c2b993b..08aa8f97c1 100644
--- a/lib/mini-gmp-gnulib.c
+++ b/lib/mini-gmp-gnulib.c
@@ -2,18 +2,26 @@
 
    Copyright 2018-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
+   This file is free software.
+   It is dual-licensed under "the GNU LGPLv3+ or the GNU GPLv2+".
+   You can redistribute it and/or modify it under either
+     - the terms of the GNU Lesser General Public License as published
+       by the Free Software Foundation; either version 3, or (at your
+       option) any later version, or
+     - the terms of the GNU General Public License as published by the
+       Free Software Foundation; either version 2, or (at your option)
+       any later version, or
+     - the same dual license "the GNU LGPLv3+ or the GNU GPLv2+".
+
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License and the GNU General Public License
+   for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public
+   License and of the GNU General Public License along with this
+   program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c
index de061e673a..8577b59ef6 100644
--- a/lib/mini-gmp.c
+++ b/lib/mini-gmp.c
@@ -2,21 +2,21 @@
 
    Contributed to the GNU project by Niels Möller
 
-Copyright 1991-1997, 1999-2020 Free Software Foundation, Inc.
+Copyright 1991-1997, 1999-2021 Free Software Foundation, Inc.
 
 This file is part of the GNU MP Library.
 
 The GNU MP Library is free software; you can redistribute it and/or modify
 it under the terms of either:
 
-  * the GNU General Public License as published by the Free
+  * the GNU Lesser General Public License as published by the Free
     Software Foundation; either version 3 of the License, or (at your
     option) any later version.
 
 or
 
   * the GNU General Public License as published by the Free Software
-    Foundation; either version 3 of the License, or (at your option) any
+    Foundation; either version 2 of the License, or (at your option) any
     later version.
 
 or both in parallel, as here.
@@ -27,7 +27,7 @@ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
Public License
 for more details.
 
 You should have received copies of the GNU General Public License and the
-GNU General Public License along with the GNU MP Library.  If not,
+GNU Lesser General Public License along with the GNU MP Library.  If not,
 see https://www.gnu.org/licenses/.  */
 
 /* NOTE: All functions in this file which are not declared in
@@ -148,6 +148,7 @@ see https://www.gnu.org/licenses/.  */
       mp_limb_t __x0, __x1, __x2, __x3;                                        
\
       unsigned __ul, __vl, __uh, __vh;                                 \
       mp_limb_t __u = (u), __v = (v);                                  \
+      assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));            \
                                                                        \
       __ul = __u & GMP_LLIMB_MASK;                                     \
       __uh = __u >> (GMP_LIMB_BITS / 2);                               \
@@ -783,6 +784,7 @@ mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
     mp_limb_t p, ql;
     unsigned ul, uh, qh;
 
+    assert (sizeof (unsigned) * 2 >= sizeof (mp_limb_t));
     /* For notation, let b denote the half-limb base, so that B = b^2.
        Split u1 = b uh + ul. */
     ul = u1 & GMP_LLIMB_MASK;
@@ -3198,6 +3200,7 @@ void
 mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
 {
   int sgn;
+  mp_bitcnt_t bc;
   mpz_t t, u;
 
   sgn = y->_mp_size < 0;
@@ -3216,7 +3219,8 @@ mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned 
long z)
 
   mpz_init (u);
   mpz_init (t);
-  mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
+  bc = (mpz_sizeinbase (y, 2) - 1) / z + 1;
+  mpz_setbit (t, bc);
 
   if (z == 2) /* simplify sqrt loop: z-1 == 1 */
     do {
@@ -3523,7 +3527,8 @@ gmp_stronglucas (const mpz_t x, mpz_t Qk)
   mpz_init (V);
 
   /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
-  b0 = mpz_scan0 (n, 0);
+  b0 = mpn_common_scan (~ n->_mp_d[0], 0, n->_mp_d, n->_mp_size, GMP_LIMB_MAX);
+  /* b0 = mpz_scan0 (n, 0); */
 
   /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
   Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
@@ -3555,11 +3560,6 @@ gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
       mpz_powm_ui (y, y, 2, n);
       if (mpz_cmp (y, nm1) == 0)
        return 1;
-      /* y == 1 means that the previous y was a non-trivial square root
-        of 1 (mod n). y == 0 means that n is a power of the base.
-        In either case, n is not prime. */
-      if (mpz_cmp_ui (y, 1) <= 0)
-       return 0;
     }
   return 0;
 }
diff --git a/lib/mini-gmp.h b/lib/mini-gmp.h
index 59a37e6494..59c24cf511 100644
--- a/lib/mini-gmp.h
+++ b/lib/mini-gmp.h
@@ -1,20 +1,20 @@
 /* mini-gmp, a minimalistic implementation of a GNU GMP subset.
 
-Copyright 2011-2015, 2017, 2019-2020 Free Software Foundation, Inc.
+Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc.
 
 This file is part of the GNU MP Library.
 
 The GNU MP Library is free software; you can redistribute it and/or modify
 it under the terms of either:
 
-  * the GNU General Public License as published by the Free
+  * the GNU Lesser General Public License as published by the Free
     Software Foundation; either version 3 of the License, or (at your
     option) any later version.
 
 or
 
   * the GNU General Public License as published by the Free Software
-    Foundation; either version 3 of the License, or (at your option) any
+    Foundation; either version 2 of the License, or (at your option) any
     later version.
 
 or both in parallel, as here.
@@ -25,7 +25,7 @@ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
Public License
 for more details.
 
 You should have received copies of the GNU General Public License and the
-GNU General Public License along with the GNU MP Library.  If not,
+GNU Lesser General Public License along with the GNU MP Library.  If not,
 see https://www.gnu.org/licenses/.  */
 
 /* About mini-gmp: This is a minimal implementation of a subset of the
@@ -296,6 +296,7 @@ int mpz_init_set_str (mpz_t, const char *, int);
   || defined (_STDIO_H_INCLUDED)      /* QNX4 */               \
   || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */            \
   || defined (__STDIO_LOADED)         /* VMS */                        \
+  || defined (_STDIO)                 /* HPE NonStop */         \
   || defined (__DEFINED_FILE)         /* musl */
 size_t mpz_out_str (FILE *, int, const mpz_t);
 #endif
diff --git a/lib/minmax.h b/lib/minmax.h
index eb9fb09a54..a03361bafa 100644
--- a/lib/minmax.h
+++ b/lib/minmax.h
@@ -2,18 +2,18 @@
    Copyright (C) 1995, 1998, 2001, 2003, 2005, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _MINMAX_H
 #define _MINMAX_H
diff --git a/lib/mkostemp.c b/lib/mkostemp.c
index 9d733ddd10..285f1badf8 100644
--- a/lib/mkostemp.c
+++ b/lib/mkostemp.c
@@ -2,17 +2,17 @@
    Foundation, Inc.
    This file is derived from the one in the GNU C Library.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if !_LIBC
diff --git a/lib/mktime-internal.h b/lib/mktime-internal.h
index 9c447bd7b0..7386625d3d 100644
--- a/lib/mktime-internal.h
+++ b/lib/mktime-internal.h
@@ -4,16 +4,16 @@
    Contributed by Paul Eggert <eggert@cs.ucla.edu>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/mktime.c b/lib/mktime.c
index 2c7cd7ba83..ae721c72e6 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -4,16 +4,16 @@
    Contributed by Paul Eggert <eggert@twinsun.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/nproc.c b/lib/nproc.c
new file mode 100644
index 0000000000..a9e369dd3f
--- /dev/null
+++ b/lib/nproc.c
@@ -0,0 +1,403 @@
+/* Detect the number of processors.
+
+   Copyright (C) 2009-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Glen Lenker and Bruno Haible.  */
+
+#include <config.h>
+#include "nproc.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if HAVE_PTHREAD_GETAFFINITY_NP && 0
+# include <pthread.h>
+# include <sched.h>
+#endif
+#if HAVE_SCHED_GETAFFINITY_LIKE_GLIBC || HAVE_SCHED_GETAFFINITY_NP
+# include <sched.h>
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_PSTAT_H
+# include <sys/pstat.h>
+#endif
+
+#if HAVE_SYS_SYSMP_H
+# include <sys/sysmp.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_SYS_SYSCTL_H && ! defined __GLIBC__
+# include <sys/sysctl.h>
+#endif
+
+#if defined _WIN32 && ! defined __CYGWIN__
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+#include "c-ctype.h"
+
+#include "minmax.h"
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Return the number of processors available to the current process, based
+   on a modern system call that returns the "affinity" between the current
+   process and each CPU.  Return 0 if unknown or if such a system call does
+   not exist.  */
+static unsigned long
+num_processors_via_affinity_mask (void)
+{
+  /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np,
+     but with different APIs.  Also it requires linking with -lpthread.
+     Therefore this code is not enabled.
+     glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has
+     sched_getaffinity_np.  */
+#if HAVE_PTHREAD_GETAFFINITY_NP && defined __GLIBC__ && 0
+  {
+    cpu_set_t set;
+
+    if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0)
+      {
+        unsigned long count;
+
+# ifdef CPU_COUNT
+        /* glibc >= 2.6 has the CPU_COUNT macro.  */
+        count = CPU_COUNT (&set);
+# else
+        size_t i;
+
+        count = 0;
+        for (i = 0; i < CPU_SETSIZE; i++)
+          if (CPU_ISSET (i, &set))
+            count++;
+# endif
+        if (count > 0)
+          return count;
+      }
+  }
+#elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0
+  {
+    cpuset_t *set;
+
+    set = cpuset_create ();
+    if (set != NULL)
+      {
+        unsigned long count = 0;
+
+        if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
+            == 0)
+          {
+            cpuid_t i;
+
+            for (i = 0;; i++)
+              {
+                int ret = cpuset_isset (i, set);
+                if (ret < 0)
+                  break;
+                if (ret > 0)
+                  count++;
+              }
+          }
+        cpuset_destroy (set);
+        if (count > 0)
+          return count;
+      }
+  }
+#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
+  {
+    cpu_set_t set;
+
+    if (sched_getaffinity (0, sizeof (set), &set) == 0)
+      {
+        unsigned long count;
+
+# ifdef CPU_COUNT
+        /* glibc >= 2.6 has the CPU_COUNT macro.  */
+        count = CPU_COUNT (&set);
+# else
+        size_t i;
+
+        count = 0;
+        for (i = 0; i < CPU_SETSIZE; i++)
+          if (CPU_ISSET (i, &set))
+            count++;
+# endif
+        if (count > 0)
+          return count;
+      }
+  }
+#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
+  {
+    cpuset_t *set;
+
+    set = cpuset_create ();
+    if (set != NULL)
+      {
+        unsigned long count = 0;
+
+        if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
+          {
+            cpuid_t i;
+
+            for (i = 0;; i++)
+              {
+                int ret = cpuset_isset (i, set);
+                if (ret < 0)
+                  break;
+                if (ret > 0)
+                  count++;
+              }
+          }
+        cpuset_destroy (set);
+        if (count > 0)
+          return count;
+      }
+  }
+#endif
+
+#if defined _WIN32 && ! defined __CYGWIN__
+  { /* This works on native Windows platforms.  */
+    DWORD_PTR process_mask;
+    DWORD_PTR system_mask;
+
+    if (GetProcessAffinityMask (GetCurrentProcess (),
+                                &process_mask, &system_mask))
+      {
+        DWORD_PTR mask = process_mask;
+        unsigned long count = 0;
+
+        for (; mask != 0; mask = mask >> 1)
+          if (mask & 1)
+            count++;
+        if (count > 0)
+          return count;
+      }
+  }
+#endif
+
+  return 0;
+}
+
+
+/* Return the total number of processors.  Here QUERY must be one of
+   NPROC_ALL, NPROC_CURRENT.  The result is guaranteed to be at least 1.  */
+static unsigned long int
+num_processors_ignoring_omp (enum nproc_query query)
+{
+  /* On systems with a modern affinity mask system call, we have
+         sysconf (_SC_NPROCESSORS_CONF)
+            >= sysconf (_SC_NPROCESSORS_ONLN)
+               >= num_processors_via_affinity_mask ()
+     The first number is the number of CPUs configured in the system.
+     The second number is the number of CPUs available to the scheduler.
+     The third number is the number of CPUs available to the current process.
+
+     Note! On Linux systems with glibc, the first and second number come from
+     the /sys and /proc file systems (see
+     glibc/sysdeps/unix/sysv/linux/getsysstats.c).
+     In some situations these file systems are not mounted, and the sysconf 
call
+     returns 1 or 2 (<https://sourceware.org/bugzilla/show_bug.cgi?id=21542>),
+     which does not reflect the reality.  */
+
+  if (query == NPROC_CURRENT)
+    {
+      /* Try the modern affinity mask system call.  */
+      {
+        unsigned long nprocs = num_processors_via_affinity_mask ();
+
+        if (nprocs > 0)
+          return nprocs;
+      }
+
+#if defined _SC_NPROCESSORS_ONLN
+      { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
+           Cygwin, Haiku.  */
+        long int nprocs = sysconf (_SC_NPROCESSORS_ONLN);
+        if (nprocs > 0)
+          return nprocs;
+      }
+#endif
+    }
+  else /* query == NPROC_ALL */
+    {
+#if defined _SC_NPROCESSORS_CONF
+      { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
+           Cygwin, Haiku.  */
+        long int nprocs = sysconf (_SC_NPROCESSORS_CONF);
+
+# if __GLIBC__ >= 2 && defined __linux__
+        /* On Linux systems with glibc, this information comes from the /sys 
and
+           /proc file systems (see 
glibc/sysdeps/unix/sysv/linux/getsysstats.c).
+           In some situations these file systems are not mounted, and the
+           sysconf call returns 1 or 2.  But we wish to guarantee that
+           num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT).  */
+        if (nprocs == 1 || nprocs == 2)
+          {
+            unsigned long nprocs_current = num_processors_via_affinity_mask ();
+
+            if (/* nprocs_current > 0 && */ nprocs_current > nprocs)
+              nprocs = nprocs_current;
+          }
+# endif
+
+        if (nprocs > 0)
+          return nprocs;
+      }
+#endif
+    }
+
+#if HAVE_PSTAT_GETDYNAMIC
+  { /* This works on HP-UX.  */
+    struct pst_dynamic psd;
+    if (pstat_getdynamic (&psd, sizeof psd, 1, 0) >= 0)
+      {
+        /* The field psd_proc_cnt contains the number of active processors.
+           In newer releases of HP-UX 11, the field psd_max_proc_cnt includes
+           deactivated processors.  */
+        if (query == NPROC_CURRENT)
+          {
+            if (psd.psd_proc_cnt > 0)
+              return psd.psd_proc_cnt;
+          }
+        else
+          {
+            if (psd.psd_max_proc_cnt > 0)
+              return psd.psd_max_proc_cnt;
+          }
+      }
+  }
+#endif
+
+#if HAVE_SYSMP && defined MP_NAPROCS && defined MP_NPROCS
+  { /* This works on IRIX.  */
+    /* MP_NPROCS yields the number of installed processors.
+       MP_NAPROCS yields the number of processors available to unprivileged
+       processes.  */
+    int nprocs =
+      sysmp (query == NPROC_CURRENT && getuid () != 0
+             ? MP_NAPROCS
+             : MP_NPROCS);
+    if (nprocs > 0)
+      return nprocs;
+  }
+#endif
+
+  /* Finally, as fallback, use the APIs that don't distinguish between
+     NPROC_CURRENT and NPROC_ALL.  */
+
+#if HAVE_SYSCTL && ! defined __GLIBC__ && defined HW_NCPU
+  { /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD.  */
+    int nprocs;
+    size_t len = sizeof (nprocs);
+    static int const mib[][2] = {
+# ifdef HW_NCPUONLINE
+      { CTL_HW, HW_NCPUONLINE },
+# endif
+      { CTL_HW, HW_NCPU }
+    };
+    for (int i = 0; i < ARRAY_SIZE (mib); i++)
+      {
+        if (sysctl (mib[i], ARRAY_SIZE (mib[i]), &nprocs, &len, NULL, 0) == 0
+            && len == sizeof (nprocs)
+            && 0 < nprocs)
+          return nprocs;
+      }
+  }
+#endif
+
+#if defined _WIN32 && ! defined __CYGWIN__
+  { /* This works on native Windows platforms.  */
+    SYSTEM_INFO system_info;
+    GetSystemInfo (&system_info);
+    if (0 < system_info.dwNumberOfProcessors)
+      return system_info.dwNumberOfProcessors;
+  }
+#endif
+
+  return 1;
+}
+
+/* Parse OMP environment variables without dependence on OMP.
+   Return 0 for invalid values.  */
+static unsigned long int
+parse_omp_threads (char const* threads)
+{
+  unsigned long int ret = 0;
+
+  if (threads == NULL)
+    return ret;
+
+  /* The OpenMP spec says that the value assigned to the environment variables
+     "may have leading and trailing white space".  */
+  while (*threads != '\0' && c_isspace (*threads))
+    threads++;
+
+  /* Convert it from positive decimal to 'unsigned long'.  */
+  if (c_isdigit (*threads))
+    {
+      char *endptr = NULL;
+      unsigned long int value = strtoul (threads, &endptr, 10);
+
+      if (endptr != NULL)
+        {
+          while (*endptr != '\0' && c_isspace (*endptr))
+            endptr++;
+          if (*endptr == '\0')
+            return value;
+          /* Also accept the first value in a nesting level,
+             since we can't determine the nesting level from env vars.  */
+          else if (*endptr == ',')
+            return value;
+        }
+    }
+
+  return ret;
+}
+
+unsigned long int
+num_processors (enum nproc_query query)
+{
+  unsigned long int omp_env_limit = ULONG_MAX;
+
+  if (query == NPROC_CURRENT_OVERRIDABLE)
+    {
+      unsigned long int omp_env_threads;
+      /* Honor the OpenMP environment variables, recognized also by all
+         programs that are based on OpenMP.  */
+      omp_env_threads = parse_omp_threads (getenv ("OMP_NUM_THREADS"));
+      omp_env_limit = parse_omp_threads (getenv ("OMP_THREAD_LIMIT"));
+      if (! omp_env_limit)
+        omp_env_limit = ULONG_MAX;
+
+      if (omp_env_threads)
+        return MIN (omp_env_threads, omp_env_limit);
+
+      query = NPROC_CURRENT;
+    }
+  /* Here query is one of NPROC_ALL, NPROC_CURRENT.  */
+  {
+    unsigned long nprocs = num_processors_ignoring_omp (query);
+    return MIN (nprocs, omp_env_limit);
+  }
+}
diff --git a/lib/nproc.h b/lib/nproc.h
new file mode 100644
index 0000000000..d7659a5cad
--- /dev/null
+++ b/lib/nproc.h
@@ -0,0 +1,46 @@
+/* Detect the number of processors.
+
+   Copyright (C) 2009-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Glen Lenker and Bruno Haible.  */
+
+/* Allow the use in C++ code.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* A "processor" in this context means a thread execution unit, that is either
+   - an execution core in a (possibly multi-core) chip, in a (possibly multi-
+     chip) module, in a single computer, or
+   - a thread execution unit inside a core
+     (hyper-threading, see <https://en.wikipedia.org/wiki/Hyper-threading>).
+   Which of the two definitions is used, is unspecified.  */
+
+enum nproc_query
+{
+  NPROC_ALL,                 /* total number of processors */
+  NPROC_CURRENT,             /* processors available to the current process */
+  NPROC_CURRENT_OVERRIDABLE  /* likewise, but overridable through the
+                                OMP_NUM_THREADS environment variable */
+};
+
+/* Return the total number of processors.  The result is guaranteed to
+   be at least 1.  */
+extern unsigned long int num_processors (enum nproc_query query);
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
diff --git a/lib/nstrftime.c b/lib/nstrftime.c
index 2f5e4fbe63..7f258e8727 100644
--- a/lib/nstrftime.c
+++ b/lib/nstrftime.c
@@ -1,19 +1,18 @@
 /* Copyright (C) 1991-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
-   License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   The GNU C Library is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifdef _LIBC
 # define USE_IN_EXTENDED_LOCALE_MODEL 1
diff --git a/lib/open.c b/lib/open.c
index 8599185331..372cda8816 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -1,17 +1,17 @@
 /* Open a descriptor to a file.
    Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
diff --git a/lib/pathmax.h b/lib/pathmax.h
index 49cf4629c7..716f4a9aae 100644
--- a/lib/pathmax.h
+++ b/lib/pathmax.h
@@ -2,18 +2,18 @@
    Copyright (C) 1992, 1999, 2001, 2003, 2005, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _PATHMAX_H
 # define _PATHMAX_H
diff --git a/lib/pipe2.c b/lib/pipe2.c
index adbaa4a102..9ba8c3b703 100644
--- a/lib/pipe2.c
+++ b/lib/pipe2.c
@@ -1,18 +1,18 @@
 /* Create a pipe, with specific opening flags.
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
@@ -41,7 +41,7 @@ pipe2 (int fd[2], int flags)
 {
   /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
      creating the pipe but later fail at changing fcntl, we want
-     to leave fd unchanged: https://austingroupbugs.net/view.php?id=467  */
+     to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
   int tmp[2];
   tmp[0] = fd[0];
   tmp[1] = fd[1];
diff --git a/lib/pselect.c b/lib/pselect.c
index 0fda4eef6e..b5fadc6728 100644
--- a/lib/pselect.c
+++ b/lib/pselect.c
@@ -4,18 +4,18 @@
 
    This file is part of gnulib.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* written by Paul Eggert */
 
diff --git a/lib/pthread_sigmask.c b/lib/pthread_sigmask.c
index 8a692048a0..11b7091e7f 100644
--- a/lib/pthread_sigmask.c
+++ b/lib/pthread_sigmask.c
@@ -1,17 +1,17 @@
 /* POSIX compatible signal blocking for threads.
    Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/rawmemchr.c b/lib/rawmemchr.c
index bbb250feb8..e7a00b8030 100644
--- a/lib/rawmemchr.c
+++ b/lib/rawmemchr.c
@@ -1,17 +1,17 @@
 /* Searching in a string.
    Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
@@ -19,68 +19,57 @@
 /* Specification.  */
 #include <string.h>
 
+/* A function definition is only needed if HAVE_RAWMEMCHR is not defined.  */
+#if !HAVE_RAWMEMCHR
+
+# include <limits.h>
+# include <stdalign.h>
+# include <stdint.h>
+
+# include "verify.h"
+
 /* Find the first occurrence of C in S.  */
 void *
 rawmemchr (const void *s, int c_in)
 {
-  /* On 32-bit hardware, choosing longword to be a 32-bit unsigned
-     long instead of a 64-bit uintmax_t tends to give better
-     performance.  On 64-bit hardware, unsigned long is generally 64
-     bits already.  Change this typedef to experiment with
-     performance.  */
-  typedef unsigned long int longword;
+  /* Change this typedef to experiment with performance.  */
+  typedef uintptr_t longword;
+  /* If you change the "uintptr_t", you should change UINTPTR_WIDTH to match.
+     This verifies that the type does not have padding bits.  */
+  verify (UINTPTR_WIDTH == UCHAR_WIDTH * sizeof (longword));
 
   const unsigned char *char_ptr;
-  const longword *longword_ptr;
-  longword repeated_one;
-  longword repeated_c;
-  unsigned char c;
-
-  c = (unsigned char) c_in;
+  unsigned char c = c_in;
 
   /* Handle the first few bytes by reading one byte at a time.
      Do this until CHAR_PTR is aligned on a longword boundary.  */
   for (char_ptr = (const unsigned char *) s;
-       (size_t) char_ptr % sizeof (longword) != 0;
+       (uintptr_t) char_ptr % alignof (longword) != 0;
        ++char_ptr)
     if (*char_ptr == c)
       return (void *) char_ptr;
 
-  longword_ptr = (const longword *) char_ptr;
-
-  /* All these elucidatory comments refer to 4-byte longwords,
-     but the theory applies equally well to any size longwords.  */
+  longword const *longword_ptr = s = char_ptr;
 
   /* Compute auxiliary longword values:
      repeated_one is a value which has a 1 in every byte.
      repeated_c has c in every byte.  */
-  repeated_one = 0x01010101;
-  repeated_c = c | (c << 8);
-  repeated_c |= repeated_c << 16;
-  if (0xffffffffU < (longword) -1)
-    {
-      repeated_one |= repeated_one << 31 << 1;
-      repeated_c |= repeated_c << 31 << 1;
-      if (8 < sizeof (longword))
-        {
-          size_t i;
-
-          for (i = 64; i < sizeof (longword) * 8; i *= 2)
-            {
-              repeated_one |= repeated_one << i;
-              repeated_c |= repeated_c << i;
-            }
-        }
-    }
+  longword repeated_one = (longword) -1 / UCHAR_MAX;
+  longword repeated_c = repeated_one * c;
+  longword repeated_hibit = repeated_one * (UCHAR_MAX / 2 + 1);
 
   /* Instead of the traditional loop which tests each byte, we will
-     test a longword at a time.  The tricky part is testing if *any of
-     the four* bytes in the longword in question are equal to NUL or
+     test a longword at a time.  The tricky part is testing if any of
+     the bytes in the longword in question are equal to
      c.  We first use an xor with repeated_c.  This reduces the task
-     to testing whether *any of the four* bytes in longword1 is zero.
+     to testing whether any of the bytes in longword1 is zero.
+
+     (The following comments assume 8-bit bytes, as POSIX requires;
+     the code's use of UCHAR_MAX should work even if bytes have more
+     than 8 bits.)
 
      We compute tmp =
-       ((longword1 - repeated_one) & ~longword1) & (repeated_one << 7).
+       ((longword1 - repeated_one) & ~longword1) & (repeated_one * 0x80).
      That is, we perform the following operations:
        1. Subtract repeated_one.
        2. & ~longword1.
@@ -114,23 +103,23 @@ rawmemchr (const void *s, int c_in)
     {
       longword longword1 = *longword_ptr ^ repeated_c;
 
-      if ((((longword1 - repeated_one) & ~longword1)
-           & (repeated_one << 7)) != 0)
+      if ((((longword1 - repeated_one) & ~longword1) & repeated_hibit) != 0)
         break;
       longword_ptr++;
     }
 
-  char_ptr = (const unsigned char *) longword_ptr;
+  char_ptr = s = longword_ptr;
 
   /* At this point, we know that one of the sizeof (longword) bytes
-     starting at char_ptr is == c.  On little-endian machines, we
+     starting at char_ptr is == c.  If we knew endianness, we
      could determine the first such byte without any further memory
      accesses, just by looking at the tmp result from the last loop
-     iteration.  But this does not work on big-endian machines.
-     Choose code that works in both cases.  */
+     iteration.  However, the following simple and portable code does
+     not attempt this potential optimization.  */
 
-  char_ptr = (unsigned char *) longword_ptr;
   while (*char_ptr != c)
     char_ptr++;
   return (void *) char_ptr;
 }
+
+#endif
diff --git a/lib/rawmemchr.valgrind b/lib/rawmemchr.valgrind
index 087d5e4178..d489c320c3 100644
--- a/lib/rawmemchr.valgrind
+++ b/lib/rawmemchr.valgrind
@@ -2,17 +2,17 @@
 
 # Copyright (C) 2008-2021 Free Software Foundation, Inc.
 #
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
+# This file is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2.1 of the
+# License, or (at your option) any later version.
 #
-# This program is distributed in the hope that it will be useful,
+# This file is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# GNU Lesser General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Lesser General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 # This use is OK because it provides only a speedup.
diff --git a/lib/readlink.c b/lib/readlink.c
index c4b635ce71..ad4d51dc64 100644
--- a/lib/readlink.c
+++ b/lib/readlink.c
@@ -1,17 +1,17 @@
 /* Read the contents of a symbolic link.
    Copyright (C) 2003-2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
@@ -29,8 +29,8 @@
    such as DJGPP 2.03 and mingw32.  */
 
 ssize_t
-readlink (char const *file, char *buf _GL_UNUSED,
-          size_t bufsize _GL_UNUSED)
+readlink (char const *file, _GL_UNUSED char *buf,
+          _GL_UNUSED size_t bufsize)
 {
   struct stat statbuf;
 
diff --git a/lib/realloc.c b/lib/realloc.c
new file mode 100644
index 0000000000..af03f0c577
--- /dev/null
+++ b/lib/realloc.c
@@ -0,0 +1,63 @@
+/* realloc() function that is glibc compatible.
+
+   Copyright (C) 1997, 2003-2004, 2006-2007, 2009-2021 Free Software
+   Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* written by Jim Meyering and Bruno Haible */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <errno.h>
+
+#include "xalloc-oversized.h"
+
+/* Call the system's realloc below.  This file does not define
+   _GL_USE_STDLIB_ALLOC because it needs Gnulib's malloc if present.  */
+#undef realloc
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.  If P is NULL, use malloc.  Otherwise if N is zero,
+   free P and return NULL.  */
+
+void *
+rpl_realloc (void *p, size_t n)
+{
+  if (p == NULL)
+    return malloc (n);
+
+  if (n == 0)
+    {
+      free (p);
+      return NULL;
+    }
+
+  if (xalloc_oversized (n, 1))
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+
+  void *result = realloc (p, n);
+
+#if !HAVE_MALLOC_POSIX
+  if (result == NULL)
+    errno = ENOMEM;
+#endif
+
+  return result;
+}
diff --git a/lib/regcomp.c b/lib/regcomp.c
index 0c31b0e14c..887e5b5068 100644
--- a/lib/regcomp.c
+++ b/lib/regcomp.c
@@ -4,16 +4,16 @@
    Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -1695,12 +1695,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t 
*dfa, Idx node, bool root)
   reg_errcode_t err;
   Idx i;
   re_node_set eclosure;
-  bool ok;
   bool incomplete = false;
   err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
   if (__glibc_unlikely (err != REG_NOERROR))
     return err;
 
+  /* An epsilon closure includes itself.  */
+  eclosure.elems[eclosure.nelem++] = node;
+
   /* This indicates that we are calculating this node now.
      We reference this value to avoid infinite loop.  */
   dfa->eclosures[node].nelem = -1;
@@ -1753,10 +1755,6 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, 
Idx node, bool root)
          }
       }
 
-  /* An epsilon closure includes itself.  */
-  ok = re_node_set_insert (&eclosure, node);
-  if (__glibc_unlikely (! ok))
-    return REG_ESPACE;
   if (incomplete && !root)
     dfa->eclosures[node].nelem = 0;
   else
diff --git a/lib/regex.c b/lib/regex.c
index f76a416b3b..d32863972c 100644
--- a/lib/regex.c
+++ b/lib/regex.c
@@ -4,16 +4,16 @@
    Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -24,6 +24,7 @@
 
 # if __GNUC_PREREQ (4, 6)
 #  pragma GCC diagnostic ignored "-Wsuggest-attribute=pure"
+#  pragma GCC diagnostic ignored "-Wvla"
 # endif
 # if __GNUC_PREREQ (4, 3)
 #  pragma GCC diagnostic ignored "-Wold-style-definition"
diff --git a/lib/regex.h b/lib/regex.h
index d291e38793..adb69768ee 100644
--- a/lib/regex.h
+++ b/lib/regex.h
@@ -4,16 +4,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -522,6 +522,30 @@ typedef struct
 
 /* Declarations for routines.  */
 
+#ifndef _REGEX_NELTS
+# if (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__ \
+       && !defined __STDC_NO_VLA__)
+#  define _REGEX_NELTS(n) n
+# else
+#  define _REGEX_NELTS(n)
+# endif
+#endif
+
+#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wvla"
+#endif
+
+#ifndef _Attr_access_
+# ifdef __attr_access
+#  define _Attr_access_(arg) __attr_access (arg)
+# elif defined __GNUC__ && 10 <= __GNUC__
+#  define _Attr_access_(x) __attribute__ ((__access__ x))
+# else
+#  define _Attr_access_(x)
+# endif
+#endif
+
 #ifdef __USE_GNU
 /* Sets the current default syntax to SYNTAX, and return the old syntax.
    You can also simply assign to the 're_syntax_options' variable.  */
@@ -536,7 +560,8 @@ extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
    'regcomp', with a malloc'ed value, or set to NULL before calling
    'regfree'.  */
 extern const char *re_compile_pattern (const char *__pattern, size_t __length,
-                                      struct re_pattern_buffer *__buffer);
+                                      struct re_pattern_buffer *__buffer)
+    _Attr_access_ ((__read_only__, 1, 2));
 
 
 /* Compile a fastmap for the compiled pattern in BUFFER; used to
@@ -553,7 +578,8 @@ extern int re_compile_fastmap (struct re_pattern_buffer 
*__buffer);
 extern regoff_t re_search (struct re_pattern_buffer *__buffer,
                           const char *__String, regoff_t __length,
                           regoff_t __start, regoff_t __range,
-                          struct re_registers *__regs);
+                          struct re_registers *__regs)
+    _Attr_access_ ((__read_only__, 2, 3));
 
 
 /* Like 're_search', but search in the concatenation of STRING1 and
@@ -563,14 +589,17 @@ extern regoff_t re_search_2 (struct re_pattern_buffer 
*__buffer,
                             const char *__string2, regoff_t __length2,
                             regoff_t __start, regoff_t __range,
                             struct re_registers *__regs,
-                            regoff_t __stop);
+                            regoff_t __stop)
+    _Attr_access_ ((__read_only__, 2, 3))
+    _Attr_access_ ((__read_only__, 4, 5));
 
 
 /* Like 're_search', but return how many characters in STRING the regexp
    in BUFFER matched, starting at position START.  */
 extern regoff_t re_match (struct re_pattern_buffer *__buffer,
                          const char *__String, regoff_t __length,
-                         regoff_t __start, struct re_registers *__regs);
+                         regoff_t __start, struct re_registers *__regs)
+    _Attr_access_ ((__read_only__, 2, 3));
 
 
 /* Relates to 're_match' as 're_search_2' relates to 're_search'.  */
@@ -578,7 +607,9 @@ extern regoff_t re_match_2 (struct re_pattern_buffer 
*__buffer,
                            const char *__string1, regoff_t __length1,
                            const char *__string2, regoff_t __length2,
                            regoff_t __start, struct re_registers *__regs,
-                           regoff_t __stop);
+                           regoff_t __stop)
+    _Attr_access_ ((__read_only__, 2, 3))
+    _Attr_access_ ((__read_only__, 4, 5));
 
 
 /* Set REGS to hold NUM_REGS registers, storing them in STARTS and
@@ -647,14 +678,19 @@ extern int regcomp (regex_t *_Restrict_ __preg,
 
 extern int regexec (const regex_t *_Restrict_ __preg,
                    const char *_Restrict_ __String, size_t __nmatch,
-                   regmatch_t __pmatch[_Restrict_arr_],
+                   regmatch_t __pmatch[_Restrict_arr_
+                                       _REGEX_NELTS (__nmatch)],
                    int __eflags);
 
 extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg,
-                       char *_Restrict_ __errbuf, size_t __errbuf_size);
+                       char *_Restrict_ __errbuf, size_t __errbuf_size)
+    _Attr_access_ ((__write_only__, 3, 4));
 
 extern void regfree (regex_t *__preg);
 
+#if defined __GNUC__ && 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
+# pragma GCC diagnostic pop
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/lib/regex_internal.c b/lib/regex_internal.c
index 73087c8610..aefcfa2f52 100644
--- a/lib/regex_internal.c
+++ b/lib/regex_internal.c
@@ -4,16 +4,16 @@
    Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -1211,6 +1211,10 @@ re_node_set_merge (re_node_set *dest, const re_node_set 
*src)
 
   if (__glibc_unlikely (dest->nelem == 0))
     {
+      /* Although we already guaranteed above that dest->alloc != 0 and
+         therefore dest->elems != NULL, add a debug assertion to pacify
+         GCC 11.2.1's -fanalyzer.  */
+      DEBUG_ASSERT (dest->elems);
       dest->nelem = src->nelem;
       memcpy (dest->elems, src->elems, src->nelem * sizeof (Idx));
       return REG_NOERROR;
@@ -1286,7 +1290,10 @@ re_node_set_insert (re_node_set *set, Idx elem)
 
   if (__glibc_unlikely (set->nelem) == 0)
     {
-      /* We already guaranteed above that set->alloc != 0.  */
+      /* Although we already guaranteed above that set->alloc != 0 and
+         therefore set->elems != NULL, add a debug assertion to pacify
+         GCC 11.2 -fanalyzer.  */
+      DEBUG_ASSERT (set->elems);
       set->elems[0] = elem;
       ++set->nelem;
       return true;
@@ -1314,6 +1321,7 @@ re_node_set_insert (re_node_set *set, Idx elem)
     {
       for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
        set->elems[idx] = set->elems[idx - 1];
+      DEBUG_ASSERT (set->elems[idx - 1] < elem);
     }
 
   /* Insert the new element.  */
diff --git a/lib/regex_internal.h b/lib/regex_internal.h
index 4c634edcbf..1245e782ff 100644
--- a/lib/regex_internal.h
+++ b/lib/regex_internal.h
@@ -4,16 +4,16 @@
    Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -32,7 +32,10 @@
 #include <stdbool.h>
 #include <stdint.h>
 
-#include <dynarray.h>
+#ifndef _LIBC
+# include <dynarray.h>
+#endif
+
 #include <intprops.h>
 #include <verify.h>
 
@@ -50,14 +53,14 @@
 # define lock_fini(lock) ((void) 0)
 # define lock_lock(lock) __libc_lock_lock (lock)
 # define lock_unlock(lock) __libc_lock_unlock (lock)
-#elif defined GNULIB_LOCK && !defined USE_UNLOCKED_IO
+#elif defined GNULIB_LOCK && !defined GNULIB_REGEX_SINGLE_THREAD
 # include "glthread/lock.h"
 # define lock_define(name) gl_lock_define (, name)
 # define lock_init(lock) glthread_lock_init (&(lock))
 # define lock_fini(lock) glthread_lock_destroy (&(lock))
 # define lock_lock(lock) glthread_lock_lock (&(lock))
 # define lock_unlock(lock) glthread_lock_unlock (&(lock))
-#elif defined GNULIB_PTHREAD && !defined USE_UNLOCKED_IO
+#elif defined GNULIB_PTHREAD && !defined GNULIB_REGEX_SINGLE_THREAD
 # include <pthread.h>
 # define lock_define(name) pthread_mutex_t name;
 # define lock_init(lock) pthread_mutex_init (&(lock), 0)
diff --git a/lib/regexec.c b/lib/regexec.c
index 15dc57bd0e..83e9aaf8ca 100644
--- a/lib/regexec.c
+++ b/lib/regexec.c
@@ -4,16 +4,16 @@
    Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -59,7 +59,7 @@ static void update_regs (const re_dfa_t *dfa, regmatch_t 
*pmatch,
                         Idx cur_idx, Idx nmatch);
 static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
                                      Idx str_idx, Idx dest_node, Idx nregs,
-                                     regmatch_t *regs,
+                                     regmatch_t *regs, regmatch_t *prevregs,
                                      re_node_set *eps_via_nodes);
 static reg_errcode_t set_regs (const regex_t *preg,
                               const re_match_context_t *mctx,
@@ -186,11 +186,12 @@ static reg_errcode_t extend_buffers (re_match_context_t 
*mctx, int min_len);
    REG_NOTBOL is set, then ^ does not match at the beginning of the
    string; if REG_NOTEOL is set, then $ does not match at the end.
 
-   We return 0 if we find a match and REG_NOMATCH if not.  */
+   Return 0 if a match is found, REG_NOMATCH if not, REG_BADPAT if
+   EFLAGS is invalid.  */
 
 int
 regexec (const regex_t *__restrict preg, const char *__restrict string,
-        size_t nmatch, regmatch_t pmatch[], int eflags)
+        size_t nmatch, regmatch_t pmatch[_REGEX_NELTS (nmatch)], int eflags)
 {
   reg_errcode_t err;
   Idx start, length;
@@ -234,7 +235,7 @@ int
 attribute_compat_text_section
 __compat_regexec (const regex_t *__restrict preg,
                  const char *__restrict string, size_t nmatch,
-                 regmatch_t pmatch[], int eflags)
+                 regmatch_t pmatch[_REGEX_NELTS (nmatch)], int eflags)
 {
   return regexec (preg, string, nmatch, pmatch,
                  eflags & (REG_NOTBOL | REG_NOTEOL));
@@ -269,8 +270,8 @@ compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
    strings.)
 
    On success, re_match* functions return the length of the match, re_search*
-   return the position of the start of the match.  Return value -1 means no
-   match was found and -2 indicates an internal error.  */
+   return the position of the start of the match.  They return -1 on
+   match failure, -2 on error.  */
 
 regoff_t
 re_match (struct re_pattern_buffer *bufp, const char *string, Idx length,
@@ -1206,27 +1207,30 @@ check_halt_state_context (const re_match_context_t 
*mctx,
 /* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
    corresponding to the DFA).
    Return the destination node, and update EPS_VIA_NODES;
-   return -1 in case of errors.  */
+   return -1 on match failure, -2 on error.  */
 
 static Idx
 proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
+                  regmatch_t *prevregs,
                   Idx *pidx, Idx node, re_node_set *eps_via_nodes,
                   struct re_fail_stack_t *fs)
 {
   const re_dfa_t *const dfa = mctx->dfa;
-  Idx i;
-  bool ok;
   if (IS_EPSILON_NODE (dfa->nodes[node].type))
     {
       re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
       re_node_set *edests = &dfa->edests[node];
-      Idx dest_node;
-      ok = re_node_set_insert (eps_via_nodes, node);
-      if (__glibc_unlikely (! ok))
-       return -2;
-      /* Pick up a valid destination, or return -1 if none
-        is found.  */
-      for (dest_node = -1, i = 0; i < edests->nelem; ++i)
+
+      if (! re_node_set_contains (eps_via_nodes, node))
+        {
+          bool ok = re_node_set_insert (eps_via_nodes, node);
+          if (__glibc_unlikely (! ok))
+            return -2;
+        }
+
+      /* Pick a valid destination, or return -1 if none is found.  */
+      Idx dest_node = -1;
+      for (Idx i = 0; i < edests->nelem; i++)
        {
          Idx candidate = edests->elems[i];
          if (!re_node_set_contains (cur_nodes, candidate))
@@ -1244,7 +1248,7 @@ proceed_next_node (const re_match_context_t *mctx, Idx 
nregs, regmatch_t *regs,
              /* Otherwise, push the second epsilon-transition on the fail 
stack.  */
              else if (fs != NULL
                       && push_fail_stack (fs, *pidx, candidate, nregs, regs,
-                                          eps_via_nodes))
+                                          prevregs, eps_via_nodes))
                return -2;
 
              /* We know we are going to exit.  */
@@ -1288,7 +1292,7 @@ proceed_next_node (const re_match_context_t *mctx, Idx 
nregs, regmatch_t *regs,
          if (naccepted == 0)
            {
              Idx dest_node;
-             ok = re_node_set_insert (eps_via_nodes, node);
+             bool ok = re_node_set_insert (eps_via_nodes, node);
              if (__glibc_unlikely (! ok))
                return -2;
              dest_node = dfa->edests[node].elems[0];
@@ -1317,7 +1321,8 @@ proceed_next_node (const re_match_context_t *mctx, Idx 
nregs, regmatch_t *regs,
 static reg_errcode_t
 __attribute_warn_unused_result__
 push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node,
-                Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+                Idx nregs, regmatch_t *regs, regmatch_t *prevregs,
+                re_node_set *eps_via_nodes)
 {
   reg_errcode_t err;
   Idx num = fs->num++;
@@ -1333,25 +1338,30 @@ push_fail_stack (struct re_fail_stack_t *fs, Idx 
str_idx, Idx dest_node,
     }
   fs->stack[num].idx = str_idx;
   fs->stack[num].node = dest_node;
-  fs->stack[num].regs = re_malloc (regmatch_t, nregs);
+  fs->stack[num].regs = re_malloc (regmatch_t, 2 * nregs);
   if (fs->stack[num].regs == NULL)
     return REG_ESPACE;
   memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+  memcpy (fs->stack[num].regs + nregs, prevregs, sizeof (regmatch_t) * nregs);
   err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
   return err;
 }
 
 static Idx
 pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs,
-               regmatch_t *regs, re_node_set *eps_via_nodes)
+               regmatch_t *regs, regmatch_t *prevregs,
+               re_node_set *eps_via_nodes)
 {
+  if (fs == NULL || fs->num == 0)
+    return -1;
   Idx num = --fs->num;
-  DEBUG_ASSERT (num >= 0);
   *pidx = fs->stack[num].idx;
   memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+  memcpy (prevregs, fs->stack[num].regs + nregs, sizeof (regmatch_t) * nregs);
   re_node_set_free (eps_via_nodes);
   re_free (fs->stack[num].regs);
   *eps_via_nodes = fs->stack[num].eps_via_nodes;
+  DEBUG_ASSERT (0 <= fs->stack[num].node);
   return fs->stack[num].node;
 }
 
@@ -1407,33 +1417,32 @@ set_regs (const regex_t *preg, const re_match_context_t 
*mctx, size_t nmatch,
     {
       update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
 
-      if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+      if ((idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+         || (fs && re_node_set_contains (&eps_via_nodes, cur_node)))
        {
          Idx reg_idx;
+         cur_node = -1;
          if (fs)
            {
              for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
                if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
-                 break;
-             if (reg_idx == nmatch)
-               {
-                 re_node_set_free (&eps_via_nodes);
-                 regmatch_list_free (&prev_match);
-                 return free_fail_stack_return (fs);
-               }
-             cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
-                                        &eps_via_nodes);
+                 {
+                   cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+                                              prev_idx_match, &eps_via_nodes);
+                   break;
+                 }
            }
-         else
+         if (cur_node < 0)
            {
              re_node_set_free (&eps_via_nodes);
              regmatch_list_free (&prev_match);
-             return REG_NOERROR;
+             return free_fail_stack_return (fs);
            }
        }
 
       /* Proceed to next node.  */
-      cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+      cur_node = proceed_next_node (mctx, nmatch, pmatch, prev_idx_match,
+                                   &idx, cur_node,
                                    &eps_via_nodes, fs);
 
       if (__glibc_unlikely (cur_node < 0))
@@ -1445,13 +1454,13 @@ set_regs (const regex_t *preg, const re_match_context_t 
*mctx, size_t nmatch,
              free_fail_stack_return (fs);
              return REG_ESPACE;
            }
-         if (fs)
-           cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
-                                      &eps_via_nodes);
-         else
+         cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+                                    prev_idx_match, &eps_via_nodes);
+         if (cur_node < 0)
            {
              re_node_set_free (&eps_via_nodes);
              regmatch_list_free (&prev_match);
+             free_fail_stack_return (fs);
              return REG_NOMATCH;
            }
        }
@@ -1495,10 +1504,10 @@ update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
     }
   else if (type == OP_CLOSE_SUBEXP)
     {
+      /* We are at the last node of this sub expression.  */
       Idx reg_num = dfa->nodes[cur_node].opr.idx + 1;
       if (reg_num < nmatch)
        {
-         /* We are at the last node of this sub expression.  */
          if (pmatch[reg_num].rm_so < cur_idx)
            {
              pmatch[reg_num].rm_eo = cur_idx;
@@ -2195,6 +2204,7 @@ sift_states_iter_mb (const re_match_context_t *mctx, 
re_sift_context_t *sctx,
 
 /* Return the next state to which the current state STATE will transit by
    accepting the current input byte, and update STATE_LOG if necessary.
+   Return NULL on failure.
    If STATE can accept a multibyte char/collating element/back reference
    update the destination of STATE_LOG.  */
 
@@ -2395,7 +2405,7 @@ check_subexp_matching_top (re_match_context_t *mctx, 
re_node_set *cur_nodes,
 
 #if 0
 /* Return the next state to which the current state STATE will transit by
-   accepting the current input byte.  */
+   accepting the current input byte.  Return NULL on failure.  */
 
 static re_dfastate_t *
 transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
@@ -2817,7 +2827,8 @@ find_subexp_node (const re_dfa_t *dfa, const re_node_set 
*nodes,
 /* Check whether the node TOP_NODE at TOP_STR can arrive to the node
    LAST_NODE at LAST_STR.  We record the path onto PATH since it will be
    heavily reused.
-   Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise.  */
+   Return REG_NOERROR if it can arrive, REG_NOMATCH if it cannot,
+   REG_ESPACE if memory is exhausted.  */
 
 static reg_errcode_t
 __attribute_warn_unused_result__
@@ -3433,7 +3444,8 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
 /* Group all nodes belonging to STATE into several destinations.
    Then for all destinations, set the nodes belonging to the destination
    to DESTS_NODE[i] and set the characters accepted by the destination
-   to DEST_CH[i].  This function return the number of destinations.  */
+   to DEST_CH[i].  Return the number of destinations if successful,
+   -1 on internal error.  */
 
 static Idx
 group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
@@ -4211,7 +4223,8 @@ match_ctx_add_subtop (re_match_context_t *mctx, Idx node, 
Idx str_idx)
 }
 
 /* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
-   at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP.  */
+   at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP.
+   Return the new entry if successful, NULL if memory is exhausted.  */
 
 static re_sub_match_last_t *
 match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx)
diff --git a/lib/root-uid.h b/lib/root-uid.h
index cb74a49c1b..b367d5ab69 100644
--- a/lib/root-uid.h
+++ b/lib/root-uid.h
@@ -2,20 +2,20 @@
 
    Copyright 2012-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <https://www.gnu.org/licenses/>.
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
-   Written by Paul Eggert.  */
+/* Written by Paul Eggert.  */
 
 #ifndef ROOT_UID_H_
 #define ROOT_UID_H_
diff --git a/lib/save-cwd.h b/lib/save-cwd.h
index e1e69eceaf..3cefba58c0 100644
--- a/lib/save-cwd.h
+++ b/lib/save-cwd.h
@@ -1,7 +1,7 @@
 /* Save and restore current working directory.
 
-   Copyright (C) 1995, 1997-1998, 2003, 2009-2021 Free Software
-   Foundation, Inc.
+   Copyright (C) 1995, 1997-1998, 2003, 2009-2021 Free Software Foundation,
+   Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
diff --git a/lib/scratch_buffer.h b/lib/scratch_buffer.h
index 603b0d65d0..88735771d2 100644
--- a/lib/scratch_buffer.h
+++ b/lib/scratch_buffer.h
@@ -1,17 +1,17 @@
 /* Variable-sized buffer with on-stack default allocation.
    Copyright (C) 2017-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert, 2017.  */
@@ -19,12 +19,109 @@
 #ifndef _GL_SCRATCH_BUFFER_H
 #define _GL_SCRATCH_BUFFER_H
 
-#include <libc-config.h>
+/* Scratch buffers with a default stack allocation and fallback to
+   heap allocation.  It is expected that this function is used in this
+   way:
 
+     struct scratch_buffer tmpbuf;
+     scratch_buffer_init (&tmpbuf);
+
+     while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
+       if (!scratch_buffer_grow (&tmpbuf))
+         return -1;
+
+     scratch_buffer_free (&tmpbuf);
+     return 0;
+
+   The allocation functions (scratch_buffer_grow,
+   scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make
+   sure that the heap allocation, if any, is freed, so that the code
+   above does not have a memory leak.  The buffer still remains in a
+   state that can be deallocated using scratch_buffer_free, so a loop
+   like this is valid as well:
+
+     struct scratch_buffer tmpbuf;
+     scratch_buffer_init (&tmpbuf);
+
+     while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
+       if (!scratch_buffer_grow (&tmpbuf))
+         break;
+
+     scratch_buffer_free (&tmpbuf);
+
+   scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed
+   to grow the buffer by at least 512 bytes.  This means that when
+   using the scratch buffer as a backing store for a non-character
+   array whose element size, in bytes, is 512 or smaller, the scratch
+   buffer only has to grow once to make room for at least one more
+   element.
+*/
+
+/* Scratch buffer.  Must be initialized with scratch_buffer_init
+   before its use.  */
+struct scratch_buffer;
+
+/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
+   and BUFFER->length reflects the available space.  */
+#if 0
+extern void scratch_buffer_init (struct scratch_buffer *buffer);
+#endif
+
+/* Deallocates *BUFFER (if it was heap-allocated).  */
+#if 0
+extern void scratch_buffer_free (struct scratch_buffer *buffer);
+#endif
+
+/* Grow *BUFFER by some arbitrary amount.  The buffer contents is NOT
+   preserved.  Return true on success, false on allocation failure (in
+   which case the old buffer is freed).  On success, the new buffer is
+   larger than the previous size.  On failure, *BUFFER is deallocated,
+   but remains in a free-able state, and errno is set.  */
+#if 0
+extern bool scratch_buffer_grow (struct scratch_buffer *buffer);
+#endif
+
+/* Like scratch_buffer_grow, but preserve the old buffer
+   contents on success, as a prefix of the new buffer.  */
+#if 0
+extern bool scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
+#endif
+
+/* Grow *BUFFER so that it can store at least NELEM elements of SIZE
+   bytes.  The buffer contents are NOT preserved.  Both NELEM and SIZE
+   can be zero.  Return true on success, false on allocation failure
+   (in which case the old buffer is freed, but *BUFFER remains in a
+   free-able state, and errno is set).  It is unspecified whether this
+   function can reduce the array size.  */
+#if 0
+extern bool scratch_buffer_set_array_size (struct scratch_buffer *buffer,
+                                           size_t nelem, size_t size);
+#endif
+
+/* Return a copy of *BUFFER's first SIZE bytes as a heap-allocated block,
+   deallocating *BUFFER if it was heap-allocated.  SIZE must be at
+   most *BUFFER's size.  Return NULL (setting errno) on memory
+   exhaustion.  */
+#if 0
+extern void *scratch_buffer_dupfree (struct scratch_buffer *buffer,
+                                     size_t size);
+#endif
+
+
+/* The implementation is imported from glibc.  */
+
+/* Avoid possible conflicts with symbols exported by the GNU libc.  */
 #define __libc_scratch_buffer_dupfree gl_scratch_buffer_dupfree
 #define __libc_scratch_buffer_grow gl_scratch_buffer_grow
 #define __libc_scratch_buffer_grow_preserve gl_scratch_buffer_grow_preserve
 #define __libc_scratch_buffer_set_array_size gl_scratch_buffer_set_array_size
-#include <malloc/scratch_buffer.h>
+
+#ifndef _GL_LIKELY
+/* Rely on __builtin_expect, as provided by the module 'builtin-expect'.  */
+# define _GL_LIKELY(cond) __builtin_expect ((cond), 1)
+# define _GL_UNLIKELY(cond) __builtin_expect ((cond), 0)
+#endif
+
+#include <malloc/scratch_buffer.gl.h>
 
 #endif /* _GL_SCRATCH_BUFFER_H */
diff --git a/lib/set-permissions.c b/lib/set-permissions.c
index 607983cb93..5c837f1238 100644
--- a/lib/set-permissions.c
+++ b/lib/set-permissions.c
@@ -775,7 +775,7 @@ chmod_or_fchmod (const char *name, int desc, mode_t mode)
 int
 set_permissions (struct permission_context *ctx, const char *name, int desc)
 {
-  bool acls_set _GL_UNUSED = false;
+  _GL_UNUSED bool acls_set = false;
   bool early_chmod;
   bool must_chmod = false;
   int ret = 0;
diff --git a/lib/sha1.c b/lib/sha1.c
index 612d46de82..52b1020319 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -3,18 +3,18 @@
 
    Copyright (C) 2000-2001, 2003-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3, or (at your option) any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Scott G. Miller
    Credits:
@@ -23,6 +23,7 @@
 
 #include <config.h>
 
+/* Specification.  */
 #if HAVE_OPENSSL_SHA1
 # define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
 #endif
@@ -30,13 +31,8 @@
 
 #include <stdalign.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <string.h>
 
-#if USE_UNLOCKED_IO
-# include "unlocked-io.h"
-#endif
-
 #include <byteswap.h>
 #ifdef WORDS_BIGENDIAN
 # define SWAP(n) (n)
@@ -44,12 +40,8 @@
 # define SWAP(n) bswap_32 (n)
 #endif
 
-#define BLOCKSIZE 32768
-#if BLOCKSIZE % 64 != 0
-# error "invalid BLOCKSIZE"
-#endif
-
 #if ! HAVE_OPENSSL_SHA1
+
 /* This array contains the bytes used to pad the buffer to the next
    64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
 static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
@@ -120,93 +112,7 @@ sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf)
 
   return sha1_read_ctx (ctx, resbuf);
 }
-#endif
-
-#ifdef GL_COMPILE_CRYPTO_STREAM
-
-#include "af_alg.h"
 
-/* Compute SHA1 message digest for bytes read from STREAM.  The
-   resulting message digest number will be written into the 20 bytes
-   beginning at RESBLOCK.  */
-int
-sha1_stream (FILE *stream, void *resblock)
-{
-  switch (afalg_stream (stream, "sha1", resblock, SHA1_DIGEST_SIZE))
-    {
-    case 0: return 0;
-    case -EIO: return 1;
-    }
-
-  char *buffer = malloc (BLOCKSIZE + 72);
-  if (!buffer)
-    return 1;
-
-  struct sha1_ctx ctx;
-  sha1_init_ctx (&ctx);
-  size_t sum;
-
-  /* Iterate over full file contents.  */
-  while (1)
-    {
-      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-         computation function processes the whole buffer so that with the
-         next round of the loop another block can be read.  */
-      size_t n;
-      sum = 0;
-
-      /* Read block.  Take care for partial reads.  */
-      while (1)
-        {
-          /* Either process a partial fread() from this loop,
-             or the fread() in afalg_stream may have gotten EOF.
-             We need to avoid a subsequent fread() as EOF may
-             not be sticky.  For details of such systems, see:
-             https://sourceware.org/bugzilla/show_bug.cgi?id=1190  */
-          if (feof (stream))
-            goto process_partial_block;
-
-          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-          sum += n;
-
-          if (sum == BLOCKSIZE)
-            break;
-
-          if (n == 0)
-            {
-              /* Check for the error flag IFF N == 0, so that we don't
-                 exit the loop after a partial read due to e.g., EAGAIN
-                 or EWOULDBLOCK.  */
-              if (ferror (stream))
-                {
-                  free (buffer);
-                  return 1;
-                }
-              goto process_partial_block;
-            }
-        }
-
-      /* Process buffer with BLOCKSIZE bytes.  Note that
-                        BLOCKSIZE % 64 == 0
-       */
-      sha1_process_block (buffer, BLOCKSIZE, &ctx);
-    }
-
- process_partial_block:;
-
-  /* Process any remaining bytes.  */
-  if (sum > 0)
-    sha1_process_bytes (buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  sha1_finish_ctx (&ctx, resblock);
-  free (buffer);
-  return 0;
-}
-#endif
-
-#if ! HAVE_OPENSSL_SHA1
 /* Compute SHA1 message digest for LEN bytes beginning at BUFFER.  The
    result is always in little endian byte order, so that a byte-wise
    output yields to the wanted ASCII representation of the message
@@ -444,6 +350,7 @@ sha1_process_block (const void *buffer, size_t len, struct 
sha1_ctx *ctx)
       e = ctx->E += e;
     }
 }
+
 #endif
 
 /*
diff --git a/lib/sha1.h b/lib/sha1.h
index 94ccd18fda..e12a23cd4d 100644
--- a/lib/sha1.h
+++ b/lib/sha1.h
@@ -3,18 +3,18 @@
    Copyright (C) 2000-2001, 2003, 2005-2006, 2008-2021 Free Software
    Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3, or (at your option) any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef SHA1_H
 # define SHA1_H 1
@@ -30,7 +30,7 @@
 extern "C" {
 # endif
 
-#define SHA1_DIGEST_SIZE 20
+# define SHA1_DIGEST_SIZE 20
 
 # if HAVE_OPENSSL_SHA1
 #  define GL_OPENSSL_NAME 1
@@ -88,6 +88,7 @@ extern void *sha1_buffer (const char *buffer, size_t len,
                           void *restrict resblock);
 
 # endif
+
 /* Compute SHA1 message digest for bytes read from STREAM.
    STREAM is an open file stream.  Regular files are handled more efficiently.
    The contents of STREAM from its current position to its end will be read.
diff --git a/lib/sha256.c b/lib/sha256.c
index 129d64b174..2b8687f1db 100644
--- a/lib/sha256.c
+++ b/lib/sha256.c
@@ -3,17 +3,17 @@
 
    Copyright (C) 2005-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by David Madore, considerably copypasting from
@@ -22,6 +22,7 @@
 
 #include <config.h>
 
+/* Specification.  */
 #if HAVE_OPENSSL_SHA256
 # define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
 #endif
@@ -29,13 +30,8 @@
 
 #include <stdalign.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <string.h>
 
-#if USE_UNLOCKED_IO
-# include "unlocked-io.h"
-#endif
-
 #include <byteswap.h>
 #ifdef WORDS_BIGENDIAN
 # define SWAP(n) (n)
@@ -43,12 +39,8 @@
 # define SWAP(n) bswap_32 (n)
 #endif
 
-#define BLOCKSIZE 32768
-#if BLOCKSIZE % 64 != 0
-# error "invalid BLOCKSIZE"
-#endif
-
 #if ! HAVE_OPENSSL_SHA256
+
 /* This array contains the bytes used to pad the buffer to the next
    64-byte boundary.  */
 static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
@@ -167,110 +159,7 @@ sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
   sha256_conclude_ctx (ctx);
   return sha224_read_ctx (ctx, resbuf);
 }
-#endif
-
-#ifdef GL_COMPILE_CRYPTO_STREAM
-
-#include "af_alg.h"
-
-/* Compute message digest for bytes read from STREAM using algorithm ALG.
-   Write the message digest into RESBLOCK, which contains HASHLEN bytes.
-   The initial and finishing operations are INIT_CTX and FINISH_CTX.
-   Return zero if and only if successful.  */
-static int
-shaxxx_stream (FILE *stream, char const *alg, void *resblock,
-               ssize_t hashlen, void (*init_ctx) (struct sha256_ctx *),
-               void *(*finish_ctx) (struct sha256_ctx *, void *))
-{
-  switch (afalg_stream (stream, alg, resblock, hashlen))
-    {
-    case 0: return 0;
-    case -EIO: return 1;
-    }
-
-  char *buffer = malloc (BLOCKSIZE + 72);
-  if (!buffer)
-    return 1;
-
-  struct sha256_ctx ctx;
-  init_ctx (&ctx);
-  size_t sum;
-
-  /* Iterate over full file contents.  */
-  while (1)
-    {
-      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-         computation function processes the whole buffer so that with the
-         next round of the loop another block can be read.  */
-      size_t n;
-      sum = 0;
-
-      /* Read block.  Take care for partial reads.  */
-      while (1)
-        {
-          /* Either process a partial fread() from this loop,
-             or the fread() in afalg_stream may have gotten EOF.
-             We need to avoid a subsequent fread() as EOF may
-             not be sticky.  For details of such systems, see:
-             https://sourceware.org/bugzilla/show_bug.cgi?id=1190  */
-          if (feof (stream))
-            goto process_partial_block;
-
-          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-          sum += n;
-
-          if (sum == BLOCKSIZE)
-            break;
-
-          if (n == 0)
-            {
-              /* Check for the error flag IFF N == 0, so that we don't
-                 exit the loop after a partial read due to e.g., EAGAIN
-                 or EWOULDBLOCK.  */
-              if (ferror (stream))
-                {
-                  free (buffer);
-                  return 1;
-                }
-              goto process_partial_block;
-            }
-        }
-
-      /* Process buffer with BLOCKSIZE bytes.  Note that
-                        BLOCKSIZE % 64 == 0
-       */
-      sha256_process_block (buffer, BLOCKSIZE, &ctx);
-    }
-
- process_partial_block:;
-
-  /* Process any remaining bytes.  */
-  if (sum > 0)
-    sha256_process_bytes (buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  finish_ctx (&ctx, resblock);
-  free (buffer);
-  return 0;
-}
 
-int
-sha256_stream (FILE *stream, void *resblock)
-{
-  return shaxxx_stream (stream, "sha256", resblock, SHA256_DIGEST_SIZE,
-                        sha256_init_ctx, sha256_finish_ctx);
-}
-
-int
-sha224_stream (FILE *stream, void *resblock)
-{
-  return shaxxx_stream (stream, "sha224", resblock, SHA224_DIGEST_SIZE,
-                        sha224_init_ctx, sha224_finish_ctx);
-}
-#endif
-
-#if ! HAVE_OPENSSL_SHA256
 /* Compute SHA256 message digest for LEN bytes beginning at BUFFER.  The
    result is always in little endian byte order, so that a byte-wise
    output yields to the wanted ASCII representation of the message
@@ -533,6 +422,7 @@ sha256_process_block (const void *buffer, size_t len, 
struct sha256_ctx *ctx)
       h = ctx->state[7] += h;
     }
 }
+
 #endif
 
 /*
diff --git a/lib/sha256.h b/lib/sha256.h
index b4bc082267..e09b3de807 100644
--- a/lib/sha256.h
+++ b/lib/sha256.h
@@ -2,17 +2,17 @@
    library functions.
    Copyright (C) 2005-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef SHA256_H
@@ -93,6 +93,7 @@ extern void *sha224_buffer (const char *buffer, size_t len,
                             void *restrict resblock);
 
 # endif
+
 /* Compute SHA256 (SHA224) message digest for bytes read from STREAM.
    STREAM is an open file stream.  Regular files are handled more efficiently.
    The contents of STREAM from its current position to its end will be read.
diff --git a/lib/sha512.c b/lib/sha512.c
index 4ac3fa3e42..2865d6e588 100644
--- a/lib/sha512.c
+++ b/lib/sha512.c
@@ -3,17 +3,17 @@
 
    Copyright (C) 2005-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by David Madore, considerably copypasting from
@@ -22,6 +22,7 @@
 
 #include <config.h>
 
+/* Specification.  */
 #if HAVE_OPENSSL_SHA512
 # define GL_OPENSSL_INLINE _GL_EXTERN_INLINE
 #endif
@@ -29,13 +30,8 @@
 
 #include <stdalign.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <string.h>
 
-#if USE_UNLOCKED_IO
-# include "unlocked-io.h"
-#endif
-
 #include <byteswap.h>
 #ifdef WORDS_BIGENDIAN
 # define SWAP(n) (n)
@@ -43,12 +39,8 @@
 # define SWAP(n) bswap_64 (n)
 #endif
 
-#define BLOCKSIZE 32768
-#if BLOCKSIZE % 128 != 0
-# error "invalid BLOCKSIZE"
-#endif
-
 #if ! HAVE_OPENSSL_SHA512
+
 /* This array contains the bytes used to pad the buffer to the next
    128-byte boundary.  */
 static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ...  */ };
@@ -168,110 +160,7 @@ sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
   sha512_conclude_ctx (ctx);
   return sha384_read_ctx (ctx, resbuf);
 }
-#endif
-
-#ifdef GL_COMPILE_CRYPTO_STREAM
-
-#include "af_alg.h"
-
-/* Compute message digest for bytes read from STREAM using algorithm ALG.
-   Write the message digest into RESBLOCK, which contains HASHLEN bytes.
-   The initial and finishing operations are INIT_CTX and FINISH_CTX.
-   Return zero if and only if successful.  */
-static int
-shaxxx_stream (FILE *stream, char const *alg, void *resblock,
-               ssize_t hashlen, void (*init_ctx) (struct sha512_ctx *),
-               void *(*finish_ctx) (struct sha512_ctx *, void *))
-{
-  switch (afalg_stream (stream, alg, resblock, hashlen))
-    {
-    case 0: return 0;
-    case -EIO: return 1;
-    }
-
-  char *buffer = malloc (BLOCKSIZE + 72);
-  if (!buffer)
-    return 1;
-
-  struct sha512_ctx ctx;
-  init_ctx (&ctx);
-  size_t sum;
-
-  /* Iterate over full file contents.  */
-  while (1)
-    {
-      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
-         computation function processes the whole buffer so that with the
-         next round of the loop another block can be read.  */
-      size_t n;
-      sum = 0;
-
-      /* Read block.  Take care for partial reads.  */
-      while (1)
-        {
-          /* Either process a partial fread() from this loop,
-             or the fread() in afalg_stream may have gotten EOF.
-             We need to avoid a subsequent fread() as EOF may
-             not be sticky.  For details of such systems, see:
-             https://sourceware.org/bugzilla/show_bug.cgi?id=1190  */
-          if (feof (stream))
-            goto process_partial_block;
-
-          n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
-
-          sum += n;
-
-          if (sum == BLOCKSIZE)
-            break;
-
-          if (n == 0)
-            {
-              /* Check for the error flag IFF N == 0, so that we don't
-                 exit the loop after a partial read due to e.g., EAGAIN
-                 or EWOULDBLOCK.  */
-              if (ferror (stream))
-                {
-                  free (buffer);
-                  return 1;
-                }
-              goto process_partial_block;
-            }
-        }
-
-      /* Process buffer with BLOCKSIZE bytes.  Note that
-                        BLOCKSIZE % 128 == 0
-       */
-      sha512_process_block (buffer, BLOCKSIZE, &ctx);
-    }
-
- process_partial_block:;
-
-  /* Process any remaining bytes.  */
-  if (sum > 0)
-    sha512_process_bytes (buffer, sum, &ctx);
-
-  /* Construct result in desired memory.  */
-  finish_ctx (&ctx, resblock);
-  free (buffer);
-  return 0;
-}
 
-int
-sha512_stream (FILE *stream, void *resblock)
-{
-  return shaxxx_stream (stream, "sha512", resblock, SHA512_DIGEST_SIZE,
-                        sha512_init_ctx, sha512_finish_ctx);
-}
-
-int
-sha384_stream (FILE *stream, void *resblock)
-{
-  return shaxxx_stream (stream, "sha384", resblock, SHA384_DIGEST_SIZE,
-                        sha384_init_ctx, sha384_finish_ctx);
-}
-#endif
-
-#if ! HAVE_OPENSSL_SHA512
 /* Compute SHA512 message digest for LEN bytes beginning at BUFFER.  The
    result is always in little endian byte order, so that a byte-wise
    output yields to the wanted ASCII representation of the message
@@ -578,6 +467,7 @@ sha512_process_block (const void *buffer, size_t len, 
struct sha512_ctx *ctx)
       h = ctx->state[7] = u64plus (ctx->state[7], h);
     }
 }
+
 #endif
 
 /*
diff --git a/lib/sha512.h b/lib/sha512.h
index 81b53034c7..e15afe996e 100644
--- a/lib/sha512.h
+++ b/lib/sha512.h
@@ -2,17 +2,17 @@
    library functions.
    Copyright (C) 2005-2006, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef SHA512_H
@@ -96,6 +96,7 @@ extern void *sha384_buffer (const char *buffer, size_t len,
                             void *restrict resblock);
 
 # endif
+
 /* Compute SHA512 (SHA384) message digest for bytes read from STREAM.
    STREAM is an open file stream.  Regular files are handled more efficiently.
    The contents of STREAM from its current position to its end will be read.
diff --git a/lib/sigdescr_np.c b/lib/sigdescr_np.c
index 6c9bf283a8..bf6abe55c4 100644
--- a/lib/sigdescr_np.c
+++ b/lib/sigdescr_np.c
@@ -1,17 +1,17 @@
 /* English descriptions of signals.
    Copyright (C) 2020-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
@@ -189,7 +189,7 @@ sigdescr_np (int sig)
       return "Instruction emulation needed";
     #endif
     /* Mac OS X, FreeBSD, NetBSD, OpenBSD, Minix */
-    #if defined SIGINFO
+    #if defined SIGINFO && SIGINFO != SIGPWR
     case SIGINFO:
       return "Information request";
     #endif
diff --git a/lib/signal.in.h b/lib/signal.in.h
index ed01d672c9..275da8c817 100644
--- a/lib/signal.in.h
+++ b/lib/signal.in.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
diff --git a/lib/stat-time.c b/lib/stat-time.c
index 81b83ddb4f..7b92792694 100644
--- a/lib/stat-time.c
+++ b/lib/stat-time.c
@@ -1,3 +1,21 @@
+/* stat-related time functions.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define _GL_STAT_TIME_INLINE _GL_EXTERN_INLINE
 #include "stat-time.h"
diff --git a/lib/stat-time.h b/lib/stat-time.h
index 523ed21b08..6b2cc686ae 100644
--- a/lib/stat-time.h
+++ b/lib/stat-time.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2005, 2007, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
@@ -102,7 +102,7 @@ get_stat_mtime_ns (struct stat const *st)
 
 /* Return the nanosecond component of *ST's birth time.  */
 _GL_STAT_TIME_INLINE long int _GL_ATTRIBUTE_PURE
-get_stat_birthtime_ns (struct stat const *st _GL_UNUSED)
+get_stat_birthtime_ns (_GL_UNUSED struct stat const *st)
 {
 # if defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
   return STAT_TIMESPEC (st, st_birthtim).tv_nsec;
@@ -158,7 +158,7 @@ get_stat_mtime (struct stat const *st)
 /* Return *ST's birth time, if available; otherwise return a value
    with tv_sec and tv_nsec both equal to -1.  */
 _GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
-get_stat_birthtime (struct stat const *st _GL_UNUSED)
+get_stat_birthtime (_GL_UNUSED struct stat const *st)
 {
   struct timespec t;
 
@@ -208,7 +208,7 @@ get_stat_birthtime (struct stat const *st _GL_UNUSED)
    errno to EOVERFLOW if normalization overflowed.  This function
    is intended to be private to this .h file.  */
 _GL_STAT_TIME_INLINE int
-stat_time_normalize (int result, struct stat *st _GL_UNUSED)
+stat_time_normalize (int result, _GL_UNUSED struct stat *st)
 {
 #if defined __sun && defined STAT_TIMESPEC
   if (result == 0)
diff --git a/lib/stdalign.in.h b/lib/stdalign.in.h
index eae9d13221..592d58e372 100644
--- a/lib/stdalign.in.h
+++ b/lib/stdalign.in.h
@@ -2,18 +2,18 @@
 
    Copyright 2011-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert and Bruno Haible.  */
 
@@ -104,12 +104,13 @@
 #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
 # if defined __cplusplus && 201103 <= __cplusplus
 #  define _Alignas(a) alignas (a)
-# elif ((defined __APPLE__ && defined __MACH__                  \
-         ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__)                 \
-         : __GNUC__ && !defined __ibmxl__)                      \
-        || (4 <= __clang_major__)                               \
-        || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC))  \
-        || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__)
+# elif (!defined __attribute__ \
+        && ((defined __APPLE__ && defined __MACH__ \
+             ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
+             : __GNUC__ && !defined __ibmxl__) \
+            || (4 <= __clang_major__) \
+            || (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \
+            || __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))
 #  define _Alignas(a) __attribute__ ((__aligned__ (a)))
 # elif 1300 <= _MSC_VER
 #  define _Alignas(a) __declspec (align (a))
diff --git a/lib/stddef.in.h b/lib/stddef.in.h
index 0f506a5b18..42290d448d 100644
--- a/lib/stddef.in.h
+++ b/lib/stddef.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Eric Blake.  */
 
@@ -42,6 +42,13 @@
 #   define _GL_STDDEF_WINT_T
 #  endif
 #  @INCLUDE_NEXT@ @NEXT_STDDEF_H@
+   /* On TinyCC, make sure that the macros that indicate the special invocation
+      convention get undefined.  */
+#  undef __need_wchar_t
+#  undef __need_size_t
+#  undef __need_ptrdiff_t
+#  undef __need_NULL
+#  undef __need_wint_t
 # endif
 
 #else
@@ -51,7 +58,7 @@
 
 /* On AIX 7.2, with xlc in 64-bit mode, <stddef.h> defines max_align_t to a
    type with alignment 4, but 'long' has alignment 8.  */
-#  if defined _AIX && defined _ARCH_PPC64
+#  if defined _AIX && defined __LP64__
 #   if !GNULIB_defined_max_align_t
 #    ifdef _MAX_ALIGN_T
 /* /usr/include/stddef.h has already defined max_align_t.  Override it.  */
@@ -109,7 +116,7 @@ typedef long max_align_t;
     && defined __cplusplus
 # include <cstddef>
 #else
-# if ! (@HAVE_MAX_ALIGN_T@ || defined _GCC_MAX_ALIGN_T)
+# if ! (@HAVE_MAX_ALIGN_T@ || (defined _GCC_MAX_ALIGN_T && !defined __clang__))
 #  if !GNULIB_defined_max_align_t
 /* On the x86, the maximum storage alignment of double, long, etc. is 4,
    but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8,
diff --git a/lib/stdint.in.h b/lib/stdint.in.h
index 7a8f27cef7..85c5418f14 100644
--- a/lib/stdint.in.h
+++ b/lib/stdint.in.h
@@ -2,18 +2,18 @@
    Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood.
    This file is part of gnulib.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /*
  * ISO C 99 <stdint.h> for platforms that lack it.
@@ -85,7 +85,7 @@
 
 /* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides
    wint_t.  */
-#if @GNULIB_OVERRIDES_WINT_T@
+#if @GNULIBHEADERS_OVERRIDE_WINT_T@
 # undef WINT_MIN
 # undef WINT_MAX
 # define WINT_MIN 0x0U
@@ -598,7 +598,7 @@ typedef int _verify_intmax_size[sizeof (intmax_t) == sizeof 
(uintmax_t)
 /* wint_t limits */
 /* If gnulib's <wchar.h> or <wctype.h> overrides wint_t, @WINT_T_SUFFIX@ is not
    accurate, therefore use the definitions from above.  */
-# if !@GNULIB_OVERRIDES_WINT_T@
+# if !@GNULIBHEADERS_OVERRIDE_WINT_T@
 #  undef WINT_MIN
 #  undef WINT_MAX
 #  if @HAVE_SIGNED_WINT_T@
diff --git a/lib/stdio-impl.h b/lib/stdio-impl.h
index 2a5db74f28..3fa94b487e 100644
--- a/lib/stdio-impl.h
+++ b/lib/stdio-impl.h
@@ -1,17 +1,17 @@
 /* Implementation details of FILE streams.
    Copyright (C) 2007-2008, 2010-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Many stdio implementations have the same logic and therefore can share
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index a930840505..0ca2c8e10c 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2004, 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
@@ -56,6 +56,52 @@
    May also define off_t to a 64-bit type on native Windows.  */
 #include <sys/types.h>
 
+/* Solaris 10 and NetBSD 7.0 declare renameat in <unistd.h>, not in <stdio.h>. 
 */
+/* But in any case avoid namespace pollution on glibc systems.  */
+#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && (defined __sun || 
defined __NetBSD__) \
+    && ! defined __GLIBC__
+# include <unistd.h>
+#endif
+
+/* Android 4.3 declares renameat in <sys/stat.h>, not in <stdio.h>.  */
+/* But in any case avoid namespace pollution on glibc systems.  */
+#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \
+    && ! defined __GLIBC__
+# include <sys/stat.h>
+#endif
+
+/* MSVC declares 'perror' in <stdlib.h>, not in <stdio.h>.  We must include
+   it before we  #define perror rpl_perror.  */
+/* But in any case avoid namespace pollution on glibc systems.  */
+#if (@GNULIB_PERROR@ || defined GNULIB_POSIXCHECK) \
+    && (defined _WIN32 && ! defined __CYGWIN__) \
+    && ! defined __GLIBC__
+# include <stdlib.h>
+#endif
+
+/* MSVC declares 'remove' in <io.h>, not in <stdio.h>.  We must include
+   it before we  #define remove rpl_remove.  */
+/* MSVC declares 'rename' in <io.h>, not in <stdio.h>.  We must include
+   it before we  #define rename rpl_rename.  */
+/* But in any case avoid namespace pollution on glibc systems.  */
+#if (@GNULIB_REMOVE@ || @GNULIB_RENAME@ || defined GNULIB_POSIXCHECK) \
+    && (defined _WIN32 && ! defined __CYGWIN__) \
+    && ! defined __GLIBC__
+# include <io.h>
+#endif
+
+
+/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
+   that can be freed by passing them as the Ith argument to the
+   function F.  */
+#ifndef _GL_ATTRIBUTE_DEALLOC
+# if __GNUC__ >= 11
+#  define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
+# else
+#  define _GL_ATTRIBUTE_DEALLOC(f, i)
+# endif
+#endif
+
 /* The __attribute__ feature is available in gcc versions 2.5 and later.
    The __-protected variants of the attributes 'format' and 'printf' are
    accepted by gcc versions 2.6.4 (effectively 2.7) and later.
@@ -127,41 +173,6 @@
 #define _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM(formatstring_parameter, 
first_argument) \
   _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument))
 
-/* Solaris 10 and NetBSD 7.0 declare renameat in <unistd.h>, not in <stdio.h>. 
 */
-/* But in any case avoid namespace pollution on glibc systems.  */
-#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && (defined __sun || 
defined __NetBSD__) \
-    && ! defined __GLIBC__
-# include <unistd.h>
-#endif
-
-/* Android 4.3 declares renameat in <sys/stat.h>, not in <stdio.h>.  */
-/* But in any case avoid namespace pollution on glibc systems.  */
-#if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && defined __ANDROID__ \
-    && ! defined __GLIBC__
-# include <sys/stat.h>
-#endif
-
-/* MSVC declares 'perror' in <stdlib.h>, not in <stdio.h>.  We must include
-   it before we  #define perror rpl_perror.  */
-/* But in any case avoid namespace pollution on glibc systems.  */
-#if (@GNULIB_PERROR@ || defined GNULIB_POSIXCHECK) \
-    && (defined _WIN32 && ! defined __CYGWIN__) \
-    && ! defined __GLIBC__
-# include <stdlib.h>
-#endif
-
-/* MSVC declares 'remove' in <io.h>, not in <stdio.h>.  We must include
-   it before we  #define remove rpl_remove.  */
-/* MSVC declares 'rename' in <io.h>, not in <stdio.h>.  We must include
-   it before we  #define rename rpl_rename.  */
-/* But in any case avoid namespace pollution on glibc systems.  */
-#if (@GNULIB_REMOVE@ || @GNULIB_RENAME@ || defined GNULIB_POSIXCHECK) \
-    && (defined _WIN32 && ! defined __CYGWIN__) \
-    && ! defined __GLIBC__
-# include <io.h>
-#endif
-
-
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 /* The definition of _GL_ARG_NONNULL is copied here.  */
@@ -242,7 +253,7 @@ _GL_WARN_ON_USE (fclose, "fclose is not always POSIX 
compliant - "
 _GL_CXXALIAS_MDA (fcloseall, int, (void));
 # else
 #  if @HAVE_DECL_FCLOSEALL@
-#   if defined __FreeBSD__
+#   if defined __FreeBSD__ || defined __DragonFly__
 _GL_CXXALIAS_SYS (fcloseall, void, (void));
 #   else
 _GL_CXXALIAS_SYS (fcloseall, int, (void));
@@ -260,8 +271,9 @@ _GL_CXXALIASWARN (fcloseall);
 #   undef fdopen
 #   define fdopen rpl_fdopen
 #  endif
-_GL_FUNCDECL_RPL (fdopen, FILE *, (int fd, const char *mode)
-                                  _GL_ARG_NONNULL ((2)));
+_GL_FUNCDECL_RPL (fdopen, FILE *,
+                  (int fd, const char *mode)
+                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
 _GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char *mode));
 # elif defined _WIN32 && !defined __CYGWIN__
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -270,28 +282,42 @@ _GL_CXXALIAS_RPL (fdopen, FILE *, (int fd, const char 
*mode));
 #  endif
 _GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (fdopen, FILE *,
+                  (int fd, const char *mode)
+                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+#  endif
 _GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));
 # endif
 _GL_CXXALIASWARN (fdopen);
-#elif defined GNULIB_POSIXCHECK
-# undef fdopen
+#else
+# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fdopen
+/* For -Wmismatched-dealloc: Associate fdopen with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (fdopen, FILE *,
+                  (int fd, const char *mode)
+                  _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef fdopen
 /* Assume fdopen is always declared.  */
 _GL_WARN_ON_USE (fdopen, "fdopen on native Windows platforms is not POSIX 
compliant - "
                  "use gnulib module fdopen for portability");
-#elif @GNULIB_MDA_FDOPEN@
+# elif @GNULIB_MDA_FDOPEN@
 /* On native Windows, map 'fdopen' to '_fdopen', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
    platforms by defining GNULIB_NAMESPACE::fdopen always.  */
-# if defined _WIN32 && !defined __CYGWIN__
-#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#   undef fdopen
-#   define fdopen _fdopen
-#  endif
+#  if defined _WIN32 && !defined __CYGWIN__
+#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#    undef fdopen
+#    define fdopen _fdopen
+#   endif
 _GL_CXXALIAS_MDA (fdopen, FILE *, (int fd, const char *mode));
-# else
+#  else
 _GL_CXXALIAS_SYS (fdopen, FILE *, (int fd, const char *mode));
-# endif
+#  endif
 _GL_CXXALIASWARN (fdopen);
+# endif
 #endif
 
 #if @GNULIB_FFLUSH@
@@ -380,21 +406,35 @@ _GL_CXXALIASWARN (fileno);
 #  endif
 _GL_FUNCDECL_RPL (fopen, FILE *,
                   (const char *restrict filename, const char *restrict mode)
-                  _GL_ARG_NONNULL ((1, 2)));
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
 _GL_CXXALIAS_RPL (fopen, FILE *,
                   (const char *restrict filename, const char *restrict mode));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (fopen, FILE *,
+                  (const char *restrict filename, const char *restrict mode)
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+#  endif
 _GL_CXXALIAS_SYS (fopen, FILE *,
                   (const char *restrict filename, const char *restrict mode));
 # endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (fopen);
 # endif
-#elif defined GNULIB_POSIXCHECK
-# undef fopen
+#else
+# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined fopen
+/* For -Wmismatched-dealloc: Associate fopen with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (fopen, FILE *,
+                  (const char *restrict filename, const char *restrict mode)
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef fopen
 /* Assume fopen is always declared.  */
 _GL_WARN_ON_USE (fopen, "fopen on native Windows platforms is not POSIX 
compliant - "
                  "use gnulib module fopen for portability");
+# endif
 #endif
 
 #if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@
@@ -1009,22 +1049,32 @@ _GL_WARN_ON_USE (perror, "perror is not always POSIX 
compliant - "
 #   undef popen
 #   define popen rpl_popen
 #  endif
-_GL_FUNCDECL_RPL (popen, FILE *, (const char *cmd, const char *mode)
-                                 _GL_ARG_NONNULL ((1, 2)));
+_GL_FUNCDECL_RPL (popen, FILE *,
+                  (const char *cmd, const char *mode)
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));
 _GL_CXXALIAS_RPL (popen, FILE *, (const char *cmd, const char *mode));
 # else
-#  if !@HAVE_POPEN@
-_GL_FUNCDECL_SYS (popen, FILE *, (const char *cmd, const char *mode)
-                                 _GL_ARG_NONNULL ((1, 2)));
+#  if !@HAVE_POPEN@ || __GNUC__ >= 11
+_GL_FUNCDECL_SYS (popen, FILE *,
+                  (const char *cmd, const char *mode)
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));
 #  endif
 _GL_CXXALIAS_SYS (popen, FILE *, (const char *cmd, const char *mode));
 # endif
 _GL_CXXALIASWARN (popen);
-#elif defined GNULIB_POSIXCHECK
-# undef popen
-# if HAVE_RAW_DECL_POPEN
+#else
+# if @GNULIB_PCLOSE@ && __GNUC__ >= 11 && !defined popen
+/* For -Wmismatched-dealloc: Associate popen with pclose or rpl_pclose.  */
+_GL_FUNCDECL_SYS (popen, FILE *,
+                  (const char *cmd, const char *mode)
+                  _GL_ARG_NONNULL ((1, 2)) _GL_ATTRIBUTE_DEALLOC (pclose, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef popen
+#  if HAVE_RAW_DECL_POPEN
 _GL_WARN_ON_USE (popen, "popen is buggy on some platforms - "
                  "use gnulib module popen or pipe for more portability");
+#  endif
 # endif
 #endif
 
@@ -1257,6 +1307,7 @@ _GL_CXXALIASWARN (scanf);
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define snprintf rpl_snprintf
 #  endif
+#  define GNULIB_overrides_snprintf 1
 _GL_FUNCDECL_RPL (snprintf, int,
                   (char *restrict str, size_t size,
                    const char *restrict format, ...)
@@ -1302,6 +1353,7 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define sprintf rpl_sprintf
 #  endif
+#  define GNULIB_overrides_sprintf 1
 _GL_FUNCDECL_RPL (sprintf, int,
                   (char *restrict str, const char *restrict format, ...)
                   _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
@@ -1344,19 +1396,32 @@ _GL_CXXALIASWARN (tempnam);
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define tmpfile rpl_tmpfile
 #  endif
-_GL_FUNCDECL_RPL (tmpfile, FILE *, (void));
+_GL_FUNCDECL_RPL (tmpfile, FILE *, (void)
+                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));
 _GL_CXXALIAS_RPL (tmpfile, FILE *, (void));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)
+                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+#  endif
 _GL_CXXALIAS_SYS (tmpfile, FILE *, (void));
 # endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (tmpfile);
 # endif
-#elif defined GNULIB_POSIXCHECK
-# undef tmpfile
-# if HAVE_RAW_DECL_TMPFILE
+#else
+# if @GNULIB_FCLOSE@ && __GNUC__ >= 11 && !defined tmpfile
+/* For -Wmismatched-dealloc: Associate tmpfile with fclose or rpl_fclose.  */
+_GL_FUNCDECL_SYS (tmpfile, FILE *, (void)
+                                   _GL_ATTRIBUTE_DEALLOC (fclose, 1));
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef tmpfile
+#  if HAVE_RAW_DECL_TMPFILE
 _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - "
                  "use gnulib module tmpfile for portability");
+#  endif
 # endif
 #endif
 
@@ -1369,6 +1434,7 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw 
- "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define asprintf rpl_asprintf
 #  endif
+#  define GNULIB_overrides_asprintf
 _GL_FUNCDECL_RPL (asprintf, int,
                   (char **result, const char *format, ...)
                   _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
@@ -1390,6 +1456,7 @@ _GL_CXXALIASWARN (asprintf);
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define vasprintf rpl_vasprintf
 #  endif
+#  define GNULIB_overrides_vasprintf 1
 _GL_FUNCDECL_RPL (vasprintf, int,
                   (char **result, const char *format, va_list args)
                   _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
@@ -1573,6 +1640,7 @@ _GL_CXXALIASWARN (vscanf);
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define vsnprintf rpl_vsnprintf
 #  endif
+#  define GNULIB_overrides_vsnprintf 1
 _GL_FUNCDECL_RPL (vsnprintf, int,
                   (char *restrict str, size_t size,
                    const char *restrict format, va_list args)
@@ -1609,6 +1677,7 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define vsprintf rpl_vsprintf
 #  endif
+#  define GNULIB_overrides_vsprintf 1
 _GL_FUNCDECL_RPL (vsprintf, int,
                   (char *restrict str,
                    const char *restrict format, va_list args)
diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h
index 49fc44e14a..0855112d19 100644
--- a/lib/stdlib.in.h
+++ b/lib/stdlib.in.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 1995, 2001-2004, 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
@@ -99,6 +99,35 @@ struct random_data
 # include <unistd.h>
 #endif
 
+/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
+   that can be freed by passing them as the Ith argument to the
+   function F.  */
+#ifndef _GL_ATTRIBUTE_DEALLOC
+# if __GNUC__ >= 11
+#  define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
+# else
+#  define _GL_ATTRIBUTE_DEALLOC(f, i)
+# endif
+#endif
+
+/* _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that
+   can be freed via 'free'; it can be used only after declaring 'free'.  */
+/* Applies to: functions.  Cannot be used on inline functions.  */
+#ifndef _GL_ATTRIBUTE_DEALLOC_FREE
+# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)
+#endif
+
+/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly
+   allocated memory.  */
+/* Applies to: functions.  */
+#ifndef _GL_ATTRIBUTE_MALLOC
+# if __GNUC__ >= 3 || defined __clang__
+#  define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+#  define _GL_ATTRIBUTE_MALLOC
+# endif
+#endif
+
 /* The __attribute__ feature is available in gcc versions 2.5 and later.
    The attribute __pure__ was added in gcc 2.96.  */
 #ifndef _GL_ATTRIBUTE_PURE
@@ -149,6 +178,28 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
 #endif
 
 
+#if @GNULIB_FREE_POSIX@
+# if @REPLACE_FREE@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef free
+#   define free rpl_free
+#  endif
+_GL_FUNCDECL_RPL (free, void, (void *ptr));
+_GL_CXXALIAS_RPL (free, void, (void *ptr));
+# else
+_GL_CXXALIAS_SYS (free, void, (void *ptr));
+# endif
+# if __GLIBC__ >= 2
+_GL_CXXALIASWARN (free);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef free
+/* Assume free is always declared.  */
+_GL_WARN_ON_USE (free, "free is not future POSIX compliant everywhere - "
+                 "use gnulib module free for portability");
+#endif
+
+
 /* Allocate memory with indefinite extent and specified alignment.  */
 #if @GNULIB_ALIGNED_ALLOC@
 # if @REPLACE_ALIGNED_ALLOC@
@@ -156,21 +207,37 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - "
 #   undef aligned_alloc
 #   define aligned_alloc rpl_aligned_alloc
 #  endif
-_GL_FUNCDECL_RPL (aligned_alloc, void *, (size_t alignment, size_t size));
+_GL_FUNCDECL_RPL (aligned_alloc, void *,
+                  (size_t alignment, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (aligned_alloc, void *, (size_t alignment, size_t size));
 # else
 #  if @HAVE_ALIGNED_ALLOC@
+#   if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (aligned_alloc, void *,
+                  (size_t alignment, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+#   endif
 _GL_CXXALIAS_SYS (aligned_alloc, void *, (size_t alignment, size_t size));
 #  endif
 # endif
 # if @HAVE_ALIGNED_ALLOC@
 _GL_CXXALIASWARN (aligned_alloc);
 # endif
-#elif defined GNULIB_POSIXCHECK
-# undef aligned_alloc
-# if HAVE_RAW_DECL_ALIGNED_ALLOC
+#else
+# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined aligned_alloc
+/* For -Wmismatched-dealloc: Associate aligned_alloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (aligned_alloc, void *,
+                  (size_t alignment, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef aligned_alloc
+#  if HAVE_RAW_DECL_ALIGNED_ALLOC
 _GL_WARN_ON_USE (aligned_alloc, "aligned_alloc is not portable - "
                  "use gnulib module aligned_alloc for portability");
+#  endif
 # endif
 #endif
 
@@ -198,19 +265,35 @@ _GL_WARN_ON_USE (atoll, "atoll is unportable - "
 #   undef calloc
 #   define calloc rpl_calloc
 #  endif
-_GL_FUNCDECL_RPL (calloc, void *, (size_t nmemb, size_t size));
+_GL_FUNCDECL_RPL (calloc, void *,
+                  (size_t nmemb, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (calloc, void *, (size_t nmemb, size_t size));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (calloc, void *,
+                  (size_t nmemb, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+#  endif
 _GL_CXXALIAS_SYS (calloc, void *, (size_t nmemb, size_t size));
 # endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (calloc);
 # endif
-#elif defined GNULIB_POSIXCHECK
-# undef calloc
+#else
+# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined calloc
+/* For -Wmismatched-dealloc: Associate calloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (calloc, void *,
+                  (size_t nmemb, size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef calloc
 /* Assume calloc is always declared.  */
 _GL_WARN_ON_USE (calloc, "calloc is not POSIX compliant everywhere - "
                  "use gnulib module calloc-posix for portability");
+# endif
 #endif
 
 #if @GNULIB_CANONICALIZE_FILE_NAME@
@@ -218,13 +301,17 @@ _GL_WARN_ON_USE (calloc, "calloc is not POSIX compliant 
everywhere - "
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define canonicalize_file_name rpl_canonicalize_file_name
 #  endif
-_GL_FUNCDECL_RPL (canonicalize_file_name, char *, (const char *name)
-                                                  _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_RPL (canonicalize_file_name, char *,
+                  (const char *name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (canonicalize_file_name, char *, (const char *name));
 # else
-#  if !@HAVE_CANONICALIZE_FILE_NAME@
-_GL_FUNCDECL_SYS (canonicalize_file_name, char *, (const char *name)
-                                                  _GL_ARG_NONNULL ((1)));
+#  if !@HAVE_CANONICALIZE_FILE_NAME@ || __GNUC__ >= 11
+_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
+                  (const char *name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 #  endif
 _GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const char *name));
 # endif
@@ -233,12 +320,22 @@ _GL_CXXALIAS_SYS (canonicalize_file_name, char *, (const 
char *name));
      (!@HAVE_CANONICALIZE_FILE_NAME@ || @REPLACE_CANONICALIZE_FILE_NAME@)
 # endif
 _GL_CXXALIASWARN (canonicalize_file_name);
-#elif defined GNULIB_POSIXCHECK
-# undef canonicalize_file_name
-# if HAVE_RAW_DECL_CANONICALIZE_FILE_NAME
+#else
+# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined canonicalize_file_name
+/* For -Wmismatched-dealloc: Associate canonicalize_file_name with free or
+   rpl_free.  */
+_GL_FUNCDECL_SYS (canonicalize_file_name, char *,
+                  (const char *name)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef canonicalize_file_name
+#  if HAVE_RAW_DECL_CANONICALIZE_FILE_NAME
 _GL_WARN_ON_USE (canonicalize_file_name,
                  "canonicalize_file_name is unportable - "
                  "use gnulib module canonicalize-lgpl for portability");
+#  endif
 # endif
 #endif
 
@@ -288,27 +385,6 @@ _GL_CXXALIASWARN (fcvt);
 # endif
 #endif
 
-#if @GNULIB_FREE_POSIX@
-# if @REPLACE_FREE@
-#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#   undef free
-#   define free rpl_free
-#  endif
-_GL_FUNCDECL_RPL (free, void, (void *ptr));
-_GL_CXXALIAS_RPL (free, void, (void *ptr));
-# else
-_GL_CXXALIAS_SYS (free, void, (void *ptr));
-# endif
-# if __GLIBC__ >= 2
-_GL_CXXALIASWARN (free);
-# endif
-#elif defined GNULIB_POSIXCHECK
-# undef free
-/* Assume free is always declared.  */
-_GL_WARN_ON_USE (free, "free is not future POSIX compliant everywhere - "
-                 "use gnulib module free for portability");
-#endif
-
 #if @GNULIB_MDA_GCVT@
 /* On native Windows, map 'gcvt' to '_gcvt', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
@@ -404,19 +480,35 @@ _GL_WARN_ON_USE (grantpt, "grantpt is not portable - "
 #   undef malloc
 #   define malloc rpl_malloc
 #  endif
-_GL_FUNCDECL_RPL (malloc, void *, (size_t size));
+_GL_FUNCDECL_RPL (malloc, void *,
+                  (size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (malloc, void *, (size_t size));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (malloc, void *,
+                  (size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+#  endif
 _GL_CXXALIAS_SYS (malloc, void *, (size_t size));
 # endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (malloc);
 # endif
-#elif defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
-# undef malloc
+#else
+# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined malloc
+/* For -Wmismatched-dealloc: Associate malloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (malloc, void *,
+                  (size_t size)
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
+#  undef malloc
 /* Assume malloc is always declared.  */
 _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - "
                  "use gnulib module malloc-posix for portability");
+# endif
 #endif
 
 /* Convert a multibyte character to a wide character.  */
@@ -1015,29 +1107,53 @@ _GL_WARN_ON_USE (setstate_r, "setstate_r is unportable 
- "
 #   undef realloc
 #   define realloc rpl_realloc
 #  endif
-_GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size));
+_GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size)
+                                   _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size));
 # else
+#  if __GNUC__ >= 11
+/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size)
+                                   _GL_ATTRIBUTE_DEALLOC_FREE);
+#  endif
 _GL_CXXALIAS_SYS (realloc, void *, (void *ptr, size_t size));
 # endif
 # if __GLIBC__ >= 2
 _GL_CXXALIASWARN (realloc);
 # endif
-#elif defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
-# undef realloc
+#else
+# if @GNULIB_FREE_POSIX@ && __GNUC__ >= 11 && !defined realloc
+/* For -Wmismatched-dealloc: Associate realloc with free or rpl_free.  */
+_GL_FUNCDECL_SYS (realloc, void *, (void *ptr, size_t size)
+                                   _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK && !_GL_USE_STDLIB_ALLOC
+#  undef realloc
 /* Assume realloc is always declared.  */
 _GL_WARN_ON_USE (realloc, "realloc is not POSIX compliant everywhere - "
                  "use gnulib module realloc-posix for portability");
+# endif
 #endif
 
 
 #if @GNULIB_REALLOCARRAY@
-# if ! @HAVE_REALLOCARRAY@
+# if @REPLACE_REALLOCARRAY@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef reallocarray
+#   define reallocarray rpl_reallocarray
+#  endif
+_GL_FUNCDECL_RPL (reallocarray, void *,
+                  (void *ptr, size_t nmemb, size_t size));
+_GL_CXXALIAS_RPL (reallocarray, void *,
+                  (void *ptr, size_t nmemb, size_t size));
+# else
+#  if ! @HAVE_REALLOCARRAY@
 _GL_FUNCDECL_SYS (reallocarray, void *,
                   (void *ptr, size_t nmemb, size_t size));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (reallocarray, void *,
                   (void *ptr, size_t nmemb, size_t size));
+# endif
 _GL_CXXALIASWARN (reallocarray);
 #elif defined GNULIB_POSIXCHECK
 # undef reallocarray
@@ -1202,6 +1318,47 @@ _GL_WARN_ON_USE (strtold, "strtold is unportable - "
 # endif
 #endif
 
+#if @GNULIB_STRTOL@
+/* Parse a signed integer whose textual representation starts at STRING.
+   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
+   it may be decimal or octal (with prefix "0") or hexadecimal (with prefix
+   "0x").
+   If ENDPTR is not NULL, the address of the first byte after the integer is
+   stored in *ENDPTR.
+   Upon overflow, the return value is LONG_MAX or LONG_MIN, and errno is set
+   to ERANGE.  */
+# if @REPLACE_STRTOL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define strtol rpl_strtol
+#  endif
+#  define GNULIB_defined_strtol_function 1
+_GL_FUNCDECL_RPL (strtol, long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (strtol, long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# else
+#  if !@HAVE_STRTOL@
+_GL_FUNCDECL_SYS (strtol, long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (strtol, long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# endif
+_GL_CXXALIASWARN (strtol);
+#elif defined GNULIB_POSIXCHECK
+# undef strtol
+# if HAVE_RAW_DECL_STRTOL
+_GL_WARN_ON_USE (strtol, "strtol is unportable - "
+                 "use gnulib module strtol for portability");
+# endif
+#endif
+
 #if @GNULIB_STRTOLL@
 /* Parse a signed integer whose textual representation starts at STRING.
    The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
@@ -1211,15 +1368,29 @@ _GL_WARN_ON_USE (strtold, "strtold is unportable - "
    stored in *ENDPTR.
    Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set
    to ERANGE.  */
-# if !@HAVE_STRTOLL@
+# if @REPLACE_STRTOLL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define strtoll rpl_strtoll
+#  endif
+#  define GNULIB_defined_strtoll_function 1
+_GL_FUNCDECL_RPL (strtoll, long long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (strtoll, long long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# else
+#  if !@HAVE_STRTOLL@
 _GL_FUNCDECL_SYS (strtoll, long long,
                   (const char *restrict string, char **restrict endptr,
                    int base)
                   _GL_ARG_NONNULL ((1)));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (strtoll, long long,
                   (const char *restrict string, char **restrict endptr,
                    int base));
+# endif
 _GL_CXXALIASWARN (strtoll);
 #elif defined GNULIB_POSIXCHECK
 # undef strtoll
@@ -1229,6 +1400,46 @@ _GL_WARN_ON_USE (strtoll, "strtoll is unportable - "
 # endif
 #endif
 
+#if @GNULIB_STRTOUL@
+/* Parse an unsigned integer whose textual representation starts at STRING.
+   The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
+   it may be decimal or octal (with prefix "0") or hexadecimal (with prefix
+   "0x").
+   If ENDPTR is not NULL, the address of the first byte after the integer is
+   stored in *ENDPTR.
+   Upon overflow, the return value is ULONG_MAX, and errno is set to ERANGE.  
*/
+# if @REPLACE_STRTOUL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define strtoul rpl_strtoul
+#  endif
+#  define GNULIB_defined_strtoul_function 1
+_GL_FUNCDECL_RPL (strtoul, unsigned long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (strtoul, unsigned long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# else
+#  if !@HAVE_STRTOUL@
+_GL_FUNCDECL_SYS (strtoul, unsigned long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+#  endif
+_GL_CXXALIAS_SYS (strtoul, unsigned long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# endif
+_GL_CXXALIASWARN (strtoul);
+#elif defined GNULIB_POSIXCHECK
+# undef strtoul
+# if HAVE_RAW_DECL_STRTOUL
+_GL_WARN_ON_USE (strtoul, "strtoul is unportable - "
+                 "use gnulib module strtoul for portability");
+# endif
+#endif
+
 #if @GNULIB_STRTOULL@
 /* Parse an unsigned integer whose textual representation starts at STRING.
    The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0,
@@ -1238,15 +1449,29 @@ _GL_WARN_ON_USE (strtoll, "strtoll is unportable - "
    stored in *ENDPTR.
    Upon overflow, the return value is ULLONG_MAX, and errno is set to
    ERANGE.  */
-# if !@HAVE_STRTOULL@
+# if @REPLACE_STRTOULL@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   define strtoull rpl_strtoull
+#  endif
+#  define GNULIB_defined_strtoull_function 1
+_GL_FUNCDECL_RPL (strtoull, unsigned long long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base)
+                  _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (strtoull, unsigned long long,
+                  (const char *restrict string, char **restrict endptr,
+                   int base));
+# else
+#  if !@HAVE_STRTOULL@
 _GL_FUNCDECL_SYS (strtoull, unsigned long long,
                   (const char *restrict string, char **restrict endptr,
                    int base)
                   _GL_ARG_NONNULL ((1)));
-# endif
+#  endif
 _GL_CXXALIAS_SYS (strtoull, unsigned long long,
                   (const char *restrict string, char **restrict endptr,
                    int base));
+# endif
 _GL_CXXALIASWARN (strtoull);
 #elif defined GNULIB_POSIXCHECK
 # undef strtoull
diff --git a/lib/stpcpy.c b/lib/stpcpy.c
index a4165ba4bf..c312fe44ba 100644
--- a/lib/stpcpy.c
+++ b/lib/stpcpy.c
@@ -5,17 +5,17 @@
    NOTE: The canonical source of this file is maintained with the GNU C 
Library.
    Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 
-   This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3 of the License, or any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
diff --git a/lib/str-two-way.h b/lib/str-two-way.h
index 005a19fb51..fc2db03b7b 100644
--- a/lib/str-two-way.h
+++ b/lib/str-two-way.h
@@ -3,18 +3,18 @@
    This file is part of the GNU C Library.
    Written by Eric Blake <ebb9@byu.net>, 2008.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Before including this file, you need to include <config.h> and
    <string.h>, and define:
diff --git a/lib/strftime.h b/lib/strftime.h
index 7284f67133..790a80ed8f 100644
--- a/lib/strftime.h
+++ b/lib/strftime.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2002, 2004, 2008-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <time.h>
diff --git a/lib/string.in.h b/lib/string.in.h
index c76c1820b3..8d77ae3800 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 1995-1996, 2001-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
@@ -52,16 +52,6 @@
 # include <wchar.h>
 #endif
 
-/* The __attribute__ feature is available in gcc versions 2.5 and later.
-   The attribute __pure__ was added in gcc 2.96.  */
-#ifndef _GL_ATTRIBUTE_PURE
-# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined 
__clang__
-#  define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
-# else
-#  define _GL_ATTRIBUTE_PURE /* empty */
-# endif
-#endif
-
 /* NetBSD 5.0 declares strsignal in <unistd.h>, not in <string.h>.  */
 /* But in any case avoid namespace pollution on glibc systems.  */
 #if (@GNULIB_STRSIGNAL@ || defined GNULIB_POSIXCHECK) && defined __NetBSD__ \
@@ -77,12 +67,31 @@
 # include <strings.h>
 #endif
 
+/* The __attribute__ feature is available in gcc versions 2.5 and later.
+   The attribute __pure__ was added in gcc 2.96.  */
+#ifndef _GL_ATTRIBUTE_PURE
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined 
__clang__
+#  define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define _GL_ATTRIBUTE_PURE /* empty */
+# endif
+#endif
+
 /* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
 
 /* The definition of _GL_ARG_NONNULL is copied here.  */
 
 /* The definition of _GL_WARN_ON_USE is copied here.  */
 
+/* Declare 'free' if needed for _GL_ATTRIBUTE_DEALLOC_FREE.  */
+_GL_EXTERN_C void free (void *);
+#if @GNULIB_FREE_POSIX@
+# if (@REPLACE_FREE@ && !defined free \
+      && !(defined __cplusplus && defined GNULIB_NAMESPACE))
+#  define free rpl_free
+_GL_EXTERN_C void free (void *);
+# endif
+#endif
 
 /* Clear a block of memory.  The compiler will not delete a call to
    this function, even if the block is dead after the call.  */
@@ -418,7 +427,10 @@ _GL_WARN_ON_USE (strchrnul, "strchrnul is unportable - "
 #   undef strdup
 #   define strdup rpl_strdup
 #  endif
-_GL_FUNCDECL_RPL (strdup, char *, (char const *__s) _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_RPL (strdup, char *,
+                  (char const *__s)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 _GL_CXXALIAS_RPL (strdup, char *, (char const *__s));
 # elif defined _WIN32 && !defined __CYGWIN__
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -431,35 +443,47 @@ _GL_CXXALIAS_MDA (strdup, char *, (char const *__s));
     /* strdup exists as a function and as a macro.  Get rid of the macro.  */
 #   undef strdup
 #  endif
-#  if !(@HAVE_DECL_STRDUP@ || defined strdup)
-_GL_FUNCDECL_SYS (strdup, char *, (char const *__s) _GL_ARG_NONNULL ((1)));
+#  if (!@HAVE_DECL_STRDUP@ || __GNUC__ >= 11) && !defined strdup
+_GL_FUNCDECL_SYS (strdup, char *,
+                  (char const *__s)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
 #  endif
 _GL_CXXALIAS_SYS (strdup, char *, (char const *__s));
 # endif
 _GL_CXXALIASWARN (strdup);
-#elif defined GNULIB_POSIXCHECK
-# undef strdup
-# if HAVE_RAW_DECL_STRDUP
+#else
+# if __GNUC__ >= 11 && !defined strdup
+/* For -Wmismatched-dealloc: Associate strdup with free or rpl_free.  */
+_GL_FUNCDECL_SYS (strdup, char *,
+                  (char const *__s)
+                  _GL_ARG_NONNULL ((1))
+                  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE);
+# endif
+# if defined GNULIB_POSIXCHECK
+#  undef strdup
+#  if HAVE_RAW_DECL_STRDUP
 _GL_WARN_ON_USE (strdup, "strdup is unportable - "
                  "use gnulib module strdup for portability");
-# endif
-#elif @GNULIB_MDA_STRDUP@
+#  endif
+# elif @GNULIB_MDA_STRDUP@
 /* On native Windows, map 'creat' to '_creat', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
-   platforms by defining GNULIB_NAMESPACE::creat always.  */
-# if defined _WIN32 && !defined __CYGWIN__
-#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-#   undef strdup
-#   define strdup _strdup
-#  endif
+   platforms by defining GNULIB_NAMESPACE::strdup always.  */
+#  if defined _WIN32 && !defined __CYGWIN__
+#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#    undef strdup
+#    define strdup _strdup
+#   endif
 _GL_CXXALIAS_MDA (strdup, char *, (char const *__s));
-# else
-#  if defined __cplusplus && defined GNULIB_NAMESPACE && defined strdup
-#   undef strdup
-#  endif
+#  else
+#   if defined __cplusplus && defined GNULIB_NAMESPACE && defined strdup
+#    undef strdup
+#   endif
 _GL_CXXALIAS_SYS (strdup, char *, (char const *__s));
-# endif
+#  endif
 _GL_CXXALIASWARN (strdup);
+# endif
 #endif
 
 /* Append no more than N characters from SRC onto DEST.  */
diff --git a/lib/strnlen.c b/lib/strnlen.c
index c27a0392c2..ded06ce23f 100644
--- a/lib/strnlen.c
+++ b/lib/strnlen.c
@@ -2,18 +2,18 @@
    Copyright (C) 2005-2007, 2009-2021 Free Software Foundation, Inc.
    Written by Simon Josefsson.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
diff --git a/lib/strtoimax.c b/lib/strtoimax.c
index 37a25c31d4..bf8534a767 100644
--- a/lib/strtoimax.c
+++ b/lib/strtoimax.c
@@ -3,17 +3,17 @@
    Copyright (C) 1999, 2001-2004, 2006, 2009-2021 Free Software Foundation,
    Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert. */
diff --git a/lib/strtol.c b/lib/strtol.c
index 2f2159b623..c49321ba0c 100644
--- a/lib/strtol.c
+++ b/lib/strtol.c
@@ -6,17 +6,17 @@
    NOTE: The canonical source of this file is maintained with the GNU C
    Library.  Bugs can be reported to bug-glibc@gnu.org.
 
-   This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3 of the License, or any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifdef _LIBC
@@ -51,6 +51,7 @@
 
 /* Determine the name.  */
 #ifdef USE_IN_EXTENDED_LOCALE_MODEL
+# undef strtol
 # if UNSIGNED
 #  ifdef USE_WIDE_CHAR
 #   ifdef QUAD
@@ -82,6 +83,7 @@
 # endif
 #else
 # if UNSIGNED
+#  undef strtol
 #  ifdef USE_WIDE_CHAR
 #   ifdef QUAD
 #    define strtol wcstoull
@@ -97,6 +99,7 @@
 #  endif
 # else
 #  ifdef USE_WIDE_CHAR
+#   undef strtol
 #   ifdef QUAD
 #    define strtol wcstoll
 #   else
@@ -104,6 +107,7 @@
 #   endif
 #  else
 #   ifdef QUAD
+#    undef strtol
 #    define strtol strtoll
 #   endif
 #  endif
@@ -131,6 +135,12 @@
 #endif
 
 
+#ifdef USE_NUMBER_GROUPING
+# define GROUP_PARAM_PROTO , int group
+#else
+# define GROUP_PARAM_PROTO
+#endif
+
 /* We use this code also for the extended locale handling where the
    function gets as an additional argument the locale which has to be
    used.  To access the values we have to redefine the _NL_CURRENT
@@ -166,19 +176,23 @@
 # define UCHAR_TYPE unsigned char
 # define STRING_TYPE char
 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
-#  define ISSPACE(Ch) __isspace_l ((Ch), loc)
-#  define ISALPHA(Ch) __isalpha_l ((Ch), loc)
-#  define TOUPPER(Ch) __toupper_l ((Ch), loc)
+#  define ISSPACE(Ch) __isspace_l ((unsigned char) (Ch), loc)
+#  define ISALPHA(Ch) __isalpha_l ((unsigned char) (Ch), loc)
+#  define TOUPPER(Ch) __toupper_l ((unsigned char) (Ch), loc)
 # else
-#  define ISSPACE(Ch) isspace (Ch)
-#  define ISALPHA(Ch) isalpha (Ch)
-#  define TOUPPER(Ch) toupper (Ch)
+#  define ISSPACE(Ch) isspace ((unsigned char) (Ch))
+#  define ISALPHA(Ch) isalpha ((unsigned char) (Ch))
+#  define TOUPPER(Ch) toupper ((unsigned char) (Ch))
 # endif
 #endif
 
-#define INTERNAL(X) INTERNAL1(X)
-#define INTERNAL1(X) __##X##_internal
-#define WEAKNAME(X) WEAKNAME1(X)
+#ifdef USE_NUMBER_GROUPING
+# define INTERNAL(X) INTERNAL1(X)
+# define INTERNAL1(X) __##X##_internal
+# define WEAKNAME(X) WEAKNAME1(X)
+#else
+# define INTERNAL(X) X
+#endif
 
 #ifdef USE_NUMBER_GROUPING
 /* This file defines a function to check for correct grouping.  */
@@ -196,7 +210,7 @@
 
 INT
 INTERNAL (strtol) (const STRING_TYPE *nptr, STRING_TYPE **endptr,
-                   int base, int group LOCALE_PARAM_PROTO)
+                   int base GROUP_PARAM_PROTO LOCALE_PARAM_PROTO)
 {
   int negative;
   register unsigned LONG int cutoff;
@@ -379,15 +393,16 @@ noconv:
   return 0L;
 }
 
+#ifdef USE_NUMBER_GROUPING
 /* External user entry point.  */
 
-
 INT
-#ifdef weak_function
+# ifdef weak_function
 weak_function
-#endif
+# endif
 strtol (const STRING_TYPE *nptr, STRING_TYPE **endptr,
         int base LOCALE_PARAM_PROTO)
 {
   return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM);
 }
+#endif
diff --git a/lib/strtoll.c b/lib/strtoll.c
index 30daefc50f..8e6f93faeb 100644
--- a/lib/strtoll.c
+++ b/lib/strtoll.c
@@ -3,17 +3,17 @@
    Inc.
    This file is part of the GNU C Library.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #define QUAD    1
diff --git a/lib/symlink.c b/lib/symlink.c
index 2f6c0d484b..4bb0884aca 100644
--- a/lib/symlink.c
+++ b/lib/symlink.c
@@ -1,17 +1,17 @@
 /* Stub for symlink().
    Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
@@ -47,8 +47,8 @@ rpl_symlink (char const *contents, char const *name)
 
 /* The system does not support symlinks.  */
 int
-symlink (char const *contents _GL_UNUSED,
-         char const *name _GL_UNUSED)
+symlink (_GL_UNUSED char const *contents,
+         _GL_UNUSED char const *name)
 {
   errno = ENOSYS;
   return -1;
diff --git a/lib/sys_random.in.h b/lib/sys_random.in.h
index 5b9280dda3..1abd6c544e 100644
--- a/lib/sys_random.in.h
+++ b/lib/sys_random.in.h
@@ -1,18 +1,18 @@
 /* Substitute for <sys/random.h>.
    Copyright (C) 2020-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 # if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
diff --git a/lib/sys_select.in.h b/lib/sys_select.in.h
index 1dacb21087..910bea5d12 100644
--- a/lib/sys_select.in.h
+++ b/lib/sys_select.in.h
@@ -1,18 +1,18 @@
 /* Substitute for <sys/select.h>.
    Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 # if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
@@ -21,7 +21,7 @@
 
 /* On OSF/1 and Solaris 2.6, <sys/types.h> and <sys/time.h>
    both include <sys/select.h>.
-   On Cygwin, <sys/time.h> includes <sys/select.h>.
+   On Cygwin and OpenBSD, <sys/time.h> includes <sys/select.h>.
    Simply delegate to the system's header in this case.  */
 #if (@HAVE_SYS_SELECT_H@                                                \
      && !defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TYPES_H             \
@@ -39,6 +39,7 @@
            || (!defined _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H       \
                && ((defined __osf__ && defined _SYS_TIME_H_             \
                     && defined _OSF_SOURCE)                             \
+                   || (defined __OpenBSD__ && defined _SYS_TIME_H_)     \
                    || (defined __sun && defined _SYS_TIME_H             \
                        && (! (defined _XOPEN_SOURCE                     \
                               || defined _POSIX_C_SOURCE)               \
diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h
index 13d12943cd..babe3dba3e 100644
--- a/lib/sys_stat.in.h
+++ b/lib/sys_stat.in.h
@@ -1,18 +1,18 @@
 /* Provide a more complete sys/stat.h header file.
    Copyright (C) 2005-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Eric Blake, Paul Eggert, and Jim Meyering.  */
 
diff --git a/lib/sys_time.in.h b/lib/sys_time.in.h
index 90a67d1842..8035fbe7ec 100644
--- a/lib/sys_time.in.h
+++ b/lib/sys_time.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
 
diff --git a/lib/sys_types.in.h b/lib/sys_types.in.h
index 654e80335f..2079d72efc 100644
--- a/lib/sys_types.in.h
+++ b/lib/sys_types.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
diff --git a/lib/tempname.c b/lib/tempname.c
index e243483eaf..7675aa076d 100644
--- a/lib/tempname.c
+++ b/lib/tempname.c
@@ -2,16 +2,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
@@ -181,13 +181,13 @@ try_file (char *tmpl, void *flags)
 }
 
 static int
-try_dir (char *tmpl, void *flags _GL_UNUSED)
+try_dir (char *tmpl, _GL_UNUSED void *flags)
 {
   return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
 }
 
 static int
-try_nocreate (char *tmpl, void *flags _GL_UNUSED)
+try_nocreate (char *tmpl, _GL_UNUSED void *flags)
 {
   struct_stat64 st;
 
diff --git a/lib/tempname.h b/lib/tempname.h
index a8681fc998..795bb49764 100644
--- a/lib/tempname.h
+++ b/lib/tempname.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* header written by Eric Blake */
diff --git a/lib/time-internal.h b/lib/time-internal.h
index 067ee729ed..6bbd0a727b 100644
--- a/lib/time-internal.h
+++ b/lib/time-internal.h
@@ -2,18 +2,18 @@
 
    Copyright 2015-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
 
diff --git a/lib/time.in.h b/lib/time.in.h
index 1385980cdf..a73fe59cbb 100644
--- a/lib/time.in.h
+++ b/lib/time.in.h
@@ -2,18 +2,18 @@
 
    Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if __GNUC__ >= 3
 @PRAGMA_SYSTEM_HEADER@
@@ -340,22 +340,60 @@ _GL_CXXALIASWARN (strftime);
 # endif
 
 # if defined _GNU_SOURCE && @GNULIB_TIME_RZ@ && ! @HAVE_TIMEZONE_T@
+/* Functions that use a first-class time zone data type, instead of
+   relying on an implicit global time zone.
+   Inspired by NetBSD.  */
+
+/* Represents a time zone.
+   (timezone_t) NULL stands for UTC.  */
 typedef struct tm_zone *timezone_t;
+
+/* tzalloc (name)
+   Returns a time zone object for the given time zone NAME.  This object
+   represents the time zone that other functions would use it the TZ
+   environment variable was set to NAME.
+   If NAME is NULL, the result represents the time zone that other functions
+   would use it the TZ environment variable was unset.
+   May return NULL if NAME is invalid (this is platform dependent) or
+   upon memory allocation failure.  */
 _GL_FUNCDECL_SYS (tzalloc, timezone_t, (char const *__name));
 _GL_CXXALIAS_SYS (tzalloc, timezone_t, (char const *__name));
+
+/* tzfree (tz)
+   Frees a time zone object.
+   The argument must have been returned by tzalloc().  */
 _GL_FUNCDECL_SYS (tzfree, void, (timezone_t __tz));
 _GL_CXXALIAS_SYS (tzfree, void, (timezone_t __tz));
+
+/* localtime_rz (tz, &t, &result)
+   Converts an absolute time T to a broken-down time RESULT, assuming the
+   time zone TZ.
+   This function is like 'localtime_r', but relies on the argument TZ instead
+   of an implicit global time zone.  */
 _GL_FUNCDECL_SYS (localtime_rz, struct tm *,
                   (timezone_t __tz, time_t const *restrict __timer,
                    struct tm *restrict __result) _GL_ARG_NONNULL ((2, 3)));
 _GL_CXXALIAS_SYS (localtime_rz, struct tm *,
                   (timezone_t __tz, time_t const *restrict __timer,
                    struct tm *restrict __result));
+
+/* mktime_z (tz, &tm)
+   Normalizes the broken-down time TM and converts it to an absolute time,
+   assuming the time zone TZ.  Returns the absolute time.
+   This function is like 'mktime', but relies on the argument TZ instead
+   of an implicit global time zone.  */
 _GL_FUNCDECL_SYS (mktime_z, time_t,
-                  (timezone_t __tz, struct tm *restrict __result)
+                  (timezone_t __tz, struct tm *restrict __tm)
                   _GL_ARG_NONNULL ((2)));
 _GL_CXXALIAS_SYS (mktime_z, time_t,
-                  (timezone_t __tz, struct tm *restrict __result));
+                  (timezone_t __tz, struct tm *restrict __tm));
+
+/* Time zone abbreviation strings (returned by 'localtime_rz' or 'mktime_z'
+   in the 'tm_zone' member of 'struct tm') are valid as long as
+     - the 'struct tm' argument is not destroyed or overwritten,
+   and
+     - the 'timezone_t' argument is not freed through tzfree().  */
+
 # endif
 
 /* Convert TM to a time_t value, assuming UTC.  */
diff --git a/lib/time_r.c b/lib/time_r.c
index d908986870..88d3c1c76f 100644
--- a/lib/time_r.c
+++ b/lib/time_r.c
@@ -2,18 +2,18 @@
 
    Copyright (C) 2003, 2006-2007, 2010-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
 
diff --git a/lib/time_rz.c b/lib/time_rz.c
index 3ac053c621..e7722447c0 100644
--- a/lib/time_rz.c
+++ b/lib/time_rz.c
@@ -2,18 +2,18 @@
 
    Copyright 2015-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
 
diff --git a/lib/timegm.c b/lib/timegm.c
index e4127e71c0..7e723e1fb8 100644
--- a/lib/timegm.c
+++ b/lib/timegm.c
@@ -4,16 +4,16 @@
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public
+   modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
-   version 3 of the License, or (at your option) any later version.
+   version 2.1 of the License, or (at your option) any later version.
 
    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public
+   You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
diff --git a/lib/timespec.c b/lib/timespec.c
index 2b6098ed7b..957b5fbba4 100644
--- a/lib/timespec.c
+++ b/lib/timespec.c
@@ -1,3 +1,21 @@
+/* Inline functions for <timespec.h>.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define _GL_TIMESPEC_INLINE _GL_EXTERN_INLINE
 #include "timespec.h"
diff --git a/lib/timespec.h b/lib/timespec.h
index 9a71e9ea89..94a5db751f 100644
--- a/lib/timespec.h
+++ b/lib/timespec.h
@@ -3,17 +3,17 @@
    Copyright (C) 2000, 2002, 2004-2005, 2007, 2009-2021 Free Software
    Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #if ! defined TIMESPEC_H
diff --git a/lib/u64.c b/lib/u64.c
index 1e3854ddcd..c905af626f 100644
--- a/lib/u64.c
+++ b/lib/u64.c
@@ -1,4 +1,22 @@
+/* uint64_t-like operations that work even on hosts lacking uint64_t
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define _GL_U64_INLINE _GL_EXTERN_INLINE
 #include "u64.h"
 typedef int dummy;
diff --git a/lib/u64.h b/lib/u64.h
index ad719c84f8..8d21ec17ed 100644
--- a/lib/u64.h
+++ b/lib/u64.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/unistd.c b/lib/unistd.c
index 72bad1c052..0763456021 100644
--- a/lib/unistd.c
+++ b/lib/unistd.c
@@ -1,4 +1,22 @@
+/* Inline functions for <unistd.h>.
+
+   Copyright (C) 2012-2021 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
 #include <config.h>
+
 #define _GL_UNISTD_INLINE _GL_EXTERN_INLINE
 #include "unistd.h"
 typedef int dummy;
diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index 5e9b47d981..73c882f97b 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -1,18 +1,18 @@
 /* Substitute for and wrapper around <unistd.h>.
    Copyright (C) 2003-2021 Free Software Foundation, Inc.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3, or (at your option)
-   any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef _@GUARD_PREFIX@_UNISTD_H
 
@@ -1521,6 +1521,7 @@ _GL_WARN_ON_USE (group_member, "group_member is 
unportable - "
 #   undef isatty
 #   define isatty rpl_isatty
 #  endif
+#  define GNULIB_defined_isatty 1
 _GL_FUNCDECL_RPL (isatty, int, (int fd));
 _GL_CXXALIAS_RPL (isatty, int, (int fd));
 # elif defined _WIN32 && !defined __CYGWIN__
@@ -2027,15 +2028,23 @@ _GL_WARN_ON_USE (sleep, "sleep is unportable - "
 #if @GNULIB_MDA_SWAB@
 /* On native Windows, map 'swab' to '_swab', so that -loldnames is not
    required.  In C++ with GNULIB_NAMESPACE, avoid differences between
-   platforms by defining GNULIB_NAMESPACE::creat always.  */
+   platforms by defining GNULIB_NAMESPACE::swab always.  */
 # if defined _WIN32 && !defined __CYGWIN__
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   undef swab
 #   define swab _swab
 #  endif
-_GL_CXXALIAS_MDA (swab, void, (char *from, char *to, int n));
+/* Need to cast, because in old mingw the arguments are
+                             (const char *from, char *to, size_t n).  */
+_GL_CXXALIAS_MDA_CAST (swab, void, (char *from, char *to, int n));
 # else
+#  if defined __hpux /* HP-UX */
+_GL_CXXALIAS_SYS (swab, void, (const char *from, char *to, int n));
+#  elif defined __sun && !defined _XPG4 /* Solaris */
+_GL_CXXALIAS_SYS (swab, void, (const char *from, char *to, ssize_t n));
+#  else
 _GL_CXXALIAS_SYS (swab, void, (const void *from, void *to, ssize_t n));
+#  endif
 # endif
 _GL_CXXALIASWARN (swab);
 #endif
diff --git a/lib/unlocked-io.h b/lib/unlocked-io.h
index 86b91c19dd..ca184b31fb 100644
--- a/lib/unlocked-io.h
+++ b/lib/unlocked-io.h
@@ -33,91 +33,91 @@
 
 # include <stdio.h>
 
-# if HAVE_DECL_CLEARERR_UNLOCKED
+# if HAVE_DECL_CLEARERR_UNLOCKED || defined clearerr_unlocked
 #  undef clearerr
 #  define clearerr(x) clearerr_unlocked (x)
 # else
 #  define clearerr_unlocked(x) clearerr (x)
 # endif
 
-# if HAVE_DECL_FEOF_UNLOCKED
+# if HAVE_DECL_FEOF_UNLOCKED || defined feof_unlocked
 #  undef feof
 #  define feof(x) feof_unlocked (x)
 # else
 #  define feof_unlocked(x) feof (x)
 # endif
 
-# if HAVE_DECL_FERROR_UNLOCKED
+# if HAVE_DECL_FERROR_UNLOCKED || defined ferror_unlocked
 #  undef ferror
 #  define ferror(x) ferror_unlocked (x)
 # else
 #  define ferror_unlocked(x) ferror (x)
 # endif
 
-# if HAVE_DECL_FFLUSH_UNLOCKED
+# if HAVE_DECL_FFLUSH_UNLOCKED || defined fflush_unlocked
 #  undef fflush
 #  define fflush(x) fflush_unlocked (x)
 # else
 #  define fflush_unlocked(x) fflush (x)
 # endif
 
-# if HAVE_DECL_FGETS_UNLOCKED
+# if HAVE_DECL_FGETS_UNLOCKED || defined fgets_unlocked
 #  undef fgets
 #  define fgets(x,y,z) fgets_unlocked (x,y,z)
 # else
 #  define fgets_unlocked(x,y,z) fgets (x,y,z)
 # endif
 
-# if HAVE_DECL_FPUTC_UNLOCKED
+# if HAVE_DECL_FPUTC_UNLOCKED || defined fputc_unlocked
 #  undef fputc
 #  define fputc(x,y) fputc_unlocked (x,y)
 # else
 #  define fputc_unlocked(x,y) fputc (x,y)
 # endif
 
-# if HAVE_DECL_FPUTS_UNLOCKED
+# if HAVE_DECL_FPUTS_UNLOCKED || defined fputs_unlocked
 #  undef fputs
 #  define fputs(x,y) fputs_unlocked (x,y)
 # else
 #  define fputs_unlocked(x,y) fputs (x,y)
 # endif
 
-# if HAVE_DECL_FREAD_UNLOCKED
+# if HAVE_DECL_FREAD_UNLOCKED || defined fread_unlocked
 #  undef fread
 #  define fread(w,x,y,z) fread_unlocked (w,x,y,z)
 # else
 #  define fread_unlocked(w,x,y,z) fread (w,x,y,z)
 # endif
 
-# if HAVE_DECL_FWRITE_UNLOCKED
+# if HAVE_DECL_FWRITE_UNLOCKED || defined fwrite_unlocked
 #  undef fwrite
 #  define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z)
 # else
 #  define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
 # endif
 
-# if HAVE_DECL_GETC_UNLOCKED
+# if HAVE_DECL_GETC_UNLOCKED || defined get_unlocked
 #  undef getc
 #  define getc(x) getc_unlocked (x)
 # else
 #  define getc_unlocked(x) getc (x)
 # endif
 
-# if HAVE_DECL_GETCHAR_UNLOCKED
+# if HAVE_DECL_GETCHAR_UNLOCKED || defined getchar_unlocked
 #  undef getchar
 #  define getchar() getchar_unlocked ()
 # else
 #  define getchar_unlocked() getchar ()
 # endif
 
-# if HAVE_DECL_PUTC_UNLOCKED
+# if HAVE_DECL_PUTC_UNLOCKED || defined putc_unlocked
 #  undef putc
 #  define putc(x,y) putc_unlocked (x,y)
 # else
 #  define putc_unlocked(x,y) putc (x,y)
 # endif
 
-# if HAVE_DECL_PUTCHAR_UNLOCKED
+# if HAVE_DECL_PUTCHAR_UNLOCKED || defined putchar_unlocked
 #  undef putchar
 #  define putchar(x) putchar_unlocked (x)
 # else
diff --git a/lib/utimens.c b/lib/utimens.c
index 44d1ea003e..a34180050e 100644
--- a/lib/utimens.c
+++ b/lib/utimens.c
@@ -2,17 +2,17 @@
 
    Copyright (C) 2003-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3 of the License, or any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
@@ -126,14 +126,14 @@ validate_timespec (struct timespec timespec[2])
   return result + (utime_omit_count == 1);
 }
 
-/* Normalize any UTIME_NOW or UTIME_OMIT values in *TS, using stat
-   buffer STATBUF to obtain the current timestamps of the file.  If
+/* Normalize any UTIME_NOW or UTIME_OMIT values in (*TS)[0] and (*TS)[1],
+   using STATBUF to obtain the current timestamps of the file.  If
    both times are UTIME_NOW, set *TS to NULL (as this can avoid some
    permissions issues).  If both times are UTIME_OMIT, return true
    (nothing further beyond the prior collection of STATBUF is
    necessary); otherwise return false.  */
 static bool
-update_timespec (struct stat const *statbuf, struct timespec *ts[2])
+update_timespec (struct stat const *statbuf, struct timespec **ts)
 {
   struct timespec *timespec = *ts;
   if (timespec[0].tv_nsec == UTIME_OMIT
diff --git a/lib/utimens.h b/lib/utimens.h
index 295d3d71cc..d17953c052 100644
--- a/lib/utimens.h
+++ b/lib/utimens.h
@@ -2,17 +2,17 @@
 
    Copyright 2012-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 3 of the License, or any
-   later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 3 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert.  */
diff --git a/lib/verify.h b/lib/verify.h
index 65514c34b9..a8ca59b093 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 2005-2006, 2009-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* Written by Paul Eggert, Bruno Haible, and Jim Meyering.  */
@@ -25,7 +25,7 @@
    works as per C11.  This is supported by GCC 4.6.0+ and by clang 4+.
 
    Define _GL_HAVE__STATIC_ASSERT1 to 1 if _Static_assert (R) works as
-   per C2X.  This is supported by GCC 9.1+.
+   per C2x.  This is supported by GCC 9.1+.
 
    Support compilers claiming conformance to the relevant standard,
    and also support GCC when not pedantic.  If we were willing to slow
@@ -202,7 +202,7 @@ template <int w>
 
    This macro requires three or more arguments but uses at most the first
    two, so that the _Static_assert macro optionally defined below supports
-   both the C11 two-argument syntax and the C2X one-argument syntax.
+   both the C11 two-argument syntax and the C2x one-argument syntax.
 
    Unfortunately, unlike C11, this implementation must appear as an
    ordinary declaration, and cannot appear inside struct { ... }.  */
diff --git a/lib/warn-on-use.h b/lib/warn-on-use.h
index 5d5b17f05b..612937abb0 100644
--- a/lib/warn-on-use.h
+++ b/lib/warn-on-use.h
@@ -2,16 +2,16 @@
    Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 3 of the License, or
+   under the terms of the GNU Lesser General Public License as published
+   by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* _GL_WARN_ON_USE (function, "literal string") issues a declaration
diff --git a/lib/xalloc-oversized.h b/lib/xalloc-oversized.h
index 53daf59663..4184f33955 100644
--- a/lib/xalloc-oversized.h
+++ b/lib/xalloc-oversized.h
@@ -2,17 +2,17 @@
 
    Copyright (C) 1990-2000, 2003-2004, 2006-2021 Free Software Foundation, Inc.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful,
+   This file is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GNU Lesser General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef XALLOC_OVERSIZED_H_
@@ -21,34 +21,39 @@
 #include <stddef.h>
 #include <stdint.h>
 
-/* True if N * S would overflow in a size_t calculation,
-   or would generate a value larger than PTRDIFF_MAX.
+/* True if N * S does not fit into both ptrdiff_t and size_t.
+   N and S should be nonnegative and free of side effects.
    This expands to a constant expression if N and S are both constants.
-   By gnulib convention, SIZE_MAX represents overflow in size
+   By gnulib convention, SIZE_MAX represents overflow in size_t
    calculations, so the conservative size_t-based dividend to use here
    is SIZE_MAX - 1.  */
 #define __xalloc_oversized(n, s) \
-  ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n))
+  ((s) != 0 \
+   && ((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) \
+       < (n)))
 
-#if PTRDIFF_MAX < SIZE_MAX
-typedef ptrdiff_t __xalloc_count_type;
-#else
-typedef size_t __xalloc_count_type;
-#endif
+/* Return 1 if and only if an array of N objects, each of size S,
+   cannot exist reliably because its total size in bytes would exceed
+   MIN (PTRDIFF_MAX, SIZE_MAX - 1).
+
+   N and S should be nonnegative and free of side effects.
 
-/* Return 1 if an array of N objects, each of size S, cannot exist
-   reliably due to size or ptrdiff_t arithmetic overflow.  S must be
-   positive and N must be nonnegative.  This is a macro, not a
-   function, so that it works correctly even when SIZE_MAX < N.  */
+   Warning: (xalloc_oversized (N, S) ? NULL : malloc (N * S)) can
+   misbehave if N and S are both narrower than ptrdiff_t and size_t,
+   and can be rewritten as (xalloc_oversized (N, S) ?  NULL
+   : malloc (N * (size_t) S)).
 
-#if 7 <= __GNUC__ && !defined __clang__
+   This is a macro, not a function, so that it works even if an
+   argument exceeds MAX (PTRDIFF_MAX, SIZE_MAX).  */
+#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX
 # define xalloc_oversized(n, s) \
-   __builtin_mul_overflow_p (n, s, (__xalloc_count_type) 1)
-#elif 5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__
+   __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1)
+#elif (5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ \
+       && PTRDIFF_MAX < SIZE_MAX)
 # define xalloc_oversized(n, s) \
    (__builtin_constant_p (n) && __builtin_constant_p (s) \
     ? __xalloc_oversized (n, s) \
-    : ({ __xalloc_count_type __xalloc_count; \
+    : ({ ptrdiff_t __xalloc_count; \
          __builtin_mul_overflow (n, s, &__xalloc_count); }))
 
 /* Other compilers use integer division; this may be slower but is
diff --git a/lisp/ChangeLog.15 b/lisp/ChangeLog.15
index bd1fbe61ad..29fbe47489 100644
--- a/lisp/ChangeLog.15
+++ b/lisp/ChangeLog.15
@@ -17307,7 +17307,7 @@
        * simple.el (normal-erase-is-backspace-mode): Use input-decode-map
        rather than fiddling with global-map bindings, since it should only
        affect per-terminal settings.
-       See http://bugs.gentoo.org/show_bug.cgi?id=289709.
+       See https://bugs.gentoo.org/show_bug.cgi?id=289709.
 
        * minibuffer.el (completion-table-with-terminator): Allow to specify
        the terminator-regexp.
diff --git a/lisp/Makefile.in b/lisp/Makefile.in
index 431217a9da..3e764c5a78 100644
--- a/lisp/Makefile.in
+++ b/lisp/Makefile.in
@@ -91,8 +91,19 @@ COMPILE_FIRST = \
        $(lisp)/emacs-lisp/byte-opt.elc \
        $(lisp)/emacs-lisp/bytecomp.elc
 ifeq ($(HAVE_NATIVE_COMP),yes)
-COMPILE_FIRST += $(lisp)/emacs-lisp/comp.elc
-COMPILE_FIRST += $(lisp)/emacs-lisp/comp-cstr.elc
+COMPILE_FIRST += \
+       $(lisp)/emacs-lisp/comp.elc \
+       $(lisp)/emacs-lisp/comp-cstr.elc \
+       $(lisp)/emacs-lisp/cl-macs.elc \
+       $(lisp)/emacs-lisp/rx.elc \
+       $(lisp)/emacs-lisp/cl-seq.elc \
+       $(lisp)/help-mode.elc \
+       $(lisp)/emacs-lisp/cl-extra.elc \
+       $(lisp)/emacs-lisp/gv.elc \
+       $(lisp)/emacs-lisp/seq.elc \
+       $(lisp)/emacs-lisp/cl-lib.elc \
+       $(lisp)/emacs-lisp/warnings.elc \
+       $(lisp)/emacs-lisp/subr-x.elc
 endif
 COMPILE_FIRST += $(lisp)/emacs-lisp/autoload.elc
 
@@ -281,6 +292,14 @@ else
                -f batch-byte-compile $(THEFILE)
 endif
 
+ifeq ($(HAVE_NATIVE_COMP),yes)
+.PHONY: $(THEFILE)n
+$(THEFILE)n:
+       $(AM_V_ELN)$(emacs) $(BYTE_COMPILE_FLAGS) \
+               -l comp -f byte-compile-refresh-preloaded \
+               --eval '(batch-native-compile t)' $(THEFILE)
+endif
+
 # Files MUST be compiled one by one. If we compile several files in a
 # row (i.e., in the same instance of Emacs) we can't make sure that
 # the compilation environment is clean.  We also set the load-path of
diff --git a/lisp/abbrev.el b/lisp/abbrev.el
index f370bd3ea6..d3daf637cc 100644
--- a/lisp/abbrev.el
+++ b/lisp/abbrev.el
@@ -583,6 +583,7 @@ PROPS is a property list.  The following properties are 
special:
 An obsolete but still supported calling form is:
 
 \(define-abbrev TABLE NAME EXPANSION &optional HOOK COUNT SYSTEM)."
+  (declare (indent defun))
   (when (and (consp props) (or (null (car props)) (numberp (car props))))
     ;; Old-style calling convention.
     (setq props `(:count ,(car props)
@@ -973,11 +974,11 @@ full text instead of the abbrevs that expand into that 
text."
        (buf (get-buffer-create "*abbrev-suggest*")))
     (set-buffer buf)
     (erase-buffer)
-        (insert "** Abbrev expansion usage **
+        (insert (substitute-command-keys "** Abbrev expansion usage **
 
 Below is a list of expansions for which abbrevs are defined, and
 the number of times the expansion was typed manually.  To display
-and edit all abbrevs, type `M-x edit-abbrevs RET'\n\n")
+and edit all abbrevs, type \\[edit-abbrevs].\n\n"))
        (dolist (expansion totals)
          (insert (format " %s: %d\n" (car expansion) (cdr expansion))))
        (display-buffer buf)))
@@ -1139,7 +1140,7 @@ Properties with special meaning:
 - `:enable-function' can be set to a function of no argument which returns
   non-nil if and only if the abbrevs in this table should be used for this
   instance of `expand-abbrev'."
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   ;; We used to manually add the docstring, but we also want to record this
   ;; location as the definition of the variable (in load-history), so we may
   ;; as well just use `defvar'.
diff --git a/lisp/align.el b/lisp/align.el
index 7ced7b7044..2fd6dcda6d 100644
--- a/lisp/align.el
+++ b/lisp/align.el
@@ -553,8 +553,7 @@ The possible settings for `align-region-separate' are:
      (modes    . align-text-modes)
      (repeat   . t)
      (run-if   . ,(lambda ()
-                    (and current-prefix-arg
-                         (not (eq '- current-prefix-arg))))))
+                    (not (eq '- current-prefix-arg)))))
 
     ;; With a negative prefix argument, lists of dollar figures will
     ;; be aligned.
@@ -836,11 +835,22 @@ See the variable `align-exclude-rules-list' for more 
details.")
 ;;;###autoload
 (defun align (beg end &optional separate rules exclude-rules)
   "Attempt to align a region based on a set of alignment rules.
-BEG and END mark the region.  If BEG and END are specifically set to
-nil (this can only be done programmatically), the beginning and end of
-the current alignment section will be calculated based on the location
-of point, and the value of `align-region-separate' (or possibly each
-rule's `separate' attribute).
+Interactively, BEG and END are the mark/point of the current region.
+
+Many modes define specific alignment rules, and some of these
+rules in some modes react to the current prefix argument.  For
+instance, in `text-mode', `M-x align' will align into columns
+based on space delimiters, while `C-u - M-x align' will align
+into columns based on the \"$\" character.  See the
+`align-rules-list' variable definition for the specific rules.
+
+Also see `align-regexp', which will guide you through various
+parameters for aligning text.
+
+Non-interactively, if BEG and END are nil, the beginning and end
+of the current alignment section will be calculated based on the
+location of point, and the value of `align-region-separate' (or
+possibly each rule's `separate' attribute).
 
 If SEPARATE is non-nil, it overrides the value of
 `align-region-separate' for all rules, except those that have their
@@ -889,6 +899,15 @@ on the format of these lists."
 BEG and END mark the limits of the region.  Interactively, this function
 prompts for the regular expression REGEXP to align with.
 
+Interactively, if you specify a prefix argument, the function
+will guide you through entering the full regular expression, and
+then prompts for which subexpression parenthesis GROUP (default
+1) within REGEXP to modify, the amount of SPACING (default
+`align-default-spacing') to use, and whether or not to REPEAT the
+rule throughout the line.
+
+See `align-rules-list' for more information about these options.
+
 For example, let's say you had a list of phone numbers, and wanted to
 align them so that the opening parentheses would line up:
 
@@ -908,15 +927,8 @@ regular expression after you enter it.  Interactively, you 
only
 need to supply the characters to be lined up, and any preceding
 whitespace is replaced.
 
-Non-interactively (or if you specify a prefix argument), you must
-enter the full regular expression, including the subexpression.
-Interactively, the function also then prompts for which
-subexpression parenthesis GROUP (default 1) within REGEXP to
-modify, the amount of SPACING (default `align-default-spacing')
-to use, and whether or not to REPEAT the rule throughout the
-line.
-
-See `align-rules-list' for more information about these options.
+Non-interactively, you must enter the full regular expression,
+including the subexpression.
 
 The non-interactive form of the previous example would look something like:
   (align-regexp (point-min) (point-max) \"\\\\(\\\\s-*\\\\)(\")
@@ -928,7 +940,7 @@ construct a rule to pass to `align-region', which does the 
real work."
     (list (region-beginning) (region-end))
     (if current-prefix-arg
        (list (read-string "Complex align using regexp: "
-                          "\\(\\s-*\\)" 'align-regexp-history)
+                           "\\(\\s-*\\) " 'align-regexp-history)
              (string-to-number
               (read-string
                "Parenthesis group to modify (justify if negative): " "1"))
diff --git a/lisp/allout-widgets.el b/lisp/allout-widgets.el
index 668e7b91e8..f18d488854 100644
--- a/lisp/allout-widgets.el
+++ b/lisp/allout-widgets.el
@@ -880,7 +880,7 @@ encompassing condition-case."
     ;; reraise the error, or one concerning this function if unexpected:
     (if (equal mode 'error)
         (apply #'signal args)
-      (error "%s: unexpected mode, %s %s" this mode args))))
+      (error "%s: Unexpected mode, %s %s" this mode args))))
 ;;;_   > allout-widgets-changes-exceed-threshold-p ()
 (defun allout-widgets-adjusting-message (message)
   "Post MESSAGE when pending are likely to make a big enough delay.
diff --git a/lisp/allout.el b/lisp/allout.el
index c123e8ded4..174184fc7a 100644
--- a/lisp/allout.el
+++ b/lisp/allout.el
@@ -823,12 +823,12 @@ such topics are encrypted.)"
   :group 'allout-encryption)
 (make-variable-buffer-local 'allout-encrypt-unencrypted-on-saves)
 (defvar allout-auto-save-temporarily-disabled nil
-  "True while topic encryption is pending and auto-saving was active.
+  "Non-nil while topic encryption is pending and auto-saving was active.
 
 The value of `buffer-saved-size' at the time of decryption is used,
 for restoring when all encryptions are established.")
 (defvar-local allout-just-did-undo nil
-  "True just after undo commands, until allout-post-command-business.")
+  "Non-nil just after undo commands, until allout-post-command-business.")
 
 ;;;_ + Developer
 ;;;_  = allout-developer group
@@ -3079,6 +3079,8 @@ Move to buffer limit in indicated direction if headings 
are exhausted."
          (backward (if (< arg 0) (setq arg (* -1 arg))))
         (step (if backward -1 1))
          (progress (allout-current-bullet-pos))
+         ;; Move to the next physical line.
+         (line-move-visual nil)
         prev got)
 
     (while (> arg 0)
@@ -3190,7 +3192,7 @@ Set by `allout-pre-command-business', to support allout 
addons in
 coordinating with allout activity.")
 ;;;_   = allout-this-command-hid-text
 (defvar-local allout-this-command-hid-text nil
-  "True if the most recent allout-mode command hid any text.")
+  "Non-nil if the most recent `allout-mode' command hid any text.")
 ;;;_   > allout-post-command-business ()
 (defun allout-post-command-business ()
   "Outline `post-command-hook' function.
@@ -4787,7 +4789,7 @@ Useful for coherently exposing to a random point in a 
hidden region."
                   (setq bag-it (1+ bag-it))
                    (if (> bag-it 1)
                        (error "allout-show-to-offshoot: %s"
-                              "Stumped by aberrant nesting.")))
+                              "Stumped by aberrant nesting")))
           (if (> bag-it 0) (setq bag-it 0))
           (allout-show-children)
           (goto-char orig-pref)))
@@ -5402,7 +5404,7 @@ Defaults:
          ;; Specified but not a buffer -- get it:
          (let ((got (get-buffer frombuf)))
            (if (not got)
-               (error "allout-process-exposed: source buffer %s not found."
+                (error "allout-process-exposed: Source buffer %s not found"
                       frombuf)
              (setq frombuf got))))
     ;; not specified -- default it:
diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el
index 4315a7f3ce..2e51264ec3 100644
--- a/lisp/ansi-color.el
+++ b/lisp/ansi-color.el
@@ -90,53 +90,168 @@ as a PDF file."
   :version "21.1"
   :group 'processes)
 
+(defface ansi-color-bold
+  '((t :inherit 'bold))
+  "Face used to render bold text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-faint
+  '((t :weight light))
+  "Face used to render faint text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-italic
+  '((t :inherit 'italic))
+  "Face used to render italic text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-underline
+  '((t :inherit 'underline))
+  "Face used to render underlined text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-slow-blink
+  '((t :box (:line-width -1)))
+  "Face used to render slowly blinking text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-fast-blink
+  '((t :box (:line-width -1)))
+  "Face used to render rapidly blinking text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-inverse
+  '((t :inverse-video t))
+  "Face used to render inverted video text."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-black
+  '((t :foreground "black" :background "black"))
+  "Face used to render black color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-red
+  '((t :foreground "red3" :background "red3"))
+  "Face used to render red color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-green
+  '((t :foreground "green3" :background "green3"))
+  "Face used to render green color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-yellow
+  '((t :foreground "yellow3" :background "yellow3"))
+  "Face used to render yellow color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-blue
+  '((t :foreground "blue2" :background "blue2"))
+  "Face used to render blue color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-magenta
+  '((t :foreground "magenta3" :background "magenta3"))
+  "Face used to render magenta color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-cyan
+  '((t :foreground "cyan3" :background "cyan3"))
+  "Face used to render cyan color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-white
+  '((t :foreground "grey90" :background "gray90"))
+  "Face used to render white color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-black
+  '((t :foreground "gray30" :background "gray30"))
+  "Face used to render bright black color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-red
+  '((t :foreground "red2" :background "red2"))
+  "Face used to render bright red color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-green
+  '((t :foreground "green2" :background "green2"))
+  "Face used to render bright green color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-yellow
+  '((t :foreground "yellow2" :background "yellow2"))
+  "Face used to render bright yellow color code."
+  :group 'ansi-colors)
+
+(defface ansi-color-bright-blue
+  '((t :foreground "blue1" :background "blue1"))
+  "Face used to render bright blue color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-magenta
+  '((t :foreground "magenta2" :background "magenta2"))
+  "Face used to render bright magenta color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-cyan
+  '((t :foreground "cyan2" :background "cyan2"))
+  "Face used to render bright cyan color code."
+  :group 'ansi-colors
+  :version "28.1")
+
+(defface ansi-color-bright-white
+  '((t :foreground "white" :background "white"))
+  "Face used to render bright white color code."
+  :group 'ansi-colors
+  :version "28.1")
+
 (defcustom ansi-color-faces-vector
   [default bold default italic underline success warning error]
   "Faces used for SGR control sequences determining a face.
 This vector holds the faces used for SGR control sequence parameters 0
 to 7.
 
-Parameter  Description        Face used by default
-  0        default            default
-  1        bold               bold
-  2        faint              default
-  3        italic             italic
-  4        underlined         underline
-  5        slowly blinking    success
-  6        rapidly blinking   warning
-  7        negative image     error
-
-Note that the symbol `default' is special: It will not be combined
-with the current face.
-
-This vector is used by `ansi-color-make-color-map' to create a color
-map.  This color map is stored in the variable `ansi-color-map'."
+This variable is obsolete.  To customize the display of faces used by
+ansi-color, change 'ansi-color-FACE', e.g. `ansi-color-bold'.  To
+customize the actual faces used (e.g. to temporarily display SGR
+control sequences differently), use `ansi-color-basic-faces-vector'."
   :type '(vector face face face face face face face face)
-  :set 'ansi-color-map-update
-  :initialize 'custom-initialize-default
   :group 'ansi-colors)
+(make-obsolete-variable 'ansi-color-faces-vector 'ansi-color-basic-faces-vector
+                        "28.1")
 
 (defcustom ansi-color-names-vector
   ["black" "red3" "green3" "yellow3" "blue2" "magenta3" "cyan3" "gray90"]
   "Colors used for SGR control sequences determining a color.
-This vector holds the colors used for SGR control sequences parameters
+This vector holds the colors used for SGR control sequence parameters
 30 to 37 (foreground colors) and 40 to 47 (background colors).
 
-Parameter  Color
-  30  40   black
-  31  41   red
-  32  42   green
-  33  43   yellow
-  34  44   blue
-  35  45   magenta
-  36  46   cyan
-  37  47   white
-
-This vector is used by `ansi-color-make-color-map' to create a color
-map.  This color map is stored in the variable `ansi-color-map'.
-
-Each element may also be a cons cell where the car and cdr specify the
-foreground and background colors, respectively."
+This variable is obsolete.  To customize the display of colors used by
+ansi-color, change 'ansi-color-COLOR', e.g. `ansi-color-red'.  To
+customize the actual faces used (e.g. to temporarily display SGR
+control sequences differently), use `ansi-color-normal-colors-vector'."
   :type '(vector (choice color (cons color color))
                  (choice color (cons color color))
                  (choice color (cons color color))
@@ -145,10 +260,87 @@ foreground and background colors, respectively."
                  (choice color (cons color color))
                  (choice color (cons color color))
                  (choice color (cons color color)))
-  :set 'ansi-color-map-update
-  :initialize 'custom-initialize-default
   :version "24.4" ; default colors copied from `xterm-standard-colors'
   :group 'ansi-colors)
+(make-obsolete-variable 'ansi-color-faces-vector
+                        'ansi-color-normal-colors-vector "28.1")
+
+(defvar ansi-color-basic-faces-vector
+  [nil
+   ansi-color-bold
+   ansi-color-faint
+   ansi-color-italic
+   ansi-color-underline
+   ansi-color-slow-blink
+   ansi-color-fast-blink
+   ansi-color-inverse]
+  "Faces used for SGR control sequences determining a face.
+This vector holds the faces used for SGR control sequence parameters 0
+to 7.
+
+Parameter  Description
+  0        default
+  1        bold
+  2        faint
+  3        italic
+  4        underlined
+  5        slowly blinking
+  6        rapidly blinking
+  7        negative image")
+
+(defvar ansi-color-normal-colors-vector
+  [ansi-color-black
+   ansi-color-red
+   ansi-color-green
+   ansi-color-yellow
+   ansi-color-blue
+   ansi-color-magenta
+   ansi-color-cyan
+   ansi-color-white]
+  "Faces used for SGR control sequences determining a color.
+This vector holds the faces used for SGR control sequence parameters
+30 to 37 (foreground colors) and 40 to 47 (background colors).
+
+Parameter  Color
+  30  40   black
+  31  41   red
+  32  42   green
+  33  43   yellow
+  34  44   blue
+  35  45   magenta
+  36  46   cyan
+  37  47   white")
+
+(defvar ansi-color-bright-colors-vector
+  [ansi-color-bright-black
+   ansi-color-bright-red
+   ansi-color-bright-green
+   ansi-color-bright-yellow
+   ansi-color-bright-blue
+   ansi-color-bright-magenta
+   ansi-color-bright-cyan
+   ansi-color-bright-white]
+  "Faces used for SGR control sequences determining a \"bright\" color.
+This vector holds the faces used for SGR control sequence parameters
+90 to 97 (bright foreground colors) and 100 to 107 (bright background
+colors).
+
+Parameter   Color
+  90  100   bright black
+  91  101   bright red
+  92  102   bright green
+  93  103   bright yellow
+  94  104   bright blue
+  95  105   bright magenta
+  96  106   bright cyan
+  97  107   bright white")
+
+(defcustom ansi-color-bold-is-bright nil
+  "If set to non-nil, combining ANSI bold and a color produces the bright
+version of that color."
+  :type 'boolean
+  :version "28.1"
+  :group 'ansi-colors)
 
 (defconst ansi-color-control-seq-regexp
   ;; See ECMA 48, section 5.4 "Control Sequences".
@@ -266,11 +458,18 @@ variable, and is meant to be used in 
`compilation-filter-hook'."
 ;; Working with strings
 (defvar-local ansi-color-context nil
   "Context saved between two calls to `ansi-color-apply'.
-This is a list of the form (CODES FRAGMENT) or nil.  CODES
+This is a list of the form (FACE-VEC FRAGMENT) or nil.  FACE-VEC
 represents the state the last call to `ansi-color-apply' ended
-with, currently a list of ansi codes, and FRAGMENT is a string
-starting with an escape sequence, possibly the start of a new
-escape sequence.")
+with, currently a list of the form:
+
+  (BASIC-FACES FG BG)
+
+BASIC-FACES is a bool-vector that specifies which basic faces
+from `ansi-color-basic-faces-vector' to apply.  FG and BG are
+ANSI color codes for the foreground and background color.
+
+FRAGMENT is a string starting with an escape sequence, possibly
+the start of a new escape sequence.")
 
 (defun ansi-color-filter-apply (string)
   "Filter out all ANSI control sequences from STRING.
@@ -281,17 +480,17 @@ will be used for the next call to `ansi-color-apply'.  Set
 `ansi-color-context' to nil if you don't want this.
 
 This function can be added to `comint-preoutput-filter-functions'."
-  (let ((start 0) end result)
+  (let ((context (ansi-color--ensure-context 'ansi-color-context nil))
+        (start 0) end result)
     ;; if context was saved and is a string, prepend it
-    (if (cadr ansi-color-context)
-        (setq string (concat (cadr ansi-color-context) string)
-              ansi-color-context nil))
+    (setq string (concat (cadr context) string))
+    (setcar (cdr context) "")
     ;; find the next escape sequence
     (while (setq end (string-match ansi-color-control-seq-regexp string start))
       (push (substring string start end) result)
       (setq start (match-end 0)))
     ;; save context, add the remainder of the string to the result
-    (let (fragment)
+    (let ((fragment ""))
       (push (substring string start
                        (if (string-match "\033" string start)
                            (let ((pos (match-beginning 0)))
@@ -299,31 +498,16 @@ This function can be added to 
`comint-preoutput-filter-functions'."
                              pos)
                          nil))
             result)
-      (setq ansi-color-context (if fragment (list nil fragment))))
+      (setcar (cdr context) fragment))
     (apply #'concat (nreverse result))))
 
-(defun ansi-color--find-face (codes)
-  "Return the face corresponding to CODES."
-  (let (faces)
-    (while codes
-      (let ((face (ansi-color-get-face-1 (pop codes))))
-       ;; In the (default underline) face, say, the value of the
-       ;; "underline" attribute of the `default' face wins.
-       (unless (eq face 'default)
-         (push face faces))))
-    ;; Avoid some long-lived conses in the common case.
-    (if (cdr faces)
-       (nreverse faces)
-      (car faces))))
-
 (defun ansi-color-apply (string)
   "Translates SGR control sequences into text properties.
 Delete all other control sequences without processing them.
 
 Applies SGR control sequences setting foreground and background colors
-to STRING using text properties and returns the result.  The colors used
-are given in `ansi-color-faces-vector' and `ansi-color-names-vector'.
-See function `ansi-color-apply-sequence' for details.
+to STRING using text properties and returns the result.  See function
+`ansi-color-apply-sequence' for details.
 
 Every call to this function will set and use the buffer-local variable
 `ansi-color-context' to save partial escape sequences and current ansi codes.
@@ -331,49 +515,157 @@ This information will be used for the next call to 
`ansi-color-apply'.
 Set `ansi-color-context' to nil if you don't want this.
 
 This function can be added to `comint-preoutput-filter-functions'."
-  (let ((codes (car ansi-color-context))
-       (start 0) end result)
+  (let* ((context
+          (ansi-color--ensure-context 'ansi-color-context nil))
+         (face-vec (car context))
+         (start 0)
+         end result)
     ;; If context was saved and is a string, prepend it.
-    (if (cadr ansi-color-context)
-        (setq string (concat (cadr ansi-color-context) string)
-              ansi-color-context nil))
+    (setq string (concat (cadr context) string))
+    (setcar (cdr context) "")
     ;; Find the next escape sequence.
     (while (setq end (string-match ansi-color-control-seq-regexp string start))
       (let ((esc-end (match-end 0)))
         ;; Colorize the old block from start to end using old face.
-        (when codes
+        (when-let ((face (ansi-color--face-vec-face face-vec)))
           (put-text-property start end 'font-lock-face
-                             (ansi-color--find-face codes) string))
+                             face string))
         (push (substring string start end) result)
         (setq start (match-end 0))
         ;; If this is a color escape sequence,
         (when (eq (aref string (1- esc-end)) ?m)
           ;; create a new face from it.
-          (setq codes (ansi-color-apply-sequence
-                       (substring string end esc-end) codes)))))
+          (let ((cur-pos end))
+            (ansi-color--update-face-vec
+             face-vec
+             (lambda ()
+               (when (string-match ansi-color-parameter-regexp
+                                   string cur-pos)
+                 (setq cur-pos (match-end 0))
+                 (when (<= cur-pos esc-end)
+                   (string-to-number (match-string 1 string))))))))))
     ;; if the rest of the string should have a face, put it there
-    (when codes
+    (when-let ((face (ansi-color--face-vec-face face-vec)))
       (put-text-property start (length string)
-                         'font-lock-face (ansi-color--find-face codes) string))
+                         'font-lock-face face string))
     ;; save context, add the remainder of the string to the result
-    (let (fragment)
-      (if (string-match "\033" string start)
-         (let ((pos (match-beginning 0)))
-           (setq fragment (substring string pos))
-           (push (substring string start pos) result))
-       (push (substring string start) result))
-      (setq ansi-color-context (if (or codes fragment) (list codes fragment))))
+    (if (string-match "\033" string start)
+        (let ((pos (match-beginning 0)))
+          (setcar (cdr context) (substring string pos))
+          (push (substring string start pos) result))
+      (push (substring string start) result))
     (apply 'concat (nreverse result))))
 
+(defun ansi-color--ensure-context (context-sym position)
+  "Return CONTEXT-SYM's value as a valid context.
+If it is nil, set CONTEXT-SYM's value to a new context and return
+it. Context is a list of the form as described in
+`ansi-color-context' if POSITION is nil, or
+`ansi-color-context-region' if POSITION is non-nil.
+
+If CONTEXT-SYM's value is already non-nil, return it. If its
+marker doesn't point anywhere yet, position it before character
+number POSITION, if non-nil."
+  (let ((context (symbol-value context-sym)))
+    (if context
+        (if position
+            (let ((marker (cadr context)))
+              (unless (marker-position marker)
+                (set-marker marker position))
+              context)
+          context)
+      (set context-sym
+           (list (list (make-bool-vector 8 nil)
+                       nil nil)
+                 (if position
+                     (copy-marker position)
+                   ""))))))
+
+(defun ansi-color--face-vec-face (face-vec)
+  "Return the face corresponding to FACE-VEC.
+FACE-VEC is a list containing information about the ANSI sequence
+code.  It is usually stored as the car of the variable
+`ansi-color-context-region'."
+  (let* ((basic-faces (car face-vec))
+         (colors (cdr face-vec))
+         (bright (and ansi-color-bold-is-bright (aref basic-faces 1)))
+         (faces nil))
+
+    (when-let ((fg (car colors)))
+      (push
+       `(:foreground
+         ,(or (ansi-color--code-as-hex fg)
+              (face-foreground
+               (aref (if (or bright (>= fg 8))
+                         ansi-color-bright-colors-vector
+                       ansi-color-normal-colors-vector)
+                     (mod fg 8))
+               nil 'default)))
+       faces))
+    (when-let ((bg (cadr colors)))
+      (push
+       `(:background
+         ,(or (ansi-color--code-as-hex bg)
+              (face-background
+               (aref (if (or bright (>= bg 8))
+                         ansi-color-bright-colors-vector
+                       ansi-color-normal-colors-vector)
+                     (mod bg 8))
+               nil 'default)))
+       faces))
+
+    (let ((i 8))
+      (while (> i 0)
+        (setq i (1- i))
+        (when (aref basic-faces i)
+          (push (aref ansi-color-basic-faces-vector i) faces))))
+    ;; Avoid some long-lived conses in the common case.
+    (if (cdr faces)
+        faces
+      (car faces))))
+
+(defun ansi-color--code-as-hex (color)
+  "Convert COLOR to hexadecimal string representation.
+COLOR is an ANSI color code.  If it is between 16 and 255
+inclusive, it corresponds to a color from an 8-bit color cube.
+If it is greater or equal than 256, it is subtracted by 256 to
+directly specify a 24-bit color.
+
+Return a hexadecimal string, specifying the color, or nil, if
+COLOR is less than 16."
+  (cond
+   ((< color 16) nil)
+   ((>= color 256) (format "#%06X" (- color 256)))
+   ((>= color 232) ;; Grayscale
+    (format "#%06X" (* #x010101 (+ 8 (* 10 (- color 232))))))
+   (t ;; 6x6x6 color cube
+    (setq color (- color 16))
+    (let ((res 0)
+          (frac (* 6 6)))
+      (while (<= 1 frac)                ; Repeat 3 times
+        (setq res (* res #x000100))
+        (let ((color-num (mod (/ color frac) 6)))
+          (unless (zerop color-num)
+            (setq res (+ res #x37 (* #x28 color-num)))))
+        (setq frac (/ frac 6)))
+      (format "#%06X" res)))))
+
 ;; Working with regions
 
 (defvar-local ansi-color-context-region nil
   "Context saved between two calls to `ansi-color-apply-on-region'.
-This is a list of the form (CODES MARKER) or nil.  CODES
+This is a list of the form (FACE-VEC MARKER) or nil.  FACE-VEC
 represents the state the last call to `ansi-color-apply-on-region'
-ended with, currently a list of ansi codes, and MARKER is a
-buffer position within an escape sequence or the last position
-processed.")
+ended with, currently a list of the form:
+
+  (BASIC-FACES FG BG).
+
+BASIC-FACES is a bool-vector that specifies which basic faces
+from `ansi-color-basic-faces-vector' to apply.  FG and BG are
+ANSI color codes for the foreground and background color.
+
+MARKER is a buffer position within an escape sequence or the last
+position processed.")
 
 (defun ansi-color-filter-region (begin end)
   "Filter out all ANSI control sequences from region BEGIN to END.
@@ -383,8 +675,10 @@ Every call to this function will set and use the 
buffer-local variable
 used for the next call to `ansi-color-apply-on-region'.  Specifically,
 it will override BEGIN, the start of the region.  Set
 `ansi-color-context-region' to nil if you don't want this."
-  (let ((end-marker (copy-marker end))
-       (start (or (cadr ansi-color-context-region) begin)))
+  (let* ((end-marker (copy-marker end))
+         (context (ansi-color--ensure-context
+                   'ansi-color-context-region begin))
+         (start (cadr context)))
     (save-excursion
       (goto-char start)
       ;; Delete escape sequences.
@@ -392,8 +686,8 @@ it will override BEGIN, the start of the region.  Set
         (delete-region (match-beginning 0) (match-end 0)))
       ;; save context, add the remainder of the string to the result
       (if (re-search-forward "\033" end-marker t)
-         (setq ansi-color-context-region (list nil (match-beginning 0)))
-       (setq ansi-color-context-region nil)))))
+         (set-marker start (match-beginning 0))
+        (set-marker start nil)))))
 
 (defun ansi-color-apply-on-region (begin end &optional preserve-sequences)
   "Translates SGR control sequences into overlays or extents.
@@ -402,8 +696,7 @@ Delete all other control sequences without processing them.
 SGR control sequences are applied by calling the function
 specified by `ansi-color-apply-face-function'.  The default
 function sets foreground and background colors to the text
-between BEGIN and END, using overlays.  The colors used are given
-in `ansi-color-faces-vector' and `ansi-color-names-vector'.  See
+between BEGIN and END, using overlays.  See function
 `ansi-color-apply-sequence' for details.
 
 Every call to this function will set and use the buffer-local
@@ -416,58 +709,58 @@ this.
 
 If PRESERVE-SEQUENCES is t, the sequences are hidden instead of
 being deleted."
-  (let ((codes (car ansi-color-context-region))
-        (start-marker (or (cadr ansi-color-context-region)
-                          (copy-marker begin)))
-        (end-marker (copy-marker end)))
+  (let* ((context (ansi-color--ensure-context
+                   'ansi-color-context-region begin))
+         (face-vec (car context))
+         (start-marker (cadr context))
+         (end-marker (copy-marker end)))
     (save-excursion
       (goto-char start-marker)
       ;; Find the next escape sequence.
       (while (re-search-forward ansi-color-control-seq-regexp end-marker t)
         ;; Extract escape sequence.
-        (let ((esc-seq (buffer-substring
-                        (match-beginning 0) (point))))
-          (if preserve-sequences
-              ;; Make the escape sequence transparent.
-              (overlay-put (make-overlay (match-beginning 0) (point))
-                           'invisible t)
-            ;; Otherwise, strip.
-            (delete-region (match-beginning 0) (point)))
-
+        (let ((esc-beg (match-beginning 0))
+              (esc-end (point)))
           ;; Colorize the old block from start to end using old face.
           (funcall ansi-color-apply-face-function
                    (prog1 (marker-position start-marker)
                      ;; Store new start position.
-                     (set-marker start-marker (point)))
-                   (match-beginning 0) (ansi-color--find-face codes))
+                     (set-marker start-marker esc-end))
+                   esc-beg (ansi-color--face-vec-face face-vec))
           ;; If this is a color sequence,
-          (when (eq (aref esc-seq (1- (length esc-seq))) ?m)
-            ;; update the list of ansi codes.
-            (setq codes (ansi-color-apply-sequence esc-seq codes)))))
+          (when (eq (char-before esc-end) ?m)
+            (goto-char esc-beg)
+            (ansi-color--update-face-vec
+             face-vec (lambda ()
+                        (when (re-search-forward ansi-color-parameter-regexp
+                                                 esc-end t)
+                          (string-to-number (match-string 1))))))
+
+          (if preserve-sequences
+              ;; Make the escape sequence transparent.
+              (overlay-put (make-overlay esc-beg esc-end) 'invisible t)
+            ;; Otherwise, strip.
+            (delete-region esc-beg esc-end))))
       ;; search for the possible start of a new escape sequence
       (if (re-search-forward "\033" end-marker t)
-         (progn
-           ;; if the rest of the region should have a face, put it there
-           (funcall ansi-color-apply-face-function
-                    start-marker (point) (ansi-color--find-face codes))
-           ;; save codes and point
-           (setq ansi-color-context-region
-                 (list codes (copy-marker (match-beginning 0)))))
-       ;; if the rest of the region should have a face, put it there
-       (funcall ansi-color-apply-face-function
-                start-marker end-marker (ansi-color--find-face codes))
-        ;; Save a restart position when there are codes active. It's
-        ;; convenient for man.el's process filter to pass `begin'
-        ;; positions that overlap regions previously colored; these
-        ;; `codes' should not be applied to that overlap, so we need
-        ;; to know where they should really start.
-       (setq ansi-color-context-region
-              (if codes (list codes (copy-marker (point)))))))
-    ;; Clean up our temporary markers.
-    (unless (eq start-marker (cadr ansi-color-context-region))
-      (set-marker start-marker nil))
-    (unless (eq end-marker (cadr ansi-color-context-region))
-      (set-marker end-marker nil))))
+          (progn
+            (while (re-search-forward "\033" end-marker t))
+            (backward-char)
+            (funcall ansi-color-apply-face-function
+                     start-marker (point)
+                     (ansi-color--face-vec-face face-vec))
+            (set-marker start-marker (point)))
+        (let ((faces (ansi-color--face-vec-face face-vec)))
+          (funcall ansi-color-apply-face-function
+                   start-marker end-marker faces)
+          ;; Save a restart position when there are codes active. It's
+          ;; convenient for man.el's process filter to pass `begin'
+          ;; positions that overlap regions previously colored; these
+          ;; `codes' should not be applied to that overlap, so we need
+          ;; to know where they should really start.
+          (set-marker start-marker (when faces end-marker)))))
+    ;; Clean up our temporary marker.
+    (set-marker end-marker nil)))
 
 (defun ansi-color-apply-overlay-face (beg end face)
   "Make an overlay from BEG to END, and apply face FACE.
@@ -570,11 +863,12 @@ ESCAPE-SEQUENCE is an escape sequence parsed by
 
 For each new code, the following happens: if it is 1-7, add it to
 the list of codes; if it is 21-25 or 27, delete appropriate
-parameters from the list of codes; if it is 30-37 resp. 39, the
-foreground color code is replaced or added resp. deleted; if it
-is 40-47 resp. 49, the background color code is replaced or added
-resp. deleted; any other code is discarded together with the old
-codes. Finally, the so changed list of codes is returned."
+parameters from the list of codes; if it is 30-37 (or 90-97) resp. 39,
+the foreground color code is replaced or added resp. deleted; if it
+is 40-47 (or 100-107) resp. 49, the background color code is replaced
+or added resp. deleted; any other code is discarded together with the
+old codes.  Finally, the so changed list of codes is returned."
+  (declare (obsolete ansi-color--update-face-vec "29.1"))
   (let ((new-codes (ansi-color-parse-sequence escape-sequence)))
     (while new-codes
       (let* ((new (pop new-codes))
@@ -591,7 +885,7 @@ codes.      Finally, the so changed list of codes is 
returned."
                                        (22 (remq 1 codes))
                                        (25 (remq 6 codes))
                                        (_ codes)))))
-               ((or 3 4) (let ((r (mod new 10)))
+               ((or 3 4 9 10) (let ((r (mod new 10)))
                            (unless (= r 8)
                              (let (beg)
                                (while (and codes (/= q (/ (car codes) 10)))
@@ -603,6 +897,72 @@ codes.     Finally, the so changed list of codes is 
returned."
                (_ nil)))))
     codes))
 
+(defun ansi-color--update-face-vec (face-vec iterator)
+  "Apply escape sequences to FACE-VEC.
+
+Destructively modify FACE-VEC, which should be a list containing
+face information.  It is described in
+`ansi-color-context-region'.  ITERATOR is a function which is
+called repeatedly with zero arguments and should return either
+the next ANSI code in the current sequence as a number or nil if
+there are no more ANSI codes left.
+
+For each new code, the following happens: if it is 1-7, set the
+corresponding properties; if it is 21-25 or 27, unset appropriate
+properties; if it is 30-37 (or 90-97) or resp. 39, set the
+foreground color or resp. unset it; if it is 40-47 (or 100-107)
+resp. 49, set the background color or resp. unset it; if it is 38
+or 48, the following codes are used to set the foreground or
+background color and the correct color mode; any other code will
+unset all properties and colors."
+  (let ((basic-faces (car face-vec))
+        (colors (cdr face-vec))
+        new q do-clear)
+    (while (setq new (funcall iterator))
+      (setq q (/ new 10))
+      (pcase q
+        (0 (if (memq new '(0 8 9))
+               (setq do-clear t)
+             (aset basic-faces new t)))
+        (2 (if (memq new '(20 26 28 29))
+               (setq do-clear t)
+             ;; The standard says `21 doubly underlined' while
+             ;; https://en.wikipedia.org/wiki/ANSI_escape_code claims
+             ;; `21 Bright/Bold: off or Underline: Double'.
+             (aset basic-faces (- new 20) nil)
+             (aset basic-faces (pcase new (22 1) (25 6) (_ 0)) nil)))
+        ((or 3 4 9 10)
+         (let ((r (mod new 10))
+               (cell (if (memq q '(3 9)) colors (cdr colors))))
+           (pcase r
+             (8
+              (pcase (funcall iterator)
+                (5 (setq new (setcar cell (funcall iterator)))
+                   (setq do-clear (or (null new) (>= new 256))))
+                (2
+                 (let ((red (funcall iterator))
+                       (green (funcall iterator))
+                       (blue (funcall iterator)))
+                   (if (and red green blue
+                            (progn
+                              (setq new (+ (* #x010000 red)
+                                           (* #x000100 green)
+                                           (* #x000001 blue)))
+                              (<= new #xFFFFFF)))
+                       (setcar cell (+ 256 new))
+                     (setq do-clear t))))
+                (_ (setq do-clear t))))
+             (9 (setcar cell nil))
+             (_ (setcar cell (+ (if (memq q '(3 4)) 0 8) r))))))
+        (_ (setq do-clear t)))
+
+      (when do-clear
+        (setq do-clear nil)
+        ;; Zero out our bool vector without any allocation.
+        (bool-vector-intersection basic-faces #&8"\0" basic-faces)
+        (setcar colors nil)
+        (setcar (cdr colors) nil)))))
+
 (defun ansi-color-make-color-map ()
   "Create a vector of face definitions and return it.
 
@@ -610,7 +970,9 @@ The index into the vector is an ANSI code.  See the 
documentation of
 `ansi-color-map' for an example.
 
 The face definitions are based upon the variables
-`ansi-color-faces-vector' and `ansi-color-names-vector'."
+`ansi-color-faces-vector' and `ansi-color-names-vector'.
+
+This function is obsolete, and no longer needed to use ansi-color."
   (let ((map (make-vector 50 nil))
         (index 0))
     ;; miscellaneous attributes
@@ -638,34 +1000,58 @@ The face definitions are based upon the variables
        (setq index (1+ index)) )
      ansi-color-names-vector)
     map))
+(make-obsolete 'ansi-color-make-color-map "you can remove it." "28.1")
 
-(defvar ansi-color-map (ansi-color-make-color-map)
-  "A brand new color map suitable for `ansi-color-get-face'.
+(defvar ansi-color-map
+  (with-no-warnings (ansi-color-make-color-map))
+  "A brand new color map, formerly suitable for `ansi-color-get-face'.
 
 The value of this variable is usually constructed by
 `ansi-color-make-color-map'.  The values in the array are such that the
 numbers included in an SGR control sequences point to the correct
 foreground or background colors.
 
-Example: The sequence \\033[34m specifies a blue foreground.  Therefore:
-     (aref ansi-color-map 34)
-          => (foreground-color . \"blue\")")
+This variable is obsolete, and no longer needed to use ansi-color.")
+(make-obsolete-variable 'ansi-color-map "you can remove it." "28.1")
 
 (defun ansi-color-map-update (symbol value)
   "Update `ansi-color-map'.
 
-Whenever the vectors used to construct `ansi-color-map' are changed,
-this function is called.  Therefore this function is listed as the :set
-property of `ansi-color-faces-vector' and `ansi-color-names-vector'."
+This function is obsolete, and no longer needed to use ansi-color."
   (set-default symbol value)
-  (setq ansi-color-map (ansi-color-make-color-map)))
-
-(defun ansi-color-get-face-1 (ansi-code)
-  "Get face definition from `ansi-color-map'.
-ANSI-CODE is used as an index into the vector."
-  (condition-case nil
-      (aref ansi-color-map ansi-code)
-    (args-out-of-range nil)))
+  (with-no-warnings
+    (setq ansi-color-map (ansi-color-make-color-map))))
+(make-obsolete 'ansi-color-map-update "you can remove it." "28.1")
+
+(defun ansi-color-get-face-1 (ansi-code &optional bright)
+  "Get face definition for ANSI-CODE.
+BRIGHT, if non-nil, requests \"bright\" ANSI colors, even if ANSI-CODE
+is a normal-intensity color."
+  (declare (obsolete ansi-color--face-vec-face "29.1"))
+  (when (and bright (<= 30 ansi-code 49))
+    (setq ansi-code (+ ansi-code 60)))
+  (cond ((<= 0 ansi-code 7)
+         (aref ansi-color-basic-faces-vector ansi-code))
+        ((<= 30 ansi-code 38)
+         (list :foreground
+               (face-foreground
+                (aref ansi-color-normal-colors-vector (- ansi-code 30))
+                nil 'default)))
+        ((<= 40 ansi-code 48)
+         (list :background
+               (face-background
+                (aref ansi-color-normal-colors-vector (- ansi-code 40))
+                nil 'default)))
+        ((<= 90 ansi-code 98)
+         (list :foreground
+               (face-foreground
+                (aref ansi-color-bright-colors-vector (- ansi-code 90))
+                nil 'default)))
+        ((<= 100 ansi-code 108)
+         (list :background
+               (face-background
+                (aref ansi-color-bright-colors-vector (- ansi-code 100))
+                nil 'default)))))
 
 (provide 'ansi-color)
 
diff --git a/lisp/apropos.el b/lisp/apropos.el
index fc15cd3e01..00919ed91b 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -515,9 +515,9 @@ variables, not just user options."
                      current-prefix-arg))
   (apropos-command pattern nil
                   (if (or do-all apropos-do-all)
-                      #'(lambda (symbol)
-                          (and (boundp symbol)
-                               (get symbol 'variable-documentation)))
+                       (lambda (symbol)
+                         (and (boundp symbol)
+                              (get symbol 'variable-documentation)))
                     #'custom-variable-p)))
 
 ;;;###autoload
diff --git a/lisp/array.el b/lisp/array.el
index 6632da55dd..2c9a6815d2 100644
--- a/lisp/array.el
+++ b/lisp/array.el
@@ -805,8 +805,9 @@ NOT recognized as integers or real numbers.
   The array MUST reside at the top of the buffer.
 
   TABs are not respected, and may be converted into spaces at any time.
-Setting the variable `array-respect-tabs' to non-nil will prevent TAB 
conversion,
-but will cause many functions to give errors if they encounter one.
+Setting the variable `array-respect-tabs' to non-nil will prevent
+TAB conversion, but will cause many functions to give errors if
+they encounter one.
 
   Upon entering array mode, you will be prompted for the values of
 several variables.  Others will be calculated based on the values you
diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el
index 063d0a14d6..b448c0f8da 100644
--- a/lisp/autoinsert.el
+++ b/lisp/autoinsert.el
@@ -415,6 +415,7 @@ Matches the visited file name against the elements of 
`auto-insert-alist'."
   "Associate CONDITION with (additional) ACTION in `auto-insert-alist'.
 Optional AFTER means to insert action after all existing actions for CONDITION,
 or if CONDITION had no actions, after all other CONDITIONs."
+  (declare (indent defun))
   (let ((elt (assoc condition auto-insert-alist)))
     (if elt
        (setcdr elt
diff --git a/lisp/avoid.el b/lisp/avoid.el
index d3afecf8cc..03707d1046 100644
--- a/lisp/avoid.el
+++ b/lisp/avoid.el
@@ -43,7 +43,7 @@
 ;;
 ;; (if (eq window-system 'x)
 ;;     (mouse-avoidance-set-pointer-shape
-;;          (nth (random 4)
+;;          (seq-random-elt
 ;;               (list x-pointer-man x-pointer-spider
 ;;                     x-pointer-gobbler x-pointer-gumby))))
 ;;
@@ -125,7 +125,6 @@ TOP-OR-BOTTOM-POS: Distance from top or bottom edge of 
frame or window."
 ;; Internal variables
 (defvar mouse-avoidance-state nil)
 (defvar mouse-avoidance-pointer-shapes nil)
-(defvar mouse-avoidance-n-pointer-shapes 0)
 (defvar mouse-avoidance-old-pointer-shape nil)
 (defvar mouse-avoidance-animating-pointer nil)
 
@@ -306,11 +305,8 @@ redefine this function to suit your own tastes."
                      (all-completions "x-pointer-" obarray
                                       (lambda (x)
                                          (and (boundp x)
-                                              (integerp (symbol-value x)))))))
-       (setq mouse-avoidance-n-pointer-shapes
-             (length mouse-avoidance-pointer-shapes))))
-  (nth (random mouse-avoidance-n-pointer-shapes)
-       mouse-avoidance-pointer-shapes))
+                                               (integerp (symbol-value 
x)))))))))
+  (seq-random-elt mouse-avoidance-pointer-shapes))
 
 (defun mouse-avoidance-ignore-p ()
   (let ((mp (mouse-position)))
diff --git a/lisp/bindings.el b/lisp/bindings.el
index 343f1ba0fa..121e484a0e 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -505,7 +505,7 @@ mouse-1: Display Line and Column Mode Menu"))
      local-map ,mode-line-column-line-number-mode-map
      mouse-face mode-line-highlight
      ;; XXX needs better description
-     help-echo "Size indication mode\n\
+     help-echo "Window Scroll Percentage
 mouse-1: Display Line and Column Mode Menu")
     (size-indication-mode
      (8 ,(propertize
@@ -981,7 +981,7 @@ if `inhibit-field-text-motion' is non-nil."
 (define-key ctl-x-map "\M-:" 'repeat-complex-command)
 (define-key ctl-x-map "u" 'undo)
 (put 'undo :advertised-binding [?\C-x ?u])
-;; Many people are used to typing C-/ on X terminals and getting C-_.
+;; Many people are used to typing C-/ on GUI frames and getting C-_.
 (define-key global-map [?\C-/] 'undo)
 (define-key global-map "\C-_" 'undo)
 ;; Richard said that we should not use C-x <uppercase letter> and I have
@@ -994,6 +994,9 @@ if `inhibit-field-text-motion' is non-nil."
   "Keymap to repeat undo key sequences `C-x u u'.  Used in `repeat-mode'.")
 (put 'undo 'repeat-map 'undo-repeat-map)
 
+(define-key global-map '[(control ??)] 'undo-redo)
+(define-key global-map [?\C-\M-_] 'undo-redo)
+
 (define-key esc-map "!" 'shell-command)
 (define-key esc-map "|" 'shell-command-on-region)
 (define-key esc-map "&" 'async-shell-command)
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index d64966df5a..a4c28e751c 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -479,7 +479,7 @@ See user option `bookmark-set-fringe'."
       (dolist (buf (buffer-list))
         (with-current-buffer buf
           (when (equal filename buffer-file-name)
-            (setq overlays (overlays-in pos pos))
+            (setq overlays (overlays-in pos (1+ pos)))
             (while (and (not found) (setq temp (pop overlays)))
               (when (eq 'bookmark (overlay-get temp 'category))
                 (delete-overlay (setq found temp))))))))))
@@ -498,11 +498,8 @@ If DEFAULT is nil then return empty string for empty 
input."
                                                'string-lessp)
                                        (bookmark-all-names)))
     (let* ((completion-ignore-case bookmark-completion-ignore-case)
-           (default (unless (equal "" default) default))
-          (prompt (concat prompt (if default
-                                      (format " (%s): " default)
-                                    ": "))))
-      (completing-read prompt
+           (default (unless (equal "" default) default)))
+      (completing-read (format-prompt prompt default)
                        (lambda (string pred action)
                          (if (eq action 'metadata)
                              '(metadata (category . bookmark))
@@ -2317,10 +2314,10 @@ Prompt with completion for the new path."
             (lambda ()
               (setq timer (run-with-idle-timer
                            bookmark-search-delay 'repeat
-                           #'(lambda (buf)
-                               (with-current-buffer buf
-                                 (bookmark-bmenu-filter-alist-by-regexp
-                                  (minibuffer-contents))))
+                           (lambda (buf)
+                             (with-current-buffer buf
+                               (bookmark-bmenu-filter-alist-by-regexp
+                                (minibuffer-contents))))
                            (current-buffer))))
           (read-string "Pattern: ")
           (when timer (cancel-timer timer) (setq timer nil)))
diff --git a/lisp/button.el b/lisp/button.el
index aedd07b762..e3f91cb4a6 100644
--- a/lisp/button.el
+++ b/lisp/button.el
@@ -130,6 +130,7 @@ In addition, the keyword argument :supertype may be used to 
specify a
 `button-type' from which NAME inherits its default property values
 (however, the inheritance happens only when NAME is defined; subsequent
 changes to a supertype are not reflected in its subtypes)."
+  (declare (indent defun))
   (let ((catsym (make-symbol (concat (symbol-name name) "-button")))
        (super-catsym
         (button-category-symbol
@@ -615,13 +616,19 @@ button at point is the button to describe."
       (button--describe props)
       t)))
 
-(defun button-buttonize (string callback &optional data)
+(define-obsolete-function-alias 'button-buttonize #'buttonize "29.1")
+
+(defun buttonize (string callback &optional data help-echo)
   "Make STRING into a button and return it.
 When clicked, CALLBACK will be called with the DATA as the
 function argument.  If DATA isn't present (or is nil), the button
-itself will be used instead as the function argument."
+itself will be used instead as the function argument.
+
+If HELP-ECHO, use that as the `help-echo' property."
   (propertize string
               'face 'button
+              'mouse-face 'highlight
+              'help-echo help-echo
               'button t
               'follow-link t
               'category t
diff --git a/lisp/calc/calc-help.el b/lisp/calc/calc-help.el
index dd5063f27d..8481d0b5e9 100644
--- a/lisp/calc/calc-help.el
+++ b/lisp/calc/calc-help.el
@@ -111,9 +111,6 @@ C-w  Describe how there is no warranty for Calc."
   (with-current-buffer "*Help*"
     (let ((inhibit-read-only t))
       (goto-char (point-min))
-      (when (search-forward "Major Mode Bindings:" nil t)
-        (delete-region (point-min) (point))
-        (insert "Calc Mode Bindings:"))
       (when (search-forward "Global bindings:" nil t)
         (forward-line -1)
         (delete-region (point) (point-max)))
diff --git a/lisp/calc/calc-math.el b/lisp/calc/calc-math.el
index 1c2e7bcf2b..ba2b6b2ca9 100644
--- a/lisp/calc/calc-math.el
+++ b/lisp/calc/calc-math.el
@@ -618,8 +618,9 @@ If this can't be done, return NIL."
 (defun math-nth-root-float (a nrf-n &optional guess)
   (math-inexact-result)
   (math-with-extra-prec 1
-    (let ((math-nrf-nf (math-float nrf-n))
-         (math-nrf-nfm1 (math-float (1- nrf-n))))
+    (let ((math-nrf-n nrf-n)
+         (math-nrf-nf (math-float nrf-n))
+          (math-nrf-nfm1 (math-float (1- nrf-n))))
       (math-nth-root-float-iter a (or guess
                                      (math-make-float
                                       1 (/ (+ (math-numdigs (nth 1 a))
diff --git a/lisp/calc/calc-prog.el b/lisp/calc/calc-prog.el
index f9dd9eb98a..b381f8afcf 100644
--- a/lisp/calc/calc-prog.el
+++ b/lisp/calc/calc-prog.el
@@ -124,7 +124,7 @@
        (or (memq (car-safe (car-safe place)) '(error xxxerror))
            (setq place (aref (nth 2 (nth 2 (symbol-function 'calc-do))) 27)))
        (or (memq (car (car place)) '(error xxxerror))
-           (error "foo"))
+            (error "Foo"))
        (setcar (car place) 'xxxerror))
     (error (error "The calc-do function has been modified; unable to patch"))))
 
@@ -205,9 +205,8 @@
         (progn
           (setq cmd-base-default (concat "User-" keyname))
            (setq cmd (completing-read
-                      (concat "Define M-x command name (default calc-"
-                              cmd-base-default
-                              "): ")
+                      (format-prompt "Define M-x command name"
+                                     (concat "calc-" cmd-base-default))
                       obarray 'commandp nil
                       (if (and odef (symbolp (cdr odef)))
                           (symbol-name (cdr odef))
@@ -241,8 +240,8 @@
           (setq func
                  (concat "calcFunc-"
                          (completing-read
-                          (concat "Define algebraic function name (default "
-                                  cmd-base-default "): ")
+                          (format-prompt "Define algebraic function name"
+                                         cmd-base-default)
                           (mapcar (lambda (x) (substring x 9))
                                   (all-completions "calcFunc-"
                                                    obarray))
diff --git a/lisp/calc/calc-store.el b/lisp/calc/calc-store.el
index ee29c440fe..b3968555b6 100644
--- a/lisp/calc/calc-store.el
+++ b/lisp/calc/calc-store.el
@@ -586,7 +586,7 @@
 (defun calc-permanent-variable (&optional var)
   (interactive)
   (calc-wrapper
-   (or var (setq var (calc-read-var-name "Save variable (default all): ")))
+   (or var (setq var (calc-read-var-name (format-prompt "Save variable" 
"all"))))
    (let (calc-pv-pos)
      (and var (or (and (boundp var) (symbol-value var))
                  (error "No such variable")))
diff --git a/lisp/calc/calc-units.el b/lisp/calc/calc-units.el
index fd6f3a7b67..f6d749db11 100644
--- a/lisp/calc/calc-units.el
+++ b/lisp/calc/calc-units.el
@@ -486,18 +486,13 @@ If COMP or STD is non-nil, put that in the units table 
instead."
      (setq defunits (math-get-default-units expr))
      (unless new-units
        (setq new-units
-             (read-string (concat
+             (read-string (format-prompt
                            (if (and uoldname (not nouold))
                                (concat "Old units: "
                                        uoldname
                                        ", new units")
                              "New units")
-                           (if defunits
-                               (concat
-                                " (default "
-                                defunits
-                                "): ")
-                             ": "))))
+                           defunits)))
        (if (and
             (string= new-units "")
             defunits)
@@ -533,14 +528,7 @@ If COMP or STD is non-nil, put that in the units table 
instead."
      (let* ((old-units (math-extract-units expr))
             (defunits (math-get-default-units expr))
             units
-            (new-units
-             (read-string (concat "New units"
-                                  (if defunits
-                                     (concat
-                                      " (default "
-                                      defunits
-                                      "): ")
-                                   ": ")))))
+            (new-units (read-string (format-prompt "New units" defunits))))
        (if (and
             (string= new-units "")
             defunits)
@@ -596,19 +584,14 @@ If COMP or STD is non-nil, put that in the units table 
instead."
         (setq expr (math-mul expr uold)))
      (setq defunits (math-get-default-units expr))
      (setq unew (or new-units
-                    (completing-read
-                     (concat
-                      (if uoldname
-                          (concat "Old temperature units: "
-                                  uoldname
-                                  ", new units")
-                        "New temperature units")
-                      (if defunits
-                          (concat " (default "
-                                  defunits
-                                  "): ")
-                        ": "))
-                     tempunits)))
+                    (completing-read (format-prompt
+                                      (if uoldname
+                                          (concat "Old temperature units: "
+                                                  uoldname
+                                                  ", new units")
+                                        "New temperature units")
+                                      defunits)
+                                     tempunits)))
      (setq unew (math-read-expr (if (string= unew "") defunits unew)))
      (when (eq (car-safe unew) 'error)
        (error "Bad format in units expression: %s" (nth 2 unew)))
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index 45a4d56a37..bd4ec4ff2f 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -494,6 +494,7 @@ This setting only applies to floats in normal display 
mode.")
 (defmacro defcalcmodevar (var defval &optional doc)
   "Declare VAR as a Calc variable, with default value DEFVAL and doc-string 
DOC.
 The variable VAR will be added to `calc-mode-var-list'."
+  (declare (doc-string 3) (indent defun))
   `(progn
      (defvar ,var ,defval ,doc)
      (add-to-list 'calc-mode-var-list (list (quote ,var) ,defval))))
@@ -731,7 +732,7 @@ If nil, symbolic math routines make no assumptions about 
variables.")
   "Initial height of Calculator window.")
 
 (defcalcmodevar calc-display-trail t
-  "If non-nil, M-x calc creates a window to display Calculator trail.")
+  "If non-nil, \\[calc] creates a window to display Calculator trail.")
 
 (defcalcmodevar calc-show-selections t
   "If non-nil, selected sub-formulas are shown by obscuring rest of formula.
@@ -1468,7 +1469,9 @@ See `window-dedicated-p' for what that means."
       (with-current-buffer (calc-trail-buffer)
         (and calc-display-trail
              (calc-trail-display 1 t)))
-      (message "Welcome to the GNU Emacs Calculator!  Press `?' or `h' for 
help, `q' to quit")
+      (message (substitute-command-keys
+                (concat "Welcome to the GNU Emacs Calculator!  
\\<calc-mode-map>"
+                        "Press \\[calc-help] or \\[calc-help-prefix] for help, 
\\[calc-quit] to quit")))
       (run-hooks 'calc-start-hook)
       (and (windowp full-display)
            (window-point full-display)
@@ -3436,7 +3439,7 @@ The prefix `calcFunc-' is added to the specified name to 
get the
 actual Lisp function name.
 
 See Info node `(calc)Defining Functions'."
-  (declare (doc-string 3)) ;; FIXME: Edebug spec?
+  (declare (doc-string 3) (indent defun)) ;; FIXME: Edebug spec?
   (require 'calc-ext)
   (math-do-defmath func args body))
 
diff --git a/lisp/calendar/time-date.el b/lisp/calendar/time-date.el
index 0aa38166bc..155c34927f 100644
--- a/lisp/calendar/time-date.el
+++ b/lisp/calendar/time-date.el
@@ -406,7 +406,11 @@ entries only for the values that should be altered.
 
 For instance, if you want to \"add two months\" to TIME, then
 leave all other fields but the month field in DELTA nil, and make
-the month field 2.  The values in DELTA can be negative.
+the month field 2.  For instance:
+
+  (decoded-time-add (decode-time) (make-decoded-time :month 2))
+
+The values in DELTA can be negative.
 
 If applying a month/year delta leaves the time spec invalid, it
 is decreased to be valid (\"add one month\" to January 31st 2019
diff --git a/lisp/cedet/data-debug.el b/lisp/cedet/data-debug.el
index 428848be04..d8d1364491 100644
--- a/lisp/cedet/data-debug.el
+++ b/lisp/cedet/data-debug.el
@@ -413,7 +413,9 @@ PREBUTTONTEXT is some text between prefix and the stuff 
list button."
   )
 
 (defun data-debug-insert-hash-table-button (hash-table prefix prebuttontext)
-  "Insert HASH-TABLE as expandable button with recursive prefix PREFIX and 
PREBUTTONTEXT in front of the button text."
+  "Insert HASH-TABLE as expandable button, using PREFIX and PREBUTTONTEXT.
+PREFIX is a recursive prefix and PREBUTTONTEXT is text to be inserted
+in front of the button text."
   (let ((string (propertize (format "%s" hash-table)
                            'face 'font-lock-keyword-face)))
     (insert (propertize
diff --git a/lisp/cedet/mode-local.el b/lisp/cedet/mode-local.el
index 02d69a1686..e0717fbfe5 100644
--- a/lisp/cedet/mode-local.el
+++ b/lisp/cedet/mode-local.el
@@ -156,7 +156,7 @@ local variables have been defined."
 DOCSTRING is optional and not used.
 To work properly, this should be put after PARENT mode local variables
 definition."
-  (declare (obsolete define-derived-mode "27.1"))
+  (declare (obsolete define-derived-mode "27.1") (indent 2))
   `(mode-local--set-parent ',mode ',parent))
 
 (defun mode-local-use-bindings-p (this-mode desired-mode)
@@ -567,6 +567,7 @@ appropriate arguments deduced from ARGS.
 OVERARGS is a list of arguments passed to the override and
 `NAME-default' function, in place of those deduced from ARGS."
   (declare (doc-string 3)
+           (indent defun)
            (debug (&define name lambda-list stringp def-body)))
   `(eval-and-compile
      (defun ,name ,args
@@ -595,21 +596,23 @@ DOCSTRING is the documentation string.
 BODY is the implementation of this function."
   ;; FIXME: Make this obsolete and use cl-defmethod with &context instead.
   (declare (doc-string 4)
+           (indent defun)
            (debug (&define name symbolp lambda-list stringp def-body)))
   (let ((newname (intern (format "%s-%s" name mode))))
     `(progn
        (eval-and-compile
         (defun ,newname ,args
-          ,(format "%s\n\nOverride %s in `%s' buffers."
-                   docstring name mode)
+           ,(concat docstring "\n"
+                    (internal--format-docstring-line
+                     "Override `%s' in `%s' buffers."
+                     name mode))
           ;; The body for this implementation
           ,@body)
          ;; For find-func to locate the definition of NEWNAME.
          (put ',newname 'definition-name ',name))
        (mode-local-bind '((,name . ,newname))
                         '(override-flag t)
-                        ',mode))
-    ))
+                        ',mode))))
 
 ;;; Read/Query Support
 (defun mode-local-read-function (prompt &optional initial hist default)
diff --git a/lisp/cedet/semantic/analyze/complete.el 
b/lisp/cedet/semantic/analyze/complete.el
index 1e8cd9af08..5c3228ae16 100644
--- a/lisp/cedet/semantic/analyze/complete.el
+++ b/lisp/cedet/semantic/analyze/complete.el
@@ -70,7 +70,8 @@ context.  Passing in a context is useful if the caller also 
needs
 to access parts of the analysis.
 The remaining FLAGS arguments are passed to the mode specific completion 
engine.
 Bad flags should be ignored by modes that don't use them.
-See `semantic-analyze-possible-completions-default' for details on the default 
FLAGS.
+See `semantic-analyze-possible-completions-default' for details
+on the default FLAGS.
 
 Completions run through the following filters:
   * Elements currently in scope
diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el
index 6cfbdd5f03..375b97a7a5 100644
--- a/lisp/cedet/semantic/complete.el
+++ b/lisp/cedet/semantic/complete.el
@@ -224,11 +224,10 @@ HISTORY is a symbol representing a variable to story the 
history in."
 
       ;; @todo - move from () to into the editable area
       (if (string-match ":" prompt)
-         (setq prompt (concat
-                       (substring prompt 0 (match-beginning 0))
-                       " (default " default-as-string ")"
-                       (substring prompt (match-beginning 0))))
-       (setq prompt (concat prompt " (" default-as-string "): "))))
+          (setq prompt (format-prompt
+                        (substring prompt 0 (match-beginning 0))
+                        default-as-string))
+        (setq prompt (format-prompt prompt default-as-string))))
     ;;
     ;; Perform the Completion
     ;;
diff --git a/lisp/cedet/semantic/db-find.el b/lisp/cedet/semantic/db-find.el
index 61baaa020f..e6a7879775 100644
--- a/lisp/cedet/semantic/db-find.el
+++ b/lisp/cedet/semantic/db-find.el
@@ -914,7 +914,7 @@ but should be good enough for debugging assertions."
           (null (car (cdr (car resultp)))))))
 
 (defun semanticdb-find-result-prin1-to-string (result)
-  "Presuming RESULT satisfies `semanticdb-find-results-p', provide a short 
PRIN1 output."
+  "If RESULT satisfies `semanticdb-find-results-p', provide a short PRIN1 
output."
   (if (< (length result) 2)
       (concat "#<FIND RESULT "
              (mapconcat (lambda (a)
diff --git a/lisp/cedet/semantic/decorate/mode.el 
b/lisp/cedet/semantic/decorate/mode.el
index c6bf15205f..0a234b3000 100644
--- a/lisp/cedet/semantic/decorate/mode.el
+++ b/lisp/cedet/semantic/decorate/mode.el
@@ -391,6 +391,7 @@ etc., found in the semantic-decorate library.
 To add other kind of decorations on a tag, `NAME-highlight' must use
 `semantic-decorate-tag', and other functions of the semantic
 decoration API found in this library."
+  (declare (indent 1))
   (let ((predicate   (semantic-decorate-style-predicate   name))
         (highlighter (semantic-decorate-style-highlighter name))
        (predicatedef   (semantic-decorate-style-predicate-default   name))
@@ -409,8 +410,11 @@ decoration API found in this library."
        ;; Create an override method to specify if a given tag belongs
        ;; to this type of decoration
        (define-overloadable-function ,predicate (tag)
-         ,(format "Return non-nil to decorate TAG with `%s' style.\n%s"
-                  name doc))
+         ,(concat
+           (internal--format-docstring-line
+            "Return non-nil to decorate TAG with `%s' style."
+            name)
+           "\n" doc))
        ;; Create an override method that will perform the highlight
        ;; operation if the -p method returns non-nil.
        (define-overloadable-function ,highlighter (tag)
diff --git a/lisp/cedet/semantic/dep.el b/lisp/cedet/semantic/dep.el
index 0694b9c232..cae38e6f11 100644
--- a/lisp/cedet/semantic/dep.el
+++ b/lisp/cedet/semantic/dep.el
@@ -82,6 +82,7 @@ users will customize.
 
 Creates a customizable variable users can customize that will
 keep semantic data structures up to date."
+  (declare (indent defun))
   `(progn
      ;; Create a variable users can customize.
      (defcustom ,name ,value
diff --git a/lisp/cedet/semantic/grm-wy-boot.el 
b/lisp/cedet/semantic/grm-wy-boot.el
index a6bf211713..ce63421fb3 100644
--- a/lisp/cedet/semantic/grm-wy-boot.el
+++ b/lisp/cedet/semantic/grm-wy-boot.el
@@ -149,10 +149,10 @@
      ((type_decl))
      ((use_macros_decl)))
     (default_prec_decl
-      ((DEFAULT-PREC)
-       `(wisent-raw-tag
-         (semantic-tag "default-prec" 'assoc :value
-                      '("t")))))
+     ((DEFAULT-PREC)
+      `(wisent-raw-tag
+        (semantic-tag "default-prec" 'assoc :value
+                     '("t")))))
     (no_default_prec_decl
      ((NO-DEFAULT-PREC)
       `(wisent-raw-tag
diff --git a/lisp/cedet/semantic/idle.el b/lisp/cedet/semantic/idle.el
index b1805f720d..a14994424d 100644
--- a/lisp/cedet/semantic/idle.el
+++ b/lisp/cedet/semantic/idle.el
@@ -577,10 +577,11 @@ This routine creates the following functions and 
variables:"
     `(progn
        (define-minor-mode ,global
         ,(concat "Toggle " (symbol-name global) ".
-With ARG, turn the minor mode on if ARG is positive, off otherwise.
-
-When this minor mode is enabled, `" (symbol-name mode) "' is
-turned on in every Semantic-supported buffer.")
+With ARG, turn the minor mode on if ARG is positive, off otherwise.\n\n"
+                  (internal--format-docstring-line
+                   "When this minor mode is enabled, `%s' is \
+turned on in every Semantic-supported buffer."
+                   (symbol-name mode)))
          :global t
         :group 'semantic
         :group 'semantic-modes
@@ -618,8 +619,9 @@ turned on in every Semantic-supported buffer.")
                                "")     ; idle schedulers are quiet?
 
        (defun ,func ()
-        ,(concat "Perform idle activity for the minor mode `"
-                 (symbol-name mode) "'.")
+         ,(internal--format-docstring-line
+           "Perform idle activity for the minor mode `%s'."
+           (symbol-name mode))
         ,@forms))))
 
 ;;; SUMMARY MODE
diff --git a/lisp/cedet/semantic/lex-spp.el b/lisp/cedet/semantic/lex-spp.el
index 8073640a8b..3297367db9 100644
--- a/lisp/cedet/semantic/lex-spp.el
+++ b/lisp/cedet/semantic/lex-spp.el
@@ -1165,7 +1165,8 @@ of type `spp-macro-def' is to be created.
 VALFORM are forms that return the value to be saved for this macro, or nil.
 When implementing a macro, you can use `semantic-lex-spp-stream-for-macro'
 to convert text into a lexical stream for storage in the macro."
-  (declare (debug (&define name stringp stringp form def-body)))
+  (declare (debug (&define name stringp stringp form def-body))
+           (indent 1))
   (let ((start (make-symbol "start"))
        (end (make-symbol "end"))
        (val (make-symbol "val"))
@@ -1199,7 +1200,8 @@ REGEXP is a regular expression for the analyzer to match.
 See `define-lex-regex-analyzer' for more on regexp.
 TOKIDX is an index into REGEXP for which a new lexical token
 of type `spp-macro-undef' is to be created."
-  (declare (debug (&define name stringp stringp form)))
+  (declare (debug (&define name stringp stringp form))
+           (indent 1))
   (let ((start (make-symbol "start"))
        (end (make-symbol "end")))
     `(define-lex-regex-analyzer ,name
@@ -1260,7 +1262,8 @@ type of include.  The return value should be of the form:
   (NAME . TYPE)
 where NAME is the name of the include, and TYPE is the type of the include,
 where a valid symbol is `system', or nil."
-  (declare (debug (&define name stringp stringp form def-body)))
+  (declare (debug (&define name stringp stringp form def-body))
+           (indent 1))
   (let ((start (make-symbol "start"))
        (end (make-symbol "end"))
        (val (make-symbol "val"))
diff --git a/lisp/cedet/semantic/lex.el b/lisp/cedet/semantic/lex.el
index 69f20deeb7..d524b733db 100644
--- a/lisp/cedet/semantic/lex.el
+++ b/lisp/cedet/semantic/lex.el
@@ -760,7 +760,7 @@ If two analyzers can match the same text, it is important 
to order the
 analyzers so that the one you want to match first occurs first.  For
 example, it is good to put a number analyzer in front of a symbol
 analyzer which might mistake a number for a symbol."
-  (declare (debug (&define name stringp (&rest symbolp))))
+  (declare (debug (&define name stringp (&rest symbolp))) (indent 1))
   `(defun ,name  (start end &optional depth length)
      ,(concat doc "\nSee `semantic-lex' for more information.")
      ;; Make sure the state of block parsing starts over.
@@ -1096,7 +1096,7 @@ Proper action in FORMS is to move the value of 
`semantic-lex-end-point' to
 after the location of the analyzed entry, and to add any discovered tokens
 at the beginning of `semantic-lex-token-stream'.
 This can be done by using `semantic-lex-push-token'."
-  (declare (debug (&define name stringp form def-body)))
+  (declare (debug (&define name stringp form def-body)) (indent 1))
   `(eval-and-compile
      ;; This is the real info used by `define-lex' (via 
semantic-lex-one-token).
      (defconst ,name '(,condition ,@forms) ,doc)
@@ -1118,7 +1118,7 @@ This can be done by using `semantic-lex-push-token'."
   "Create a lexical analyzer with NAME and DOC that will match REGEXP.
 FORMS are evaluated upon a successful match.
 See `define-lex-analyzer' for more about analyzers."
-  (declare (debug (&define name stringp form def-body)))
+  (declare (debug (&define name stringp form def-body)) (indent 1))
   `(define-lex-analyzer ,name
      ,doc
      (looking-at ,regexp)
@@ -1137,7 +1137,8 @@ FORMS are evaluated upon a successful match BEFORE the 
new token is
 created.  It is valid to ignore FORMS.
 See `define-lex-analyzer' for more about analyzers."
   (declare (debug
-            (&define name stringp form symbolp [ &optional form ] def-body)))
+            (&define name stringp form symbolp [ &optional form ] def-body))
+           (indent 1))
   `(define-lex-analyzer ,name
      ,doc
      (looking-at ,regexp)
@@ -1162,7 +1163,8 @@ where BLOCK-SYM is the symbol returned in a block token.  
OPEN-DELIM
 and CLOSE-DELIM are respectively the open and close delimiters
 identifying a block.  OPEN-SYM and CLOSE-SYM are respectively the
 symbols returned in open and close tokens."
-  (declare (debug (&define name stringp form (&rest form))))
+  (declare (debug (&define name stringp form (&rest form)))
+           (indent 1))
   (let ((specs (cons spec1 specs))
         spec open olist clist)
     (while specs
@@ -1471,6 +1473,7 @@ syntax as specified by the syntax table."
 (defmacro define-lex-keyword-type-analyzer (name doc syntax)
   "Define a keyword type analyzer NAME with DOC string.
 SYNTAX is the regexp that matches a keyword syntactic expression."
+  (declare (indent 1))
   (let ((key (make-symbol "key")))
     `(define-lex-analyzer ,name
        ,doc
@@ -1486,6 +1489,7 @@ SYNTAX is the regexp that matches a keyword syntactic 
expression."
   "Define a sexp type analyzer NAME with DOC string.
 SYNTAX is the regexp that matches the beginning of the s-expression.
 TOKEN is the lexical token returned when SYNTAX matches."
+  (declare (indent 1))
   `(define-lex-regex-analyzer ,name
      ,doc
      ,syntax
@@ -1504,6 +1508,7 @@ SYNTAX is the regexp that matches a syntactic expression.
 MATCHES is an alist of lexical elements used to refine the syntactic
 expression.
 DEFAULT is the default lexical token returned when no MATCHES."
+  (declare (indent 1))
   (if matches
       (let* ((val (make-symbol "val"))
              (lst (make-symbol "lst"))
@@ -1536,6 +1541,7 @@ SYNTAX is the regexp that matches a syntactic expression.
 MATCHES is an alist of lexical elements used to refine the syntactic
 expression.
 DEFAULT is the default lexical token returned when no MATCHES."
+  (declare (indent 1))
   (if matches
       (let* ((val (make-symbol "val"))
              (lst (make-symbol "lst"))
@@ -1633,6 +1639,7 @@ When the lexer encounters the open-paren delimiter \"(\":
  - If the maximum depth of parenthesis tracking is reached (current
    depth >= max depth), it returns the whole parenthesis block as
    a (PAREN_BLOCK start . end) token."
+  (declare (indent 1))
   (let* ((val (make-symbol "val"))
          (lst (make-symbol "lst"))
          (elt (make-symbol "elt")))
diff --git a/lisp/cedet/semantic/tag-ls.el b/lisp/cedet/semantic/tag-ls.el
index 3aa1a62901..4bdae58690 100644
--- a/lisp/cedet/semantic/tag-ls.el
+++ b/lisp/cedet/semantic/tag-ls.el
@@ -130,7 +130,10 @@ are the same.
 
 Similar tags that have sub-tags such as arg lists or type members,
 are similar w/out checking the sub-list of tags.
-Optional argument IGNORABLE-ATTRIBUTES are attributes to ignore while 
comparing similarity.
+
+Optional argument IGNORABLE-ATTRIBUTES are attributes to ignore while comparing
+similarity.
+
 By default, `semantic-tag-similar-ignorable-attributes' is referenced for
 attributes, and IGNORABLE-ATTRIBUTES will augment this list.
 
@@ -191,11 +194,14 @@ See `semantic-tag-similar-p' for details."
 ;; will contain the info needed to determine the full name.
 (define-overloadable-function semantic-tag-full-package (tag &optional 
stream-or-buffer)
   "Return the fully qualified package name of TAG in a package hierarchy.
-STREAM-OR-BUFFER can be anything convertible by 
`semantic-something-to-tag-table',
-but must be a toplevel semantic tag stream that contains TAG.
+STREAM-OR-BUFFER can be anything convertible by
+`semantic-something-to-tag-table', but must be a toplevel
+semantic tag stream that contains TAG.
+
 A Package Hierarchy is defined in UML by the way classes and methods
 are organized on disk.  Some languages use this concept such that a
 class can be accessed via it's fully qualified name, (such as Java.)
+
 Other languages qualify names within a Namespace (such as C++) which
 result in a different package like structure.
 
@@ -214,11 +220,14 @@ Return the name of the first tag of class `package' in 
STREAM."
 
 (define-overloadable-function semantic-tag-full-name (tag &optional 
stream-or-buffer)
   "Return the fully qualified name of TAG in the package hierarchy.
-STREAM-OR-BUFFER can be anything convertible by 
`semantic-something-to-tag-table',
-but must be a toplevel semantic tag stream that contains TAG.
+STREAM-OR-BUFFER can be anything convertible by
+`semantic-something-to-tag-table', but must be a toplevel
+semantic tag stream that contains TAG.
+
 A Package Hierarchy is defined in UML by the way classes and methods
 are organized on disk.  Some languages use this concept such that a
 class can be accessed via it's fully qualified name, (such as Java.)
+
 Other languages qualify names within a Namespace (such as C++) which
 result in a different package like structure.
 
diff --git a/lisp/cedet/semantic/wisent.el b/lisp/cedet/semantic/wisent.el
index f5f381d407..afcdd14282 100644
--- a/lisp/cedet/semantic/wisent.el
+++ b/lisp/cedet/semantic/wisent.el
@@ -66,7 +66,7 @@ Returned tokens must have the form:
   (TOKSYM VALUE START . END)
 
 where VALUE is the buffer substring between START and END positions."
-  (declare (debug (&define name stringp def-body)))
+  (declare (debug (&define name stringp def-body)) (indent 1))
   `(defun
      ,name () ,doc
      (cond
diff --git a/lisp/cedet/semantic/wisent/python.el 
b/lisp/cedet/semantic/wisent/python.el
index fb878dde71..2eeade6646 100644
--- a/lisp/cedet/semantic/wisent/python.el
+++ b/lisp/cedet/semantic/wisent/python.el
@@ -118,9 +118,9 @@ curly braces."
         ;; look-ahead assertions.)
         (when (and (= (- end start) 2)
                    (looking-at "\"\\{3\\}\\|'\\{3\\}"))
-          (error "unterminated syntax"))
+          (error "Unterminated syntax"))
         (goto-char end))
-    (error "unterminated syntax")))
+    (error "Unterminated syntax")))
 
 (defun wisent-python-forward-balanced-expression ()
   "Move point to the end of the balanced expression at point.
@@ -145,7 +145,7 @@ triple-quoted string syntax."
        ;; delimiter (backquote) characters, line continuation, and end
        ;; of comment characters (AKA newline characters in Python).
        ((zerop (skip-syntax-forward "-w_.$\\>"))
-        (error "can't figure out how to go forward from here"))))
+        (error "Can't figure out how to go forward from here"))))
     ;; Skip closing character.  As a last resort this should raise an
     ;; error if we hit EOB before we find our closing character..
     (forward-char 1)))
diff --git a/lisp/cedet/srecode/dictionary.el b/lisp/cedet/srecode/dictionary.el
index d6dfc58411..e47a09fd84 100644
--- a/lisp/cedet/srecode/dictionary.el
+++ b/lisp/cedet/srecode/dictionary.el
@@ -364,7 +364,7 @@ values but STATE is nil."
        ;; Value is some other object; create a compound value.
        (t
        (unless state
-         (error "Cannot insert compound values without state."))
+          (error "Cannot insert compound values without state"))
 
        (srecode-dictionary-set-value
         dict name
diff --git a/lisp/cmuscheme.el b/lisp/cmuscheme.el
index e197069d6b..47113ad8c2 100644
--- a/lisp/cmuscheme.el
+++ b/lisp/cmuscheme.el
@@ -245,7 +245,8 @@ Search in the directories \"~\" and `user-emacs-directory',
 in this order.  Return nil if no start file found."
   (let* ((progname (file-name-nondirectory prog))
         (start-file (concat "~/.emacs_" progname))
-        (alt-start-file (concat user-emacs-directory "init_" progname ".scm")))
+         (alt-start-file (locate-user-emacs-file
+                          (concat "init_" progname ".scm"))))
     (if (file-exists-p start-file)
         start-file
       (and (file-exists-p alt-start-file) alt-start-file))))
diff --git a/lisp/comint.el b/lisp/comint.el
index 8bf23897f9..544f0b8b82 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -372,6 +372,7 @@ This variable is buffer-local."
    "\\(^ *\\|"
    (regexp-opt
     '("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the"
+      "Current"
       "Enter Auth" "enter auth" "Old" "old" "New" "new" "'s" "login"
       "Kerberos" "CVS" "UNIX" " SMB" "LDAP" "PEM" "SUDO"
       "[sudo]" "doas" "Repeat" "Bad" "Retype" "Verify")
@@ -381,10 +382,15 @@ This variable is buffer-local."
    "\\(?:" (regexp-opt password-word-equivalents) "\\|Response\\)"
    "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?"
    ;; "[[:alpha:]]" used to be "for", which fails to match non-English.
-   "\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:space:]]*\\'")
+   "\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:space:]]*\\'"
+   ;; The ccrypt encryption dialogue doesn't end with a colon, so
+   ;; treat it specially.
+   "\\|^Enter encryption key: (repeat) *\\'"
+   ;; openssh-8.6p1 format: "(user@host) Password:".
+   "\\|^([^)@ \t\n]+@[^)@ \t\n]+) Password: *\\'")
   "Regexp matching prompts for passwords in the inferior process.
 This is used by `comint-watch-for-password-prompt'."
-  :version "28.1"
+  :version "29.1"
   :type 'regexp
   :group 'comint)
 
@@ -885,12 +891,13 @@ series of processes in the same Comint buffer.  The hook
   ;; and there is no way for us to define it here.
   ;; Some programs that use terminfo get very confused
   ;; if TERM is not a valid terminal type.
-  (if (and (boundp 'system-uses-terminfo) system-uses-terminfo)
-      (list (format "TERM=%s" comint-terminfo-terminal)
-            "TERMCAP="
-            (format "COLUMNS=%d" (window-width)))
-    (list "TERM=emacs"
-          (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width)))))
+  (with-connection-local-variables
+   (if system-uses-terminfo
+       (list (format "TERM=%s" comint-terminfo-terminal)
+             "TERMCAP="
+             (format "COLUMNS=%d" (window-width)))
+     (list "TERM=emacs"
+           (format "TERMCAP=emacs:co#%d:tc=unknown:" (window-width))))))
 
 (defun comint-nonblank-p (str)
   "Return non-nil if STR contains non-whitespace syntax."
@@ -1900,6 +1907,14 @@ Similarly for Soar, Scheme, etc."
                           (delete-region pmark start)
                           copy))))
 
+        ;; Delete and reinsert input.  This seems like a no-op, except
+        ;; for the resulting entries in the undo list: undoing this
+        ;; insertion will delete the region, moving the process mark
+        ;; back to its original position.
+        (let ((inhibit-read-only t))
+          (delete-region pmark (point))
+          (insert input))
+
         (unless no-newline
           (insert ?\n))
 
@@ -1943,7 +1958,7 @@ Similarly for Soar, Scheme, etc."
         ;; in case we get output amidst sending the input.
         (set-marker comint-last-input-start pmark)
         (set-marker comint-last-input-end (point))
-        (set-marker (process-mark proc) (point))
+        (set-marker pmark (point))
         ;; clear the "accumulation" marker
         (set-marker comint-accum-marker nil)
         (let ((comint-input-sender-no-newline no-newline))
@@ -1986,6 +2001,7 @@ Similarly for Soar, Scheme, etc."
 
         ;; This used to call comint-output-filter-functions,
         ;; but that scrolled the buffer in undesirable ways.
+        (set-marker comint-last-output-start pmark)
         (run-hook-with-args 'comint-output-filter-functions "")))))
 
 (defvar comint-preoutput-filter-functions nil
@@ -2450,11 +2466,19 @@ This function could be in the list 
`comint-output-filter-functions'."
   (when (let ((case-fold-search t))
          (string-match comint-password-prompt-regexp
                         (string-replace "\r" "" string)))
-    (let ((comint--prompt-recursion-depth (1+ comint--prompt-recursion-depth)))
-      (if (> comint--prompt-recursion-depth 10)
-          (message "Password prompt recursion too deep")
-        (comint-send-invisible
-         (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+"))))))
+    ;; Use `run-at-time' in order not to pause execution of the
+    ;; process filter with a minibuffer
+    (run-at-time
+     0 nil
+     (lambda (current-buf)
+       (with-current-buffer current-buf
+         (let ((comint--prompt-recursion-depth
+                (1+ comint--prompt-recursion-depth)))
+           (if (> comint--prompt-recursion-depth 10)
+               (message "Password prompt recursion too deep")
+             (comint-send-invisible
+              (string-trim string "[ \n\r\t\v\f\b\a]+" "\n+"))))))
+     (current-buffer))))
 
 ;; Low-level process communication
 
@@ -3504,6 +3528,20 @@ to send all the accumulated input, at once.
 The entire accumulated text becomes one item in the input history
 when you send it."
   (interactive)
+  (when-let* ((proc (get-buffer-process (current-buffer)))
+              (pmark (process-mark proc))
+              ((or (marker-position comint-accum-marker)
+                   (set-marker comint-accum-marker pmark)
+                   t))
+              ((>= (point) comint-accum-marker pmark)))
+    ;; Delete and reinsert input.  This seems like a no-op, except for
+    ;; the resulting entries in the undo list: undoing this insertion
+    ;; will delete the region, moving the accumulation marker back to
+    ;; its original position.
+    (let ((text (buffer-substring comint-accum-marker (point)))
+          (inhibit-read-only t))
+      (delete-region comint-accum-marker (point))
+      (insert text)))
   (insert "\n")
   (set-marker comint-accum-marker (point))
   (if comint-input-ring-index
diff --git a/lisp/completion.el b/lisp/completion.el
index e36c722841..643f2da0d2 100644
--- a/lisp/completion.el
+++ b/lisp/completion.el
@@ -1088,7 +1088,8 @@ Must be called after `find-exact-completion'."
   #'completion-locate-db-error "27.1")
 (defun completion-locate-db-error ()
   ;; recursive error: really scrod
-  (error "Completion database corrupted.  Try M-x clear-all-completions.  Send 
bug report"))
+  (error (substitute-command-keys
+          "Completion database corrupted.  Try \\[clear-all-completions].  
Send bug report")))
 
 ;; WRITES
 (defun add-completion-to-tail-if-new (string)
diff --git a/lisp/composite.el b/lisp/composite.el
index a16c0cc237..c2289e8998 100644
--- a/lisp/composite.el
+++ b/lisp/composite.el
@@ -815,6 +815,35 @@ prepending a space before it."
              (setq i (1+ i)))))))
     gstring))
 
+(defun compose-gstring-for-variation-glyph (gstring _direction)
+  "Compose glyph-string GSTRING for graphic display.
+GSTRING must have two glyphs; the first is a glyph for a han character,
+and the second is a glyph for a variation selector."
+  (let* ((font (lgstring-font gstring))
+        (han (lgstring-char gstring 0))
+        (vs (lgstring-char gstring 1))
+        (glyphs (font-variation-glyphs font han))
+        (g0 (lgstring-glyph gstring 0))
+        (g1 (lgstring-glyph gstring 1)))
+    (catch 'tag
+      (dolist (elt glyphs)
+       (if (= (car elt) vs)
+           (progn
+             (lglyph-set-code g0 (cdr elt))
+             (lglyph-set-from-to g0 (lglyph-from g0) (lglyph-to g1))
+             (lgstring-set-glyph gstring 1 nil)
+             (throw 'tag gstring)))))))
+
+;; We explicitly don't handle #xFE0F (VS-16) here, because that's
+;; taken care of by font_range in font.c, which will check for an
+;; emoji font for codepoints used in compositions even if they're not
+;; emoji themselves, and thus choose the Emoji presentation for them
+;; when followed by VS-16.  VS-15 *is* handled here, because if it's
+;; handled in font_range, we end up choosing the Emoji presentation
+;; rather than the Text presentation.
+(let ((elt '([".." 1 compose-gstring-for-variation-glyph])))
+  (set-char-table-range composition-function-table '(#xFE00 . #xFE0E) elt)
+  (set-char-table-range composition-function-table '(#xE0100 . #xE01EF) elt))
 
 (defun auto-compose-chars (func from to font-object string direction)
   "Compose the characters at FROM by FUNC.
@@ -872,6 +901,4 @@ For more information on Auto Composition mode, see
 
 (provide 'composite)
 
-
-
 ;;; composite.el ends here
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 69baf17f5e..34a6db508d 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -1133,7 +1133,7 @@ for the MODE to customize."
 
 (defun customize-read-group ()
   (let ((completion-ignore-case t))
-    (completing-read "Customize group (default emacs): "
+    (completing-read (format-prompt "Customize group" "emacs")
                      obarray
                      (lambda (symbol)
                        (or (and (get symbol 'custom-loads)
@@ -1205,7 +1205,7 @@ Show the buffer in another window, but don't select it."
     (unless (eq symbol basevar)
       (message "`%s' is an alias for `%s'" symbol basevar))))
 
-(defvar customize-changed-options-previous-release "26.3"
+(defvar customize-changed-options-previous-release "28.1"
   "Version for `customize-changed' to refer back to by default.")
 
 ;; Packages will update this variable, so make it available.
diff --git a/lisp/cus-face.el b/lisp/cus-face.el
index 6c0052bf86..5037ee77c7 100644
--- a/lisp/cus-face.el
+++ b/lisp/cus-face.el
@@ -31,6 +31,9 @@
 
 (defun custom-declare-face (face spec doc &rest args)
   "Like `defface', but with FACE evaluated as a normal argument."
+  (when (and doc
+             (not (stringp doc)))
+    (error "Invalid (or missing) doc string %S" doc))
   (unless (get face 'face-defface-spec)
     (face-spec-set face (purecopy spec) 'face-defface-spec)
     (push (cons 'defface face) current-load-list)
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 1a3e5682bb..a46107a678 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -386,7 +386,7 @@ Leaving \"Default\" unchecked is equivalent with specifying 
a default of
                                      (const :tag "When sent SIGUSR1" sigusr1)
                                      (const :tag "When sent SIGUSR2" sigusr2))
                              "24.1")
-
+             (translate-upper-case-key-bindings keyboard boolean "29.1")
              ;; This is not good news because it will use the wrong
              ;; version-specific directories when you upgrade.  We need
              ;; customization of the front of the list, maintaining the
diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 07881e9b74..f618e3341c 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -627,22 +627,24 @@ Theme files are named *-theme.el in `"))
   (let ((help-echo "mouse-2: Enable this theme for this session")
        widget)
     (dolist (theme (custom-available-themes))
-      (setq widget (widget-create 'checkbox
-                                 :value (custom-theme-enabled-p theme)
-                                 :theme-name theme
-                                 :help-echo help-echo
-                                  :action #'custom-theme-checkbox-toggle))
-      (push (cons theme widget) custom--listed-themes)
-      (widget-create-child-and-convert widget 'push-button
-                                      :button-face-get 'ignore
-                                      :mouse-face-get 'ignore
-                                      :value (format " %s" theme)
-                                       :action #'widget-parent-action
-                                      :help-echo help-echo)
-      (widget-insert " -- "
-                    (propertize (custom-theme-summary theme)
-                                'face 'shadow)
-                    ?\n)))
+      ;; Don't list obsolete themes.
+      (unless (get theme 'byte-obsolete-info)
+        (setq widget (widget-create 'checkbox
+                                   :value (custom-theme-enabled-p theme)
+                                   :theme-name theme
+                                   :help-echo help-echo
+                                    :action #'custom-theme-checkbox-toggle))
+        (push (cons theme widget) custom--listed-themes)
+        (widget-create-child-and-convert widget 'push-button
+                                        :button-face-get 'ignore
+                                        :mouse-face-get 'ignore
+                                        :value (format " %s" theme)
+                                         :action #'widget-parent-action
+                                        :help-echo help-echo)
+        (widget-insert " -- "
+                      (propertize (custom-theme-summary theme)
+                                  'face 'shadow)
+                      ?\n))))
   (goto-char (point-min))
   (widget-setup))
 
diff --git a/lisp/custom.el b/lisp/custom.el
index f392bd8d36..9252e80411 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -364,7 +364,8 @@ call that function directly.
 
 See Info node `(elisp) Customization' in the Emacs Lisp manual
 for more information."
-  (declare (doc-string 3) (debug (name body)))
+  (declare (doc-string 3) (debug (name body))
+           (indent defun))
   ;; It is better not to use backquote in this file,
   ;; because that makes a bootstrapping problem
   ;; if you need to recompile all the Lisp files using interpreted code.
@@ -378,7 +379,7 @@ for more information."
          ;; expression is checked by the byte-compiler, and that
          ;; lexical-binding is obeyed, so quote the expression with
          ;; `lambda' rather than with `quote'.
-         ``(funcall #',(lambda () ,standard))
+         ``(funcall #',(lambda () "" ,standard))
        `',standard)
     ,doc
     ,@args))
@@ -447,7 +448,7 @@ In the ATTS property list, possible attributes are 
`:family',
 
 See Info node `(elisp) Faces' in the Emacs Lisp manual for more
 information."
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   ;; It is better not to use backquote in this file,
   ;; because that makes a bootstrapping problem
   ;; if you need to recompile all the Lisp files using interpreted code.
@@ -507,11 +508,15 @@ The remaining arguments should have the form
    [KEYWORD VALUE]...
 
 For a list of valid keywords, see the common keywords listed in
-`defcustom'.
+`defcustom'.  The keyword :prefix can only be used for
+customization groups, and means that the given string should be
+removed from variable names before creating unlispified names,
+when the user option `custom-unlispify-remove-prefixes' is
+non-nil.
 
 See Info node `(elisp) Customization' in the Emacs Lisp manual
 for more information."
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   ;; It is better not to use backquote in this file,
   ;; because that makes a bootstrapping problem
   ;; if you need to recompile all the Lisp files using interpreted code.
@@ -1131,29 +1136,24 @@ list, in which A occurs before B if B was defined with a
 ;;   (provide-theme 'THEME)
 
 
-;; The IGNORED arguments to deftheme come from the XEmacs theme code, where
-;; they were used to supply keyword-value pairs like `:immediate',
-;; `:variable-reset-string', etc.  We don't use any of these, so ignore them.
-
-(defmacro deftheme (theme &optional doc &rest _ignored)
+(defmacro deftheme (theme &optional doc)
   "Declare THEME to be a Custom theme.
 The optional argument DOC is a doc string describing the theme.
 
 Any theme `foo' should be defined in a file called `foo-theme.el';
 see `custom-make-theme-feature' for more information."
   (declare (doc-string 2)
-           (advertised-calling-convention (theme &optional doc) "22.1"))
+           (indent 1))
   (let ((feature (custom-make-theme-feature theme)))
     ;; It is better not to use backquote in this file,
     ;; because that makes a bootstrapping problem
     ;; if you need to recompile all the Lisp files using interpreted code.
     (list 'custom-declare-theme (list 'quote theme) (list 'quote feature) 
doc)))
 
-(defun custom-declare-theme (theme feature &optional doc &rest _ignored)
+(defun custom-declare-theme (theme feature &optional doc)
   "Like `deftheme', but THEME is evaluated as a normal argument.
 FEATURE is the feature this theme provides.  Normally, this is a symbol
 created from THEME by `custom-make-theme-feature'."
-  (declare (advertised-calling-convention (theme feature &optional doc) 
"22.1"))
   (unless (custom-theme-name-valid-p theme)
     (error "Custom theme cannot be named %S" theme))
   (unless (memq theme custom-known-themes)
@@ -1331,6 +1331,13 @@ Return t if THEME was successfully loaded, nil 
otherwise."
                  t))))
           (t
            (error "Unable to load theme `%s'" theme))))
+  (when-let ((obs (get theme 'byte-obsolete-info)))
+    (display-warning 'initialization
+                     (format "The `%s' theme is obsolete%s"
+                             theme
+                             (if (nth 2 obs)
+                                 (format " since Emacs %s" (nth 2 obs))
+                               ""))))
   ;; Optimization: if the theme changes the `default' face, put that
   ;; entry first.  This avoids some `frame-set-background-mode' rigmarole
   ;; by assigning the new background immediately.
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index 7ab90d08ac..2a239f8100 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -417,6 +417,7 @@ The character information includes:
            (display-table (or (window-display-table)
                               buffer-display-table
                               standard-display-table))
+           (composition-string nil)
            (disp-vector (and display-table (aref display-table char)))
            (multibyte-p enable-multibyte-characters)
            (overlays (mapcar (lambda (o) (overlay-properties o))
@@ -538,7 +539,8 @@ The character information includes:
                     (setcar composition nil)))
                 (setcar (cdr composition)
                         (format "composed to form \"%s\" (see below)"
-                                (buffer-substring from to)))))
+                                (setq composition-string
+                                      (buffer-substring from to))))))
             (setq composition nil)))
 
       (setq item-list
@@ -677,11 +679,16 @@ The character information includes:
                   (let ((display (describe-char-display pos char)))
                     (if (display-graphic-p (selected-frame))
                         (if display
-                            (concat "by this font (glyph code)\n    " display)
+                            (concat "by this font (glyph code):\n    " display)
                           "no font available")
                       (if display
                           (format "terminal code %s" display)
                         "not encodable for terminal"))))))
+              ,@(when-let ((composition-name
+                            (and composition-string
+                                 (eq (aref char-script-table char) 'emoji)
+                                 (emoji-describe composition-string))))
+                  (list (list "composition name" composition-name)))
               ,@(let ((face
                        (if (not (or disp-vector composition))
                            (cond
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 1bb5b92935..7d81d45326 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -444,10 +444,10 @@ List has a form of (file-name full-file-name 
(attribute-list))."
                          ((eq op-symbol 'chgrp)
                           (file-attribute-group-id
                            (file-attributes default-file 'string))))))
-        (prompt (concat "Change " attribute-name " of %s to"
-                        (if (eq op-symbol 'touch)
-                            " (default now): "
-                          ": ")))
+         (prompt (format-prompt "Change %s of %%s to"
+                                (when (eq op-symbol 'touch)
+                                    "now")
+                                attribute-name))
         (new-attribute (dired-mark-read-string prompt nil op-symbol
                                                arg files default
                                                (cond ((eq op-symbol 'chown)
@@ -493,8 +493,7 @@ are supported.  Type M-n to pull the file attributes of the 
file
 at point into the minibuffer.
 
 See Info node `(coreutils)File permissions' for more information.
-Alternatively, see the man page for \"chmod\", using the command
-\\[man] in Emacs.
+Alternatively, see the man page for \"chmod(1)\".
 
 Note that on MS-Windows only the `w' (write) bit is meaningful:
 resetting it makes the file read-only.  Changing any other bit
@@ -2399,7 +2398,9 @@ But if `dired-copy-dereference' is non-nil, the symbolic
 links are dereferenced and then copied, similar to the \"-L\"
 option for the \"cp\" shell command.  If ARG is a cons with
 element 4 (`\\[universal-argument]'), the inverted value of
-`dired-copy-dereference' will be used."
+`dired-copy-dereference' will be used.
+
+Also see `dired-do-revert-buffer'."
   (interactive "P")
   (let ((dired-recursive-copies dired-recursive-copies)
         (dired-copy-dereference (if (equal arg '(4))
@@ -2420,7 +2421,9 @@ with the same names that the files currently have.  The 
default
 suggested for the target directory depends on the value of
 `dired-dwim-target', which see.
 
-For relative symlinks, use \\[dired-do-relsymlink]."
+For relative symlinks, use \\[dired-do-relsymlink].
+
+Also see `dired-do-revert-buffer'."
   (interactive "P")
   (dired-do-create-files 'symlink #'make-symbolic-link
                          "Symlink" arg dired-keep-marker-symlink))
@@ -2433,7 +2436,9 @@ When operating on multiple or marked files, you specify a 
directory
 and new hard links are made in that directory
 with the same names that the files currently have.  The default
 suggested for the target directory depends on the value of
-`dired-dwim-target', which see."
+`dired-dwim-target', which see.
+
+Also see `dired-do-revert-buffer'."
   (interactive "P")
   (dired-do-create-files 'hardlink #'dired-hardlink
                          "Hardlink" arg dired-keep-marker-hardlink))
@@ -2452,7 +2457,9 @@ When renaming just the current file, you specify the new 
name.
 When renaming multiple or marked files, you specify a directory.
 This command also renames any buffers that are visiting the files.
 The default suggested for the target directory depends on the value
-of `dired-dwim-target', which see."
+of `dired-dwim-target', which see.
+
+Also see `dired-do-revert-buffer'."
   (interactive "P")
   (dired-do-create-files 'move #'dired-rename-file
                         "Move" arg dired-keep-marker-rename "Rename"))
@@ -2729,7 +2736,7 @@ This function takes some pains to conform to `ls -lR' 
output."
   ;; Check that it is valid to insert DIRNAME with SWITCHES.
   ;; Signal an error if invalid (e.g. user typed `i' on `..').
   (or (file-in-directory-p dirname (expand-file-name default-directory))
-      (error  "%s: not in this directory tree" dirname))
+      (error  "%s: Not in this directory tree" dirname))
   (let ((real-switches (or switches dired-subdir-switches)))
     (when real-switches
       (let (case-fold-search)
@@ -2853,8 +2860,8 @@ of marked files.  If KILL-ROOT is non-nil, kill DIRNAME 
as well."
   ;;   if dired-actual-switches contained t.
   (setq dir1 (file-name-as-directory dir1)
        dir2 (file-name-as-directory dir2))
-  (let ((components-1 (dired-split "/" dir1))
-       (components-2 (dired-split "/" dir2)))
+  (let ((components-1 (split-string dir1 "/"))
+       (components-2 (split-string dir2 "/")))
     (while (and components-1
                components-2
                (equal (car components-1) (car components-2)))
@@ -2873,7 +2880,6 @@ of marked files.  If KILL-ROOT is non-nil, kill DIRNAME 
as well."
             nil)
            (t (error "This can't happen"))))))
 
-;; There should be a builtin split function - inverse to mapconcat.
 (defun dired-split (pat str &optional limit)
   "Splitting on regexp PAT, turn string STR into a list of substrings.
 Optional third arg LIMIT (>= 1) is a limit to the length of the
@@ -2883,6 +2889,7 @@ Thus, if SEP is a regexp that only matches itself,
    (mapconcat #'identity (dired-split SEP STRING) SEP)
 
 is always equal to STRING."
+  (declare (obsolete split-string "29.1"))
   (let* ((start (string-match pat str))
         (result (list (substring str 0 start)))
         (count 1)
diff --git a/lisp/dired-x.el b/lisp/dired-x.el
index cf257c8169..fc626aa76b 100644
--- a/lisp/dired-x.el
+++ b/lisp/dired-x.el
@@ -293,7 +293,7 @@ files"]
   \\[dired-omit-mode]\t-- toggle omitting of files
   \\[dired-mark-sexp]\t-- mark by Lisp expression
 
-To see the options you can set, use M-x customize-group RET dired-x RET.
+To see the options you can set, use \\[customize-group] RET dired-x RET.
 See also the functions:
   `dired-flag-extension'
   `dired-virtual'
@@ -554,7 +554,7 @@ If the region is active in Transient Mark mode, operate 
only on
 files in the active region if `dired-mark-region' is non-nil."
   (interactive
    (list (read-regexp
-         "Mark unmarked files matching regexp (default all): "
+          (format-prompt "Mark unmarked files matching regexp" "all")
           nil 'dired-regexp-history)
         nil current-prefix-arg nil))
   (let ((dired-marker-char (if unflag-p ?\s dired-marker-char)))
@@ -1478,12 +1478,12 @@ a prefix argument, when it offers the filename near 
point as a default."
 
 ;;; Internal functions
 
-;; Fixme: This should probably use `thing-at-point'.  -- fx
 (define-obsolete-function-alias 'dired-filename-at-point
   #'dired-x-guess-file-name-at-point "28.1")
 (defun dired-x-guess-file-name-at-point ()
   "Return the filename closest to point, expanded.
 Point should be in or after a filename."
+  (declare (obsolete "use (thing-at-point 'filename) instead." "29.1"))
   (save-excursion
     ;; First see if just past a filename.
     (or (eobp)                             ; why?
@@ -1515,7 +1515,7 @@ Point should be in or after a filename."
   "Return filename prompting with PROMPT with completion.
 If `current-prefix-arg' is non-nil, uses name at point as guess."
   (if current-prefix-arg
-      (let ((guess (dired-x-guess-file-name-at-point)))
+      (let ((guess (thing-at-point 'filename)))
         (read-file-name prompt
                         (file-name-directory guess)
                         guess
diff --git a/lisp/dired.el b/lisp/dired.el
index 07c13e18b9..40dfc39b9a 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -35,6 +35,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'subr-x))
+(eval-when-compile (require 'cl-lib))
 ;; When bootstrapping dired-loaddefs has not been generated.
 (require 'dired-loaddefs nil t)
 
@@ -247,7 +248,7 @@ This is similar to the \"-L\" option for the \"cp\" shell 
command."
   :type 'boolean
   :group 'dired)
 
-;; These variables were deleted and the replacements are on files.el.
+;; These variables were deleted and the replacements are in files.el.
 ;; We leave aliases behind for back-compatibility.
 (define-obsolete-variable-alias 'dired-free-space-program
   'directory-free-space-program "27.1")
@@ -281,6 +282,11 @@ with the buffer narrowed to the listing."
 ;; Note this can't simply be run inside function `dired-ls' as the hook
 ;; functions probably depend on the dired-subdir-alist to be OK.
 
+(defcustom dired-make-directory-clickable t
+  "When non-nil, make the directory at the start of the dired buffer 
clickable."
+  :version "29.1"
+  :type 'boolean)
+
 (defcustom dired-initial-position-hook nil
   "This hook is used to position the point.
 It is run by the function `dired-initial-position'."
@@ -1326,6 +1332,8 @@ wildcards, erases the buffer, and builds the subdir-alist 
anew
            (set-visited-file-modtime (file-attribute-modification-time
                                        attributes))))
       (set-buffer-modified-p nil)
+      (when dired-make-directory-clickable
+        (dired--make-directory-clickable))
       ;; No need to narrow since the whole buffer contains just
       ;; dired-readin's output, nothing else.  The hook can
       ;; successfully use dired functions (e.g. dired-get-filename)
@@ -1643,6 +1651,32 @@ see `dired-use-ls-dired' for more details.")
                               'invisible 'dired-hide-details-link))))
       (forward-line 1))))
 
+(defun dired--make-directory-clickable ()
+  (save-excursion
+    (goto-char (point-min))
+    (while (re-search-forward "^  /" nil t 1)
+      (let ((bound (line-end-position))
+            (segment-start (point))
+            (inhibit-read-only t)
+            (dir "/"))
+        (while (search-forward "/" bound t 1)
+          (setq dir (concat dir (buffer-substring segment-start (point))))
+          (add-text-properties
+           segment-start (1- (point))
+           `( mouse-face highlight
+              help-echo "mouse-1: goto this directory"
+              keymap ,(let* ((current-dir dir)
+                             (click (lambda ()
+                                      (interactive)
+                                      (if (assoc current-dir 
dired-subdir-alist)
+                                          (dired-goto-subdir current-dir)
+                                        (dired current-dir)))))
+                        (define-keymap
+                          [mouse-2] click
+                          [follow-link] 'mouse-face
+                          ["RET"] click))))
+          (setq segment-start (point)))))))
+
 
 ;;; Reverting a dired buffer
 
@@ -4490,6 +4524,7 @@ Ask means pop up a menu for the user to select one of 
copy, move or link."
 
 (defvar archive-superior-buffer)
 (defvar tar-superior-buffer)
+(declare-function dired-omit-mode "dired-x" (&optional arg))
 
 ;;;###autoload
 (defun dired-jump (&optional other-window file-name)
diff --git a/lisp/edmacro.el b/lisp/edmacro.el
index e90b3a006e..b3118b0aa6 100644
--- a/lisp/edmacro.el
+++ b/lisp/edmacro.el
@@ -604,6 +604,12 @@ This function assumes that the events can be stored in a 
string."
 (defun edmacro-fix-menu-commands (macro &optional noerror)
   (if (vectorp macro)
       (let (result)
+        ;; Not preloaded in without-x builds.
+        (require 'mwheel)
+        (defvar mouse-wheel-down-event)
+        (defvar mouse-wheel-left-event)
+        (defvar mouse-wheel-right-event)
+        (defvar mouse-wheel-up-event)
        ;; Make a list of the elements.
        (setq macro (append macro nil))
        (dolist (ev macro)
@@ -634,101 +640,10 @@ This function assumes that the events can be stored in a 
string."
 ;;; Parsing a human-readable keyboard macro.
 
 (defun edmacro-parse-keys (string &optional need-vector)
-  (let ((case-fold-search nil)
-       (len (length string)) ; We won't alter string in the loop below.
-       (pos 0)
-       (res []))
-    (while (and (< pos len)
-               (string-match "[^ \t\n\f]+" string pos))
-      (let* ((word-beg (match-beginning 0))
-            (word-end (match-end 0))
-            (word (substring string word-beg len))
-            (times 1)
-            key)
-       ;; Try to catch events of the form "<as df>".
-       (if (string-match "\\`<[^ <>\t\n\f][^>\t\n\f]*>" word)
-           (setq word (match-string 0 word)
-                 pos (+ word-beg (match-end 0)))
-         (setq word (substring string word-beg word-end)
-               pos word-end))
-       (when (string-match "\\([0-9]+\\)\\*." word)
-         (setq times (string-to-number (substring word 0 (match-end 1))))
-         (setq word (substring word (1+ (match-end 1)))))
-       (cond ((string-match "^<<.+>>$" word)
-              (setq key (vconcat (if (eq (key-binding [?\M-x])
-                                         'execute-extended-command)
-                                     [?\M-x]
-                                   (or (car (where-is-internal
-                                             'execute-extended-command))
-                                       [?\M-x]))
-                                 (substring word 2 -2) "\r")))
-             ((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
-                   (progn
-                     (setq word (concat (match-string 1 word)
-                                        (match-string 3 word)))
-                     (not (string-match
-                           "\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
-                           word))))
-              (setq key (list (intern word))))
-             ((or (equal word "REM") (string-match "^;;" word))
-              (setq pos (string-match "$" string pos)))
-             (t
-              (let ((orig-word word) (prefix 0) (bits 0))
-                (while (string-match "^[ACHMsS]-." word)
-                  (cl-incf bits (cdr (assq (aref word 0)
-                                        '((?A . ?\A-\^@) (?C . ?\C-\^@)
-                                          (?H . ?\H-\^@) (?M . ?\M-\^@)
-                                          (?s . ?\s-\^@) (?S . ?\S-\^@)))))
-                  (cl-incf prefix 2)
-                  (cl-callf substring word 2))
-                (when (string-match "^\\^.$" word)
-                  (cl-incf bits ?\C-\^@)
-                  (cl-incf prefix)
-                  (cl-callf substring word 1))
-                (let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
-                                           ("LFD" . "\n") ("TAB" . "\t")
-                                           ("ESC" . "\e") ("SPC" . " ")
-                                           ("DEL" . "\177")))))
-                  (when found (setq word (cdr found))))
-                (when (string-match "^\\\\[0-7]+$" word)
-                  (cl-loop for ch across word
-                            for n = 0 then (+ (* n 8) ch -48)
-                            finally do (setq word (vector n))))
-                (cond ((= bits 0)
-                       (setq key word))
-                      ((and (= bits ?\M-\^@) (stringp word)
-                            (string-match "^-?[0-9]+$" word))
-                       (setq key (cl-loop for x across word
-                                           collect (+ x bits))))
-                      ((/= (length word) 1)
-                       (error "%s must prefix a single character, not %s"
-                              (substring orig-word 0 prefix) word))
-                      ((and (/= (logand bits ?\C-\^@) 0) (stringp word)
-                            ;; We used to accept . and ? here,
-                            ;; but . is simply wrong,
-                            ;; and C-? is not used (we use DEL instead).
-                            (string-match "[@-_a-z]" word))
-                       (setq key (list (+ bits (- ?\C-\^@)
-                                          (logand (aref word 0) 31)))))
-                      (t
-                       (setq key (list (+ bits (aref word 0)))))))))
-       (when key
-         (cl-loop repeat times do (cl-callf vconcat res key)))))
-    (when (and (>= (length res) 4)
-              (eq (aref res 0) ?\C-x)
-              (eq (aref res 1) ?\()
-              (eq (aref res (- (length res) 2)) ?\C-x)
-              (eq (aref res (- (length res) 1)) ?\)))
-      (setq res (cl-subseq res 2 -2)))
-    (if (and (not need-vector)
-            (cl-loop for ch across res
-                      always (and (characterp ch)
-                                  (let ((ch2 (logand ch (lognot ?\M-\^@))))
-                                    (and (>= ch2 0) (<= ch2 127))))))
-       (concat (cl-loop for ch across res
-                         collect (if (= (logand ch ?\M-\^@) 0)
-                                     ch (+ ch 128))))
-      res)))
+  (let ((result (kbd string)))
+    (if (and need-vector (stringp result))
+        (seq-into result 'vector)
+      result)))
 
 (provide 'edmacro)
 
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index ba88c81913..f907bba4c6 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -308,51 +308,51 @@ If point is not enclosed by any lists, return ((t) . 
(t))."
           ;; called when `scan-sexps' ran perfectly, when it found
           ;; a parenthesis pointing in the direction of travel.
           ;; Also when travel started inside a comment and exited it.
-          #'(lambda ()
-              (setq outermost (list t))
-              (unless innermost
-                (setq innermost (list t)))))
+          (lambda ()
+            (setq outermost (list t))
+            (unless innermost
+              (setq innermost (list t)))))
          (ended-prematurely-fn
           ;; called when `scan-sexps' crashed against a parenthesis
           ;; pointing opposite the direction of travel.  After
           ;; traversing that character, the idea is to travel one sexp
           ;; in the opposite direction looking for a matching
           ;; delimiter.
-          #'(lambda ()
-              (let* ((pos (point))
-                     (matched
-                      (save-excursion
-                        (cond ((< direction 0)
-                               (condition-case nil
-                                   (eq (char-after pos)
-                                       (electric-pair--with-uncached-syntax
-                                           (table)
-                                         (matching-paren
-                                          (char-before
-                                           (scan-sexps (point) 1)))))
-                                 (scan-error nil)))
-                              (t
-                               ;; In this case, no need to use
-                               ;; `scan-sexps', we can use some
-                               ;; `electric-pair--syntax-ppss' in this
-                               ;; case (which uses the quicker
-                               ;; `syntax-ppss' in some cases)
-                               (let* ((ppss (electric-pair--syntax-ppss
-                                             (1- (point))))
-                                      (start (car (last (nth 9 ppss))))
-                                      (opener (char-after start)))
-                                 (and start
-                                      (eq (char-before pos)
-                                          (or (with-syntax-table table
-                                                (matching-paren opener))
-                                              opener))))))))
-                     (actual-pair (if (> direction 0)
-                                      (char-before (point))
-                                    (char-after (point)))))
-                (unless innermost
-                  (setq innermost (cons matched actual-pair)))
-                (unless matched
-                  (setq outermost (cons matched actual-pair)))))))
+          (lambda ()
+            (let* ((pos (point))
+                   (matched
+                    (save-excursion
+                      (cond ((< direction 0)
+                             (condition-case nil
+                                 (eq (char-after pos)
+                                     (electric-pair--with-uncached-syntax
+                                      (table)
+                                      (matching-paren
+                                       (char-before
+                                        (scan-sexps (point) 1)))))
+                               (scan-error nil)))
+                            (t
+                             ;; In this case, no need to use
+                             ;; `scan-sexps', we can use some
+                             ;; `electric-pair--syntax-ppss' in this
+                             ;; case (which uses the quicker
+                             ;; `syntax-ppss' in some cases)
+                             (let* ((ppss (electric-pair--syntax-ppss
+                                           (1- (point))))
+                                    (start (car (last (nth 9 ppss))))
+                                    (opener (char-after start)))
+                               (and start
+                                    (eq (char-before pos)
+                                        (or (with-syntax-table table
+                                              (matching-paren opener))
+                                            opener))))))))
+                   (actual-pair (if (> direction 0)
+                                    (char-before (point))
+                                  (char-after (point)))))
+              (unless innermost
+                (setq innermost (cons matched actual-pair)))
+              (unless matched
+                (setq outermost (cons matched actual-pair)))))))
     (save-excursion
       (while (not outermost)
         (condition-case err
diff --git a/lisp/electric.el b/lisp/electric.el
index 4394fae436..a2f24ca05c 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -506,11 +506,11 @@ This list's members correspond to left single quote, 
right single
 quote, left double quote, and right double quote, respectively."
   :version "26.1"
   :type '(list character character character character)
-  :safe #'(lambda (x)
-           (pcase x
-             (`(,(pred characterp) ,(pred characterp)
-                ,(pred characterp) ,(pred characterp))
-              t)))
+  :safe (lambda (x)
+          (pcase x
+            (`(,(pred characterp) ,(pred characterp)
+               ,(pred characterp) ,(pred characterp))
+             t)))
   :group 'electricity)
 
 (defcustom electric-quote-paragraph t
diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el
index f620cdbb33..aaacba2c8e 100644
--- a/lisp/emacs-lisp/autoload.el
+++ b/lisp/emacs-lisp/autoload.el
@@ -462,7 +462,7 @@ if `autoload-timestamps' is non-nil, otherwise a fixed fake 
time is inserted)."
            (insert "\n" generate-autoload-section-continuation))))))
 
 (defun autoload-find-file (file)
-  "Fetch file and put it in a temp buffer.  Return the buffer."
+  "Fetch FILE and put it in a temp buffer.  Return the buffer."
   ;; It is faster to avoid visiting the file.
   (setq file (expand-file-name file))
   (with-current-buffer (get-buffer-create " *autoload-file*")
@@ -482,10 +482,10 @@ if `autoload-timestamps' is non-nil, otherwise a fixed 
fake time is inserted)."
   "File local variable to prevent scanning this file for autoload cookies.")
 
 (defun autoload-file-load-name (file outfile)
-  "Compute the name that will be used to load FILE."
-  ;; OUTFILE should be the name of the global loaddefs.el file, which
-  ;; is expected to be at the root directory of the files we're
-  ;; scanning for autoloads and will be in the `load-path'.
+  "Compute the name that will be used to load FILE.
+OUTFILE should be the name of the global loaddefs.el file, which
+is expected to be at the root directory of the files we are
+scanning for autoloads and will be in the `load-path'."
   (let* ((name (file-relative-name file (file-name-directory outfile)))
          (names '())
          (dir (file-name-directory outfile)))
diff --git a/lisp/emacs-lisp/avl-tree.el b/lisp/emacs-lisp/avl-tree.el
index 4382985eb8..3f803107a1 100644
--- a/lisp/emacs-lisp/avl-tree.el
+++ b/lisp/emacs-lisp/avl-tree.el
@@ -330,8 +330,7 @@ inserted data."
               data)))
        (if (or (funcall cmpfun newdata data)
                (funcall cmpfun data newdata))
-           (error "avl-tree-enter:\
- updated data does not match existing data"))
+            (error "avl-tree-enter: Updated data does not match existing 
data"))
        (setf (avl-tree--node-data br) newdata)
        (cons nil newdata))  ; return value
       ))))
diff --git a/lisp/emacs-lisp/backquote.el b/lisp/emacs-lisp/backquote.el
index 173c11644d..fe39e8d099 100644
--- a/lisp/emacs-lisp/backquote.el
+++ b/lisp/emacs-lisp/backquote.el
@@ -103,7 +103,10 @@ b              => (ba bb bc)               ; assume b has 
this value
 \\=`(a ,b c)      => (a (ba bb bc) c)  ; insert the value of b
 \\=`(a ,@b c)     => (a ba bb bc c)    ; splice in the value of b
 
-Vectors work just like lists.  Nested backquotes are permitted."
+Vectors work just like lists.  Nested backquotes are permitted.
+
+Note that some macros, such as `pcase', use this symbol for other
+purposes."
   (cdr (backquote-process structure)))
 
 ;; GNU Emacs has no reader macros
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index c15814afa0..9c64083b64 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -317,6 +317,10 @@ occur an indeterminate number of times and thus have 
effect on code
 sequentially preceding the mutation itself.
 Same format as `byte-optimize--lexvars', with shared structure and contents.")
 
+(defvar byte-optimize--inhibit-outside-loop-constprop nil
+  "If t, don't propagate values for variables declared outside the inner loop.
+This indicates the loop discovery phase.")
+
 (defvar byte-optimize--dynamic-vars nil
   "List of variables declared as dynamic during optimisation.")
 
@@ -402,15 +406,13 @@ for speeding up processing.")
            (cond
             ((not lexvar) form)
             (for-effect nil)
-            ((cddr lexvar)            ; Value available?
-             (if (assq form byte-optimize--vars-outside-loop)
-                 ;; Cannot substitute; mark for retention to avoid the
-                 ;; variable being eliminated.
-                 (progn
-                   (setcar (cdr lexvar) t)
-                   form)
-               ;; variable value to use
-               (caddr lexvar)))
+            ((and (cddr lexvar)         ; substitution available
+                  ;; Perform substitution, except during the loop mutation
+                  ;; discovery phase if the variable was bound outside the
+                  ;; innermost loop.
+                  (not (and byte-optimize--inhibit-outside-loop-constprop
+                            (assq form byte-optimize--vars-outside-loop))))
+             (caddr lexvar))
             (t form))))
         (t form)))
       (`(quote . ,v)
@@ -488,14 +490,26 @@ for speeding up processing.")
          (cons fn (nreverse args))))
 
       (`(while ,exp . ,exps)
-       ;; FIXME: We conservatively prevent the substitution of any variable
-       ;; bound outside the loop in case it is mutated later in the loop,
-       ;; but this misses many opportunities: variables not mutated in the
-       ;; loop at all, and variables affecting the initial condition (which
-       ;; is always executed unconditionally).
+       ;; FIXME: If the loop condition is statically nil after substitution
+       ;; of surrounding variables then we can eliminate the whole loop,
+       ;; even if those variables are mutated inside the loop.
+       ;; We currently don't perform this important optimisation.
        (let* ((byte-optimize--vars-outside-loop byte-optimize--lexvars)
-              (condition (byte-optimize-form exp nil))
-              (body (byte-optimize-body exps t)))
+              (condition-body
+               (if byte-optimize--inhibit-outside-loop-constprop
+                   ;; We are already inside the discovery phase of an outer
+                   ;; loop so there is no need for traversing this loop twice.
+                   (cons exp exps)
+                 ;; Discovery phase: run optimisation without substitution
+                 ;; of variables bound outside this loop.
+                 (let ((byte-optimize--inhibit-outside-loop-constprop t))
+                   (cons (byte-optimize-form exp nil)
+                         (byte-optimize-body exps t)))))
+              ;; Optimise again, this time with constprop enabled (unless
+              ;; we are in discovery of an outer loop),
+              ;; as mutated variables have been marked as non-substitutable.
+              (condition (byte-optimize-form (car condition-body) nil))
+              (body (byte-optimize-body (cdr condition-body) t)))
          `(while ,condition . ,body)))
 
       (`(interactive . ,_)
@@ -793,8 +807,10 @@ for speeding up processing.")
                (bindings nil))
           (dolist (var let-vars)
             ;; VAR is (NAME EXPR [KEEP [VALUE]])
-            (when (or (not (nthcdr 3 var)) (nth 2 var))
-              ;; Value not present, or variable marked to be kept.
+            (when (or (not (nthcdr 3 var)) (nth 2 var)
+                      byte-optimize--inhibit-outside-loop-constprop)
+              ;; Value not present, or variable marked to be kept,
+              ;; or we are in the loop discovery phase: keep the binding.
               (push (list (nth 0 var) (nth 1 var)) bindings)))
           (cons bindings opt-body)))
 
@@ -1170,6 +1186,72 @@ See Info node `(elisp) Integer Basics'."
 
 (put 'concat 'byte-optimizer #'byte-optimize-concat)
 
+(defun byte-optimize-define-key (form)
+  "Expand key bindings in FORM."
+  (let ((key (nth 2 form)))
+    (if (and (vectorp key)
+             (= (length key) 1)
+             (stringp (aref key 0)))
+        ;; We have key on the form ["C-c C-c"].
+        (if (not (kbd-valid-p (aref key 0)))
+            (error "Invalid `kbd' syntax: %S" key)
+          (list (nth 0 form) (nth 1 form)
+                (kbd (aref key 0)) (nth 4 form)))
+      ;; No improvement.
+      form)))
+
+(put 'define-key 'byte-optimizer #'byte-optimize-define-key)
+
+(defun byte-optimize-define-keymap (form)
+  "Expand key bindings in FORM."
+  (let ((result nil)
+        (orig-form form)
+        improved)
+    (push (pop form) result)
+    (while (and form
+                (keywordp (car form))
+                (not (eq (car form) :menu)))
+      (unless (memq (car form)
+                    '(:full :keymap :parent :suppress :name :prefix))
+        (error "Invalid keyword: %s" (car form)))
+      (push (pop form) result)
+      (when (null form)
+        (error "Uneven number of keywords in %S" form))
+      (push (pop form) result))
+    ;; Bindings.
+    (while form
+      (let ((key (pop form)))
+        (if (and (vectorp key)
+                 (= (length key) 1)
+                 (stringp (aref key 0)))
+            (progn
+              (unless (kbd-valid-p (aref key 0))
+                (error "Invalid `kbd' syntax: %S" key))
+              (push (kbd (aref key 0)) result)
+              (setq improved t))
+          ;; No improvement.
+          (push key result)))
+      (when (null form)
+        (error "Uneven number of key bindings in %S" form))
+      (push (pop form) result))
+    (if improved
+        (nreverse result)
+      orig-form)))
+
+(defun byte-optimize-define-keymap--define (form)
+  "Expand key bindings in FORM."
+  (if (not (consp (nth 1 form)))
+      form
+    (let ((optimized (byte-optimize-define-keymap (nth 1 form))))
+      (if (eq optimized (nth 1 form))
+          ;; No improvement.
+          form
+        (list (car form) optimized)))))
+
+(put 'define-keymap 'byte-optimizer #'byte-optimize-define-keymap)
+(put 'define-keymap--define 'byte-optimizer
+     #'byte-optimize-define-keymap--define)
+
 ;; I'm not convinced that this is necessary.  Doesn't the optimizer loop
 ;; take care of this? - Jamie
 ;; I think this may some times be necessary to reduce ie (quote 5) to 5,
@@ -1245,7 +1327,7 @@ See Info node `(elisp) Integer Basics'."
            (list 'or (car (car clauses))
                  (byte-optimize-cond
                   (cons (car form) (cdr (cdr form)))))
-         form))
+         (and clauses form)))
     form))
 
 (defun byte-optimize-if (form)
@@ -1351,17 +1433,24 @@ See Info node `(elisp) Integer Basics'."
                              (and (consp binding) (cadr binding)))
                            bindings)
                  ,const)
-       `(let* ,(butlast bindings) ,(cadar (last bindings)) ,const)))
+       `(let* ,(butlast bindings)
+          ,@(and (consp (car (last bindings)))
+                 (cdar (last bindings)))
+          ,const)))
 
     ;; Body is last variable.
-    (`(,head ,bindings ,(and var (pred symbolp) (pred (not keywordp))
-                             (pred (not booleanp))
-                             (guard (eq var (caar (last bindings))))))
+    (`(,head ,(and bindings
+                   (let last-var (let ((last (car (last bindings))))
+                                   (if (consp last) (car last) last))))
+             ,(and last-var             ; non-linear pattern
+                   (pred symbolp) (pred (not keywordp)) (pred (not booleanp))))
      (if (eq head 'let)
          `(progn ,@(mapcar (lambda (binding)
                              (and (consp binding) (cadr binding)))
                            bindings))
-       `(let* ,(butlast bindings) ,(cadar (last bindings)))))
+       `(let* ,(butlast bindings)
+          ,@(and (consp (car (last bindings)))
+                 (cdar (last bindings))))))
 
     (_ form)))
 
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 35c80e524c..d82d9454e8 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -380,7 +380,7 @@ You don't need this.  (See bytecomp.el commentary for more 
details.)
   "Define an inline function.  The syntax is just like that of `defun'.
 
 \(fn NAME ARGLIST &optional DOCSTRING DECL &rest BODY)"
-  (declare (debug defun) (doc-string 3))
+  (declare (debug defun) (doc-string 3) (indent 2))
   (or (memq (get name 'byte-optimizer)
            '(nil byte-compile-inline-expand))
       (error "`%s' is a primitive" name))
@@ -422,7 +422,8 @@ was first made obsolete, for example a date or a release 
number."
                                            &optional docstring)
   "Set OBSOLETE-NAME's function definition to CURRENT-NAME and mark it 
obsolete.
 
-\(define-obsolete-function-alias \\='old-fun \\='new-fun \"28.1\" \"old-fun's 
doc.\")
+\(define-obsolete-function-alias \\='old-fun \\='new-fun \"28.1\" \
+\"old-fun's doc.\")
 
 is equivalent to the following two lines of code:
 
@@ -433,7 +434,7 @@ WHEN should be a string indicating when the function was 
first
 made obsolete, for example a date or a release number.
 
 See the docstrings of `defalias' and `make-obsolete' for more details."
-  (declare (doc-string 4))
+  (declare (doc-string 4) (indent defun))
   `(progn
      (defalias ,obsolete-name ,current-name ,docstring)
      (make-obsolete ,obsolete-name ,current-name ,when)))
@@ -482,7 +483,7 @@ For the benefit of Customize, if OBSOLETE-NAME has
 any of the following properties, they are copied to
 CURRENT-NAME, if it does not already have them:
 `saved-value', `saved-variable-comment'."
-  (declare (doc-string 4))
+  (declare (doc-string 4) (indent defun))
   `(progn
      (defvaralias ,obsolete-name ,current-name ,docstring)
      ;; See Bug#4706.
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index be74195778..471a0b623a 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -299,7 +299,7 @@ The information is logged to `byte-compile-log-buffer'."
   '(redefine callargs free-vars unresolved
              obsolete noruntime interactive-only
              make-local mapcar constants suspicious lexical lexical-dynamic
-             docstrings)
+             docstrings not-unused)
   "The list of warning types used when `byte-compile-warnings' is t.")
 (defcustom byte-compile-warnings t
   "List of warnings that the byte-compiler should issue (t for all).
@@ -321,6 +321,7 @@ Elements of the list may be:
               lexically bound variable declared dynamic elsewhere
   make-local  calls to `make-variable-buffer-local' that may be incorrect.
   mapcar      mapcar called for effect.
+  not-unused  warning about using variables with symbol names starting with _.
   constants   let-binding of, or assignment to, constants/nonvariables.
   docstrings  docstrings that are too wide (longer than
               `byte-compile-docstring-max-column' or
@@ -1082,7 +1083,7 @@ If STR is something like \"Buffer foo.el\", return 
#<buffer foo.el>
 (defconst emacs-lisp-compilation-parse-errors-filename-function
   #'emacs-lisp-compilation-file-name-or-buffer
   "The value for `compilation-parse-errors-filename-function' for when
-we go into emacs-lisp-compilation-mode.")
+we go into `emacs-lisp-compilation-mode'.")
 
 (defcustom emacs-lisp-compilation-search-path '(nil)
   "Directories to search for files named in byte-compile error messages.
@@ -1649,16 +1650,27 @@ URLs."
    (replace-regexp-in-string
     (rx (or
          ;; Ignore some URLs.
-         (seq "http" (? "s") "://" (* anychar))
+         (seq "http" (? "s") "://" (* nonl))
          ;; Ignore these `substitute-command-keys' substitutions.
          (seq "\\" (or "="
                        (seq "<" (* (not ">")) ">")
                        (seq "{" (* (not "}")) "}")))
          ;; Ignore the function signature that's stashed at the end of
          ;; the doc string (in some circumstances).
-         (seq bol "(fn (" (* nonl))))
+         (seq bol "(" (+ (any word "-/:[]&"))
+              ;; One or more arguments.
+              (+ " " (or
+                      ;; Arguments.
+                      (+ (or (syntax symbol)
+                             (any word "-/:[]&=().?^\\#'")))
+                      ;; Argument that is a list.
+                      (seq "(" (* (not ")")) ")")))
+              ")")))
     ""
-    ;; Heuristic: assume these substitutions are of some length N.
+    ;; Heuristic: We can't reliably do `subsititute-command-keys'
+    ;; substitutions, since the value of a keymap in general can't be
+    ;; known at compile time.  So instead, we assume that these
+    ;; substitutions are of some length N.
     (replace-regexp-in-string
      (rx "\\" (or (seq "[" (* (not "]")) "]")))
      (make-string byte-compile--wide-docstring-substitution-len ?x)
@@ -1678,13 +1690,6 @@ value, it will override this variable."
   "Warn if documentation string of FORM is too wide.
 It is too wide if it has any lines longer than the largest of
 `fill-column' and `byte-compile-docstring-max-column'."
-  ;; This has some limitations that it would be nice to fix:
-  ;; 1. We don't try to handle defuns.  It is somewhat tricky to get
-  ;;    it right since `defun' is a macro.  Also, some macros
-  ;;    themselves produce defuns (e.g. `define-derived-mode').
-  ;; 2. We assume that any `subsititute-command-keys' command replacement has a
-  ;;    given length.  We can't reliably do these replacements, since the value
-  ;;    of the keymaps in general can't be known at compile time.
   (when (byte-compile-warning-enabled-p 'docstrings)
     (let ((col (max byte-compile-docstring-max-column fill-column))
           kind name docs)
@@ -1695,12 +1700,10 @@ It is too wide if it has any lines longer than the 
largest of
          (setq kind (nth 0 form))
          (setq name (nth 1 form))
          (setq docs (nth 3 form)))
-        ;; Here is how one could add lambda's here:
-        ;; ('lambda
-        ;;   (setq kind "")   ; can't be "function", unfortunately
-        ;;   (setq docs (and (stringp (nth 2 form))
-        ;;                   (nth 2 form))))
-        )
+        ('lambda
+          (setq kind "")          ; can't be "function", unfortunately
+          (setq docs (and (stringp (nth 2 form))
+                          (nth 2 form)))))
       (when (and (consp name) (eq (car name) 'quote))
         (setq name (cadr name)))
       (setq name (if name (format " `%s'" name) ""))
@@ -2808,8 +2811,8 @@ not to take responsibility for the actual compilation of 
the code."
           t)))))
 
 (defun byte-compile-output-as-comment (exp quoted)
-  "Print Lisp object EXP in the output file, inside a comment,
-and return the file (byte) position it will have.
+  "Print Lisp object EXP in the output file, inside a comment.
+Return the file (byte) position it will have.
 If QUOTED is non-nil, print with quoting; otherwise, print without quoting."
   (with-current-buffer byte-compile--outbuffer
     (let ((position (point)))
@@ -2930,6 +2933,8 @@ If FORM is a lambda or a macro, byte-compile it as a 
function."
                   (macroexp--const-symbol-p arg t))
               (error "Invalid lambda variable %s" arg))
              ((eq arg '&rest)
+               (unless (cdr list)
+                 (error "&rest without variable name"))
               (when (cddr list)
                 (error "Garbage following &rest VAR in lambda-list"))
                (when (memq (cadr list) '(&optional &rest))
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index 0a6b04b4c1..03e109f250 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -608,10 +608,9 @@ FORM is the parent form that binds this var."
     (`((,(and var (guard (eq ?_ (aref (symbol-name var) 0)))) . ,_)
        ,_ ,_ ,_ ,_)
      ;; FIXME: Convert this warning to use `macroexp--warn-wrap'
-     ;; so as to give better position information and obey
-     ;; `byte-compile-warnings'.
-     (byte-compile-warn
-      "%s `%S' not left unused" varkind var))
+     ;; so as to give better position information.
+     (when (byte-compile-warning-enabled-p 'not-unused var)
+       (byte-compile-warn "%s `%S' not left unused" varkind var)))
     ((and (let (or 'let* 'let) (car form))
           `((,var) ;; (or `(,var nil) : Too many false positives: bug#47080
             t nil ,_ ,_))
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 5224a943ac..7bb82c2e8b 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -164,6 +164,7 @@
 (require 'cl-lib)
 (require 'help-mode) ;; for help-xref-info-regexp
 (require 'thingatpt) ;; for handy thing-at-point-looking-at
+(require 'lisp-mode) ;; for lisp-mode-symbol-regexp
 (require 'dired)     ;; for dired-get-filename and dired-map-over-marks
 (require 'lisp-mnt)
 
@@ -253,7 +254,7 @@ with these words enabled."
 (defcustom checkdoc-max-keyref-before-warn nil
   "If non-nil, number of \\\\=[command-to-keystroke] tokens allowed in a doc 
string.
 Any more than this and a warning is generated suggesting that the construct
-\\\\={keymap} be used instead.  If the value is nil, never warn.
+\\\\={mapvar} be used instead.  If the value is nil, never warn.
 
 It used to not be practical to use `\\\\=[...]' very many times,
 because display of the documentation string would become slow.
@@ -338,6 +339,7 @@ See Info node `(elisp) Documentation Tips' for background."
 ;; (setq checkdoc--argument-missing-flag nil)      ; optional
 ;; (setq checkdoc--disambiguate-symbol-flag nil)   ; optional
 ;; (setq checkdoc--interactive-docstring-flag nil) ; optional
+;; (setq checkdoc-verb-check-experimental-flag nil)
 ;; Then use `M-x find-dired' ("-name '*.el'") and `M-x checkdoc-dired'
 
 (defvar checkdoc--argument-missing-flag t
@@ -492,6 +494,9 @@ be re-created.")
 (defconst checkdoc--help-buffer "*Checkdoc Help*"
   "Name of buffer used for Checkdoc Help.")
 
+(defvar checkdoc-commentary-header-string "\n;;; Commentary:\n;; \n\n"
+  "String inserted as commentary marker in `checkdoc-file-comments-engine'.")
+
 ;;; User level commands
 ;;
 ;;;###autoload
@@ -1625,7 +1630,7 @@ mouse-[0-3]\\)\\)\\>"))
             (checkdoc-create-error
              (concat
               "Keycode " (match-string 1)
-              " embedded in doc string.  Use \\\\<keymap> & \\\\[function] "
+              " embedded in doc string.  Use \\\\<mapvar> & \\\\[command] "
               "instead")
              (match-beginning 1) (match-end 1) t))))
      ;; Optionally warn about too many command substitutions.
@@ -1635,7 +1640,7 @@ mouse-[0-3]\\)\\)\\>"))
                                      (1+ checkdoc-max-keyref-before-warn))
                   (not (re-search-forward "\\\\\\\\{\\w+}" e t)))
              (checkdoc-create-error
-              "Too many occurrences of \\[function].  Use \\{keymap} instead"
+              "Too many occurrences of \\[command].  Use \\{mapvar} instead"
               s (marker-position e)))))
      ;; Ambiguous quoted symbol.  When a symbol is both bound and fbound,
      ;; and is referred to in documentation, it should be prefixed with
@@ -1653,7 +1658,10 @@ mouse-[0-3]\\)\\)\\>"))
                   me (match-end 1))
             (if (and sym (boundp sym) (fboundp sym)
                       checkdoc--disambiguate-symbol-flag
-                     (save-excursion
+                      ;; Mode names do not need disambiguating.  (Bug#4110)
+                      (not (string-match (rx "-mode" string-end)
+                                         (symbol-name sym)))
+                      (save-excursion
                        (goto-char mb)
                        (forward-word-strictly -1)
                        (not (looking-at
@@ -1685,20 +1693,28 @@ function,command,variable,option or symbol." ms1))))))
      ;;   first line can be wider if necessary to fit the
      ;;   information that ought to be there.
      (save-excursion
-       (let ((start (point))
-            (eol nil))
+       (let* ((start (point))
+              (eol nil)
+              ;; Respect this file local variable.
+              (max-column (max 80 byte-compile-docstring-max-column))
+              ;; Allow the first line to be three characters longer, to
+              ;; fit the leading ` "' while still having a docstring
+              ;; shorter than e.g. 80 characters.
+              (first t)
+              (get-max-column (lambda () (+ max-column (if first 3 0)))))
         (while (and (< (point) e)
                     (or (progn (end-of-line) (setq eol (point))
-                               (< (current-column) 80))
+                                (< (current-column) (funcall get-max-column)))
                         (progn (beginning-of-line)
                                (re-search-forward "\\\\\\\\[[<{]"
                                                   eol t))
-                        (checkdoc-in-sample-code-p start e)))
+                         (checkdoc-in-sample-code-p start e)))
+           (setq first nil)
           (forward-line 1))
         (end-of-line)
-        (if (and (< (point) e) (> (current-column) 80))
+         (if (and (< (point) e) (> (current-column) (funcall get-max-column)))
             (checkdoc-create-error
-             "Some lines are over 80 columns wide"
+              (format "Some lines are over %d columns wide" max-column)
              s (save-excursion (goto-char s) (line-end-position))))))
      ;; Here we deviate to tests based on a variable or function.
      ;; We must do this before checking for symbols in quotes because there
@@ -2093,31 +2109,35 @@ The text checked is between START and LIMIT."
 
 (defun checkdoc-in-abbreviation-p (begin)
   "Return non-nil if point is at an abbreviation.
-Examples of abbreviations handled: \"e.g.\", \"i.e.\", \"cf.\"."
+Examples of recognized abbreviations: \"e.g.\", \"i.e.\", \"cf.\"."
   (save-excursion
     (goto-char begin)
     (condition-case nil
-        (progn
-          (forward-sexp -1)
+        (let (single-letter)
+          (forward-word -1)
+          ;; Skip over all dots backwards, as `forward-word' will only
+          ;; go one dot at a time in a string like "e.g.".
+          (while (save-excursion (forward-char -1)
+                                 (looking-at (rx ".")))
+            (forward-word -1))
+          (when (= (point) (1- begin))
+            (setq single-letter t))
           ;; Piece of an abbreviation.
           (looking-at
-           (rx (or letter     ; single letter, as in "a."
-                   (seq
-                    ;; There might exist an escaped parenthesis, as
-                    ;; this is often used in docstrings.  In this
-                    ;; case, `forward-sexp' will have skipped over it,
-                    ;; so we need to skip it here too.
-                    (? "\\(")
-                    ;; The abbreviations:
-                    (or (seq (any "cC") "f")              ; cf.
-                        (seq (any "eE") ".g")             ; e.g.
-                        (seq (any "iI") "." (any "eE")))) ; i.e.
-                   "etc"                                  ; etc.
-                   "vs"                                   ; vs.
-                   ;; Some non-standard or less common ones that we
-                   ;; might as well ignore.
-                   "Inc" "Univ" "misc" "resp")
-               ".")))
+           (if single-letter
+               ;; Handle a single letter, as in "a.", as this might be
+               ;; a part of a list.
+               (rx letter ".")
+             (rx (or
+                  ;; The abbreviations (a trailing dot is added below).
+                  (seq (any "cC") "f")            ; cf.
+                  (seq (any "eE") ".g")           ; e.g.
+                  (seq (any "iI") "." (any "eE")) ; i.e.
+                  "a.k.a" "etc" "vs" "N.B"
+                  ;; Some non-standard or less common ones that we
+                  ;; might as well accept.
+                  "Inc" "Univ" "misc" "resp")
+                 "."))))
       (error t))))
 
 (defun checkdoc-proper-noun-region-engine (begin end)
@@ -2368,8 +2388,13 @@ Code:, and others referenced in the style guide."
        err
        (or
        ;; * Commentary Section
-       (if (not (lm-commentary-mark))
-           (progn
+        (if (and (not (lm-commentary-mark))
+                 ;; No need for a commentary section in test files.
+                 (not (string-match
+                       (rx (or (seq (or "-test.el" "-tests.el") string-end)
+                               "/test/" "/tests/"))
+                       (buffer-file-name))))
+            (progn
              (goto-char (point-min))
              (cond
               ((re-search-forward
@@ -2387,7 +2412,7 @@ Code:, and others referenced in the style guide."
                  nil nil t)))
              (if (checkdoc-y-or-n-p
                    "You should have a \";;; Commentary:\", add one?")
-                 (insert "\n;;; Commentary:\n;; \n\n")
+                  (insert checkdoc-commentary-header-string)
                (checkdoc-create-error
                 "You should have a section marked \";;; Commentary:\""
                 nil nil t)))
@@ -2457,10 +2482,9 @@ Code:, and others referenced in the style guide."
        (save-excursion
          (goto-char (point-max))
          (if (not (re-search-backward
-                   (concat "^;;;[ \t]+" (regexp-quote fn) "\\(" (regexp-quote 
fe)
-                           "\\)?[ \t]+ends here[ \t]*$"
-                           "\\|^;;;[ \t]+ End of file[ \t]+"
-                           (regexp-quote fn) "\\(" (regexp-quote fe) "\\)?")
+                    ;; This should match the requirement in
+                    ;; `package-buffer-info'.
+                    (concat "^;;; " (regexp-quote (concat fn fe)) " ends here")
                    nil t))
               (if (checkdoc-y-or-n-p "No identifiable footer!  Add one?")
                  (progn
@@ -2554,6 +2578,30 @@ Argument END is the maximum bounds to search in."
          (setq return type))))
     return))
 
+(defun checkdoc--error-bad-format-p ()
+  "Return non-nil if the start of error message at point has the wrong format.
+The correct format is \"Foo\" or \"some-symbol: Foo\".  See also
+`error' and Info node `(elisp) Documentation Tips'."
+  (save-excursion
+    ;; Skip the first quote character in string.
+    (forward-char 1)
+    ;; A capital letter is always okay.
+    (unless (let ((case-fold-search nil))
+              (looking-at (rx (or upper-case "%s"))))
+      ;; A defined Lisp symbol is always okay.
+      (unless (and (looking-at (rx (group (regexp lisp-mode-symbol-regexp))))
+                   (or (fboundp (intern (match-string 1)))
+                       (boundp (intern (match-string 1)))))
+        ;; Other Lisp symbols are sometimes okay.
+        (rx-let ((c (? "\\\n")))        ; `c' is for a continued line
+          (let ((case-fold-search nil)
+                (some-symbol (rx (regexp lisp-mode-symbol-regexp)
+                                 c ":" c (+ (any " \t\n"))))
+                (lowercase-str (rx c (group (any "a-z") (+ wordchar)))))
+            (if (looking-at some-symbol)
+                (looking-at (concat some-symbol lowercase-str))
+              (looking-at lowercase-str))))))))
+
 (defun checkdoc--fix-y-or-n-p ()
   "Fix `y-or-n-p' prompt to end with \"?\" or \"? \".
 The space is technically redundant, but also more compatible with
@@ -2601,16 +2649,14 @@ Argument TYPE specifies the type of question, such as 
`error' or `y-or-n-p'."
      ;; In Emacs, the convention is that error messages start with a capital
      ;; letter but *do not* end with a period.  Please follow this convention
      ;; for the sake of consistency.
-     (if (and (save-excursion (forward-char 1)
-                             (looking-at "[a-z]\\w+"))
+     (if (and (checkdoc--error-bad-format-p)
              (not (checkdoc-autofix-ask-replace
-                   (match-beginning 0) (match-end 0)
+                    (match-beginning 1) (match-end 1)
                     "Capitalize your message text?"
-                   (capitalize (match-string 0))
+                    (capitalize (match-string 1))
                    t)))
-        (checkdoc-create-error
-         "Messages should start with a capital letter"
-         (match-beginning 0) (match-end 0))
+         (checkdoc-create-error "Messages should start with a capital letter"
+          (match-beginning 1) (match-end 1))
        nil)
      ;; In general, sentences should have two spaces after the period.
      (checkdoc-sentencespace-region-engine (point)
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index 3840d13ecf..499d26b737 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -336,7 +336,7 @@ non-nil value.
 
 ;;;###autoload
 (defun cl-isqrt (x)
-  "Return the integer square root of the (integer) argument."
+  "Return the integer square root of the (integer) argument X."
   (if (and (integerp x) (> x 0))
       (let ((g (ash 2 (/ (logb x) 2)))
            g2)
@@ -455,7 +455,7 @@ as an integer unless JUNK-ALLOWED is non-nil."
 
 ;;;###autoload
 (defun cl-random (lim &optional state)
-  "Return a random nonnegative number less than LIM, an integer or float.
+  "Return a pseudo-random nonnegative number less than LIM, an integer or 
float.
 Optional second arg STATE is a random-state object."
   (or state (setq state cl--random-state))
   ;; Inspired by "ran3" from Numerical Recipes.  Additive congruential method.
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 1640975b84..3f75cf9922 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -86,6 +86,14 @@
 
 ;;; Code:
 
+;; We provide a mechanism to define new specializers.
+;; Related work can be found in:
+;; - http://www.p-cos.net/documents/filtered-dispatch.pdf
+;; - Generalizers: New metaobjects for generalized dispatch
+;;   http://research.gold.ac.uk/9924/1/els-specializers.pdf
+;; This second one is closely related to what we do here (and that's
+;; the name "generalizer" comes from).
+
 ;; The autoloads.el mechanism which adds package--builtin-versions
 ;; maintenance to loaddefs.el doesn't work for preloaded packages (such
 ;; as this one), so we have to do it by hand!
@@ -100,6 +108,7 @@
 (eval-when-compile (require 'cl-lib))
 (eval-when-compile (require 'cl-macs))  ;For cl--find-class.
 (eval-when-compile (require 'pcase))
+(eval-when-compile (require 'subr-x))
 
 (cl-defstruct (cl--generic-generalizer
                (:constructor nil)
@@ -589,19 +598,10 @@ The set of acceptable TYPEs (also called 
\"specializers\") is defined
         ;; e.g. for tracing/debug-on-entry.
         (defalias sym gfun)))))
 
-(defmacro cl--generic-with-memoization (place &rest code)
-  (declare (indent 1) (debug t))
-  (gv-letplace (getter setter) place
-    `(or ,getter
-         ,(macroexp-let2 nil val (macroexp-progn code)
-            `(progn
-               ,(funcall setter val)
-               ,val)))))
-
 (defvar cl--generic-dispatchers (make-hash-table :test #'equal))
 
 (defun cl--generic-get-dispatcher (dispatch)
-  (cl--generic-with-memoization
+  (with-memoization
       (gethash dispatch cl--generic-dispatchers)
     ;; (message "cl--generic-get-dispatcher (%S)" dispatch)
     (let* ((dispatch-arg (car dispatch))
@@ -644,10 +644,13 @@ The set of acceptable TYPEs (also called 
\"specializers\") is defined
       ;; overkill: better just use a `cl-typep' test.
       (byte-compile
        `(lambda (generic dispatches-left methods)
+          ;; FIXME: We should find a way to expand `with-memoize' once
+          ;; and forall so we don't need `subr-x' when we get here.
+          (eval-when-compile (require 'subr-x))
           (let ((method-cache (make-hash-table :test #'eql)))
             (lambda (,@fixedargs &rest args)
               (let ,bindings
-                (apply (cl--generic-with-memoization
+                (apply (with-memoization
                            (gethash ,tag-exp method-cache)
                          (cl--generic-cache-miss
                           generic ',dispatch-arg dispatches-left methods
@@ -691,7 +694,7 @@ for all those different tags in the method-cache.")
       ;; Special case needed to fix a circularity during bootstrap.
       (cl--generic-standard-method-combination generic methods)
     (let ((f
-           (cl--generic-with-memoization
+           (with-memoization
                ;; FIXME: Since the fields of `generic' are modified, this
                ;; hash-table won't work right, because the hashes will change!
                ;; It's not terribly serious, but reduces the effectiveness of
@@ -1026,7 +1029,10 @@ MET-NAME is as returned by 
`cl--generic-load-hist-format'."
     (when generic
       (require 'help-mode)              ;Needed for `help-function-def' button!
       (save-excursion
-        (insert "\n\nThis is a generic function.\n\n")
+        ;; Ensure that we have two blank lines (but not more).
+        (unless (looking-back "\n\n" (- (point) 2))
+          (insert "\n"))
+        (insert "This is a generic function.\n\n")
         (insert (propertize "Implementations:\n\n" 'face 'bold))
         ;; Loop over fanciful generics
         (dolist (method (cl--generic-method-table generic))
@@ -1140,7 +1146,7 @@ These match if the argument is a cons cell whose car is 
`eql' to VAL."
   ;; since we can't use the `head' specializer to implement itself.
   (if (not (eq (car-safe specializer) 'head))
       (cl-call-next-method)
-    (cl--generic-with-memoization
+    (with-memoization
         (gethash (cadr specializer) cl--generic-head-used)
       specializer)
     (list cl--generic-head-generalizer)))
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 6d6482c349..1852471bcb 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2888,6 +2888,9 @@ Supported keywords for slots are:
 - `:documentation': this is a docstring describing the slot.
 - `:type': the type of the field; currently only used for documentation.
 
+To see the documentation for a defined struct type, use
+\\[describe-symbol] or \\[cl-describe-type].
+
 \(fn NAME &optional DOCSTRING &rest SLOTS)"
   (declare (doc-string 2) (indent 1)
            (debug
@@ -3080,12 +3083,21 @@ Supported keywords for slots are:
                            `(nth ,pos cl-x))))))
              (push slot slots)
              (push default-value defaults)
-             ;; The arg "cl-x" is referenced by name in eg pred-form
+              ;; The arg "cl-x" is referenced by name in e.g. pred-form
              ;; and pred-check, so changing it is not straightforward.
              (push `(,defsym ,accessor (cl-x)
-                       ,(format "Access slot \"%s\" of `%s' struct CL-X.%s"
-                                slot name
-                                (if doc (concat "\n" doc) ""))
+                       ,(concat
+                         ;; NB.  This will produce incorrect results
+                         ;; in some cases, as our coding conventions
+                         ;; says that the first line must be a full
+                         ;; sentence.  However, if we don't word wrap
+                         ;; we will have byte-compiler warnings about
+                         ;; overly long docstrings.  So we can't have
+                         ;; a perfect result here, and choose to avoid
+                         ;; the byte-compiler warnings.
+                         (internal--format-docstring-line
+                          "Access slot \"%s\" of `%s' struct CL-X." slot name)
+                         (if doc (concat "\n" doc) ""))
                        (declare (side-effect-free t))
                        ,access-body)
                     forms)
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 4060fc97d0..0a10505257 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -3653,6 +3653,9 @@ Prepare every function for final compilation and drive 
the C back-end."
 (defvar comp-async-compilation nil
   "Non-nil while executing an asynchronous native compilation.")
 
+(defvar comp-running-batch-compilation nil
+  "Non-nil when compilation is driven by any `batch-*-compile' function.")
+
 (defun comp-final (_)
   "Final pass driving the C back-end for code emission."
   (maphash #'comp-compute-function-type (comp-ctxt-funcs-h comp-ctxt))
@@ -3661,7 +3664,7 @@ Prepare every function for final compilation and drive 
the C back-end."
     ;; unless during bootstrap or async compilation (bug#45056).  GCC
     ;; leaks memory but also interfere with the ability of Emacs to
     ;; detect when a sub-process completes (TODO understand why).
-    (if (or byte+native-compile comp-async-compilation)
+    (if (or comp-running-batch-compilation comp-async-compilation)
        (comp-final1)
       ;; Call comp-final1 in a child process.
       (let* ((output (comp-ctxt-output comp-ctxt))
@@ -3778,15 +3781,18 @@ Return the trampoline if found or nil otherwise."
                         for arg in lambda-list
                         unless (memq arg '(&optional &rest))
                         collect arg)))))
-         ;; Use speed 0 to maximize compilation speed and not to
-         ;; optimize away funcall calls!
+         ;; Use speed 1 for compilation speed and not to optimize away
+         ;; funcall calls!
          (byte-optimize nil)
          (native-comp-speed 1)
          (lexical-binding t))
     (comp--native-compile
      form nil
      (cl-loop
-      for dir in (comp-eln-load-path-eff)
+      for dir in (if native-compile-target-directory
+                     (list (expand-file-name comp-native-version-dir
+                                             native-compile-target-directory))
+                   (comp-eln-load-path-eff))
       for f = (expand-file-name
                (comp-trampoline-filename subr-name)
                dir)
@@ -3873,26 +3879,13 @@ processes from `comp-async-compilations'"
    do (remhash file-name comp-async-compilations))
   (hash-table-count comp-async-compilations))
 
-(declare-function w32-get-nproc "w32.c")
 (defvar comp-num-cpus nil)
 (defun comp-effective-async-max-jobs ()
   "Compute the effective number of async jobs."
   (if (zerop native-comp-async-jobs-number)
       (or comp-num-cpus
           (setf comp-num-cpus
-                ;; FIXME: we already have a function to determine
-                ;; the number of processors, see get_native_system_info in 
w32.c.
-                ;; The result needs to be exported to Lisp.
-                (max 1 (/ (cond ((eq 'windows-nt system-type)
-                                 (w32-get-nproc))
-                                ((executable-find "nproc")
-                                 (string-to-number
-                                  (shell-command-to-string "nproc")))
-                                ((eq 'berkeley-unix system-type)
-                                 (string-to-number
-                                  (shell-command-to-string "sysctl -n 
hw.ncpu")))
-                                (t 1))
-                          2))))
+               (max 1 (/ (num-processors) 2))))
     native-comp-async-jobs-number))
 
 (defvar comp-last-scanned-async-output nil)
@@ -4191,19 +4184,28 @@ form, return the compiled function."
   (comp--native-compile function-or-file nil output))
 
 ;;;###autoload
-(defun batch-native-compile ()
-  "Perform native compilation on remaining command-line arguments.
-Use this from the command line, with ‘-batch’;
-it won’t work in an interactive Emacs.
-Native compilation equivalent to `batch-byte-compile'."
+(defun batch-native-compile (&optional for-tarball)
+  "Perform batch native compilation of remaining command-line arguments.
+
+Native compilation equivalent of `batch-byte-compile'.
+Use this from the command line, with `-batch'; it won't work
+in an interactive Emacs session.
+Optional argument FOR-TARBALL non-nil means the file being compiled
+as part of building the source tarball, in which case the .eln file
+will be placed under the native-lisp/ directory (actually, in the
+last directory in `native-comp-eln-load-path')."
   (comp-ensure-native-compiler)
-  (cl-loop for file in command-line-args-left
-           if (or (null byte+native-compile)
-                  (cl-notany (lambda (re) (string-match re file))
-                             native-comp-bootstrap-deny-list))
-           do (comp--native-compile file)
-           else
-           do (byte-compile-file file)))
+  (let ((comp-running-batch-compilation t)
+        (native-compile-target-directory
+            (if for-tarball
+                (car (last native-comp-eln-load-path)))))
+    (cl-loop for file in command-line-args-left
+             if (or (null byte+native-compile)
+                    (cl-notany (lambda (re) (string-match re file))
+                               native-comp-bootstrap-deny-list))
+             do (comp--native-compile file)
+             else
+             do (byte-compile-file file))))
 
 ;;;###autoload
 (defun batch-byte+native-compile ()
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 0592db85df..163528acf6 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -701,7 +701,8 @@ To specify a nil argument interactively, exit with an empty 
minibuffer."
   (interactive
    (list (let ((name
                (completing-read
-                "Cancel debug on entry to function (default all functions): "
+                 (format-prompt "Cancel debug on entry to function"
+                                "all functions")
                 (mapcar #'symbol-name (debug--function-list)) nil t)))
           (when name
             (unless (string= name "")
@@ -804,7 +805,8 @@ To specify a nil argument interactively, exit with an empty 
minibuffer."
   (interactive
    (list (let ((name
                 (completing-read
-                 "Cancel debug on set for variable (default all variables): "
+                 (format-prompt "Cancel debug on set for variable"
+                                "all variables")
                  (mapcar #'symbol-name (debug--variable-list)) nil t)))
            (when name
              (unless (string= name "")
diff --git a/lisp/emacs-lisp/derived.el b/lisp/emacs-lisp/derived.el
index 5e9644d823..af5eecc22a 100644
--- a/lisp/emacs-lisp/derived.el
+++ b/lisp/emacs-lisp/derived.el
@@ -94,19 +94,19 @@
 ;;; PRIVATE: defsubst must be defined before they are first used
 
 (defsubst derived-mode-hook-name (mode)
-  "Construct a mode-hook name based on a MODE name."
+  "Construct a mode-hook name based on the symbol MODE."
   (intern (concat (symbol-name mode) "-hook")))
 
 (defsubst derived-mode-map-name (mode)
-  "Construct a map name based on a MODE name."
+  "Construct a map name based on the symbol MODE."
   (intern (concat (symbol-name mode) "-map")))
 
 (defsubst derived-mode-syntax-table-name (mode)
-  "Construct a syntax-table name based on a MODE name."
+  "Construct a syntax-table name based on the symbol MODE."
   (intern (concat (symbol-name mode) "-syntax-table")))
 
 (defsubst derived-mode-abbrev-table-name (mode)
-  "Construct an abbrev-table name based on a MODE name."
+  "Construct an abbrev-table name based on the symbol MODE."
   (intern (concat (symbol-name mode) "-abbrev-table")))
 
 ;; PUBLIC: define a new major mode which inherits from an existing one.
@@ -120,7 +120,7 @@ The arguments are as follows:
 CHILD:     the name of the command for the derived mode.
 PARENT:    the name of the command for the parent mode (e.g. `text-mode')
            or nil if there is no parent.
-NAME:      a string which will appear in the status line (e.g. \"Hypertext\")
+NAME:      a string that will appear in the mode line (e.g. \"HTML\")
 DOCSTRING: an optional documentation string--if you do not supply one,
            the function will attempt to invent something useful.
 KEYWORD-ARGS:
@@ -166,8 +166,8 @@ the parent, and then sets the variable `case-fold-search' 
to nil:
 Note that if the documentation string had been left out, it would have
 been generated automatically, with a reference to the keymap.
 
-The new mode runs the hook constructed by the function
-`derived-mode-hook-name'.
+The new mode runs the hook named MODE-hook.  For `foo-mode',
+the hook will be named `foo-mode-hook'.
 
 See Info node `(elisp)Derived Modes' for more details.
 
@@ -175,12 +175,7 @@ See Info node `(elisp)Derived Modes' for more details.
   (declare (debug (&define name symbolp sexp [&optional stringp]
                           [&rest keywordp sexp] def-body))
           (doc-string 4)
-          ;; Ask not what
-          ;;(indent 3)
-          ;; can do for you, ask what it can do to others. IOW, the
-          ;; missing of indentation setting here is the indentation
-          ;; setting and not an oversight.
-          )
+          (indent defun))
 
   (when (and docstring (not (stringp docstring)))
     ;; Some trickiness, since what appears to be the docstring may really be
@@ -321,7 +316,7 @@ No problems result if this variable is not bound.
              (format "Major mode derived from `%s' by `define-derived-mode'.
 It inherits all of the parent's attributes, but has its own keymap%s:
 
-  `%s'%s
+%s
 
 which more-or-less shadow%s %s's corresponding table%s."
                      parent
@@ -330,12 +325,14 @@ which more-or-less shadow%s %s's corresponding table%s."
                            (abbrev "\nand abbrev table")
                            (syntax "\nand syntax table")
                            (t ""))
-                     map
-                     (cond ((and abbrev syntax)
-                            (format ", `%s' and `%s'" abbrev syntax))
-                           ((or abbrev syntax)
-                            (format " and `%s'" (or abbrev syntax)))
-                           (t ""))
+                      (internal--format-docstring-line
+                       "  `%s'%s"
+                       map
+                       (cond ((and abbrev syntax)
+                              (format ", `%s' and `%s'" abbrev syntax))
+                             ((or abbrev syntax)
+                              (format " and `%s'" (or abbrev syntax)))
+                             (t "")))
                      (if (or abbrev syntax) "" "s")
                      parent
                      (if (or abbrev syntax) "s" "")))))
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index dfbae746cc..db86e0e029 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -93,7 +93,7 @@ Enable the mode if ARG is nil, omitted, or is a positive 
number.
 Disable the mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `%S'.
+evaluate `%s'.
 
 The mode's hook is called both when the mode is enabled and when
 it is disabled.")
@@ -109,7 +109,9 @@ it is disabled.")
              (docs-fc (bound-and-true-p emacs-lisp-docstring-fill-column))
              (fill-column (if (integerp docs-fc) docs-fc 65))
              (argdoc (format easy-mmode--arg-docstring mode-pretty-name
-                             getter))
+                             ;; Avoid having quotes turn into pretty quotes.
+                             (string-replace "'" "\\\\='"
+                                             (format "%S" getter))))
              (filled (if (fboundp 'fill-region)
                          (with-temp-buffer
                            (insert argdoc)
@@ -163,8 +165,8 @@ BODY contains code to execute each time the mode is enabled 
or disabled.
                Not used if you also specify :variable.
 :lighter SPEC  Text displayed in the mode line when the mode is on.
 :keymap MAP    Keymap bound to the mode keymap.  Defaults to `MODE-map'.
-               If non-nil, it should be a variable name (whose value is
-               a keymap), or an expression that returns either a keymap or
+                If non-nil, it should be an unquoted variable name (whose value
+                is a keymap), or an expression that returns either a keymap or
                a list of (KEY . BINDING) pairs where KEY and BINDING are
                suitable for `define-key'.  If you supply a KEYMAP argument
                that is not a symbol, this macro defines the variable MODE-map
@@ -196,6 +198,7 @@ INIT-VALUE LIGHTER KEYMAP.
 
 \(fn MODE DOC [KEYWORD VAL ... &rest BODY])"
   (declare (doc-string 2)
+           (indent defun)
            (debug (&define name string-or-null-p
                           [&optional [&not keywordp] sexp
                            &optional [&not keywordp] sexp
@@ -448,7 +451,7 @@ after running the major mode's hook.  However, MODE is not 
turned
 on if the hook has explicitly disabled it.
 
 \(fn GLOBAL-MODE MODE TURN-ON [KEY VALUE]... BODY...)"
-  (declare (doc-string 2))
+  (declare (doc-string 2) (indent defun))
   (let* ((global-mode-name (symbol-name global-mode))
         (mode-name (symbol-name mode))
         (pretty-name (easy-mmode-pretty-mode-name mode))
@@ -496,15 +499,17 @@ on if the hook has explicitly disabled it.
        (define-minor-mode ,global-mode
          ,(concat (format "Toggle %s in all buffers.\n" pretty-name)
                   (internal--format-docstring-line
-                   "With prefix ARG, enable %s if ARG is positive; otherwise, \
-disable it.\n\n"
+                   (concat "With prefix ARG, enable %s if ARG is positive; "
+                           "otherwise, disable it.")
                    pretty-global-name)
+                  "\n\n"
                   "If called from Lisp, toggle the mode if ARG is `toggle'.
 Enable the mode if ARG is nil, omitted, or is a positive number.
 Disable the mode if ARG is a negative number.\n\n"
                   (internal--format-docstring-line
-                   "%s is enabled in all buffers where `%s' would do it.\n\n"
+                   "%s is enabled in all buffers where `%s' would do it."
                    pretty-name turn-on)
+                  "\n\n"
                   (internal--format-docstring-line
                    "See `%s' for more information on %s."
                    mode pretty-name)
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 4f3c05baa9..a38c8bd5ca 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -3519,7 +3519,8 @@ The removes the effect of `edebug-on-entry'.  If FUNCTION 
is
 nil, remove `edebug-on-entry' on all functions."
   (interactive
    (list (let ((name (completing-read
-                      "Cancel edebug on entry to (default all functions): "
+                      (format-prompt "Cancel edebug on entry to"
+                                     "all functions")
                       (let ((functions (edebug--edebug-on-entry-functions)))
                         (unless functions
                           (user-error "No functions have `edebug-on-entry'"))
@@ -4548,7 +4549,8 @@ instrumentation for, defaulting to all functions."
         (user-error "Found no functions to remove instrumentation from"))
       (let ((name
              (completing-read
-              "Remove instrumentation from (default all functions): "
+              (format-prompt "Remove instrumentation from"
+                             "all functions")
               functions)))
         (if (and name
                  (not (equal name "")))
diff --git a/lisp/emacs-lisp/eieio-compat.el b/lisp/emacs-lisp/eieio-compat.el
index 6d84839c34..60b0638c63 100644
--- a/lisp/emacs-lisp/eieio-compat.el
+++ b/lisp/emacs-lisp/eieio-compat.el
@@ -70,7 +70,8 @@ is appropriate to use.  Uses `defmethod' to create methods, 
and calls
 `defgeneric' for you.  With this implementation the ARGS are
 currently ignored.  You can use `defgeneric' to apply specialized
 top level documentation to a method."
-  (declare (doc-string 3) (obsolete cl-defgeneric "25.1"))
+  (declare (doc-string 3) (obsolete cl-defgeneric "25.1")
+           (indent defun))
   `(eieio--defalias ',method
                     (eieio--defgeneric-init-form
                      ',method
@@ -103,6 +104,7 @@ Summary:
     \"doc-string\"
      body)"
   (declare (doc-string 3) (obsolete cl-defmethod "25.1")
+           (indent defun)
            (debug
             (&define                    ; this means we are defining something
              [&name sexp]   ;Allow (setf ...) additionally to symbols.
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index b11ed3333f..7c5babcf54 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -478,7 +478,8 @@ See `defclass' for more information."
       ;; (dotimes (cnt (length cslots))
       ;;   (setf (gethash (cl--slot-descriptor-name (aref cslots cnt)) oa) (- 
-1 cnt)))
       (dotimes (cnt (length slots))
-        (setf (gethash (cl--slot-descriptor-name (aref slots cnt)) oa) cnt))
+        (setf (gethash (cl--slot-descriptor-name (aref slots cnt)) oa)
+              (+ (eval-when-compile eieio--object-num-slots) cnt)))
       (setf (eieio--class-index-table newc) oa))
 
     ;; Set up a specialized doc string.
@@ -508,6 +509,7 @@ See `defclass' for more information."
     ;; Create the cached default object.
     (let ((cache (make-record newc
                               (+ (length (eieio--class-slots newc))
+                                 ;; FIXME: Why +1 -1 ?
                                  (eval-when-compile eieio--object-num-slots)
                                  -1)
                               nil)))
@@ -747,7 +749,7 @@ Argument FN is the function calling this verifier."
                 (_ exp))))
            (gv-setter eieio-oset))
   (cl-check-type slot symbol)
-  (cl-check-type obj (or eieio-object class))
+  (cl-check-type obj (or eieio-object class cl-structure-object))
   (let* ((class (cond ((symbolp obj)
                        (error "eieio-oref called on a class: %s" obj)
                        (eieio--full-class-object obj))
@@ -763,7 +765,7 @@ Argument FN is the function calling this verifier."
          ;; to intercept missing slot definitions.  Since it is also the LAST
          ;; thing called in this fn, its return value would be retrieved.
          (slot-missing obj slot 'oref))
-      (cl-check-type obj eieio-object)
+      (cl-check-type obj (or eieio-object cl-structure-object))
       (eieio-barf-if-slot-unbound (aref obj c) obj slot 'oref))))
 
 
@@ -892,7 +894,7 @@ reverse-lookup that name, and recurse with the associated 
slot value."
   ;; Removed checks to outside this call
   (let* ((fsi (gethash slot (eieio--class-index-table class))))
     (if (integerp fsi)
-        (+ (eval-when-compile eieio--object-num-slots) fsi)
+        fsi
       (let ((fn (eieio--initarg-to-attribute class slot)))
        (if fn
             ;; Accessing a slot via its :initarg is accepted by EIEIO
@@ -953,7 +955,7 @@ need be... May remove that later...)"
        class))
 
 (defun eieio--c3-merge-lists (reversed-partial-result remaining-inputs)
-  "Merge REVERSED-PARTIAL-RESULT REMAINING-INPUTS in a consistent order, if 
possible.
+  "Try to merge REVERSED-PARTIAL-RESULT REMAINING-INPUTS in a consistent order.
 If a consistent order does not exist, signal an error."
   (setq remaining-inputs (delq nil remaining-inputs))
   (if (null remaining-inputs)
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index c16d8e110e..3fbfe011e2 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -110,7 +110,7 @@ Options in CLOS not supported in EIEIO:
 
 Due to the way class options are set up, you can add any tags you wish,
 and reference them using the function `class-option'."
-  (declare (doc-string 4))
+  (declare (doc-string 4) (indent defun))
   (cl-check-type superclasses list)
 
   (cond ((and (stringp (car options-and-doc))
@@ -205,7 +205,7 @@ and reference them using the function `class-option'."
                    (eieio-oset this ',sname value))
                 accessors)
           (push `(cl-defmethod ,acces ((this ,name))
-                   ,(format
+                   ,(internal--format-docstring-line
                      "Retrieve the slot `%S' from an object of class `%S'."
                      sname name)
                    ;; FIXME: Why is this different from the :reader case?
@@ -285,7 +285,8 @@ This method is obsolete."
 
           ;; Non-abstract classes need a constructor.
           `(defun ,name (&rest slots)
-             ,(format "Create a new object of class type `%S'." name)
+             ,(internal--format-docstring-line
+               "Create a new object of class type `%S'." name)
              (declare (compiler-macro
                        (lambda (whole)
                          (if (not (stringp (car slots)))
@@ -358,9 +359,7 @@ variable name of the same name as the slot."
 
 (defun eieio-pcase-slot-index-from-index-table (index-table slot)
   "Find the index to pass to `aref' to access SLOT."
-  (let ((index (gethash slot index-table)))
-    (if index (+ (eval-when-compile eieio--object-num-slots)
-                 index))))
+  (gethash slot index-table))
 
 (pcase-defmacro eieio (&rest fields)
   "Pcase patterns that match EIEIO object EXPVAL.
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 21f262adc6..b30d3fc30f 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -380,7 +380,14 @@ Also store it in `eldoc-last-message' and return that 
value."
 ;; it undesirable to print eldoc messages right this instant.
 (defun eldoc-display-message-no-interference-p ()
   "Return nil if displaying a message would cause interference."
-  (not (or executing-kbd-macro (bound-and-true-p edebug-active))))
+  (not (or executing-kbd-macro
+           (bound-and-true-p edebug-active)
+           ;; The following configuration shows "Matches..." in the
+           ;; echo area when point is after a closing bracket, which
+           ;; conflicts with eldoc.
+           (and show-paren-context-when-offscreen
+                (not (pos-visible-in-window-p
+                      (overlay-end show-paren--overlay)))))))
 
 
 (defvar eldoc-documentation-functions nil
@@ -477,6 +484,7 @@ This holds the results of the last documentation request."
       (let ((inhibit-read-only t)
             (things-reported-on))
         (erase-buffer) (setq buffer-read-only t)
+        (setq-local nobreak-char-display nil)
         (local-set-key "q" 'quit-window)
         (cl-loop for (docs . rest) on docs
                  for (this-doc . plist) = docs
diff --git a/lisp/emacs-lisp/elp.el b/lisp/emacs-lisp/elp.el
index 8c33b7c994..fde7947a27 100644
--- a/lisp/emacs-lisp/elp.el
+++ b/lisp/emacs-lisp/elp.el
@@ -202,14 +202,13 @@ This variable is set by the master function.")
 (defvar elp-not-profilable
   ;; First, the functions used inside each instrumented function:
   '(called-interactively-p
-    ;; Then the functions used by the above functions.  I used
-    ;; (delq nil (mapcar (lambda (x) (and (symbolp x) (fboundp x) x))
-    ;;                   (aref (symbol-function 'elp-wrapper) 2)))
-    ;; to help me find this list.
-    error call-interactively apply current-time
+    ;; (delq
+    ;;  nil (mapcar
+    ;;       (lambda (x) (and (symbolp x) (fboundp x) x))
+    ;;       (aref (aref (aref (symbol-function 'elp--make-wrapper) 2) 1) 2)))
+    error apply current-time float-time time-subtract
     ;; Andreas Politz reports problems profiling these (Bug#4233):
-    + byte-code-function-p functionp byte-code subrp
-    indirect-function fboundp)
+    + byte-code-function-p functionp byte-code subrp fboundp)
   "List of functions that cannot be profiled.
 Those functions are used internally by the profiling code and profiling
 them would thus lead to infinite recursion.")
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 59ec4d2484..7fc316d146 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -352,7 +352,6 @@ convert it to a string and pass it to COLLECTOR first."
 (defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
   "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
 
-;; Has to be a macro for `load-file-name'.
 (defmacro ert-resource-directory ()
   "Return absolute file name of the resource (test data) directory.
 
@@ -361,30 +360,121 @@ in the same directory as the test file this is called 
from.
 
 If that directory doesn't exist, find a directory based on the
 test file name.  If the file is named \"foo-tests.el\", return
-the absolute file name for \"foo-resources\".  If you want a
-different resource directory naming scheme, set the variable
-`ert-resource-directory-format'.  Before formatting, the file
-name will be trimmed using `string-trim' with arguments
+the absolute file name for \"foo-resources\".
+
+If you want a different resource directory naming scheme, set the
+variable `ert-resource-directory-format'.  Before formatting, the
+file name will be trimmed using `string-trim' with arguments
 `ert-resource-directory-trim-left-regexp' and
 `ert-resource-directory-trim-right-regexp'."
-  `(let* ((testfile ,(or (macroexp-file-name)
-                         buffer-file-name))
-          (default-directory (file-name-directory testfile)))
-     (file-truename
-      (if (file-accessible-directory-p "resources/")
-          (expand-file-name "resources/")
-        (expand-file-name
-         (format ert-resource-directory-format
-                 (string-trim testfile
-                              ert-resource-directory-trim-left-regexp
-                              ert-resource-directory-trim-right-regexp)))))))
+  `(when-let ((testfile ,(or (macroexp-file-name)
+                             buffer-file-name)))
+     (let ((default-directory (file-name-directory testfile)))
+       (file-truename
+        (if (file-accessible-directory-p "resources/")
+            (expand-file-name "resources/")
+          (expand-file-name
+           (format ert-resource-directory-format
+                   (string-trim testfile
+                                ert-resource-directory-trim-left-regexp
+                                
ert-resource-directory-trim-right-regexp))))))))
 
 (defmacro ert-resource-file (file)
-  "Return file name of resource file named FILE.
-A resource file is in the resource directory as per
-`ert-resource-directory'."
+  "Return absolute file name of resource (test data) file named FILE.
+A resource file is defined as any file placed in the resource
+directory as returned by `ert-resource-directory'."
   `(expand-file-name ,file (ert-resource-directory)))
 
+(defvar ert-temp-file-prefix "emacs-test-"
+  "Prefix used by `ert-with-temp-file' and `ert-with-temp-directory'.")
+
+(defvar ert-temp-file-suffix nil
+  "Suffix used by `ert-with-temp-file' and `ert-with-temp-directory'.")
+
+(defun ert--with-temp-file-generate-suffix (filename)
+  "Generate temp file suffix from FILENAME."
+  (thread-last
+    (file-name-base filename)
+    (replace-regexp-in-string (rx string-start
+                                  (group (+? not-newline))
+                                  (regexp "-?tests?")
+                                  string-end)
+                              "\\1")
+    (concat "-")))
+
+(defmacro ert-with-temp-file (name &rest body)
+  "Bind NAME to the name of a new temporary file and evaluate BODY.
+Delete the temporary file after BODY exits normally or
+non-locally.  NAME will be bound to the file name of the temporary
+file.
+
+The following keyword arguments are supported:
+
+:prefix STRING  If non-nil, pass STRING to `make-temp-file' as
+                the PREFIX argument.  Otherwise, use the value of
+                `ert-temp-file-prefix'.
+
+:suffix STRING  If non-nil, pass STRING to `make-temp-file' as the
+                SUFFIX argument.  Otherwise, use the value of
+                `ert-temp-file-suffix'; if the value of that
+                variable is nil, generate a suffix based on the
+                name of the file that `ert-with-temp-file' is
+                called from.
+
+:text STRING    If non-nil, pass STRING to `make-temp-file' as
+                the TEXT argument.
+
+See also `ert-with-temp-directory'."
+  (declare (indent 1) (debug (symbolp body)))
+  (cl-check-type name symbol)
+  (let (keyw prefix suffix directory text extra-keywords)
+    (while (keywordp (setq keyw (car body)))
+      (setq body (cdr body))
+      (pcase keyw
+        (:prefix (setq prefix (pop body)))
+        (:suffix (setq suffix (pop body)))
+        (:directory (setq directory (pop body)))
+        (:text (setq text (pop body)))
+        (_ (push keyw extra-keywords) (pop body))))
+    (when extra-keywords
+      (error "Invalid keywords: %s" (mapconcat #'symbol-name extra-keywords " 
")))
+    (let ((temp-file (make-symbol "temp-file"))
+          (prefix (or prefix ert-temp-file-prefix))
+          (suffix (or suffix ert-temp-file-suffix
+                      (ert--with-temp-file-generate-suffix
+                       (or (macroexp-file-name) buffer-file-name)))))
+      `(let* ((,temp-file (,(if directory 'file-name-as-directory 'identity)
+                           (make-temp-file ,prefix ,directory ,suffix ,text)))
+              (,name ,(if directory
+                          `(file-name-as-directory ,temp-file)
+                        temp-file)))
+         (unwind-protect
+             (progn ,@body)
+           (ignore-errors
+             ,(if directory
+                  `(delete-directory ,temp-file :recursive)
+                `(delete-file ,temp-file))))))))
+
+(defmacro ert-with-temp-directory (name &rest body)
+  "Bind NAME to the name of a new temporary directory and evaluate BODY.
+Delete the temporary directory after BODY exits normally or
+non-locally.
+
+NAME is bound to the directory name, not the directory file
+name.  (In other words, it will end with the directory delimiter;
+on Unix-like systems, it will end with \"/\".)
+
+The same keyword arguments are supported as in
+`ert-with-temp-file' (which see), except for :text."
+  (declare (indent 1) (debug (symbolp body)))
+  (let ((tail body) keyw)
+    (while (keywordp (setq keyw (car tail)))
+      (setq tail (cddr tail))
+      (pcase keyw (:text (error "Invalid keyword for directory: :text")))))
+  `(ert-with-temp-file ,name
+     :directory t
+     ,@body))
+
 (provide 'ert-x)
 
 ;;; ert-x.el ends here
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index d4d8510064..8ebc81fd41 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -63,6 +63,7 @@
 (require 'ewoc)
 (require 'find-func)
 (require 'pp)
+(require 'map)
 
 ;;; UI customization options.
 
@@ -88,23 +89,6 @@ Use nil for no limit (caution: backtrace lines can be very 
long)."
                                        :background "red3"))
   "Face used for unexpected results in the ERT results buffer.")
 
-
-;;; Copies/reimplementations of cl functions.
-
-(defun ert-equal-including-properties (a b)
-  "Return t if A and B have similar structure and contents.
-
-This is like `equal-including-properties' except that it compares
-the property values of text properties structurally (by
-recursing) rather than with `eq'.  Perhaps this is what
-`equal-including-properties' should do in the first place; see
-Emacs bug 6581 at URL `https://debbugs.gnu.org/cgi/bugreport.cgi?bug=6581'."
-  ;; This implementation is inefficient.  Rather than making it
-  ;; efficient, let's hope bug 6581 gets fixed so that we can delete
-  ;; it altogether.
-  (not (ert--explain-equal-including-properties a b)))
-
-
 ;;; Defining and locating tests.
 
 ;; The data structure that represents a test case.
@@ -258,7 +242,7 @@ DATA is displayed to the user and should state the reason 
for skipping."
 ;; See Bug#24402 for why this exists
 (defun ert--should-signal-hook (error-symbol data)
   "Stupid hack to stop `condition-case' from catching ert signals.
-It should only be stopped when ran from inside ert--run-test-internal."
+It should only be stopped when ran from inside `ert--run-test-internal'."
   (when (and (not (symbolp debugger))   ; only run on anonymous debugger
              (memq error-symbol '(ert-test-failed ert-test-skipped)))
     (funcall debugger 'error (cons error-symbol data))))
@@ -465,7 +449,7 @@ Errors during evaluation are caught and handled like nil."
 
 (defun ert--explain-equal-rec (a b)
   "Return a programmer-readable explanation of why A and B are not `equal'.
-Returns nil if they are."
+Return nil if they are."
   (if (not (eq (type-of a) (type-of b)))
       `(different-types ,a ,b)
     (pcase a
@@ -536,6 +520,16 @@ Returns nil if they are."
     (ert--explain-equal-rec a b)))
 (put 'equal 'ert-explainer 'ert--explain-equal)
 
+(defun ert--explain-string-equal (a b)
+  "Explainer function for `string-equal'."
+  ;; Convert if they are symbols.
+  (if (string-equal a b)
+      nil
+    (let ((as (if (symbolp a) (symbol-name a) a))
+          (bs (if (symbolp b) (symbol-name b) b)))
+      (ert--explain-equal-rec as bs))))
+(put 'string-equal 'ert-explainer 'ert--explain-string-equal)
+
 (defun ert--significant-plist-keys (plist)
   "Return the keys of PLIST that have non-null values, in order."
   (cl-assert (zerop (mod (length plist) 2)) t)
@@ -588,14 +582,9 @@ If SUFFIXP is non-nil, returns a suffix of S, otherwise a 
prefix."
           (t
            (substring s 0 len)))))
 
-;; TODO(ohler): Once bug 6581 is fixed, rename this to
-;; `ert--explain-equal-including-properties-rec' and add a fast-path
-;; wrapper like `ert--explain-equal'.
-(defun ert--explain-equal-including-properties (a b)
-  "Explainer function for `ert-equal-including-properties'.
-
-Returns a programmer-readable explanation of why A and B are not
-`ert-equal-including-properties', or nil if they are."
+(defun ert--explain-equal-including-properties-rec (a b)
+  "Return explanation of why A and B are not `equal-including-properties'.
+Return nil if they are."
   (if (not (equal a b))
       (ert--explain-equal a b)
     (cl-assert (stringp a) t)
@@ -617,15 +606,17 @@ Returns a programmer-readable explanation of why A and B 
are not
                                     ,(ert--abbreviate-string
                                       (substring-no-properties a (1+ i))
                                       10 nil))))
-             ;; TODO(ohler): Get `equal-including-properties' fixed in
-             ;; Emacs, delete `ert-equal-including-properties', and
-             ;; re-enable this assertion.
-             ;;finally (cl-assert (equal-including-properties a b) t)
-             )))
-(put 'ert-equal-including-properties
-     'ert-explainer
-     'ert--explain-equal-including-properties)
+             finally (cl-assert (equal-including-properties a b) t))))
 
+(defun ert--explain-equal-including-properties (a b)
+  "Explainer function for `equal-including-properties'."
+  ;; Do a quick comparison in C to avoid running our expensive
+  ;; comparison when possible.
+  (if (equal-including-properties a b)
+      nil
+    (ert--explain-equal-including-properties-rec a b)))
+(put 'equal-including-properties 'ert-explainer
+     'ert--explain-equal-including-properties)
 
 ;;; Implementation of `ert-info'.
 
@@ -765,10 +756,15 @@ This mainly sets up debugger-related bindings."
         ;; handle ert errors. Once that's done, remove
         ;; `ert--should-signal-hook'.  See Bug#24402 and Bug#11218 for
         ;; details.
-        (let ((debugger (lambda (&rest args)
+        (let ((lexical-binding t)
+              (debugger (lambda (&rest args)
                           (ert--run-test-debugger test-execution-info
                                                   args)))
               (debug-on-error t)
+              ;; Don't infloop if the error being called is erroring
+              ;; out, and we have `debug-on-error' bound to nil inside
+              ;; the test.
+              (backtrace-on-error-noninteractive nil)
               (debug-on-quit t)
               ;; FIXME: Do we need to store the old binding of this
               ;; and consider it in `ert--run-test-debugger'?
@@ -2647,9 +2643,135 @@ To be used in the ERT results buffer."
                          'ert--activate-font-lock-keywords)
   nil)
 
+(defun ert-test-erts-file (file &optional transform)
+  "Parse FILE as a file containing before/after parts.
+TRANSFORM will be called to get from before to after."
+  (with-temp-buffer
+    (insert-file-contents file)
+    (let ((gen-specs (list (cons 'dummy t)
+                           (cons 'code transform))))
+      ;; Find the start of a test.
+      (while (re-search-forward "^=-=\n" nil t)
+        (setq gen-specs (ert-test--erts-test gen-specs file))
+        ;; Search to the end of the test.
+        (re-search-forward "^=-=-=\n")))))
+
+(defun ert-test--erts-test (gen-specs file)
+  (let* ((file-buffer (current-buffer))
+         (specs (ert--erts-specifications (match-beginning 0)))
+         (name (cdr (assq 'name specs)))
+         (start-before (point))
+         (end-after (if (re-search-forward "^=-=-=\n" nil t)
+                        (match-beginning 0)
+                      (point-max)))
+         (skip (cdr (assq 'skip specs)))
+         end-before start-after
+         after after-point)
+    (unless name
+      (error "No name for test case"))
+    (if (and skip
+             (eval (car (read-from-string skip))))
+        ;; Skipping this test.
+        ()
+      ;; Do the test.
+      (goto-char end-after)
+      ;; We have a separate after section.
+      (if (re-search-backward "^=-=\n" start-before t)
+          (setq end-before (match-beginning 0)
+                start-after (match-end 0))
+        (setq end-before end-after
+              start-after start-before))
+      ;; Update persistent specs.
+      (when-let ((point-char (assq 'point-char specs)))
+        (setq gen-specs
+              (map-insert gen-specs 'point-char (cdr point-char))))
+      (when-let ((code (cdr (assq 'code specs))))
+        (setq gen-specs
+              (map-insert gen-specs 'code (car (read-from-string code)))))
+      ;; Get the "after" strings.
+      (with-temp-buffer
+        (insert-buffer-substring file-buffer start-after end-after)
+        (ert--erts-unquote)
+        ;; Remove the newline at the end of the buffer.
+        (when-let ((no-newline (cdr (assq 'no-after-newline specs))))
+          (goto-char (point-min))
+          (when (re-search-forward "\n\\'" nil t)
+            (delete-region (match-beginning 0) (match-end 0))))
+        ;; Get the expected "after" point.
+        (when-let ((point-char (cdr (assq 'point-char gen-specs))))
+          (goto-char (point-min))
+          (when (search-forward point-char nil t)
+            (delete-region (match-beginning 0) (match-end 0))
+            (setq after-point (point))))
+        (setq after (buffer-string)))
+      ;; Do the test.
+      (with-temp-buffer
+        (insert-buffer-substring file-buffer start-before end-before)
+        (ert--erts-unquote)
+        ;; Remove the newline at the end of the buffer.
+        (when-let ((no-newline (cdr (assq 'no-before-newline specs))))
+          (goto-char (point-min))
+          (when (re-search-forward "\n\\'" nil t)
+            (delete-region (match-beginning 0) (match-end 0))))
+        (goto-char (point-min))
+        ;; Place point in the specified place.
+        (when-let ((point-char (cdr (assq 'point-char gen-specs))))
+          (when (search-forward point-char nil t)
+            (delete-region (match-beginning 0) (match-end 0))))
+        (let ((code (cdr (assq 'code gen-specs))))
+          (unless code
+            (error "No code to run the transform"))
+          (funcall code))
+        (unless (equal (buffer-string) after)
+          (ert-fail (list (format "Mismatch in test \"%s\", file %s"
+                                  name file)
+                          (buffer-string)
+                          after)))
+        (when (and after-point
+                   (not (= after-point (point))))
+          (ert-fail (list (format "Point wrong in test \"%s\", expected point 
%d, actual %d, file %s"
+                                  name
+                                  after-point (point)
+                                  file)
+                          (buffer-string)))))))
+  ;; Return the new value of the general specifications.
+  gen-specs)
+
+(defun ert--erts-unquote ()
+  (goto-char (point-min))
+  (while (re-search-forward "^\\=-=\\(-=\\)$" nil t)
+    (delete-region (match-beginning 0) (1+ (match-beginning 0)))))
+
+(defun ert--erts-specifications (end)
+  "Find specifications before point (back to the previous test)."
+  (save-excursion
+    (goto-char end)
+    (goto-char
+     (if (re-search-backward "^=-=-=\n" nil t)
+         (match-end 0)
+       (point-min)))
+    (let ((specs nil))
+      (while (< (point) end)
+        (if (looking-at "\\([^ \n\t:]+\\):\\([ \t]+\\)?\\(.*\\)")
+            (let ((name (intern (downcase (match-string 1))))
+                  (value (match-string 3)))
+              (forward-line 1)
+              (while (looking-at "[ \t]+\\(.*\\)")
+                (setq value (concat value (match-string 1)))
+                (forward-line 1))
+              (push (cons name (substring-no-properties value)) specs))
+          (forward-line 1)))
+      (nreverse specs))))
+
 (defvar ert-unload-hook ())
 (add-hook 'ert-unload-hook #'ert--unload-function)
 
+;;; Obsolete
+
+(define-obsolete-function-alias 'ert-equal-including-properties
+  #'equal-including-properties "29.1")
+(put 'ert-equal-including-properties 'ert-explainer
+     'ert--explain-equal-including-properties)
 
 (provide 'ert)
 
diff --git a/lisp/emacs-lisp/ewoc.el b/lisp/emacs-lisp/ewoc.el
index 68f94edafd..8636dc92a1 100644
--- a/lisp/emacs-lisp/ewoc.el
+++ b/lisp/emacs-lisp/ewoc.el
@@ -49,7 +49,7 @@
 ;;
 ;; Ewoc is a package that implements a connection between an
 ;; dll (a doubly linked list) and the contents of a buffer.
-;; Possible uses are dired (have all files in a list, and show them),
+;; Possible uses are Dired (have all files in a list, and show them),
 ;; buffer-list, kom-prioritize (in the LysKOM elisp client) and
 ;; others.  pcl-cvs.el and vc.el use ewoc.el.
 ;;
@@ -381,7 +381,7 @@ arguments will be passed to MAP-FUNCTION."
 
 (defun ewoc-filter (ewoc predicate &rest args)
   "Remove all elements in EWOC for which PREDICATE returns nil.
-Note that the buffer for EWOC will be current-buffer when PREDICATE
+Note that the buffer for EWOC will be the current buffer when PREDICATE
 is called.  PREDICATE must restore the current buffer before it returns
 if it changes it.
 The PREDICATE is called with the element as its first argument.  If any
diff --git a/lisp/emacs-lisp/lisp-mnt.el b/lisp/emacs-lisp/lisp-mnt.el
index b27c7e78a8..96ac054a7d 100644
--- a/lisp/emacs-lisp/lisp-mnt.el
+++ b/lisp/emacs-lisp/lisp-mnt.el
@@ -501,9 +501,9 @@ absent, return nil."
 (defun lm-website (&optional file)
   "Return the website in file FILE, or current buffer if FILE is nil."
   (let ((page (lm-with-file file
-                (lm-header "\\(?:x-\\)?\\(?:url\\|homepage\\)"))))
-    (if (and page (string-match "^<.+>$" page))
-       (substring page 1 -1)
+                (lm-header (rx (? "x-") (or "url" "homepage"))))))
+    (if (and page (string-match (rx bol "<" (+ nonl) ">" eol) page))
+        (substring page 1 -1)
       page)))
 (defalias 'lm-homepage 'lm-website) ; for backwards-compatibility
 
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index eac3c03cd1..d90d0f5f6a 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -29,6 +29,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib))
+(eval-when-compile (require 'subr-x))
 
 (defvar font-lock-comment-face)
 (defvar font-lock-doc-face)
@@ -556,7 +557,7 @@ This will generate compile-time constants from BINDINGS."
   "Gaudy highlighting from Emacs Lisp mode used in Backtrace mode.")
 
 (defun lisp-string-in-doc-position-p (listbeg startpos)
-   "Return true if a doc string may occur at STARTPOS inside a list.
+   "Return non-nil if a doc string may occur at STARTPOS inside a list.
 LISTBEG is the position of the start of the innermost list
 containing STARTPOS."
   (let* ((firstsym (and listbeg
@@ -589,7 +590,9 @@ containing STARTPOS."
                 (= (point) startpos))))))
 
 (defun lisp-string-after-doc-keyword-p (listbeg startpos)
-  "Return true if `:documentation' symbol ends at STARTPOS inside a list.
+  "Return non-nil if `:documentation' symbol ends at STARTPOS inside a list.
+`:doc' can also be used.
+
 LISTBEG is the position of the start of the innermost list
 containing STARTPOS."
   (and listbeg                          ; We are inside a Lisp form.
@@ -597,7 +600,7 @@ containing STARTPOS."
          (goto-char startpos)
          (ignore-errors
            (progn (backward-sexp 1)
-                  (looking-at ":documentation\\_>"))))))
+                  (looking-at ":documentation\\_>\\|:doc\\_>"))))))
 
 (defun lisp-font-lock-syntactic-face-function (state)
   "Return syntactic face function for the position represented by STATE.
@@ -1075,10 +1078,11 @@ is the buffer position of the start of the containing 
expression."
                       ;; Handle prefix characters and whitespace
                       ;; following an open paren.  (Bug#1012)
                        (backward-prefix-chars)
-                       (while (not (or (looking-back "^[ \t]*\\|([ \t]+"
-                                                      
(line-beginning-position))
-                                       (and containing-sexp
-                                            (>= (1+ containing-sexp) 
(point)))))
+                       (while (not (save-excursion
+                                     (skip-chars-backward " \t")
+                                     (or (= (point) (line-beginning-position))
+                                         (and containing-sexp
+                                              (= (point) (1+ 
containing-sexp))))))
                          (forward-sexp -1)
                          (backward-prefix-chars))
                        (setq calculate-lisp-indent-last-sexp (point)))
@@ -1105,6 +1109,53 @@ is the buffer position of the start of the containing 
expression."
               (t
                normal-indent))))))
 
+(defun lisp--local-defform-body-p (state)
+  "Return non-nil when at local definition body according to STATE.
+STATE is the `parse-partial-sexp' state for current position."
+  (when-let ((start-of-innermost-containing-list (nth 1 state)))
+    (let* ((parents (nth 9 state))
+           (first-cons-after (cdr parents))
+           (second-cons-after (cdr first-cons-after))
+           first-order-parent second-order-parent)
+      (while second-cons-after
+        (when (= start-of-innermost-containing-list
+                 (car second-cons-after))
+          (setq second-order-parent (pop parents)
+                first-order-parent (pop parents)
+                ;; Leave the loop.
+                second-cons-after nil))
+        (pop second-cons-after)
+        (pop parents))
+      (when second-order-parent
+        (let (local-definitions-starting-point)
+          (and (save-excursion
+                 (goto-char (1+ second-order-parent))
+                 (when-let ((head (ignore-errors
+                                    ;; FIXME: This does not distinguish
+                                    ;; between reading nil and a read error.
+                                    ;; We don't care but still, better fix 
this.
+                                    (read (current-buffer)))))
+                   (when (memq head '( cl-flet cl-labels cl-macrolet cl-flet*
+                                       cl-symbol-macrolet))
+                     ;; In what follows, we rely on (point) returning non-nil.
+                     (setq local-definitions-starting-point
+                           (progn
+                             (parse-partial-sexp
+                              (point) first-order-parent nil
+                              ;; From docstring of `parse-partial-sexp':
+                              ;; Fourth arg non-nil means stop
+                              ;; when we come to any character
+                              ;; that starts a sexp.
+                              t)
+                             (point))))))
+               (save-excursion
+                 (when (ignore-errors
+                         ;; We rely on `backward-up-list' working
+                         ;; even when sexp is incomplete “to the right”.
+                         (backward-up-list 2)
+                         t)
+                   (= local-definitions-starting-point (point))))))))))
+
 (defun lisp-indent-function (indent-point state)
   "This function is the normal value of the variable `lisp-indent-function'.
 The function `calculate-lisp-indent' calls this to determine
@@ -1138,16 +1189,19 @@ Lisp function does not specify a special indentation."
     (if (and (elt state 2)
              (not (looking-at "\\sw\\|\\s_")))
         ;; car of form doesn't seem to be a symbol
-        (progn
+        (if (lisp--local-defform-body-p state)
+            ;; We nevertheless check whether we are in flet-like form
+            ;; as we presume local function names could be non-symbols.
+            (lisp-indent-defform state indent-point)
           (if (not (> (save-excursion (forward-line 1) (point))
                       calculate-lisp-indent-last-sexp))
-               (progn (goto-char calculate-lisp-indent-last-sexp)
-                      (beginning-of-line)
-                      (parse-partial-sexp (point)
-                                          calculate-lisp-indent-last-sexp 0 
t)))
-           ;; Indent under the list or under the first sexp on the same
-           ;; line as calculate-lisp-indent-last-sexp.  Note that first
-           ;; thing on that line has to be complete sexp since we are
+             (progn (goto-char calculate-lisp-indent-last-sexp)
+                    (beginning-of-line)
+                    (parse-partial-sexp (point)
+                                        calculate-lisp-indent-last-sexp 0 t)))
+         ;; Indent under the list or under the first sexp on the same
+         ;; line as calculate-lisp-indent-last-sexp.  Note that first
+         ;; thing on that line has to be complete sexp since we are
           ;; inside the innermost containing sexp.
           (backward-prefix-chars)
           (current-column))
@@ -1158,15 +1212,14 @@ Lisp function does not specify a special indentation."
                                        'lisp-indent-function)
                         (get (intern-soft function) 'lisp-indent-hook)))
        (cond ((or (eq method 'defun)
-                  (and (null method)
-                       (> (length function) 3)
-                       (string-match "\\`def" function)))
+                   ;; Check whether we are in flet-like form.
+                   (lisp--local-defform-body-p state))
               (lisp-indent-defform state indent-point))
              ((integerp method)
               (lisp-indent-specform method state
                                     indent-point normal-indent))
              (method
-               (funcall method indent-point state)))))))
+              (funcall method indent-point state)))))))
 
 (defcustom lisp-body-indent 2
   "Number of columns to indent the second line of a `(def...)' form."
@@ -1234,6 +1287,13 @@ Lisp function does not specify a special indentation."
 
 (put 'autoload 'lisp-indent-function 'defun) ;Elisp
 (put 'progn 'lisp-indent-function 0)
+(put 'defvar 'lisp-indent-function 'defun)
+(put 'defalias 'lisp-indent-function 'defun)
+(put 'defvaralias 'lisp-indent-function 'defun)
+(put 'defconst 'lisp-indent-function 'defun)
+(put 'define-category 'lisp-indent-function 'defun)
+(put 'define-charset-internal 'lisp-indent-function 'defun)
+(put 'define-fringe-bitmap 'lisp-indent-function 'defun)
 (put 'prog1 'lisp-indent-function 1)
 (put 'save-excursion 'lisp-indent-function 0)      ;Elisp
 (put 'save-restriction 'lisp-indent-function 0)    ;Elisp
diff --git a/lisp/emacs-lisp/map.el b/lisp/emacs-lisp/map.el
index e0af448eaf..da4502f9ed 100644
--- a/lisp/emacs-lisp/map.el
+++ b/lisp/emacs-lisp/map.el
@@ -5,7 +5,7 @@
 ;; Author: Nicolas Petton <nicolas@petton.fr>
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: extensions, lisp
-;; Version: 3.2
+;; Version: 3.2.1
 ;; Package-Requires: ((emacs "26"))
 
 ;; This file is part of GNU Emacs.
@@ -427,15 +427,15 @@ See `map-into' for all supported values of TYPE."
   "Convert MAP into a map of TYPE.")
 
 ;; FIXME: I wish there was a way to avoid this η-redex!
-(cl-defmethod map-into (map (_type (eql 'list)))
+(cl-defmethod map-into (map (_type (eql list)))
   "Convert MAP into an alist."
   (map-pairs map))
 
-(cl-defmethod map-into (map (_type (eql 'alist)))
+(cl-defmethod map-into (map (_type (eql alist)))
   "Convert MAP into an alist."
   (map-pairs map))
 
-(cl-defmethod map-into (map (_type (eql 'plist)))
+(cl-defmethod map-into (map (_type (eql plist)))
   "Convert MAP into a plist."
   (let (plist)
     (map-do (lambda (k v) (setq plist `(,v ,k ,@plist))) map)
@@ -530,7 +530,7 @@ KEYWORD-ARGS are forwarded to `make-hash-table'."
             map)
     ht))
 
-(cl-defmethod map-into (map (_type (eql 'hash-table)))
+(cl-defmethod map-into (map (_type (eql hash-table)))
   "Convert MAP into a hash-table with keys compared with `equal'."
   (map--into-hash map (list :size (map-length map) :test #'equal)))
 
diff --git a/lisp/emacs-lisp/memory-report.el b/lisp/emacs-lisp/memory-report.el
index 3166d33e02..450cdaa7a8 100644
--- a/lisp/emacs-lisp/memory-report.el
+++ b/lisp/emacs-lisp/memory-report.el
@@ -31,7 +31,7 @@
 (require 'subr-x)
 (require 'cl-lib)
 
-(defvar memory-report--type-size (make-hash-table))
+(defvar memory-report--type-size nil)
 
 ;;;###autoload
 (defun memory-report ()
@@ -84,6 +84,7 @@ by counted more than once."
       (gethash 'object memory-report--type-size)))
 
 (defun memory-report--set-size (elems)
+  (setq memory-report--type-size (make-hash-table))
   (setf (gethash 'string memory-report--type-size)
         (cadr (assq 'strings elems)))
   (setf (gethash 'cons memory-report--type-size)
@@ -282,7 +283,7 @@ by counted more than once."
                                                       buffers)
                      do (insert (memory-report--format size)
                                 "  "
-                                (button-buttonize
+                                (buttonize
                                  (buffer-name buffer)
                                  #'memory-report--buffer-details buffer)
                                 "\n"))
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index a204966644..4761a3d82b 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -714,6 +714,7 @@ REQUIREMENTS is a list of dependencies on other packages.
  where OTHER-VERSION is a string.
 
 EXTRA-PROPERTIES is currently unused."
+  (declare (indent defun))
   ;; FIXME: Placeholder!  Should we keep it?
   (error "Don't call me!"))
 
@@ -757,47 +758,47 @@ PKG-DESC is a `package-desc' object."
    (format "%s-autoloads" (package-desc-name pkg-desc))
    (package-desc-dir pkg-desc)))
 
-(defun package--activate-autoloads-and-load-path (pkg-desc)
-  "Load the autoloads file and add package dir to `load-path'.
-PKG-DESC is a `package-desc' object."
-  (let* ((old-lp load-path)
-         (pkg-dir (package-desc-dir pkg-desc))
-         (pkg-dir-dir (file-name-as-directory pkg-dir)))
-    (with-demoted-errors "Error loading autoloads: %s"
-      (load (package--autoloads-file-name pkg-desc) nil t))
-    (when (and (eq old-lp load-path)
-               (not (or (member pkg-dir load-path)
-                        (member pkg-dir-dir load-path))))
-      ;; Old packages don't add themselves to the `load-path', so we have to
-      ;; do it ourselves.
-      (push pkg-dir load-path))))
-
 (defvar Info-directory-list)
 (declare-function info-initialize "info" ())
 
 (defvar package--quickstart-pkgs t
   "If set to a list, we're computing the set of pkgs to activate.")
 
-(defun package--load-files-for-activation (pkg-desc reload)
-  "Load files for activating a package given by PKG-DESC.
-Load the autoloads file, and ensure `load-path' is setup.  If
-RELOAD is non-nil, also load all files in the package that
-correspond to previously loaded files."
-  (let* ((loaded-files-list
-          (when reload
-            (package--list-loaded-files (package-desc-dir pkg-desc)))))
-    ;; Add to load path, add autoloads, and activate the package.
-    (package--activate-autoloads-and-load-path pkg-desc)
-    ;; Call `load' on all files in `package-desc-dir' already present in
-    ;; `load-history'.  This is done so that macros in these files are updated
-    ;; to their new definitions.  If another package is being installed which
-    ;; depends on this new definition, not doing this update would cause
-    ;; compilation errors and break the installation.
-    (with-demoted-errors "Error in package--load-files-for-activation: %s"
-      (mapc (lambda (feature) (load feature nil t))
-            ;; Skip autoloads file since we already evaluated it above.
-            (remove (file-truename (package--autoloads-file-name pkg-desc))
-                    loaded-files-list)))))
+(defsubst package--library-stem (file)
+  (catch 'done
+    (let (result)
+      (dolist (suffix (get-load-suffixes) file)
+        (setq result (string-trim file nil suffix))
+        (unless (equal file result)
+          (throw 'done result))))))
+
+(defun package--reload-previously-loaded (pkg-desc)
+  "Force reimportation of files in PKG-DESC already present in `load-history'.
+New editions of files contain macro definitions and
+redefinitions, the overlooking of which would cause
+byte-compilation of the new package to fail."
+  (with-demoted-errors "Error in package--load-files-for-activation: %s"
+    (let* (result
+           (dir (package-desc-dir pkg-desc))
+           (load-path-sans-dir
+            (cl-remove-if (apply-partially #'string= dir)
+                          (or (bound-and-true-p find-function-source-path)
+                              load-path)))
+           (files (directory-files-recursively dir "\\`[^\\.].*\\.el\\'"))
+           (history (mapcar #'file-truename
+                            (cl-remove-if-not #'stringp
+                                              (mapcar #'car load-history)))))
+      (dolist (file files)
+        (when-let ((library (package--library-stem
+                             (file-relative-name file dir)))
+                   (canonical (locate-library library nil load-path-sans-dir))
+                   (found (member (file-truename canonical) history))
+                   (recent-index (length found)))
+          (unless (equal (file-name-base library)
+                         (format "%s-autoloads" (package-desc-name pkg-desc)))
+            (push (cons (expand-file-name library dir) recent-index) result))))
+      (mapc (lambda (c) (load (car c) nil t))
+            (sort result (lambda (x y) (< (cdr x) (cdr y))))))))
 
 (defun package-activate-1 (pkg-desc &optional reload deps)
   "Activate package given by PKG-DESC, even if it was already active.
@@ -824,7 +825,11 @@ correspond to previously loaded files (those returned by
       (if (listp package--quickstart-pkgs)
           ;; We're only collecting the set of packages to activate!
           (push pkg-desc package--quickstart-pkgs)
-        (package--load-files-for-activation pkg-desc reload))
+        (when reload
+          (package--reload-previously-loaded pkg-desc))
+        (with-demoted-errors "Error loading autoloads: %s"
+          (load (package--autoloads-file-name pkg-desc) nil t))
+        (add-to-list 'load-path (directory-file-name pkg-dir)))
       ;; Add info node.
       (when (file-exists-p (expand-file-name "dir" pkg-dir))
         ;; FIXME: not the friendliest, but simple.
@@ -835,48 +840,6 @@ correspond to previously loaded files (those returned by
       ;; Don't return nil.
       t)))
 
-(defun package--files-load-history ()
-  (delq nil
-        (mapcar (lambda (x)
-                  (let ((f (car x)))
-                    (and (stringp f)
-                         (file-name-sans-extension (file-truename f)))))
-                load-history)))
-
-(defun package--list-of-conflicts (dir history)
-  (require 'find-func)
-  (declare-function find-library-name "find-func" (library))
-  (delq
-   nil
-   (mapcar
-    (lambda (x) (let* ((file (file-relative-name x dir))
-                  ;; Previously loaded file, if any.
-                  (previous
-                   (ignore-error file-error ;"Can't find library"
-                     (file-name-sans-extension
-                      (file-truename (find-library-name file)))))
-                  (pos (when previous (member previous history))))
-             ;; Return (RELATIVE-FILENAME . HISTORY-POSITION)
-             (when pos
-               (cons (file-name-sans-extension file) (length pos)))))
-    (directory-files-recursively dir "\\`[^\\.].*\\.el\\'"))))
-
-(defun package--list-loaded-files (dir)
-  "Recursively list all files in DIR which correspond to loaded features.
-Returns the `file-name-sans-extension' of each file, relative to
-DIR, sorted by most recently loaded last."
-  (let* ((history (package--files-load-history))
-         (dir (file-truename dir))
-         ;; List all files that have already been loaded.
-         (list-of-conflicts (package--list-of-conflicts dir history)))
-    ;; Turn the list of (FILENAME . POS) back into a list of features.  Files 
in
-    ;; subdirectories are returned relative to DIR (so not actually features).
-    (let ((default-directory (file-name-as-directory dir)))
-      (mapcar (lambda (x) (file-truename (car x)))
-              (sort list-of-conflicts
-                    ;; Sort the files by ascending HISTORY-POSITION.
-                    (lambda (x y) (< (cdr x) (cdr y))))))))
-
 ;;;; `package-activate'
 
 (defun package--get-activatable-pkg (pkg-name)
@@ -995,7 +958,7 @@ untar into a directory named DIR; otherwise, signal an 
error."
           (package--native-compile-async new-desc))
         ;; After compilation, load again any files loaded by
         ;; `activate-1', so that we use the byte-compiled definitions.
-        (package--load-files-for-activation new-desc :reload)))
+        (package--reload-previously-loaded new-desc)))
     pkg-dir))
 
 (defun package-generate-description-file (pkg-desc pkg-file)
@@ -1081,8 +1044,7 @@ This assumes that `pkg-desc' has already been activated 
with
   "Native compile installed package PKG-DESC asynchronously.
 This assumes that `pkg-desc' has already been activated with
 `package-activate-1'."
-  (when (and (featurep 'native-compile)
-             (native-comp-available-p))
+  (when (native-comp-available-p)
     (let ((warning-minimum-level :error))
       (native-compile-async (package-desc-dir pkg-desc) t))))
 
@@ -1118,7 +1080,7 @@ is wrapped around any parts requiring it."
 
 (declare-function lm-header "lisp-mnt" (header))
 (declare-function lm-header-multiline "lisp-mnt" (header))
-(declare-function lm-homepage "lisp-mnt" (&optional file))
+(declare-function lm-website "lisp-mnt" (&optional file))
 (declare-function lm-keywords-list "lisp-mnt" (&optional file))
 (declare-function lm-maintainers "lisp-mnt" (&optional file))
 (declare-function lm-authors "lisp-mnt" (&optional file))
@@ -1153,7 +1115,7 @@ boundaries."
             (or (lm-header "package-version") (lm-header "version")))
            (pkg-version (package-strip-rcs-id version-info))
            (keywords (lm-keywords-list))
-           (homepage (lm-homepage)))
+           (website (lm-website)))
       (unless pkg-version
          (if version-info
              (error "Unrecognized package version: %s" version-info)
@@ -1164,7 +1126,7 @@ boundaries."
          (package--prepare-dependencies
           (package-read-from-string (mapconcat #'identity require-lines " "))))
        :kind 'single
-       :url homepage
+       :url website
        :keywords keywords
        :maintainer
        ;; For backward compatibility, use a single string if there's only
@@ -2170,7 +2132,7 @@ Otherwise return nil."
       ;; to make sure we use a "canonical name"!
       (if l (package-version-join l)))))
 
-(declare-function lm-homepage "lisp-mnt" (&optional file))
+(declare-function lm-website "lisp-mnt" (&optional file))
 
 ;;;###autoload
 (defun package-install-from-buffer ()
@@ -2268,7 +2230,9 @@ confirmation to install packages."
                            (mapconcat #'symbol-name available " "))))
           (mapc (lambda (p) (package-install p 'dont-select)) available)))
        ((> difference 0)
-        (message "Packages that are not available: %d (the rest is already 
installed), maybe you need to `M-x package-refresh-contents'"
+        (message (substitute-command-keys
+                  "Packages that are not available: %d (the rest is already \
+installed), maybe you need to \\[package-refresh-contents]")
                  difference))
        (t
         (message "All your packages are already installed"))))))
@@ -2486,6 +2450,15 @@ The description is read from the installed package 
files."
                      (format "%s.el" (package-desc-name desc)) srcdir))
      "")))
 
+(defun package--describe-add-library-links ()
+  "Add links to library names in package description."
+  (while (re-search-forward "\\<\\([-[:alnum:]]+\\.el\\)\\>" nil t)
+    (if (locate-library (match-string 1))
+        (make-text-button (match-beginning 1) (match-end 1)
+                          'xref (match-string-no-properties 1)
+                          'help-echo "Read this file's commentary"
+                          :type 'package--finder-xref))))
+
 (defun describe-package-1 (pkg)
   "Insert the package description for PKG.
 Helper function for `describe-package'."
@@ -2504,7 +2477,7 @@ Helper function for `describe-package'."
          (version (if desc (package-desc-version desc)))
          (archive (if desc (package-desc-archive desc)))
          (extras (and desc (package-desc-extras desc)))
-         (homepage (cdr (assoc :url extras)))
+         (website (cdr (assoc :url extras)))
          (commit (cdr (assoc :commit extras)))
          (keywords (if desc (package-desc--keywords desc)))
          (built-in (eq pkg-dir 'builtin))
@@ -2617,15 +2590,20 @@ Helper function for `describe-package'."
             (help-insert-xref-button text 'help-package
                                      (package-desc-name pkg))))
         (insert "\n")))
-    (when homepage
-      ;; Prefer https for the homepage of packages on gnu.org.
-      (if (string-match-p "^http://\\(elpa\\|www\\)\\.gnu\\.org/" homepage)
-          (let ((gnu (cdr (assoc "gnu" package-archives))))
-            (and gnu (string-match-p "^https" gnu)
-                 (setq homepage
-                       (replace-regexp-in-string "^http" "https" homepage)))))
-      (package--print-help-section "Homepage")
-      (help-insert-xref-button homepage 'help-url homepage)
+    (when website
+      ;; Prefer https for the website of packages on common domains.
+      (when (string-match-p (rx bol "http://"; (or "elpa." "www." "git." "")
+                                (or "nongnu.org" "gnu.org" "sr.ht"
+                                    "emacswiki.org" "gitlab.com" "github.com")
+                                "/")
+                            website)
+        ;; But only if the user has "https" in `package-archives'.
+        (let ((gnu (cdr (assoc "gnu" package-archives))))
+          (and gnu (string-match-p "^https" gnu)
+               (setq website
+                     (replace-regexp-in-string "^http" "https" website)))))
+      (package--print-help-section "Website")
+      (help-insert-xref-button website 'help-url website)
       (insert "\n"))
     (when keywords
       (package--print-help-section "Keywords")
@@ -2707,6 +2685,9 @@ Helper function for `describe-package'."
               t)
             (insert (or readme-string
                         "This package does not provide a description.")))))
+      ;; Make library descriptions into links.
+      (goto-char start-of-description)
+      (package--describe-add-library-links)
       ;; Make URLs in the description into links.
       (goto-char start-of-description)
       (browse-url-add-buttons))))
@@ -2752,6 +2733,15 @@ function is a convenience wrapper used by 
`describe-package-1'."
     (apply #'insert-text-button button-text 'face button-face 'follow-link t
            properties)))
 
+(defun package--finder-goto-xref (button)
+  "Jump to a Lisp file for the BUTTON at point."
+  (let* ((file (button-get button 'xref))
+         (lib (locate-library file)))
+    (if lib (finder-commentary lib)
+      (message "Unable to locate `%s'" file))))
+
+(define-button-type 'package--finder-xref 'action #'package--finder-goto-xref)
+
 (defun package--print-email-button (recipient)
   "Insert a button whose action will send an email to RECIPIENT.
 NAME should have the form (FULLNAME . EMAIL) where FULLNAME is
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index 0bf774dffd..8464b5a519 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -33,22 +33,43 @@
 
 (defcustom pp-escape-newlines t
   "Value of `print-escape-newlines' used by pp-* functions."
+  :type 'boolean)
+
+(defcustom pp-max-width t
+  "Max width to use when formatting.
+If nil, there's no max width.  If t, use the window width.
+Otherwise this should be a number."
+  :type '(choice (const :tag "none" nil)
+                 (const :tag "window width" t)
+                 number)
+  :version "29.1")
+
+(defcustom pp-use-max-width nil
+  "If non-nil, `pp'-related functions will try to fold lines.
+The target width is given by the `pp-max-width' variable."
   :type 'boolean
-  :group 'pp)
+  :version "29.1")
+
+(defvar pp--inhibit-function-formatting nil)
 
 ;;;###autoload
 (defun pp-to-string (object)
   "Return a string containing the pretty-printed representation of OBJECT.
 OBJECT can be any Lisp object.  Quoting characters are used as needed
 to make output that `read' can handle, whenever this is possible."
-  (with-temp-buffer
-    (lisp-mode-variables nil)
-    (set-syntax-table emacs-lisp-mode-syntax-table)
-    (let ((print-escape-newlines pp-escape-newlines)
-          (print-quoted t))
-      (prin1 object (current-buffer)))
-    (pp-buffer)
-    (buffer-string)))
+  (if pp-use-max-width
+      (let ((pp--inhibit-function-formatting t))
+        (with-temp-buffer
+          (pp-emacs-lisp-code object)
+          (buffer-string)))
+    (with-temp-buffer
+      (lisp-mode-variables nil)
+      (set-syntax-table emacs-lisp-mode-syntax-table)
+      (let ((print-escape-newlines pp-escape-newlines)
+            (print-quoted t))
+        (prin1 object (current-buffer)))
+      (pp-buffer)
+      (buffer-string))))
 
 ;;;###autoload
 (defun pp-buffer ()
@@ -56,7 +77,6 @@ to make output that `read' can handle, whenever this is 
possible."
   (interactive)
   (goto-char (point-min))
   (while (not (eobp))
-    ;; (message "%06d" (- (point-max) (point)))
     (cond
      ((ignore-errors (down-list 1) t)
       (save-excursion
@@ -82,11 +102,21 @@ to make output that `read' can handle, whenever this is 
possible."
   "Output the pretty-printed representation of OBJECT, any Lisp object.
 Quoting characters are printed as needed to make output that `read'
 can handle, whenever this is possible.
+
+This function does not apply special formatting rules for Emacs
+Lisp code.  See `pp-emacs-lisp-code' instead.
+
+By default, this function won't limit the line length of lists
+and vectors.  Bind `pp-use-max-width' to a non-nil value to do so.
+
 Output stream is STREAM, or value of `standard-output' (which see)."
   (princ (pp-to-string object) (or stream standard-output)))
 
-(defun pp-display-expression (expression out-buffer-name)
+;;;###autoload
+(defun pp-display-expression (expression out-buffer-name &optional lisp)
   "Prettify and display EXPRESSION in an appropriate way, depending on length.
+If LISP, format with `pp-emacs-lisp-code'; use `pp' otherwise.
+
 If a temporary buffer is needed for representation, it will be named
 after OUT-BUFFER-NAME."
   (let* ((old-show-function temp-buffer-show-function)
@@ -110,11 +140,13 @@ after OUT-BUFFER-NAME."
                           (select-window window)
                           (run-hooks 'temp-buffer-show-hook))
                       (when (window-live-p old-selected)
-                        (select-window old-selected))
-                      (message "See buffer %s." out-buffer-name)))
+                        (select-window old-selected))))
                 (message "%s" (buffer-substring (point-min) (point))))))))
     (with-output-to-temp-buffer out-buffer-name
-      (pp expression)
+      (if lisp
+          (with-current-buffer standard-output
+            (pp-emacs-lisp-code expression))
+        (pp expression))
       (with-current-buffer standard-output
        (emacs-lisp-mode)
        (setq buffer-read-only nil)
@@ -179,6 +211,188 @@ Ignores leading comment characters."
       (insert (pp-to-string (macroexpand-1 (pp-last-sexp))))
     (pp-macroexpand-expression (pp-last-sexp))))
 
+;;;###autoload
+(defun pp-emacs-lisp-code (sexp)
+  "Insert SEXP into the current buffer, formatted as Emacs Lisp code.
+Use the `pp-max-width' variable to control the desired line length."
+  (require 'edebug)
+  (let ((obuf (current-buffer)))
+    (with-temp-buffer
+      (emacs-lisp-mode)
+      (pp--insert-lisp sexp)
+      (insert "\n")
+      (goto-char (point-min))
+      (indent-sexp)
+      (while (re-search-forward " +$" nil t)
+        (replace-match ""))
+      (insert-into-buffer obuf))))
+
+(defun pp--insert-lisp (sexp)
+  (cl-case (type-of sexp)
+    (vector (pp--format-vector sexp))
+    (cons (cond
+           ((consp (cdr sexp))
+            (if (and (length= sexp 2)
+                     (eq (car sexp) 'quote))
+                (cond
+                 ((symbolp (cadr sexp))
+                  (let ((print-quoted t))
+                    (prin1 sexp (current-buffer))))
+                 ((consp (cadr sexp))
+                  (insert "'")
+                  (pp--format-list (cadr sexp)
+                                   (set-marker (make-marker) (1- (point))))))
+              (pp--format-list sexp)))
+           (t
+            (princ sexp (current-buffer)))))
+    ;; Print some of the smaller integers as characters, perhaps?
+    (integer
+     (if (<= ?0 sexp ?z)
+         (let ((print-integers-as-characters t))
+           (princ sexp (current-buffer)))
+       (princ sexp (current-buffer))))
+    (string
+     (let ((print-escape-newlines t))
+       (prin1 sexp (current-buffer))))
+    (otherwise (princ sexp (current-buffer)))))
+
+(defun pp--format-vector (sexp)
+  (insert "[")
+  (cl-loop for i from 0
+           for element across sexp
+           do (pp--insert (and (> i 0) " ") element))
+  (insert "]"))
+
+(defun pp--format-list (sexp &optional start)
+  (if (and (symbolp (car sexp))
+           (not pp--inhibit-function-formatting)
+           (not (keywordp (car sexp))))
+      (pp--format-function sexp)
+    (insert "(")
+    (pp--insert start (pop sexp))
+    (while sexp
+      (pp--insert " " (pop sexp)))
+    (insert ")")))
+
+(defun pp--format-function (sexp)
+  (let* ((sym (car sexp))
+         (edebug (get sym 'edebug-form-spec))
+         (indent (get sym 'lisp-indent-function))
+         (doc (get sym 'doc-string-elt)))
+    (when (eq indent 'defun)
+      (setq indent 2))
+    ;; We probably want to keep all the elements before the doc string
+    ;; on a single line.
+    (when doc
+      (setq indent (1- doc)))
+    ;; Special-case closures -- these shouldn't really exist in actual
+    ;; source code, so there's no indentation information.  But make
+    ;; them output slightly better.
+    (when (and (not indent)
+               (eq sym 'closure))
+      (setq indent 0))
+    (pp--insert "(" sym)
+    (pop sexp)
+    ;; Get the first entries on the first line.
+    (if indent
+        (pp--format-definition sexp indent edebug)
+      (let ((prev 0))
+        (while sexp
+          (let ((start (point)))
+            ;; Don't put sexps on the same line as a multi-line sexp
+            ;; preceding it.
+            (pp--insert (if (> prev 1) "\n" " ")
+                        (pop sexp))
+            (setq prev (count-lines start (point)))))))
+    (insert ")")))
+
+(defun pp--format-definition (sexp indent edebug)
+  (while (and (cl-plusp indent)
+              sexp)
+    (insert " ")
+    ;; We don't understand all the edebug specs.
+    (unless (consp edebug)
+      (setq edebug nil))
+    (if (and (consp (car edebug))
+             (eq (caar edebug) '&rest))
+        (pp--insert-binding (pop sexp))
+      (if (null (car sexp))
+          (insert "()")
+        (pp--insert-lisp (car sexp)))
+      (pop sexp))
+    (pop edebug)
+    (cl-decf indent))
+  (when (stringp (car sexp))
+    (insert "\n")
+    (prin1 (pop sexp) (current-buffer)))
+  ;; Then insert the rest with line breaks before each form.
+  (while sexp
+    (insert "\n")
+    (if (keywordp (car sexp))
+        (progn
+          (pp--insert-lisp (pop sexp))
+          (when sexp
+            (pp--insert " " (pop sexp))))
+      (pp--insert-lisp (pop sexp)))))
+
+(defun pp--insert-binding (sexp)
+  (insert "(")
+  (while sexp
+    (if (consp (car sexp))
+        ;; Newlines after each (...) binding.
+        (progn
+          (pp--insert-lisp (car sexp))
+          (when (cdr sexp)
+            (insert "\n")))
+      ;; Keep plain symbols on the same line.
+      (pp--insert " " (car sexp)))
+    (pop sexp))
+  (insert ")"))
+
+(defun pp--insert (delim &rest things)
+  (let ((start (if (markerp delim)
+                   (prog1
+                       delim
+                     (setq delim nil))
+                 (point-marker))))
+    (when delim
+      (insert delim))
+    (dolist (thing things)
+      (pp--insert-lisp thing))
+    ;; We need to indent what we have so far to see if we have to fold.
+    (pp--indent-buffer)
+    (when (> (current-column) (pp--max-width))
+      (save-excursion
+        (goto-char start)
+        (unless (looking-at "[ \t]+$")
+          (insert "\n"))
+        (pp--indent-buffer)
+        (goto-char (point-max))
+        ;; If we're still too wide, then go up one step and try to
+        ;; insert a newline there.
+        (when (> (current-column) (pp--max-width))
+          (condition-case ()
+              (backward-up-list 1)
+            (:success (when (looking-back " " 2)
+                        (insert "\n")))
+            (error nil)))))))
+
+(defun pp--max-width ()
+  (cond ((numberp pp-max-width)
+         pp-max-width)
+        ((null pp-max-width)
+         most-positive-fixnum)
+        ((eq pp-max-width t)
+         (window-width))
+        (t
+         (error "Invalid pp-max-width value: %s" pp-max-width))))
+
+(defun pp--indent-buffer ()
+  (goto-char (point-min))
+  (while (not (eobp))
+    (lisp-indent-line)
+    (forward-line 1)))
+
 (provide 'pp)                          ; so (require 'pp) works
 
 ;;; pp.el ends here
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index ae5988296d..451ff19631 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -4,7 +4,7 @@
 
 ;; Author: Nicolas Petton <nicolas@petton.fr>
 ;; Keywords: sequences
-;; Version: 2.22
+;; Version: 2.23
 ;; Package: seq
 
 ;; Maintainer: emacs-devel@gnu.org
@@ -490,7 +490,6 @@ Equality is defined by TESTFN if non-nil or by `equal' if 
nil."
               (seq-reverse sequence1)
               '()))
 
-;;;###autoload
 (cl-defgeneric seq-difference (sequence1 sequence2 &optional testfn)
   "Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2.
 Equality is defined by TESTFN if non-nil or by `equal' if nil."
@@ -529,7 +528,7 @@ SEQUENCE must be a sequence of numbers or markers."
   (apply #'max (seq-into sequence 'list)))
 
 (defun seq--count-successive (pred sequence)
-  "Return the number of successive elements for which (PRED element) is 
non-nil in SEQUENCE."
+  "Count successive elements for which (PRED element) is non-nil in SEQUENCE."
   (let ((n 0)
         (len (seq-length sequence)))
     (while (and (< n len)
@@ -538,7 +537,7 @@ SEQUENCE must be a sequence of numbers or markers."
     n))
 
 (defun seq--make-pcase-bindings (args)
-  "Return a list of bindings of the variables in ARGS to the elements of a 
sequence."
+  "Return list of bindings of the variables in ARGS to the elements of a 
sequence."
   (let ((bindings '())
         (index 0)
         (rest-marker nil))
@@ -570,6 +569,7 @@ SEQUENCE must be a sequence of numbers or markers."
 If no element is found, return nil."
   (ignore-errors (seq-elt sequence n)))
 
+;;;###autoload
 (cl-defgeneric seq-random-elt (sequence)
   "Return a random element from SEQUENCE.
 Signal an error if SEQUENCE is empty."
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index d4838ff0f8..a9f548b104 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -71,6 +71,7 @@ string, it'll be inserted as is, then the string will be 
`read',
 and then evaluated.
 
 There can be any number of :example/:result elements."
+  (declare (indent defun))
   `(progn
      (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
                                   shortdoc--groups))
@@ -158,6 +159,8 @@ There can be any number of :example/:result elements."
    :eval (split-string-and-unquote "foo \"bar zot\""))
   (split-string-shell-command
    :eval (split-string-shell-command "ls /tmp/'foo bar'"))
+  (string-glyph-split
+   :eval (string-glyph-split "Hello, 👼🏻🧑🏼‍🤝‍🧑🏻"))
   (string-lines
    :eval (string-lines "foo\n\nbar")
    :eval (string-lines "foo\n\nbar" t))
@@ -241,7 +244,14 @@ There can be any number of :example/:result elements."
    :eval (number-to-string 42))
   "Data About Strings"
   (length
-   :eval (length "foo"))
+   :eval (length "foo")
+   :eval (length "avocado: 🥑"))
+  (string-width
+   :eval (string-width "foo")
+   :eval (string-width "avocado: 🥑"))
+  (string-pixel-width
+   :eval (string-pixel-width "foo")
+   :eval (string-pixel-width "avocado: 🥑"))
   (string-search
    :eval (string-search "bar" "foobarzot"))
   (assoc-string
@@ -271,6 +281,9 @@ There can be any number of :example/:result elements."
    :eval (file-name-base "/tmp/foo.txt"))
   (file-relative-name
    :eval (file-relative-name "/tmp/foo" "/tmp"))
+  (file-name-split
+   :eval (file-name-split "/tmp/foo")
+   :eval (file-name-split "foo/bar"))
   (make-temp-name
    :eval (make-temp-name "/tmp/foo-"))
   (file-name-concat
@@ -348,6 +361,9 @@ There can be any number of :example/:result elements."
   (file-newer-than-file-p
    :no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
    :eg-result nil)
+  (file-has-changed-p
+   :no-eval (file-has-changed-p "/tmp/foo")
+   :eg-result t)
   (file-equal-p
    :no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
    :eg-result nil)
@@ -647,10 +663,12 @@ There can be any number of :example/:result elements."
 
 
 (define-short-documentation-group vector
+  "Making Vectors"
   (make-vector
    :eval (make-vector 5 "foo"))
   (vector
    :eval (vector 1 "b" 3))
+  "Operations on Vectors"
   (vectorp
    :eval (vectorp [1])
    :eval (vectorp "1"))
@@ -660,13 +678,16 @@ There can be any number of :example/:result elements."
    :eval (append [1 2] nil))
   (length
    :eval (length [1 2 3]))
-  (mapcar
-   :eval (mapcar #'identity [1 2 3]))
-  (reduce
-   :eval (reduce #'+ [1 2 3]))
+  (seq-reduce
+   :eval (seq-reduce #'+ [1 2 3] 0))
   (seq-subseq
    :eval (seq-subseq [1 2 3 4 5] 1 3)
-   :eval (seq-subseq [1 2 3 4 5] 1)))
+   :eval (seq-subseq [1 2 3 4 5] 1))
+  "Mapping Over Vectors"
+  (mapcar
+   :eval (mapcar #'identity [1 2 3]))
+  (mapc
+   :eval (mapc #'insert ["1" "2" "3"])))
 
 (define-short-documentation-group regexp
   "Matching Strings"
@@ -1158,6 +1179,49 @@ There can be any number of :example/:result elements."
   (sqrt
    :eval (sqrt -1)))
 
+(define-short-documentation-group text-properties
+  "Examining Text Properties"
+  (get-text-property
+   :eval (get-text-property 0 'foo (propertize "x" 'foo t)))
+  (get-char-property
+   :eval (get-char-property 0 'foo (propertize "x" 'foo t)))
+  (get-pos-property
+   :eval (get-pos-property 0 'foo (propertize "x" 'foo t)))
+  (get-char-property-and-overlay
+   :eval (get-char-property-and-overlay 0 'foo (propertize "x" 'foo t)))
+  (text-properties-at
+   :eval (text-properties-at (point)))
+  "Changing Text Properties"
+  (put-text-property
+   :eval (let ((s "abc")) (put-text-property 0 1 'foo t s) s)
+   :no-eval (put-text-property (point) (1+ (point)) 'face 'error))
+  (add-text-properties
+   :no-eval (add-text-properties (point) (1+ (point)) '(face error)))
+  (remove-text-properties
+   :no-eval (remove-text-properties (point) (1+ (point)) '(face nil)))
+  (remove-list-of-text-properties
+   :no-eval (remove-list-of-text-properties (point) (1+ (point)) '(face 
font-lock-face)))
+  (set-text-properties
+   :no-eval (set-text-properties (point) (1+ (point)) '(face error)))
+  (add-face-text-property
+   (add-face-text-property START END '(:foreground "green")))
+  (propertize
+   :eval (propertize "foo" 'face 'italic 'mouse-face 'bold-italic))
+  "Searching for Text Properties"
+  (next-property-change
+   :no-eval (next-property-change (point) (current-buffer)))
+  (previous-property-change
+   :no-eval (previous-property-change (point) (current-buffer)))
+  (next-single-property-change
+   :no-eval (next-single-property-change (point) 'face (current-buffer)))
+  (previous-single-property-change
+   :no-eval (previous-single-property-change (point) 'face (current-buffer)))
+  ;; TODO: There are some more that could be added here.
+  (text-property-search-forward
+   :no-eval (text-property-search-forward 'face nil t))
+  (text-property-search-backward
+   :no-eval (text-property-search-backward 'face nil t)))
+
 ;;;###autoload
 (defun shortdoc-display-group (group &optional function)
   "Pop to a buffer with short documentation summary for functions in GROUP.
@@ -1276,11 +1340,11 @@ function's documentation in the Info manual")))
                   (princ value (current-buffer))
                   (insert "\n"))
                  (:eg-result
-                  (insert "    eg. " double-arrow " ")
+                  (insert "    e.g. " double-arrow " ")
                   (prin1 value (current-buffer))
                   (insert "\n"))
                  (:eg-result-string
-                  (insert "    eg. " double-arrow " ")
+                  (insert "    e.g. " double-arrow " ")
                   (princ value (current-buffer))
                   (insert "\n")))))
     ;; Insert the arglist after doing the evals, in case that's pulled
diff --git a/lisp/emacs-lisp/shorthands.el b/lisp/emacs-lisp/shorthands.el
new file mode 100644
index 0000000000..e9f5880ab2
--- /dev/null
+++ b/lisp/emacs-lisp/shorthands.el
@@ -0,0 +1,80 @@
+;;; shorthands.el --- Read code considering Elisp shorthands  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: João Távora <joaotavora@gmail.com>
+;; Keywords: lisp
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Basic helpers for loading files with Shorthands.
+
+;;; Code:
+(require 'files)
+(require 'mule)
+(eval-when-compile (require 'cl-lib))
+
+(defun hack-read-symbol-shorthands ()
+  "Compute `read-symbol-shorthands' from Local Variables section."
+  ;; FIXME: relies on the `hack-local-variables--find-variables'
+  ;; detail of files.el.  That function should be exported,
+  ;; possibly be refactored into two parts, since we're only
+  ;; interested in basic "Local Variables" parsing.
+  (alist-get 'read-symbol-shorthands (hack-local-variables--find-variables)))
+
+(setq hack-read-symbol-shorthands-function #'hack-read-symbol-shorthands)
+
+
+;; FIXME: move this all to progmodes/elisp-mode.el?  OTOH it'd make
+;; more sense there, OTOH all the elisp font-lock stuff is actually in
+;; lisp/emacs-lisp/lisp-mode.el, which isn't right either.  So
+;; shorthand font-locking logic is probably better here for now.
+
+(defface elisp-shorthand-font-lock-face
+  '((t :inherit font-lock-keyword-face :foreground "cyan"))
+  "Face for highlighting shorthands in Emacs Lisp."
+  :version "28.1"
+  :group 'font-lock-faces)
+
+(defun shorthands--mismatch-from-end (str1 str2)
+  (cl-loop with l1 = (length str1) with l2 = (length str2)
+           for i from 1
+           for i1 = (- l1 i) for i2 = (- l2 i)
+           while (and (>= i1 0) (>= i2 0) (eq (aref str1 i1) (aref str2 i2)))
+           finally (return (1- i))))
+
+(defun shorthands-font-lock-shorthands (limit)
+  (when read-symbol-shorthands
+    (while (re-search-forward
+            (eval-when-compile
+              (concat "\\_<\\(" lisp-mode-symbol-regexp "\\)\\_>"))
+            limit t)
+      (let* ((existing (get-text-property (match-beginning 1) 'face))
+             (probe (and (not (memq existing '(font-lock-comment-face
+                                               font-lock-string-face)))
+                         (intern-soft (match-string 1))))
+             (sname (and probe (symbol-name probe)))
+             (mm (and sname (shorthands--mismatch-from-end
+                             (match-string 1) sname))))
+        (unless (or (null mm) (= mm (length sname)))
+          (add-face-text-property (match-beginning 1) (1+ (- (match-end 1) mm))
+                                  'elisp-shorthand-font-lock-face))))))
+
+(font-lock-add-keywords 'emacs-lisp-mode '((shorthands-font-lock-shorthands)) 
t)
+
+;;; shorthands.el ends here
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index d775f152b3..8e14faea3a 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -1302,7 +1302,7 @@ Only meaningful when called from within 
`smie-rules-function'."
                     (let ((tok (funcall smie-forward-token-function)))
                       (unless tok
                         (with-demoted-errors
-                          (error "smie-rule-separator: can't skip token %s"
+                          (error "smie-rule-separator: Can't skip token %s"
                                  smie--token))))
                     (skip-chars-forward " ")
                     (unless (eolp) (point)))))
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 3de666682f..e3caf88c2f 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -208,7 +208,9 @@ The variable list SPEC is the same as in `if-let'."
   (string= string ""))
 
 (defsubst string-join (strings &optional separator)
-  "Join all STRINGS using SEPARATOR."
+  "Join all STRINGS using SEPARATOR.
+Optional argument SEPARATOR must be a string, a vector, or a list of
+characters; nil stands for the empty string."
   (mapconcat #'identity strings separator))
 
 (define-obsolete-function-alias 'string-reverse 'reverse "25.1")
@@ -264,13 +266,13 @@ result will have lines that are longer than LENGTH."
     (buffer-string)))
 
 (defun string-limit (string length &optional end coding-system)
-  "Return (up to) a LENGTH substring of STRING.
-If STRING is shorter than or equal to LENGTH, the entire string
-is returned unchanged.
+  "Return a substring of STRING that is (up to) LENGTH characters long.
+If STRING is shorter than or equal to LENGTH characters, return the
+entire string unchanged.
 
-If STRING is longer than LENGTH, return a substring consisting of
-the first LENGTH characters of STRING.  If END is non-nil, return
-the last LENGTH characters instead.
+If STRING is longer than LENGTH characters, return a substring
+consisting of the first LENGTH characters of STRING.  If END is
+non-nil, return the last LENGTH characters instead.
 
 If CODING-SYSTEM is non-nil, STRING will be encoded before
 limiting, and LENGTH is interpreted as the number of bytes to
@@ -400,6 +402,68 @@ as the new values of the bound variables in the recursive 
invocation."
       (cl-labels ((,name ,fargs . ,body)) #',name)
       . ,aargs)))
 
+(defmacro with-memoization (place &rest code)
+  "Return the value of CODE and stash it in PLACE.
+If PLACE's value is non-nil, then don't bother evaluating CODE
+and return the value found in PLACE instead."
+  (declare (indent 1) (debug (gv-place body)))
+  (gv-letplace (getter setter) place
+    `(or ,getter
+         ,(macroexp-let2 nil val (macroexp-progn code)
+            `(progn
+               ,(funcall setter val)
+               ,val)))))
+
+;;;###autoload
+(defun ensure-empty-lines (&optional lines)
+  "Ensure that there's LINES number of empty lines before point.
+If LINES is nil or missing, a this ensures that there's a single
+empty line before point.
+
+Interactively, this command uses the numerical prefix for LINES.
+
+If there's already more empty lines before point than LINES, the
+number of blank lines will be reduced.
+
+If point is not at the beginning of a line, a newline character
+is inserted before adjusting the number of empty lines."
+  (interactive "p")
+  (unless (bolp)
+    (insert "\n"))
+  (let ((lines (or lines 1))
+        (start (save-excursion
+                 (if (re-search-backward "[^\n]" nil t)
+                     (+ (point) 2)
+                   (point-min)))))
+    (cond
+     ((> (- (point) start) lines)
+      (delete-region (point) (- (point) (- (point) start lines))))
+     ((< (- (point) start) lines)
+      (insert (make-string (- lines (- (point) start)) ?\n))))))
+
+;;;###autoload
+(defun string-pixel-width (string)
+  "Return the width of STRING in pixels."
+  (with-temp-buffer
+    (insert string)
+    (car (window-text-pixel-size
+          (current-buffer) (point-min) (point)))))
+
+;;;###autoload
+(defun string-glyph-split (string)
+  "Split STRING into a list of strings representing separate glyphs.
+This takes into account combining characters and grapheme clusters."
+  (let ((result nil)
+        (start 0)
+        comp)
+    (while (< start (length string))
+      (if (setq comp (find-composition-internal start nil string nil))
+          (progn
+            (push (substring string (car comp) (cadr comp)) result)
+            (setq start (cadr comp)))
+        (push (substring string start (1+ start)) result)
+        (setq start (1+ start))))
+    (nreverse result)))
 
 (provide 'subr-x)
 
diff --git a/lisp/emacs-lisp/tabulated-list.el 
b/lisp/emacs-lisp/tabulated-list.el
index f148bc1768..8f6c655dbe 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -115,16 +115,25 @@ where:
 This should be either a function, or a list.
 If a list, each element has the form (ID [DESC1 ... DESCN]),
 where:
+
  - ID is nil, or a Lisp object uniquely identifying this entry,
    which is used to keep the cursor on the \"same\" entry when
    rearranging the list.  Comparison is done with `equal'.
 
  - Each DESC is a column descriptor, one for each column
-   specified in `tabulated-list-format'.  A descriptor is either
-   a string, which is printed as-is, or a list (LABEL . PROPS),
-   which means to use `insert-text-button' to insert a text
-   button with label LABEL and button properties PROPS.
-   The string, or button label, must not contain any newline.
+   specified in `tabulated-list-format'.  The descriptor DESC is
+   one of:
+
+    - A string, which is printed as-is, and must not contain any
+      newlines.
+
+    - An image descriptor (a list), which is used to insert an
+      image (see Info node `(elisp) Image Descriptors').
+
+    - A list (LABEL . PROPS), which means to use
+      `insert-text-button' to insert a text button with label
+      LABEL and button properties PROPS.  LABEL must not contain
+      any newlines.
 
 If `tabulated-list-entries' is a function, it is called with no
 arguments and must return a list of the above form.")
@@ -256,7 +265,7 @@ Populated by `tabulated-list-init-header'.")
 (defvar tabulated-list--header-overlay nil)
 
 (defun tabulated-list-line-number-width ()
-  "Return the width taken by display-line-numbers in the current buffer."
+  "Return the width taken by `display-line-numbers' in the current buffer."
   ;; line-number-display-width returns the value for the selected
   ;; window, which might not be the window in which the current buffer
   ;; is displayed.
@@ -547,7 +556,9 @@ Return the column number after insertion."
         (props     (nthcdr 3 format))
         (pad-right (or (plist-get props :pad-right) 1))
          (right-align (plist-get props :right-align))
-        (label     (if (stringp col-desc) col-desc (car col-desc)))
+         (label (cond ((stringp col-desc) col-desc)
+                      ((eq (car col-desc) 'image) " ")
+                      (t (car col-desc))))
          (label-width (string-width label))
         (help-echo (concat (car format) ": " label))
         (opoint (point))
@@ -571,17 +582,22 @@ Return the column number after insertion."
                             'display `(space :align-to ,(+ x shift))))
         (setq width (- width shift))
         (setq x (+ x shift))))
-    (if (stringp col-desc)
-       (insert (if (get-text-property 0 'help-echo label)
-                   label
-                 (propertize label 'help-echo help-echo)))
-      (apply 'insert-text-button label (cdr col-desc)))
+    (cond ((stringp col-desc)
+           (insert (if (get-text-property 0 'help-echo label)
+                       label
+                     (propertize label 'help-echo help-echo))))
+          ((eq (car col-desc) 'image)
+           (insert (propertize " "
+                               'display col-desc
+                               'help-echo help-echo)))
+          ((apply 'insert-text-button label (cdr col-desc))))
     (let ((next-x (+ x pad-right width)))
       ;; No need to append any spaces if this is the last column.
       (when not-last-col
         (when (> pad-right 0) (insert (make-string pad-right ?\s)))
         (insert (propertize
-                 (make-string (- width (min width label-width)) ?\s)
+                 ;; We need at least one space to align correctly.
+                 (make-string (- width (min 1 width label-width)) ?\s)
                  'display `(space :align-to ,next-x))))
       (put-text-property opoint (point) 'tabulated-list-column-name name)
       next-x)))
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index 382f6bb1fa..1ef4931b7b 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -125,9 +125,12 @@ of SECS seconds since the epoch.  SECS may be a fraction."
       (time-convert (cons (- more-ticks (% more-ticks trunc-s-ticks)) hz)))))
 
 (defun timer-relative-time (time secs &optional usecs psecs)
-  "Advance TIME by SECS seconds and optionally USECS microseconds
-and PSECS picoseconds.  SECS may be either an integer or a
-floating point number."
+  "Advance TIME by SECS seconds.
+
+Optionally also advance it by USECS microseconds and PSECS
+picoseconds.
+
+SECS may be either an integer or a floating point number."
   (let ((delta secs))
     (if (or usecs psecs)
        (setq delta (time-add delta (list 0 0 (or usecs 0) (or psecs 0)))))
@@ -138,9 +141,13 @@ floating point number."
   (time-less-p (timer--time t1) (timer--time t2)))
 
 (defun timer-inc-time (timer secs &optional usecs psecs)
-  "Increment the time set in TIMER by SECS seconds, USECS microseconds,
-and PSECS picoseconds.  SECS may be a fraction.  If USECS or PSECS are
-omitted, they are treated as zero."
+  "Increment the time set in TIMER by SECS seconds.
+
+Optionally also increment it by USECS microseconds, and PSECS
+picoseconds.  If USECS or PSECS are omitted, they are treated as
+zero.
+
+SECS may be a fraction."
   (setf (timer--time timer)
         (timer-relative-time (timer--time timer) secs usecs psecs)))
 
diff --git a/lisp/emulation/cua-base.el b/lisp/emulation/cua-base.el
index 3976c1ea06..befcb42382 100644
--- a/lisp/emulation/cua-base.el
+++ b/lisp/emulation/cua-base.el
@@ -396,17 +396,17 @@ and after the region marked by the rectangle to search."
 
 (defcustom cua-rectangle-mark-key [(control return)]
   "Global key used to toggle the cua rectangle mark."
-  :set #'(lambda (symbol value)
-          (set symbol value)
-          (when (and (boundp 'cua--keymaps-initialized)
-                     cua--keymaps-initialized)
-            (define-key cua-global-keymap value
-              #'cua-set-rectangle-mark)
-            (when (boundp 'cua--rectangle-keymap)
-              (define-key cua--rectangle-keymap value
-                #'cua-clear-rectangle-mark)
-              (define-key cua--region-keymap value
-                #'cua-toggle-rectangle-mark))))
+  :set (lambda (symbol value)
+         (set symbol value)
+         (when (and (boundp 'cua--keymaps-initialized)
+                    cua--keymaps-initialized)
+           (define-key cua-global-keymap value
+             #'cua-set-rectangle-mark)
+           (when (boundp 'cua--rectangle-keymap)
+             (define-key cua--rectangle-keymap value
+               #'cua-clear-rectangle-mark)
+             (define-key cua--region-keymap value
+               #'cua-toggle-rectangle-mark))))
   :type 'key-sequence)
 
 (defcustom cua-rectangle-modifier-key 'meta
@@ -699,6 +699,11 @@ Repeating prefix key when region is active works as a 
single prefix key."
   (interactive)
   (cua--prefix-override-replay 0))
 
+;; These aliases are so that we can look up the commands and find the
+;; correct keys when generating menus.
+(defalias 'cua-cut-handler #'cua--prefix-override-handler)
+(defalias 'cua-copy-handler #'cua--prefix-override-handler)
+
 (defun cua--prefix-repeat-handler ()
   "Repeating prefix key when region is active works as a single prefix key."
   (interactive)
@@ -1258,10 +1263,8 @@ If ARG is the atom `-', scroll upward by nearly full 
screen."
     (define-key cua--cua-keys-keymap [(meta v)]
       #'delete-selection-repeat-replace-region))
 
-  (define-key cua--prefix-override-keymap [(control x)]
-    #'cua--prefix-override-handler)
-  (define-key cua--prefix-override-keymap [(control c)]
-    #'cua--prefix-override-handler)
+  (define-key cua--prefix-override-keymap [(control x)] #'cua-cut-handler)
+  (define-key cua--prefix-override-keymap [(control c)] #'cua-copy-handler)
 
   (define-key cua--prefix-repeat-keymap [(control x) (control x)]
     #'cua--prefix-repeat-handler)
diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el
index c3b36f10ae..59be3f4846 100644
--- a/lisp/emulation/viper-cmd.el
+++ b/lisp/emulation/viper-cmd.el
@@ -35,9 +35,7 @@
 (defvar viper--key-maps)
 (defvar viper--intercept-key-maps)
 (defvar iso-accents-mode)
-(defvar quail-mode)
 (defvar quail-current-str)
-(defvar mark-even-if-inactive)
 (defvar viper--init-message)
 (defvar viper-initial)
 (defvar undo-beg-posn)
@@ -69,8 +67,7 @@
         (nm-p (intern (concat snm "-p")))
         (nms (intern (concat snm "s"))))
     `(defun ,nm-p (com)
-       (consp (viper-memq-char com ,nms)
-             ))))
+       (consp (memq com ,nms)))))
 
 ;; Variables for defining VI commands
 
@@ -1035,23 +1032,23 @@ as a Meta key and any number of multiple escapes are 
allowed."
        cmd-info
        cmd-to-exec-at-end)
     (while (and cont
-               (viper-memq-char char
-                                (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
-                                      viper-buffer-search-char)))
+                (memq char
+                      (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
+                            viper-buffer-search-char)))
       (if com
          ;; this means that we already have a command character, so we
          ;; construct a com list and exit while.  however, if char is "
          ;; it is an error.
          (progn
            ;; new com is (CHAR . OLDCOM)
-           (if (viper-memq-char char '(?# ?\")) (user-error viper-ViperBell))
+            (if (memq char '(?# ?\")) (user-error viper-ViperBell))
            (setq com (cons char com))
            (setq cont nil))
        ;; If com is nil we set com as char, and read more.  Again, if char is
        ;; ", we read the name of register and store it in viper-use-register.
        ;; if char is !, =, or #, a complete com is formed so we exit the while
        ;; loop.
-       (cond ((viper-memq-char char '(?! ?=))
+        (cond ((memq char '(?! ?=))
               (setq com char)
               (setq char (read-char))
               (setq cont nil))
@@ -1091,7 +1088,7 @@ as a Meta key and any number of multiple escapes are 
allowed."
                 `(key-binding (char-to-string ,char)))))
 
       ;; as com is non-nil, this means that we have a command to execute
-      (if (viper-memq-char (car com) '(?r ?R))
+      (if (memq (car com) '(?r ?R))
          ;; execute appropriate region command.
          (let ((char (car com)) (com (cdr com)))
            (setq prefix-arg (cons value com))
@@ -2603,12 +2600,12 @@ On reaching beginning of line, stop and signal error."
   (let ((prev-char (viper-char-at-pos 'backward))
        (saved-point (point)))
     ;; skip non-newline separators backward
-    (while (and (not (viper-memq-char prev-char '(nil \n)))
+    (while (and (not (memq prev-char '(nil \n)))
                (< lim (point))
                ;; must be non-newline separator
                (if (eq viper-syntax-preference 'strict-vi)
-                   (viper-memq-char prev-char '(?\  ?\t))
-                 (viper-memq-char (char-syntax prev-char) '(?\  ?-))))
+                    (memq prev-char '(?\  ?\t))
+                  (memq (char-syntax prev-char) '(?\  ?-))))
       (viper-backward-char-carefully)
       (setq prev-char (viper-char-at-pos 'backward)))
 
@@ -2622,12 +2619,12 @@ On reaching beginning of line, stop and signal error."
 
     ;; skip again, but make sure we don't overshoot the limit
     (if twice
-       (while (and (not (viper-memq-char prev-char '(nil \n)))
+        (while (and (not (memq prev-char '(nil \n)))
                    (< lim (point))
                    ;; must be non-newline separator
                    (if (eq viper-syntax-preference 'strict-vi)
-                       (viper-memq-char prev-char '(?\  ?\t))
-                     (viper-memq-char (char-syntax prev-char) '(?\  ?-))))
+                        (memq prev-char '(?\  ?\t))
+                      (memq (char-syntax prev-char) '(?\  ?-))))
          (viper-backward-char-carefully)
          (setq prev-char (viper-char-at-pos 'backward))))
 
@@ -2645,10 +2642,10 @@ On reaching beginning of line, stop and signal error."
     (viper-forward-word-kernel val)
     (if com
        (progn
-         (cond ((viper-char-equal com ?c)
+          (cond ((eq com ?c)
                 (viper-separator-skipback-special 'twice viper-com-point))
                ;; Yank words including the whitespace, but not newline
-               ((viper-char-equal com ?y)
+                ((eq com ?y)
                 (viper-separator-skipback-special nil viper-com-point))
                ((viper-dotable-command-p com)
                 (viper-separator-skipback-special nil viper-com-point)))
@@ -2666,10 +2663,10 @@ On reaching beginning of line, stop and signal error."
                (viper-skip-nonseparators 'forward)
                (viper-skip-separators t))
     (if com (progn
-             (cond ((viper-char-equal com ?c)
+              (cond ((eq com ?c)
                     (viper-separator-skipback-special 'twice viper-com-point))
                    ;; Yank words including the whitespace, but not newline
-                   ((viper-char-equal com ?y)
+                    ((eq com ?y)
                     (viper-separator-skipback-special nil viper-com-point))
                    ((viper-dotable-command-p com)
                     (viper-separator-skipback-special nil viper-com-point)))
@@ -3546,10 +3543,11 @@ If MODE is set, set the macros only in that major mode."
 
 
 (defun viper-set-parsing-style-toggling-macro (unset)
-  "Set `%%%' to be a macro that toggles whether comment fields should be 
parsed for matching parentheses.
+  "Set or unset `%%%' as a macro that toggles comment parsing for parentheses.
 This is used in conjunction with the `%' command.
-
-With a prefix argument, unsets the macro."
+By default, sets the macro which will toggle whether comment fields should
+be parsed for matching parentheses.  With a prefix argument, unsets the
+macro instead."
   (interactive "P")
   (or noninteractive
       (if (not unset)
@@ -3766,7 +3764,7 @@ Null string will repeat previous search."
   (define-key viper-vi-basic-map
     (cond ((characterp viper-buffer-search-char)
           (char-to-string viper-buffer-search-char))
-         (t (error "viper-buffer-search-char: wrong value type, %S"
+          (t (error "viper-buffer-search-char: Wrong value type, %S"
                    viper-buffer-search-char)))
     #'viper-command-argument)
   (aset viper-exec-array viper-buffer-search-char #'viper-exec-buffer-search)
@@ -4713,15 +4711,15 @@ Please, specify your level now: "))
 (defun viper-submit-report ()
   "Submit bug report on Viper."
   (interactive)
-  (defvar viper-color-display-p)
+  (defvar x-display-color-p)
   (defvar viper-frame-parameters)
   (defvar viper-minibuffer-emacs-face)
   (defvar viper-minibuffer-vi-face)
   (defvar viper-minibuffer-insert-face)
   (let ((reporter-prompt-for-summary-p t)
-       (viper-color-display-p (if (viper-window-display-p)
-                             (viper-color-display-p)
-                              'non-x))
+        (x-display-color-p (if (viper-window-display-p)
+                              (x-display-color-p)
+                             'non-x))
         (viper-frame-parameters (frame-parameters (selected-frame)))
        (viper-minibuffer-emacs-face (if (viper-has-face-support-p)
                                          (facep
@@ -4779,7 +4777,7 @@ Please, specify your level now: "))
                        'viper-expert-level
                        'major-mode
                        'window-system
-                       'viper-color-display-p
+                        'x-display-color-p
                        'viper-frame-parameters
                        'viper-minibuffer-vi-face
                        'viper-minibuffer-insert-face
diff --git a/lisp/emulation/viper-ex.el b/lisp/emulation/viper-ex.el
index ef15779e1b..85c8b87b9a 100644
--- a/lisp/emulation/viper-ex.el
+++ b/lisp/emulation/viper-ex.el
@@ -25,7 +25,6 @@
 ;;; Code:
 
 ;; Compiler pacifier
-(defvar read-file-name-map)
 (defvar viper-use-register)
 (defvar viper-s-string)
 (defvar viper-shift-width)
diff --git a/lisp/emulation/viper-init.el b/lisp/emulation/viper-init.el
index 730ca0b5a2..e3790b7453 100644
--- a/lisp/emulation/viper-init.el
+++ b/lisp/emulation/viper-init.el
@@ -25,16 +25,12 @@
 ;;; Code:
 
 ;; compiler pacifier
-(defvar mark-even-if-inactive)
-(defvar quail-mode)
 (defvar iso-accents-mode)
 (defvar viper-current-state)
 (defvar viper-version)
 (defvar viper-expert-level)
 (defvar current-input-method)
 (defvar default-input-method)
-(defvar describe-current-input-method-function)
-(defvar bar-cursor)
 (defvar cursor-type)
 ;; end pacifier
 
@@ -48,11 +44,6 @@
 
 (define-obsolete-function-alias 'viper-device-type #'window-system "27.1")
 
-(defun viper-color-display-p ()
-  (condition-case nil
-      (display-color-p)
-    (error nil)))
-
 ;; in XEmacs: device-type is tty on tty and stream in batch.
 (defun viper-window-display-p ()
   (and window-system (not (memq window-system '(tty stream pc)))))
@@ -81,7 +72,7 @@ In all likelihood, you don't need to bother with this 
setting."
 (defun viper-has-face-support-p ()
   (cond ((viper-window-display-p))
        (viper-force-faces)
-       ((viper-color-display-p))
+        ((x-display-color-p))
        (t (memq window-system '(pc)))))
 
 
@@ -932,7 +923,9 @@ Should be set in `viper-custom-file-name'."
   (setq cursor-type '(bar . 2)))
 
 (defun viper-ESC-keyseq-timeout ()
-  "Key sequence beginning with ESC and separated by no more than this many 
milliseconds is considered to be generated by a keyboard function key.
+  "Return the timeout for considering an ESC sequence to be a function key.
+Sequences of keys beginning with ESC and separated by no more than this many
+milliseconds are considered to be generated by a keyboard function key.
 Setting this too high may slow down switching from insert to vi state.  Setting
 this value too low will make it impossible to use function keys in insert mode
 on a dumb terminal."
diff --git a/lisp/emulation/viper-keym.el b/lisp/emulation/viper-keym.el
index 2bb24f662f..2f7d17351d 100644
--- a/lisp/emulation/viper-keym.el
+++ b/lisp/emulation/viper-keym.el
@@ -182,7 +182,7 @@ In insert mode, this key also functions as Meta."
   :type 'string
   :group 'viper)
 
-(defconst viper-ESC-key (kbd "ESC")
+(defconst viper-ESC-key [escape]
   "Key used to ESC.")
 
 
diff --git a/lisp/emulation/viper-mous.el b/lisp/emulation/viper-mous.el
index 02db39f1cb..3d55690bd6 100644
--- a/lisp/emulation/viper-mous.el
+++ b/lisp/emulation/viper-mous.el
@@ -26,7 +26,6 @@
 
 ;; compiler pacifier
 (defvar double-click-time)
-(defvar mouse-track-multi-click-time)
 (defvar viper-search-start-marker)
 (defvar viper-local-search-start-marker)
 (defvar viper-search-history)
@@ -76,8 +75,8 @@ or a triple-click."
 
 ;; remembers prefix argument to pass along to commands invoked by second
 ;; click.
-;; This is needed because in Emacs (not XEmacs), assigning to prefix-arg
-;; causes Emacs to count the second click as if it was a single click
+;; This is needed because assigning to prefix-arg causes Emacs to
+;; count the second click as if it was a single click
 (defvar viper-global-prefix-argument nil)
 
 
diff --git a/lisp/emulation/viper-util.el b/lisp/emulation/viper-util.el
index 0f6dceb13c..71043b189d 100644
--- a/lisp/emulation/viper-util.el
+++ b/lisp/emulation/viper-util.el
@@ -29,9 +29,6 @@
 
 ;; Compiler pacifier
 (defvar viper-minibuffer-current-face)
-(defvar viper-minibuffer-insert-face)
-(defvar viper-minibuffer-vi-face)
-(defvar viper-minibuffer-emacs-face)
 (defvar viper-replace-overlay-face)
 (defvar viper-fast-keyseq-timeout)
 (defvar ex-unix-type-shell)
@@ -64,22 +61,8 @@
 (define-obsolete-function-alias 'viper-iconify
   #'iconify-or-deiconify-frame "27.1")
 
-
-;; CHAR is supposed to be a char or an integer (positive or negative)
-;; LIST is a list of chars, nil, and negative numbers
-;; Check if CHAR is a member by trying to convert in characters, if necessary.
-;; Introduced for compatibility with XEmacs, where integers are not the same as
-;; chars.
-(defun viper-memq-char (char list)
-  (cond ((and (integerp char) (>= char 0))
-        (memq char list))
-       ((memq char list))))
-
-;; Check if char-or-int and char are the same as characters
-(defun viper-char-equal (char-or-int char)
-  (cond ((and (integerp char-or-int) (>= char-or-int 0))
-        (= char-or-int char))
-       ((eq char-or-int char))))
+(define-obsolete-function-alias 'viper-memq-char #'memq "29.1")
+(define-obsolete-function-alias 'viper-char-equal #'eq "29.1")
 
 ;; Like =, but accommodates null and also is t for eq-objects
 (defun viper= (char char1)
@@ -88,8 +71,7 @@
         (= char char1))
        (t nil)))
 
-(defsubst viper-color-display-p ()
-  (x-display-color-p))
+(define-obsolete-function-alias 'viper-color-display-p #'x-display-color-p 
"29.1")
 
 (defun viper-get-cursor-color (&optional _frame)
   (cdr (assoc 'cursor-color (frame-parameters))))
@@ -110,7 +92,7 @@ Otherwise return the normal value."
 
 ;; cursor colors
 (defun viper-change-cursor-color (new-color &optional frame)
-  (if (and (viper-window-display-p) (viper-color-display-p)
+  (if (and (viper-window-display-p) (x-display-color-p)
           (stringp new-color) (x-color-defined-p new-color)
           (not (string= new-color (viper-get-cursor-color))))
       (modify-frame-parameters
@@ -142,7 +124,7 @@ Otherwise return the normal value."
 
 ;; By default, saves current frame cursor color before changing viper state
 (defun viper-save-cursor-color (before-which-mode)
-  (if (and (viper-window-display-p) (viper-color-display-p))
+  (if (and (viper-window-display-p) (x-display-color-p))
       (let ((color (viper-get-cursor-color)))
        (if (and (stringp color) (x-color-defined-p color)
                 ;; there is something fishy in that the color is not saved if
@@ -1183,25 +1165,23 @@ This option is appropriate if you like Emacs-style 
words."
            (looking-at (concat "[" viper-strict-ALPHA-chars addl-chars "]"))
          (or
           ;; or one of the additional chars being asked to include
-          (viper-memq-char char (viper-string-to-list addl-chars))
+           (memq char (viper-string-to-list addl-chars))
           (and
            ;; not one of the excluded word chars (note:
            ;; viper-non-word-characters is a list)
-           (not (viper-memq-char char viper-non-word-characters))
+            (not (memq char viper-non-word-characters))
            ;; char of the Viper-word syntax class
-           (viper-memq-char (char-syntax char)
-                            (viper-string-to-list viper-ALPHA-char-class))))))
-    ))
+            (memq (char-syntax char)
+                  (viper-string-to-list viper-ALPHA-char-class))))))))
 
 (defun viper-looking-at-separator ()
   (let ((char (char-after (point))))
     (if char
        (if (eq viper-syntax-preference 'strict-vi)
-           (viper-memq-char char (viper-string-to-list viper-strict-SEP-chars))
+            (memq char (viper-string-to-list viper-strict-SEP-chars))
          (or (eq char ?\n) ; RET is always a separator in Vi
-             (viper-memq-char (char-syntax char)
-                              (viper-string-to-list viper-SEP-char-class)))))
-    ))
+              (memq (char-syntax char)
+                               (viper-string-to-list 
viper-SEP-char-class)))))))
 
 (defsubst viper-looking-at-alphasep (&optional addl-chars)
   (or (viper-looking-at-separator) (viper-looking-at-alpha addl-chars)))
@@ -1327,8 +1307,7 @@ This option is appropriate if you like Emacs-style words."
                    ;; of the excluded characters
                    (if (and (eq syntax-of-char-looked-at ?w)
                             (not negated-syntax))
-                       (not (viper-memq-char
-                             char-looked-at viper-non-word-characters))
+                        (not (memq char-looked-at viper-non-word-characters))
                      t))
                   (funcall skip-syntax-func 1)
                 0)
diff --git a/lisp/emulation/viper.el b/lisp/emulation/viper.el
index 6ba265f8ab..1ee5365126 100644
--- a/lisp/emulation/viper.el
+++ b/lisp/emulation/viper.el
@@ -304,7 +304,6 @@
 
 ;; compiler pacifier
 (defvar mark-even-if-inactive)
-(defvar quail-mode)
 (defvar viper-expert-level)
 (defvar viper-mode-string)
 (defvar viper-major-mode-modifier-list)
@@ -577,7 +576,7 @@ For more information on Viper:
 To submit a bug report or to contact the author, type :submitReport in Vi
 command mode.  To shoo Viper away and return to pure Emacs (horror!), type:
 
-   M-x viper-go-away
+   \\[viper-go-away]
 
 This startup message appears whenever you load Viper, unless you type `y' now."
                      ))
diff --git a/lisp/env.el b/lisp/env.el
index 83f43d1006..2f7cd9d3db 100644
--- a/lisp/env.el
+++ b/lisp/env.el
@@ -218,6 +218,23 @@ in the environment list of the selected frame."
       (message "%s" (if value value "Not set")))
     value))
 
+;;;###autoload
+(defmacro with-environment-variables (variables &rest body)
+  "Set VARIABLES in the environent and execute BODY.
+VARIABLES is a list of variable settings of the form (VAR VALUE),
+where VAR is the name of the variable (a string) and VALUE
+is its value (also a string).
+
+The previous values will be be restored upon exit."
+  (declare (indent 1) (debug (sexp body)))
+  (unless (consp variables)
+    (error "Invalid VARIABLES: %s" variables))
+  `(let ((process-environment (copy-sequence process-environment)))
+     ,@(mapcar (lambda (elem)
+                 `(setenv ,(car elem) ,(cadr elem)))
+               variables)
+     ,@body))
+
 (provide 'env)
 
 ;;; env.el ends here
diff --git a/lisp/epa-hook.el b/lisp/epa-hook.el
index aa196851d4..5b250af6d7 100644
--- a/lisp/epa-hook.el
+++ b/lisp/epa-hook.el
@@ -56,15 +56,15 @@ through Custom does that automatically."
 May either be a string or a list of strings.")
 
 (put 'epa-file-encrypt-to 'safe-local-variable
-     #'(lambda (val)
-        (or (stringp val)
-            (and (listp val)
-                 (catch 'safe
-                   (mapc (lambda (elt)
-                           (unless (stringp elt)
-                             (throw 'safe nil)))
-                         val)
-                   t)))))
+     (lambda (val)
+       (or (stringp val)
+           (and (listp val)
+                (catch 'safe
+                  (mapc (lambda (elt)
+                          (unless (stringp elt)
+                            (throw 'safe nil)))
+                        val)
+                  t)))))
 
 (put 'epa-file-encrypt-to 'permanent-local t)
 
diff --git a/lisp/epa-ks.el b/lisp/epa-ks.el
index ebdb127421..35caa1a93c 100644
--- a/lisp/epa-ks.el
+++ b/lisp/epa-ks.el
@@ -149,8 +149,7 @@ If EXACT is non-nil, don't accept approximate matches."
           (cond ((null epa-keyserver)
                  (user-error "Empty keyserver pool"))
                 ((listp epa-keyserver)
-                 (nth (random (length epa-keyserver))
-                      epa-keyserver))
+                 (seq-random-elt epa-keyserver))
                 ((stringp epa-keyserver)
                  epa-keyserver)
                 ((error "Invalid type for `epa-keyserver'")))
diff --git a/lisp/epa.el b/lisp/epa.el
index 57d355cb3e..e4b89e984d 100644
--- a/lisp/epa.el
+++ b/lisp/epa.el
@@ -648,7 +648,7 @@ If SECRET is non-nil, list secret keys instead of public 
keys."
   (setq input (file-name-sans-extension (expand-file-name input)))
   (expand-file-name
    (read-file-name
-    (concat "To file (default " (file-name-nondirectory input) ") ")
+    (format-prompt "To file" (file-name-nondirectory input))
     (file-name-directory input)
     input)))
 
@@ -1236,9 +1236,7 @@ If no one is selected, symmetric encryption will be 
performed.  ")
      (list keys
           (expand-file-name
            (read-file-name
-            (concat "To file (default "
-                    (file-name-nondirectory default-name)
-                    ") ")
+             (format-prompt "To file" (file-name-nondirectory default-name))
             (file-name-directory default-name)
             default-name)))))
   (let ((context (epg-make-context epa-protocol)))
diff --git a/lisp/epg.el b/lisp/epg.el
index ea7aa869a0..3354eb2c1e 100644
--- a/lisp/epg.el
+++ b/lisp/epg.el
@@ -334,6 +334,7 @@ callback data (if any)."
 
 (cl-defstruct (epg-key
                (:constructor nil)
+               (:copier epg--copy-key)
                (:constructor epg-make-key (owner-trust))
                (:predicate nil))
   (owner-trust nil :read-only t)
@@ -1389,7 +1390,7 @@ NAME is either a string or a list of strings."
      (if (seq-find (lambda (user)
                      (eq (epg-user-id-validity user) 'revoked))
                    (epg-key-user-id-list key))
-         (let ((copy (copy-epg-key key)))
+         (let ((copy (epg--copy-key key)))
            (setf (epg-key-user-id-list copy)
                  (seq-remove (lambda (user)
                                (eq (epg-user-id-validity user) 'revoked))
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 10be2965ad..69f63dfbc4 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -199,6 +199,11 @@ active, use the `erc-server-process-alive' function 
instead.")
 (defvar-local erc-server-reconnecting nil
   "Non-nil if the user requests an explicit reconnect, and the
 current IRC process is still alive.")
+(make-obsolete-variable 'erc-server-reconnecting
+                        "see `erc--server-reconnecting'" "29.1")
+
+(defvar-local erc--server-reconnecting nil
+  "Non-nil when reconnecting.")
 
 (defvar-local erc-server-timed-out nil
   "Non-nil if the IRC server failed to respond to a ping.")
@@ -533,7 +538,8 @@ TLS (see `erc-session-client-certificate' for more 
details)."
     (with-current-buffer buffer
       (setq erc-server-process process)
       (setq erc-server-quitting nil)
-      (setq erc-server-reconnecting nil)
+      (setq erc-server-reconnecting nil
+            erc--server-reconnecting nil)
       (setq erc-server-timed-out nil)
       (setq erc-server-banned nil)
       (setq erc-server-error-occurred nil)
@@ -616,36 +622,42 @@ Make sure you are in an ERC buffer when running this."
             (erc-log-irc-protocol line nil)
             (erc-parse-server-response process line)))))))
 
-(define-inline erc-server-reconnect-p (event)
+(defun erc--server-reconnect-p (event)
+  "Return non-nil when ERC should attempt to reconnect.
+EVENT is the message received from the closed connection process."
+  (and erc-server-auto-reconnect
+       (not erc-server-banned)
+       ;; make sure we don't infinitely try to reconnect, unless the
+       ;; user wants that
+       (or (eq erc-server-reconnect-attempts t)
+           (and (integerp erc-server-reconnect-attempts)
+                (< erc-server-reconnect-count
+                   erc-server-reconnect-attempts)))
+       (or erc-server-timed-out
+           (not (string-match "^deleted" event)))
+       ;; open-network-stream-nowait error for connection refused
+       (if (string-match "^failed with code 111" event) 'nonblocking t)))
+
+(defun erc-server-reconnect-p (event)
   "Return non-nil if ERC should attempt to reconnect automatically.
 EVENT is the message received from the closed connection process."
-  (inline-letevals (event)
-    (inline-quote
-     (or erc-server-reconnecting
-         (and erc-server-auto-reconnect
-              (not erc-server-banned)
-              ;; make sure we don't infinitely try to reconnect, unless the
-              ;; user wants that
-              (or (eq erc-server-reconnect-attempts t)
-                  (and (integerp erc-server-reconnect-attempts)
-                       (< erc-server-reconnect-count
-                          erc-server-reconnect-attempts)))
-              (or erc-server-timed-out
-                  (not (string-match "^deleted" ,event)))
-              ;; open-network-stream-nowait error for connection refused
-              (if (string-match "^failed with code 111" ,event) 'nonblocking 
t))))))
+  (declare (obsolete "see `erc--server-reconnect-p'" "29.1"))
+  (or (with-suppressed-warnings ((obsolete erc-server-reconnecting))
+        erc-server-reconnecting)
+      (erc--server-reconnect-p event)))
 
 (defun erc-process-sentinel-2 (event buffer)
   "Called when `erc-process-sentinel-1' has detected an unexpected disconnect."
   (if (not (buffer-live-p buffer))
       (erc-update-mode-line)
     (with-current-buffer buffer
-      (let ((reconnect-p (erc-server-reconnect-p event)) message delay)
+      (let ((reconnect-p (erc--server-reconnect-p event)) message delay)
         (setq message (if reconnect-p 'disconnected 'disconnected-noreconnect))
         (erc-display-message nil 'error (current-buffer) message)
         (if (not reconnect-p)
             ;; terminate, do not reconnect
             (progn
+              (setq erc--server-reconnecting nil)
               (erc-display-message nil 'error (current-buffer)
                                    'terminated ?e event)
               ;; Update mode line indicators
@@ -654,7 +666,8 @@ EVENT is the message received from the closed connection 
process."
           ;; reconnect
           (condition-case nil
               (progn
-                (setq erc-server-reconnecting   nil
+                (setq erc-server-reconnecting nil
+                      erc--server-reconnecting t
                       erc-server-reconnect-count (1+ 
erc-server-reconnect-count))
                 (setq delay erc-server-reconnect-timeout)
                 (run-at-time delay nil
@@ -1169,7 +1182,8 @@ Would expand to:
 \(fn (NAME &rest ALIASES) &optional EXTRA-FN-DOC EXTRA-VAR-DOC &rest FN-BODY)"
   (declare (debug (&define [&name "erc-response-handler@"
                                   (symbolp &rest symbolp)]
-                           &optional sexp sexp def-body)))
+                           &optional sexp sexp def-body))
+           (indent defun))
   (if (numberp name) (setq name (intern (format "%03i" name))))
   (setq aliases (mapcar (lambda (a)
                           (if (numberp a)
@@ -1532,7 +1546,8 @@ add things to `%s' instead."
        'WALLOPS ?n nick ?m message))))
 
 (define-erc-response-handler (001)
-  "Set `erc-server-current-nick' to reflect server settings and display the 
welcome message."
+  "Set `erc-server-current-nick' to reflect server settings.
+Then display the welcome message."
   nil
   (erc-set-current-nick (car (erc-response.command-args parsed)))
   (erc-update-mode-line)                ; needed here?
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index 040606ea85..69972856d1 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -130,7 +130,7 @@ longer than `erc-fill-column'."
     ("<URL: *\\([^<> ]+\\) *>" 0 t browse-url-button-open-url 1)
 ;;; ("(\\(\\([^~\n \t@][^\n \t@]*\\)@\\([a-zA-Z0-9.:-]+\\)\\)" 1 t finger 2 3)
     ;; emacs internal
-    ("[`]\\([a-zA-Z][-a-zA-Z_0-9!*<=>+]+\\)[']"
+    ("[`‘]\\([a-zA-Z][-a-zA-Z_0-9!*<=>+]+\\)['’]"
      1 t erc-button-describe-symbol 1)
     ;; pseudo links
     ("\\bInfo:[\"]\\([^\"]+\\)[\"]" 0 t Info-goto-node 1)
@@ -389,12 +389,11 @@ REGEXP is the regular expression which matched for this 
button."
     (mouse-set-point event)
     (erc-button-press-button)))
 
-;; XEmacs calls this via widget-button-press with a bunch of arguments
-;; which we don't care about.
 (defun erc-button-press-button (&rest _ignore)
   "Check text at point for a callback function.
 If the text at point has a `erc-callback' property,
 call it with the value of the `erc-data' text property."
+  (declare (advertised-calling-convention () "28.1"))
   (interactive)
   (let* ((data (get-text-property (point) 'erc-data))
          (fun (get-text-property (point) 'erc-callback)))
diff --git a/lisp/obsolete/erc-compat.el b/lisp/erc/erc-compat.el
similarity index 85%
rename from lisp/obsolete/erc-compat.el
rename to lisp/erc/erc-compat.el
index 9972e927e6..9bbc1f6a0d 100644
--- a/lisp/obsolete/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -1,11 +1,10 @@
-;;; erc-compat.el --- ERC compatibility code for XEmacs  -*- lexical-binding: 
t; -*-
+;;; erc-compat.el --- ERC compatibility code for older Emacsen  -*- 
lexical-binding: t; -*-
 
 ;; Copyright (C) 2002-2003, 2005-2021 Free Software Foundation, Inc.
 
 ;; Author: Alex Schroeder <alex@gnu.org>
 ;; Maintainer: Amin Bandali <bandali@gnu.org>
 ;; URL: https://www.emacswiki.org/emacs/ERC
-;; Obsolete-since: 28.1
 
 ;; This file is part of GNU Emacs.
 
@@ -28,19 +27,20 @@
 
 ;;; Code:
 
-(require 'format-spec)
-
 ;;;###autoload(autoload 'erc-define-minor-mode "erc-compat")
-(defalias 'erc-define-minor-mode #'define-minor-mode)
+(define-obsolete-function-alias 'erc-define-minor-mode
+  #'define-minor-mode "28.1")
 
 (defun erc-decode-coding-string (s coding-system)
   "Decode S using CODING-SYSTEM."
+  (declare (obsolete decode-coding-string "28.1"))
   (decode-coding-string s coding-system t))
 
 (defun erc-encode-coding-string (s coding-system)
   "Encode S using CODING-SYSTEM.
 Return the same string, if the encoding operation is trivial.
 See `erc-encoding-coding-alist'."
+  (declare (obsolete encode-coding-string "28.1"))
   (encode-coding-string s coding-system t))
 
 (define-obsolete-function-alias 'erc-propertize #'propertize "28.1")
@@ -51,6 +51,7 @@ See `erc-encoding-coding-alist'."
 (define-obsolete-function-alias 'erc-replace-regexp-in-string 
#'replace-regexp-in-string "28.1")
 
 (defun erc-set-write-file-functions (new-val)
+  (declare (obsolete nil "28.1"))
   (set (make-local-variable 'write-file-functions) new-val))
 
 (defvar erc-emacs-build-time
@@ -58,18 +59,8 @@ See `erc-encoding-coding-alist'."
       emacs-build-time
     (format-time-string "%Y-%m-%d" emacs-build-time))
   "Time at which Emacs was dumped out, or nil if not available.")
-
-;; Emacs 21 and XEmacs do not have user-emacs-directory, but XEmacs
-;; has user-init-directory.
-(defvar erc-user-emacs-directory
-  (cond ((boundp 'user-emacs-directory)
-        user-emacs-directory)
-       ((boundp 'user-init-directory)
-        user-init-directory)
-       (t "~/.emacs.d/"))
-  "Directory beneath which additional per-user Emacs-specific files
-are placed.
-Note that this should end with a directory separator.")
+(make-obsolete-variable 'erc-emacs-build-time 'emacs-build-time "28.1")
+(define-obsolete-variable-alias 'erc-user-emacs-directory 
'user-emacs-directory "28.1")
 
 (defun erc-replace-match-subexpression-in-string
   (newtext string _match subexp _start &optional fixedcase literal)
@@ -77,6 +68,7 @@ Note that this should end with a directory separator.")
 MATCH is the text which matched the subexpression (see `match-string').
 START is the beginning position of the last match (see `match-beginning').
 See `replace-match' for explanations of FIXEDCASE and LITERAL."
+  (declare (obsolete replace-match "28.1"))
   (replace-match newtext fixedcase literal string subexp))
 
 (define-obsolete-function-alias 'erc-with-selected-window
@@ -86,10 +78,11 @@ See `replace-match' for explanations of FIXEDCASE and 
LITERAL."
 (define-obsolete-function-alias 'erc-make-obsolete-variable
   #'make-obsolete-variable "28.1")
 
-;; Provide a simpler replacement for `member-if'
+;; Provide a simpler replacement for `cl-member-if'
 (defun erc-member-if (predicate list)
   "Find the first item satisfying PREDICATE in LIST.
 Return the sublist of LIST whose car matches."
+  (declare (obsolete cl-member-if "28.1"))
   (let ((ptr list))
     (catch 'found
       (while ptr
@@ -97,11 +90,12 @@ Return the sublist of LIST whose car matches."
          (throw 'found ptr))
        (setq ptr (cdr ptr))))))
 
-;; Provide a simpler replacement for `delete-if'
+;; Provide a simpler replacement for `cl-delete-if'
 (defun erc-delete-if (predicate seq)
   "Remove all items satisfying PREDICATE in SEQ.
 This is a destructive function: it reuses the storage of SEQ
 whenever possible."
+  (declare (obsolete cl-delete-if "28.1"))
   ;; remove from car
   (while (when (funcall predicate (car seq))
           (setq seq (cdr seq))))
@@ -117,11 +111,12 @@ whenever possible."
       (setq next (cdr ptr))))
   seq)
 
-;; Provide a simpler replacement for `remove-if-not'
+;; Provide a simpler replacement for `cl-remove-if-not'
 (defun erc-remove-if-not (predicate seq)
   "Remove all items not satisfying PREDICATE in SEQ.
 This is a non-destructive function; it makes a copy of SEQ to
 avoid corrupting the original SEQ."
+  (declare (obsolete cl-remove-if-not "28.1"))
   (let (newseq)
     (dolist (el seq)
       (when (funcall predicate el)
@@ -133,6 +128,7 @@ avoid corrupting the original SEQ."
   "Return the subsequence of SEQ from START to END.
 If END is omitted, it defaults to the length of the sequence.
 If START or END is negative, it counts from the end."
+  (declare (obsolete cl-subseq "28.1"))
   (if (stringp seq) (substring seq start end)
     (let (len)
       (and end (< end 0) (setq end (+ end (setq len (length seq)))))
diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el
index 147b90291a..f27425ac8a 100644
--- a/lisp/erc/erc-dcc.el
+++ b/lisp/erc/erc-dcc.el
@@ -1,7 +1,6 @@
 ;;; erc-dcc.el --- CTCP DCC module for ERC  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1993-1995, 1998, 2002-2004, 2006-2021 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1993-2021 Free Software Foundation, Inc.
 
 ;; Author: Ben A. Mesander <ben@gnu.ai.mit.edu>
 ;;         Noah Friedman <friedman@prep.ai.mit.edu>
@@ -164,9 +163,8 @@ Looks like:
 ;;; Misc macros and utility functions
 
 (defun erc-dcc-member (&rest args)
-  "Return first matching entry in `erc-dcc-list' satisfying constraints in 
plist ARGS.
-
-Return nil on no match.
+  "Return first matching entry in `erc-dcc-list' satisfying constraints in 
ARGS.
+ARGS is a plist.  Return nil on no match.
 
 The property :nick is treated specially, if it contains a `!' character,
 it is treated as a nick!user@host string, and compared with the :nick property
@@ -184,9 +182,7 @@ compared with `erc-nick-equal-p' which is IRC 
case-insensitive."
           (let ((prop (car prem))
                 (val (cadr prem)))
             (setq prem (cddr prem)
-                  ;; plist-member is a predicate in xemacs
-                  test (and (plist-member elt prop)
-                            (plist-get elt prop)))
+                  test (cadr (plist-member elt prop)))
             ;; if the property exists and is equal, we continue, else, try the
             ;; next element of the list
             (or (and (eq prop :nick) (if (>= emacs-major-version 28)
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index fc9a8d39ef..683ac2d37c 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -137,7 +137,7 @@ Put this function on `erc-insert-post-hook' and/or 
`erc-send-post-hook'."
     (goto-char (point-max))))
 
 (defun erc-move-to-prompt-setup ()
-  "Initialize the move-to-prompt module for XEmacs."
+  "Initialize the move-to-prompt module."
   (add-hook 'pre-command-hook #'erc-move-to-prompt nil t))
 
 ;;; Keep place in unvisited channels
diff --git a/lisp/erc/erc-imenu.el b/lisp/erc/erc-imenu.el
index dcf6db7407..522bc805f8 100644
--- a/lisp/erc/erc-imenu.el
+++ b/lisp/erc/erc-imenu.el
@@ -1,7 +1,6 @@
 ;;; erc-imenu.el --- Imenu support for ERC  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2001-2002, 2004, 2006-2021 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 2001-2021 Free Software Foundation, Inc.
 
 ;; Author: Mario Lang <mlang@delysid.org>
 ;; Maintainer: Amin Bandali <bandali@gnu.org>
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index 1c7742afd2..678c596760 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -824,7 +824,7 @@ As an example:
         (ports (if (listp (nth 3 srv))
                    (erc-ports-list (nth 3 srv))
                  (list (nth 3 srv))))
-        (port (nth (random (length ports)) ports)))
+         (port (and ports (seq-random-elt ports))))
     (erc :server host :port port)))
 
 ;;; The following experimental
diff --git a/lisp/erc/erc-replace.el b/lisp/erc/erc-replace.el
index 90c0ee6f8a..b2e9047ce7 100644
--- a/lisp/erc/erc-replace.el
+++ b/lisp/erc/erc-replace.el
@@ -1,7 +1,6 @@
 ;;; erc-replace.el --- wash and massage messages inserted into the buffer  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2001-2002, 2004, 2006-2021 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 2001-2021 Free Software Foundation, Inc.
 
 ;; Author: Andreas Fuchs <asf@void.at>
 ;; Maintainer: Amin Bandali <bandali@gnu.org>
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index ac0c08bd3a..3028568753 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -12,7 +12,7 @@
 ;;               David Edmondson (dme@dme.org)
 ;;               Michael Olson (mwolson@gnu.org)
 ;;               Kelvin White (kwhite@gnu.org)
-;; Version: 5.3
+;; Version: 5.4.1
 ;; Package-Requires: ((emacs "27.1"))
 ;; Keywords: IRC, chat, client, Internet
 ;; URL: https://www.gnu.org/software/emacs/erc.html
@@ -58,7 +58,7 @@
 
 ;;; Code:
 
-(load "erc-loaddefs" nil t)
+(load "erc-loaddefs" 'noerror 'nomessage)
 
 (require 'cl-lib)
 (require 'format-spec)
@@ -69,10 +69,23 @@
 (require 'iso8601)
 (eval-when-compile (require 'subr-x))
 
+(defconst erc-version "5.4.1"
+  "This version of ERC.")
+
 (defvar erc-official-location
   "https://www.gnu.org/software/emacs/erc.html (mailing list: 
emacs-erc@gnu.org)"
   "Location of the ERC client on the Internet.")
 
+;; Map each :package-version to the associated Emacs version.
+;; (This eliminates the need for explicit :version keywords on the
+;; custom definitions.)
+(add-to-list
+ 'customize-package-emacs-version-alist
+ '(ERC ("5.2" . "22.1")
+       ("5.3" . "23.1")
+       ("5.4" . "28.1")
+       ("5.4.1" . "29.1")))
+
 (defgroup erc nil
   "Emacs Internet Relay Chat client."
   :link '(url-link "https://www.gnu.org/software/emacs/erc.html";)
@@ -188,10 +201,12 @@ parameters and authentication."
 It is not strictly necessary to provide this, since ERC will
 prompt you for it.")
 
-(defcustom erc-user-mode nil
+(defcustom erc-user-mode "+i"
+  ;; +i "Invisible".  Hides user from global /who and /names.
   "Initial user modes to be set after a connection is established."
   :group 'erc
-  :type '(choice (const nil) string function))
+  :type '(choice (const nil) string function)
+  :version "28.1")
 
 
 (defcustom erc-prompt-for-password t
@@ -857,8 +872,8 @@ See `erc-server-flood-margin' for other flood-related 
parameters.")
 ;; Script parameters
 
 (defcustom erc-startup-file-list
-  (list (concat user-emacs-directory ".ercrc.el")
-        (concat user-emacs-directory ".ercrc")
+  (list (locate-user-emacs-file ".ercrc.el")
+        (locate-user-emacs-file ".ercrc")
         "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
   "List of files to try for a startup script.
 The first existent and readable one will get executed.
@@ -1277,7 +1292,7 @@ Example:
                #\\='erc-replace-insert))
     ((remove-hook \\='erc-insert-modify-hook
                   #\\='erc-replace-insert)))"
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   (let* ((sn (symbol-name name))
          (mode (intern (format "erc-%s-mode" (downcase sn))))
          (group (intern (format "erc-%s" (downcase sn))))
@@ -2383,6 +2398,7 @@ If ARG is non-nil, show the *erc-protocol* buffer."
         (let ((inhibit-read-only t)
               (msg (list
                     (concat "Version: " erc-debug-irc-protocol-version)
+                    (concat "ERC-Version: " erc-version)
                     (concat "Emacs-Version: " emacs-version)
                     (erc-make-notice
                      (concat "This buffer displays all IRC protocol "
@@ -2801,20 +2817,17 @@ present."
   (let ((prop-val (erc-get-parsed-vector position)))
     (and prop-val (member (erc-response.command prop-val) list))))
 
-(defvar-local erc-send-input-line-function 'erc-send-input-line)
+(defvar-local erc-send-input-line-function 'erc-send-input-line
+  "Function for sending lines lacking a leading user command.
+When a line typed into a buffer contains an explicit command, like /msg,
+a corresponding handler (here, erc-cmd-MSG) is called.  But lines typed
+into a channel or query buffer already have an implicit target and
+command (PRIVMSG).  This function is called on such occasions and also
+for special purposes (see erc-dcc.el).")
 
 (defun erc-send-input-line (target line &optional force)
-  "Send LINE to TARGET.
-
-See also `erc-server-send'."
-  (setq line (format "PRIVMSG %s :%s"
-                     target
-                     ;; If the line is empty, we still want to
-                     ;; send it - i.e. an empty pasted line.
-                     (if (string= line "\n")
-                         " \n"
-                       line)))
-  (erc-server-send line force target))
+  "Send LINE to TARGET."
+  (erc-message "PRIVMSG" (concat target " " line) force))
 
 (defun erc-get-arglist (fun)
   "Return the argument list of a function without the parens."
@@ -2952,7 +2965,7 @@ Commands for which no erc-cmd-xxx exists, are tunneled 
through
 this function.  LINE is sent to the server verbatim, and
 therefore has to contain the command itself as well."
   (erc-log (format "cmd: DEFAULT: %s" line))
-  (erc-server-send (substring line 1))
+  (erc-server-send (string-trim-right (substring line 1) "[\r\n]"))
   t)
 
 (defvar erc--read-time-period-history nil)
@@ -3298,19 +3311,39 @@ a script after exceeding the flood threshold."
     t)
    (t nil)))
 
-(defun erc-cmd-WHOIS (user &optional server)
-  "Display whois information for USER.
+(defun erc-cmd-WHOIS (first &optional second)
+  "Display whois information for the given user.
 
-If SERVER is non-nil, use that, rather than the current server."
-  ;; FIXME: is the above docstring correct?  -- Lawrence 2004-01-08
-  (let ((send (if server
-                  (format "WHOIS %s %s" user server)
-                (format "WHOIS %s" user))))
+With one argument, FIRST is the nickname of the user to request
+whois information for.
+
+With two arguments, FIRST is the server, and SECOND is the user
+nickname.
+
+Specifying the server is useful for getting the time the user has
+been idle for, when the user is connected to a different server
+on the same IRC network.  (Only the server a user is connected to
+knows how long the user has been idle for.)"
+  (let ((send (if second
+                  (format "WHOIS %s %s" first second)
+                (format "WHOIS %s" first))))
     (erc-log (format "cmd: %s" send))
     (erc-server-send send)
     t))
 (defalias 'erc-cmd-WI #'erc-cmd-WHOIS)
 
+(defun erc-cmd-WII (nick)
+  "Display whois information for NICK, including idle time.
+
+This is a convenience function which calls `erc-cmd-WHOIS' with
+the given NICK for both arguments.  Using NICK in place of the
+server argument -- effectively delegating to the IRC network the
+looking up of the server to which NICK is connected -- is not
+standardized, but is widely supported across IRC networks.
+
+See `erc-cmd-WHOIS' for more details."
+  (erc-cmd-WHOIS nick nick))
+
 (defun erc-cmd-WHOAMI ()
   "Display whois information about yourself."
   (erc-cmd-WHOIS (erc-current-nick))
@@ -3591,7 +3624,7 @@ If USER is omitted, close the current query buffer if one 
exists
 
 (defun erc-quit/part-reason-default ()
   "Default quit/part message."
-  (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version))
+  (erc-version nil 'bold-erc))
 
 
 (defun erc-quit-reason-normal (&optional s)
@@ -3719,13 +3752,17 @@ the message given by REASON."
       (setq buffer (current-buffer)))
     (with-current-buffer buffer
       (setq erc-server-quitting nil)
-      (setq erc-server-reconnecting t)
+      (with-suppressed-warnings ((obsolete erc-server-reconnecting))
+        (setq erc-server-reconnecting t))
+      (setq erc--server-reconnecting t)
       (setq erc-server-reconnect-count 0)
       (setq process (get-buffer-process (erc-server-buffer)))
       (if process
           (delete-process process)
         (erc-server-reconnect))
-      (setq erc-server-reconnecting nil)))
+      (with-suppressed-warnings ((obsolete erc-server-reconnecting))
+        (setq erc-server-reconnecting nil))
+      (setq erc--server-reconnecting nil)))
   t)
 (put 'erc-cmd-RECONNECT 'process-not-needed t)
 
@@ -3744,7 +3781,8 @@ the message given by REASON."
 
 (defun erc-cmd-SV ()
   "Say the current ERC and Emacs version into channel."
-  (erc-send-message (format "I'm using ERC with GNU Emacs %s (%s%s)%s."
+  (erc-send-message (format "I'm using ERC %s with GNU Emacs %s (%s%s)%s."
+                            erc-version
                             emacs-version
                             system-configuration
                             (concat
@@ -4823,8 +4861,8 @@ See also `erc-display-message'."
   (unless erc-disable-ctcp-replies
     (erc-send-ctcp-notice
      nick (format
-           "VERSION \C-bERC\C-b - an IRC client for Emacs %s (\C-b%s\C-b)"
-           emacs-version
+           "VERSION %s (\C-b%s\C-b)"
+           (erc-version nil 'bold-erc)
            erc-official-location)))
   nil)
 
@@ -6594,6 +6632,15 @@ If BUFFER is nil, update the mode line in all ERC 
buffers."
 
 ;; Miscellaneous
 
+(defun erc-bug (subject)
+  "Send a bug report to the Emacs bug tracker and ERC mailing list."
+  (interactive "sBug Subject: ")
+  (report-emacs-bug
+   (format "ERC %s: %s" erc-version subject))
+  (save-excursion
+    (goto-char (point-min))
+    (insert "X-Debbugs-CC: emacs-erc@gnu.org\n")))
+
 (defun erc-port-to-string (p)
   "Convert port P to a string.
 P may be an integer or a service name."
@@ -6610,12 +6657,18 @@ P may be an integer or a service name."
           s
         n))))
 
-(defun erc-version (&optional here)
+(defun erc-version (&optional here bold-erc)
   "Show the version number of ERC in the minibuffer.
-If optional argument HERE is non-nil, insert version number at point."
+If optional argument HERE is non-nil, insert version number at point.
+If optional argument BOLD-ERC is non-nil, display \"ERC\" as bold."
   (interactive "P")
   (let ((version-string
-         (format "ERC (IRC client for Emacs %s)" emacs-version)))
+         (format "%s %s (IRC client for GNU Emacs %s)"
+                 (if bold-erc
+                     "\C-bERC\C-b"
+                   "ERC")
+                 erc-version
+                 emacs-version)))
     (if here
         (insert version-string)
       (if (called-interactively-p 'interactive)
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index a9775b7c56..a054cd66e2 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -315,6 +315,8 @@ and the hook `eshell-exit-hook'."
   (setq-local bookmark-make-record-function #'eshell-bookmark-make-record)
   (setq local-abbrev-table eshell-mode-abbrev-table)
 
+  (setq-local window-point-insertion-type t)
+
   (setq-local list-buffers-directory (expand-file-name default-directory))
 
   ;; always set the tab width to 8 in Eshell buffers, since external
@@ -614,6 +616,14 @@ newline."
                  (and eshell-send-direct-to-subprocesses
                       proc-running-p))
        (insert-before-markers-and-inherit ?\n))
+      ;; Delete and reinsert input.  This seems like a no-op, except
+      ;; for the resulting entries in the undo list: undoing this
+      ;; insertion will delete the region, moving the process mark
+      ;; back to its original position.
+      (let ((text (buffer-substring eshell-last-output-end (point)))
+            (inhibit-read-only t))
+        (delete-region eshell-last-output-end (point))
+        (insert text))
       (if proc-running-p
          (progn
            (eshell-update-markers eshell-last-output-end)
@@ -696,13 +706,10 @@ This is done after all necessary filtering has been done."
                   (setq oend (+ oend nchars)))
               ;; Let the ansi-color overlay hooks run.
               (let ((inhibit-modification-hooks nil))
-                (insert-before-markers string))
+                (insert string))
               (if (= (window-start) (point))
                   (set-window-start (selected-window)
                                     (- (point) nchars)))
-              (if (= (point) eshell-last-input-end)
-                  (set-marker eshell-last-input-end
-                              (- eshell-last-input-end nchars)))
               (set-marker eshell-last-output-start ostart)
               (set-marker eshell-last-output-end (point))
               (force-mode-line-update))
@@ -940,7 +947,14 @@ This function could be in the list 
`eshell-output-filter-functions'."
        (beginning-of-line)
        (if (re-search-forward eshell-password-prompt-regexp
                               eshell-last-output-end t)
-           (eshell-send-invisible))))))
+            ;; Use `run-at-time' in order not to pause execution of
+            ;; the process filter with a minibuffer
+           (run-at-time
+             0 nil
+             (lambda (current-buf)
+               (with-current-buffer current-buf
+                 (eshell-send-invisible)))
+             (current-buffer)))))))
 
 (custom-add-option 'eshell-output-filter-functions
                   'eshell-watch-for-password-prompt)
@@ -993,8 +1007,6 @@ This function could be in the list 
`eshell-output-filter-functions'."
 
 ;;; Bookmark support:
 
-(declare-function bookmark-make-record-default
-                  "bookmark" (&optional no-file no-context posn))
 (declare-function bookmark-prop-get "bookmark" (bookmark prop))
 
 (defun eshell-bookmark-name ()
diff --git a/lisp/ezimage.el b/lisp/ezimage.el
index 13f5c039a7..57033cde05 100644
--- a/lisp/ezimage.el
+++ b/lisp/ezimage.el
@@ -45,6 +45,7 @@
 (defmacro defezimage (variable imagespec docstring)
   "Define VARIABLE as an image if `defimage' is not available.
 IMAGESPEC is the image data, and DOCSTRING is documentation for the image."
+  (declare (indent defun))
   `(progn
      (defimage ,variable ,imagespec ,docstring)
      (put (quote ,variable) 'ezimage t)))
diff --git a/lisp/facemenu.el b/lisp/facemenu.el
index 7229d6163d..fe458b8c07 100644
--- a/lisp/facemenu.el
+++ b/lisp/facemenu.el
@@ -541,17 +541,18 @@ If the optional argument LIST is non-nil, it should be a 
list of
 colors to display.  Otherwise, this command computes a list of
 colors that the current display can handle.  Customize
 `list-colors-sort' to change the order in which colors are shown.
-Type `g' or \\[revert-buffer] after customizing `list-colors-sort'
-to redisplay colors in the new order.
+Type \\<help-mode-map>\\[revert-buffer] after customizing \
+`list-colors-sort' to redisplay colors in
+the new order.
 
-If the optional argument BUFFER-NAME is nil, it defaults to *Colors*.
+If the optional argument BUFFER-NAME is nil, it defaults to \"*Colors*\".
 
 If the optional argument CALLBACK is non-nil, it should be a
 function to call each time the user types RET or clicks on a
 color.  The function should accept a single argument, the color name."
   (interactive)
-  (when (and (null list) (> (display-color-cells) 0))
-    (setq list (list-colors-duplicates (defined-colors)))
+  (when (> (display-color-cells) 0)
+    (setq list (list-colors-duplicates (or list (defined-colors))))
     (when list-colors-sort
       ;; Schwartzian transform with `(color key1 key2 key3 ...)'.
       (setq list (mapcar
diff --git a/lisp/faces.el b/lisp/faces.el
index 7b96d938c5..9ec20c4298 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -88,9 +88,9 @@ a font height that isn't optimal."
   :tag "Font selection order"
   :type '(list symbol symbol symbol symbol)
   :group 'font-selection
-  :set #'(lambda (symbol value)
-          (set-default symbol value)
-          (internal-set-font-selection-order value)))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (internal-set-font-selection-order value)))
 
 
 ;; In the absence of Fontconfig support, Monospace and Sans Serif are
@@ -140,9 +140,9 @@ ALTERNATIVE2 etc."
   :tag "Alternative font families to try"
   :type '(repeat (repeat string))
   :group 'font-selection
-  :set #'(lambda (symbol value)
-          (set-default symbol value)
-          (internal-set-alternative-font-family-alist value)))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (internal-set-alternative-font-family-alist value)))
 
 
 ;; This is defined originally in xfaces.c.
@@ -167,9 +167,9 @@ REGISTRY, ALTERNATIVE1, ALTERNATIVE2, and etc."
   :type '(repeat (repeat string))
   :version "21.1"
   :group 'font-selection
-  :set #'(lambda (symbol value)
-          (set-default symbol value)
-          (internal-set-alternative-font-registry-alist value)))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (internal-set-alternative-font-registry-alist value)))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -702,9 +702,10 @@ for it to be relative to).
 
 `:weight'
 
-VALUE specifies the weight of the font to use.  It must be one of the
-symbols `ultra-bold', `extra-bold', `bold', `semi-bold', `normal',
-`semi-light', `light', `extra-light', `ultra-light'.
+VALUE specifies the weight of the font to use.  It must be one of
+the symbols `ultra-heavy', `heavy', `ultra-bold', `extra-bold',
+`bold', `semi-bold', `medium', `normal', `book', `semi-light',
+`light', `extra-light', `ultra-light', or `thin'.
 
 `:slant'
 
@@ -861,8 +862,8 @@ is specified, `:italic' is ignored."
 (defun make-face-bold (face &optional frame _noerror)
   "Make the font of FACE be bold, if possible.
 FRAME nil or not specified means change face on all frames.
-Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font weight."
+  (declare (advertised-calling-convention (face &optional frame) "29.1"))
   (interactive (list (read-face-name "Make which face bold"
                                      (face-at-point t))))
   (set-face-attribute face frame :weight 'bold))
@@ -870,8 +871,8 @@ Use `set-face-attribute' for finer control of the font 
weight."
 
 (defun make-face-unbold (face &optional frame _noerror)
   "Make the font of FACE be non-bold, if possible.
-FRAME nil or not specified means change face on all frames.
-Argument NOERROR is ignored and retained for compatibility."
+FRAME nil or not specified means change face on all frames."
+  (declare (advertised-calling-convention (face &optional frame) "29.1"))
   (interactive (list (read-face-name "Make which face non-bold"
                                      (face-at-point t))))
   (set-face-attribute face frame :weight 'normal))
@@ -880,8 +881,8 @@ Argument NOERROR is ignored and retained for compatibility."
 (defun make-face-italic (face &optional frame _noerror)
   "Make the font of FACE be italic, if possible.
 FRAME nil or not specified means change face on all frames.
-Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of the font slant."
+  (declare (advertised-calling-convention (face &optional frame) "29.1"))
   (interactive (list (read-face-name "Make which face italic"
                                      (face-at-point t))))
   (set-face-attribute face frame :slant 'italic))
@@ -889,8 +890,8 @@ Use `set-face-attribute' for finer control of the font 
slant."
 
 (defun make-face-unitalic (face &optional frame _noerror)
   "Make the font of FACE be non-italic, if possible.
-FRAME nil or not specified means change face on all frames.
-Argument NOERROR is ignored and retained for compatibility."
+FRAME nil or not specified means change face on all frames."
+  (declare (advertised-calling-convention (face &optional frame) "29.1"))
   (interactive (list (read-face-name "Make which face non-italic"
                                      (face-at-point t))))
   (set-face-attribute face frame :slant 'normal))
@@ -899,8 +900,8 @@ Argument NOERROR is ignored and retained for compatibility."
 (defun make-face-bold-italic (face &optional frame _noerror)
   "Make the font of FACE be bold and italic, if possible.
 FRAME nil or not specified means change face on all frames.
-Argument NOERROR is ignored and retained for compatibility.
 Use `set-face-attribute' for finer control of font weight and slant."
+  (declare (advertised-calling-convention (face &optional frame) "29.1"))
   (interactive (list (read-face-name "Make which face bold-italic"
                                      (face-at-point t))))
   (set-face-attribute face frame :weight 'bold :slant 'italic))
@@ -1100,7 +1101,7 @@ returned.  Otherwise, DEFAULT is returned verbatim."
   ;; prompt.  If so, remove it.
   (setq prompt (replace-regexp-in-string ": ?\\'" "" prompt))
   (let ((prompt (if default
-                    (format-message "%s (default `%s'): " prompt default)
+                    (format-prompt prompt default)
                   (format "%s: " prompt)))
         aliasfaces nonaliasfaces faces)
     ;; Build up the completion tables.
@@ -1146,27 +1147,27 @@ an integer value."
            (:foundry
            (list nil))
           (:width
-           (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
+            (mapcar (lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
                    font-width-table))
            (:weight
-           (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
+            (mapcar (lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
                    font-weight-table))
           (:slant
-           (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
+            (mapcar (lambda (x) (cons (symbol-name (aref x 1)) (aref x 1)))
                    font-slant-table))
           ((or :inverse-video :extend)
-           (mapcar #'(lambda (x) (cons (symbol-name x) x))
+            (mapcar (lambda (x) (cons (symbol-name x) x))
                    (internal-lisp-face-attribute-values attribute)))
            ((or :underline :overline :strike-through :box)
             (if (window-system frame)
-                (nconc (mapcar #'(lambda (x) (cons (symbol-name x) x))
+                (nconc (mapcar (lambda (x) (cons (symbol-name x) x))
                                (internal-lisp-face-attribute-values attribute))
-                       (mapcar #'(lambda (c) (cons c c))
+                       (mapcar (lambda (c) (cons c c))
                                (defined-colors frame)))
-             (mapcar #'(lambda (x) (cons (symbol-name x) x))
+              (mapcar (lambda (x) (cons (symbol-name x) x))
                      (internal-lisp-face-attribute-values attribute))))
            ((or :foreground :background)
-            (mapcar #'(lambda (c) (cons c c))
+            (mapcar (lambda (c) (cons c c))
                     (defined-colors frame)))
            (:height
             'integerp)
@@ -1181,7 +1182,7 @@ an integer value."
                                         x-bitmap-file-path)))))
            (:inherit
             (cons '("none" . nil)
-                  (mapcar #'(lambda (c) (cons (symbol-name c) c))
+                  (mapcar (lambda (c) (cons (symbol-name c) c))
                           (face-list))))
            (_
             (error "Internal error")))))
@@ -2285,17 +2286,19 @@ If you set `term-file-prefix' to nil, this function 
does nothing."
       (let* (term-init-func)
        ;; First, load the terminal initialization file, if it is
        ;; available and it hasn't been loaded already.
-       (tty-find-type #'(lambda (type)
-                          (let ((file (locate-library (concat term-file-prefix 
type))))
-                            (and file
-                                 (or (assoc file load-history)
-                                     (load (file-name-sans-extension file)
-                                            t t)))))
-                      type)
+        (tty-find-type (lambda (type)
+                         (let ((file (locate-library (concat term-file-prefix 
type))))
+                           (and file
+                                (or (assoc file load-history)
+                                    (load (replace-regexp-in-string
+                                           "\\.el\\(\\.gz\\)?\\'" ""
+                                           file)
+                                          t t)))))
+                       type)
        ;; Next, try to find a matching initialization function, and call it.
-       (tty-find-type #'(lambda (type)
-                          (fboundp (setq term-init-func
-                                         (intern (concat "terminal-init-" 
type)))))
+        (tty-find-type (lambda (type)
+                         (fboundp (setq term-init-func
+                                        (intern (concat "terminal-init-" 
type)))))
                       type)
        (when (fboundp term-init-func)
          (funcall term-init-func))
@@ -2875,11 +2878,15 @@ Note: Other faces cannot inherit from the cursor face."
      :background "grey96" :foreground "DarkBlue"
      ;; We use negative thickness of the horizontal box border line to
      ;; avoid enlarging the height of the echo-area display, which
-     ;; would then move the mode line a few pixels up.
-     :box (:line-width (1 . -1) :color "grey80"))
+     ;; would then move the mode line a few pixels up.  We use
+     ;; negative thickness for the vertical border line to avoid
+     ;; making the characters wider, which then would cause unpleasant
+     ;; horizontal shifts of the cursor during C-n/C-p movement
+     ;; through a line with this face.
+     :box (:line-width (-1 . -1) :color "grey80"))
     (((class color) (min-colors 88) (background dark))
      :background "grey19" :foreground "LightBlue"
-     :box (:line-width (1 . -1) :color "grey35"))
+     :box (:line-width (-1 . -1) :color "grey35"))
     (((class color grayscale) (background light)) :background "grey90")
     (((class color grayscale) (background dark)) :background "grey25")
     (t :background "grey90"))
diff --git a/lisp/ffap.el b/lisp/ffap.el
index db38016427..5d3cee591b 100644
--- a/lisp/ffap.el
+++ b/lisp/ffap.el
@@ -651,7 +651,7 @@ also is substituted for the first empty-string component, 
if there is one.
 Uses `path-separator' to separate the path into substrings."
   ;; We cannot use parse-colon-path (files.el), since it kills
   ;; "//" entries using file-name-as-directory.
-  ;; Similar: dired-split, TeX-split-string, and RHOGEE's psg-list-env
+  ;; Similar: TeX-split-string, and RHOGEE's psg-list-env
   ;; in ff-paths and bib-cite.  The EMPTY arg may help mimic kpathsea.
   (if (or empty (getenv env))          ; should return something
       (let ((start 0) match dir ret)
@@ -1639,8 +1639,9 @@ If `ffap-url-regexp' is not nil, the FILENAME may also be 
an URL.
 With a prefix, this command behaves exactly like `ffap-file-finder'.
 If `ffap-require-prefix' is set, the prefix meaning is reversed.
 See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt',
-`ffap-url-unwrap-local', `ffap-url-unwrap-remote', and the functions
-`ffap-file-at-point' and `ffap-url-at-point'."
+`ffap-url-unwrap-local', `ffap-url-unwrap-remote',
+`ffap-file-name-with-spaces', and the functions `ffap-file-at-point'
+and `ffap-url-at-point'."
   (interactive)
   (if (and (called-interactively-p 'interactive)
           (if ffap-require-prefix (not current-prefix-arg)
diff --git a/lisp/filenotify.el b/lisp/filenotify.el
index a0c3758238..26954cc73f 100644
--- a/lisp/filenotify.el
+++ b/lisp/filenotify.el
@@ -76,16 +76,17 @@ struct.")
   "Remove DESCRIPTOR from `file-notify-descriptors'.
 DESCRIPTOR should be an object returned by `file-notify-add-watch'.
 If it is registered in `file-notify-descriptors', a `stopped' event is sent."
-  (when-let* ((watch (gethash descriptor file-notify-descriptors)))
-    (let ((callback (file-notify--watch-callback watch)))
-      ;; Make sure this is the last time the callback is invoked.
+  (when-let ((watch (gethash descriptor file-notify-descriptors)))
+    (unwind-protect
+        ;; Send `stopped' event.
+        (file-notify-handle-event
+         (make-file-notify
+          :-event `(,descriptor stopped
+                    ,(file-notify--watch-absolute-filename watch))
+          :-callback (file-notify--watch-callback watch)))
+      ;; Make sure this is the last time the callback was invoked.
       (setf (file-notify--watch-callback watch) nil)
-      ;; Send `stopped' event.
-      (unwind-protect
-          (funcall
-           callback
-           `(,descriptor stopped ,(file-notify--watch-absolute-filename 
watch)))
-        (remhash descriptor file-notify-descriptors)))))
+      (remhash descriptor file-notify-descriptors))))
 
 (cl-defstruct (file-notify (:type list) :named)
   "A file system monitoring event, coming from the backends."
@@ -389,7 +390,9 @@ include the following symbols:
                         permissions or modification time
 
 If FILE is a directory, `change' watches for file creation or
-deletion in that directory.  This does not work recursively.
+deletion in that directory.  Some of the file notification
+backends report also file changes.  This does not work
+recursively.
 
 When any event happens, Emacs will call the CALLBACK function passing
 it a single argument EVENT, which is of the form
@@ -477,6 +480,14 @@ DESCRIPTOR should be an object returned by 
`file-notify-add-watch'."
       ;; Modify `file-notify-descriptors' and send a `stopped' event.
       (file-notify--rm-descriptor descriptor))))
 
+(defun file-notify-rm-all-watches ()
+  "Remove all existing file notification watches from Emacs."
+  (interactive)
+  (maphash
+   (lambda (key _value)
+     (file-notify-rm-watch key))
+   file-notify-descriptors))
+
 (defun file-notify-valid-p (descriptor)
   "Check a watch specified by its DESCRIPTOR.
 DESCRIPTOR should be an object returned by `file-notify-add-watch'."
diff --git a/lisp/files.el b/lisp/files.el
index 2f7e936ff6..c694df3826 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1059,8 +1059,10 @@ the function needs to examine, starting with FILE."
     (if root (file-name-as-directory root))))
 
 (defcustom user-emacs-directory-warning t
-  "Non-nil means warn if cannot access `user-emacs-directory'.
-Set this to nil at your own risk..."
+  "Non-nil means warn if unable to access or create `user-emacs-directory'.
+Set this to nil at your own risk, as it might lead to data loss
+when Emacs tries to write something to a non-existent or
+inaccessible location."
   :type 'boolean
   :group 'initialization
   :version "24.4")
@@ -1564,6 +1566,7 @@ This implementation works on magic file names."
 
 (defun make-nearby-temp-file (prefix &optional dir-flag suffix)
   "Create a temporary file as close as possible to `default-directory'.
+Return the absolute file name of the created file.
 If PREFIX is a relative file name, and `default-directory' is a
 remote file name or located on a mounted file systems, the
 temporary file is created in the directory returned by the
@@ -2758,6 +2761,7 @@ since only a single case-insensitive search through the 
alist is made."
      ("\\.gif\\'" . image-mode)
      ("\\.png\\'" . image-mode)
      ("\\.jpe?g\\'" . image-mode)
+     ("\\.webp\\'" . image-mode)
      ("\\.te?xt\\'" . text-mode)
      ("\\.[tT]e[xX]\\'" . tex-mode)
      ("\\.ins\\'" . tex-mode)          ;Installation files for TeX packages.
@@ -2883,6 +2887,7 @@ 
ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" .
      ("\\.[ds]?va?h?\\'" . verilog-mode)
      ("\\.by\\'" . bovine-grammar-mode)
      ("\\.wy\\'" . wisent-grammar-mode)
+     ("\\.erts\\'" . erts-mode)
      ;; .emacs or .gnus or .viper following a directory delimiter in
      ;; Unix or MS-DOS syntax.
      ("[:/\\]\\..*\\(emacs\\|gnus\\|viper\\)\\'" . emacs-lisp-mode)
@@ -2975,6 +2980,7 @@ 
ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" .
      ("\\.dng\\'" . image-mode)
      ("\\.dpx\\'" . image-mode)
      ("\\.fax\\'" . image-mode)
+     ("\\.heic\\'" . image-mode)
      ("\\.hrz\\'" . image-mode)
      ("\\.icb\\'" . image-mode)
      ("\\.icc\\'" . image-mode)
@@ -3896,7 +3902,7 @@ inhibited."
           (hack-local-variables-apply))))))
 
 (defun hack-local-variables--find-variables (&optional handle-mode)
-  "Return all local variables in the ucrrent buffer.
+  "Return all local variables in the current buffer.
 If HANDLE-MODE is nil, we gather all the specified local
 variables.  If HANDLE-MODE is neither nil nor t, we do the same,
 except that any settings of `mode' are ignored.
@@ -5045,6 +5051,29 @@ See also `file-name-sans-extension'."
   (file-name-sans-extension
    (file-name-nondirectory (or filename (buffer-file-name)))))
 
+(defun file-name-split (filename)
+  "Return a list of all the components of FILENAME.
+On most systems, this will be true:
+
+  (equal (string-join (file-name-split filename) \"/\") filename)"
+  (let ((components nil))
+    ;; If this is a directory file name, then we have a null file name
+    ;; at the end.
+    (when (directory-name-p filename)
+      (push "" components)
+      (setq filename (directory-file-name filename)))
+    ;; Loop, chopping off components.
+    (while (length> filename 0)
+      (push (file-name-nondirectory filename) components)
+      (let ((dir (file-name-directory filename)))
+        (setq filename (and dir (directory-file-name dir)))
+        ;; If there's nothing left to peel off, we're at the root and
+        ;; we can stop.
+        (when (equal dir filename)
+          (push "" components)
+          (setq filename nil))))
+    components))
+
 (defcustom make-backup-file-name-function
   #'make-backup-file-name--default-function
   "A function that `make-backup-file-name' uses to create backup file names.
@@ -5597,7 +5626,7 @@ Before and after saving the buffer, this function runs
          (if (not (file-directory-p dir))
              (if (file-exists-p dir)
                  (error "%s is not a directory" dir)
-               (error "%s: no such directory" dir))
+                (error "%s: No such directory" dir))
            (if (not (file-exists-p buffer-file-name))
                (error "Directory %s write-protected" dir)
              (if (yes-or-no-p
@@ -5745,7 +5774,9 @@ This allows you to stop `save-some-buffers' from asking
 about certain files that you'd usually rather not save.
 
 This function is called (with no parameters) from the buffer to
-be saved."
+be saved.  When the function's symbol has the property
+`save-some-buffers-function', the higher-order function is supposed
+to return a predicate used to check buffers."
   :group 'auto-save
   ;; FIXME nil should not be a valid option, let alone the default,
   ;; eg so that add-function can be used.
@@ -5756,7 +5787,7 @@ be saved."
   :version "26.1")
 
 (defun save-some-buffers-root ()
-  "A predicate to check whether the buffer is under the root directory.
+  "A predicate to check whether the buffer is under the project root directory.
 Can be used as a value of `save-some-buffers-default-predicate'
 to save buffers only under the project root or in subdirectories
 of the directory that was default during command invocation."
@@ -5765,6 +5796,7 @@ of the directory that was default during command 
invocation."
                        (project-root (project-current)))
                   default-directory)))
     (lambda () (file-in-directory-p default-directory root))))
+(put 'save-some-buffers-root 'save-some-buffers-function t)
 
 (defun save-some-buffers (&optional arg pred)
   "Save some modified file-visiting buffers.  Asks user about each one.
@@ -5796,9 +5828,10 @@ change the additional actions you can take on files."
     (setq pred save-some-buffers-default-predicate))
   ;; Allow `pred' to be a function that returns a predicate
   ;; with lexical bindings in its original environment (bug#46374).
-  (let ((pred-fun (and (functionp pred) (funcall pred))))
-    (when (functionp pred-fun)
-      (setq pred pred-fun)))
+  (when (and (symbolp pred) (get pred 'save-some-buffers-function))
+    (let ((pred-fun (and (functionp pred) (funcall pred))))
+      (when (functionp pred-fun)
+        (setq pred pred-fun))))
   (let* ((switched-buffer nil)
          (save-some-buffers--switch-window-callback
           (lambda (buffer)
@@ -6173,6 +6206,30 @@ Return nil if DIR is not an existing directory."
          (unless mismatch
            (file-equal-p root dir)))))))
 
+(defvar file-has-changed-p--hash-table (make-hash-table :test #'equal)
+  "Internal variable used by `file-has-changed-p'.")
+
+(defun file-has-changed-p (file &optional tag)
+  "Return non-nil if FILE has changed.
+The size and modification time of FILE are compared to the size
+and modification time of the same FILE during a previous
+invocation of `file-has-changed-p'.  Thus, the first invocation
+of `file-has-changed-p' always returns non-nil when FILE exists.
+The optional argument TAG, which must be a symbol, can be used to
+limit the comparison to invocations with identical tags; it can be
+the symbol of the calling function, for example."
+  (let* (;; FIXME: Shall we use `file-truename'?
+         (file (directory-file-name file))
+         (remote-file-name-inhibit-cache t)
+         (fileattr (file-attributes file 'integer))
+        (attr (and fileattr
+                    (cons (file-attribute-size fileattr)
+                         (file-attribute-modification-time fileattr))))
+        (sym (concat (symbol-name tag) "@" file))
+        (cachedattr (gethash sym file-has-changed-p--hash-table)))
+     (when (not (equal attr cachedattr))
+       (puthash sym attr file-has-changed-p--hash-table))))
+
 (defun copy-directory (directory newname &optional keep-time parents 
copy-contents)
   "Copy DIRECTORY to NEWNAME.  Both args must be strings.
 This function always sets the file modes of the output files to match
@@ -7125,16 +7182,16 @@ default directory.  However, if FULL is non-nil, they 
are absolute."
          (let ((this-dir-contents
                 ;; Filter out "." and ".."
                 (delq nil
-                      (mapcar #'(lambda (name)
-                                  (unless (string-match "\\`\\.\\.?\\'"
-                                                        
(file-name-nondirectory name))
-                                    name))
+                       (mapcar (lambda (name)
+                                 (unless (string-match "\\`\\.\\.?\\'"
+                                                       (file-name-nondirectory 
name))
+                                   name))
                               (directory-files (or dir ".") full
                                                (wildcard-to-regexp nondir))))))
            (setq contents
                  (nconc
                   (if (and dir (not full))
-                      (mapcar #'(lambda (name) (concat dir name))
+                       (mapcar (lambda (name) (concat dir name))
                               this-dir-contents)
                     this-dir-contents)
                   contents)))))
@@ -7948,7 +8005,7 @@ for the specified category of users."
        ((= char ?g) #o2070)
        ((= char ?o) #o1007)
        ((= char ?a) #o7777)
-       (t (error "%c: bad `who' character" char))))
+        (t (error "%c: Bad `who' character" char))))
 
 (defun file-modes-char-to-right (char &optional from)
   "Convert CHAR to a numeric value of mode bits.
@@ -7971,7 +8028,7 @@ If CHAR is in [Xugo], the value is taken from FROM (or 0 
if omitted)."
                       (+ gright (/ gright #o10) (* gright #o10))))
        ((= char ?o) (let ((oright (logand #o1007 from)))
                       (+ oright (* oright #o10) (* oright #o100))))
-       (t (error "%c: bad right character" char))))
+        (t (error "%c: Bad right character" char))))
 
 (defun file-modes-rights-to-number (rights who-mask &optional from)
   "Convert a symbolic mode string specification to an equivalent number.
diff --git a/lisp/find-file.el b/lisp/find-file.el
index 4d520c01cc..afe6cb5150 100644
--- a/lisp/find-file.el
+++ b/lisp/find-file.el
@@ -356,7 +356,7 @@ Variables of interest include:
    List of functions to be called if the other file has been created."
   (interactive (list current-prefix-arg nil last-nonmenu-event))
   ;; We want to preserve point in the current buffer. But the point of
-  ;; ff-find-the-other-file is to make the the other file buffer
+  ;; ff-find-the-other-file is to make the other file buffer
   ;; current, so we can't use save-excursion here (see bug 48535).
   (let ((start-buffer (current-buffer))
         (start-point (point)))
diff --git a/lisp/finder.el b/lisp/finder.el
index c2b9a6d0ef..00f321b802 100644
--- a/lisp/finder.el
+++ b/lisp/finder.el
@@ -362,19 +362,13 @@ not `finder-known-keywords'."
     (let ((package-list-unversioned t))
       (package-show-package-list packages))))
 
-(define-button-type 'finder-xref 'action #'finder-goto-xref)
-
-(defun finder-goto-xref (button)
-  "Jump to a Lisp file for the BUTTON at point."
-  (let* ((file (button-get button 'xref))
-         (lib (locate-library file)))
-    (if lib (finder-commentary lib)
-      (message "Unable to locate `%s'" file))))
-
 ;;;###autoload
 (defun finder-commentary (file)
   "Display FILE's commentary section.
 FILE should be in a form suitable for passing to `locate-library'."
+  ;; FIXME: Merge this function into `describe-package', which is
+  ;; strictly better as it has links to URL's and is in a proper help
+  ;; buffer with navigation forward and backward, etc.
   (interactive
    (list
     (completing-read "Library name: "
@@ -391,12 +385,7 @@ FILE should be in a form suitable for passing to 
`locate-library'."
     (erase-buffer)
     (insert str)
     (goto-char (point-min))
-    (while (re-search-forward "\\<\\([-[:alnum:]]+\\.el\\)\\>" nil t)
-      (if (locate-library (match-string 1))
-          (make-text-button (match-beginning 1) (match-end 1)
-                            'xref (match-string-no-properties 1)
-                            'help-echo "Read this file's commentary"
-                            :type 'finder-xref)))
+    (package--describe-add-library-links)
     (goto-char (point-min))
     (setq buffer-read-only t)
     (set-buffer-modified-p nil)
@@ -469,6 +458,9 @@ Quit the window and kill all Finder-related buffers."
   ;; continue standard unloading
   nil)
 
+(define-obsolete-function-alias 'finder-goto-xref
+  #'package--finder-goto-xref "29.1")
+
 
 (provide 'finder)
 
diff --git a/lisp/follow.el b/lisp/follow.el
index b64f4cb734..2ca2c1f17b 100644
--- a/lisp/follow.el
+++ b/lisp/follow.el
@@ -667,7 +667,8 @@ Works like `scroll-down' when not in Follow mode."
         (scroll-down-command arg))
        (arg (follow-scroll-down-arg arg))
         (t
-        (let* ((windows (follow-all-followers))
+        (let* ((orig-point (point))
+                (windows (follow-all-followers))
                (win (car (reverse windows)))
                (start (window-start (car windows))))
           (if (eq start (point-min))
@@ -678,11 +679,14 @@ Works like `scroll-down' when not in Follow mode."
             (select-window win)
             (goto-char start)
             (vertical-motion (- (- (window-height win)
-                                   (if header-line-format 2 1)
-                                   next-screen-context-lines)))
+                                   (if header-line-format 2 1) ; always 
mode-line
+                                   (if tab-line-format 1 0)
+                                    next-screen-context-lines)))
             (set-window-start win (point))
-            (goto-char start)
-            (vertical-motion (- next-screen-context-lines 1))
+             (if (< orig-point (window-end win t))
+                 (goto-char orig-point)
+               (goto-char start)
+              (vertical-motion (- next-screen-context-lines 1)))
             (setq follow-internal-force-redisplay t))))))
 (put 'follow-scroll-down 'scroll-command t)
 
@@ -947,7 +951,11 @@ used."
   (let* ((win (or win (selected-window)))
         (edges (window-inside-pixel-edges win))
         (ht (- (nth 3 edges) (nth 1 edges)))
-        (last-line-pos (posn-point (posn-at-x-y 0 (1- ht) win))))
+        (last-line-pos (posn-point
+                         (posn-at-x-y 0 (+ (window-header-line-height win)
+                                           (window-tab-line-height win)
+                                           (1- ht))
+                                      win))))
     (if (pos-visible-in-window-p last-line-pos win)
        (let ((end (window-end win t)))
          (list end (pos-visible-in-window-p (point-max) win)))
diff --git a/lisp/font-lock.el b/lisp/font-lock.el
index a4ab897f6f..c2590eb3c1 100644
--- a/lisp/font-lock.el
+++ b/lisp/font-lock.el
@@ -2075,7 +2075,7 @@ as the constructs of Haddock, Javadoc and similar 
systems."
     (((class color) (min-colors 16) (background dark))  :foreground 
"PaleGreen")
     (((class color) (min-colors 8)) :foreground "green")
     (t :weight bold :underline t))
-  "Font Lock mode face used to highlight type and classes."
+  "Font Lock mode face used to highlight type and class names."
   :group 'font-lock-faces)
 
 (defface font-lock-constant-face
diff --git a/lisp/format.el b/lisp/format.el
index 71cf885d41..8ae51f19eb 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -320,7 +320,7 @@ If the format is not specified, attempt a regexp-based 
guess.
 Set `buffer-file-format' to the format used, and call any
 format-specific mode functions."
   (interactive
-   (list (format-read "Translate buffer from format (default guess): ")))
+   (list (format-read (format-prompt "Translate buffer from format" "guess"))))
   (save-excursion
     (goto-char (point-min))
     (format-decode format (buffer-size) t)))
@@ -331,7 +331,7 @@ Arg FORMAT is optional; if omitted the format will be 
determined by looking
 for identifying regular expressions at the beginning of the region."
   (interactive
    (list (region-beginning) (region-end)
-        (format-read "Translate region from format (default guess): ")))
+         (format-read (format-prompt "Translate region from format" "guess"))))
   (save-excursion
     (goto-char from)
     (format-decode format (- to from) nil)))
@@ -519,7 +519,7 @@ the value of `foo'."
       (cdr list)
     (let ((p list))
       (while (not (eq (cdr p) cons))
-       (if (null p) (error "format-delq-cons: not an element"))
+        (if (null p) (error "format-delq-cons: Not an element"))
        (setq p (cdr p)))
       ;; Now (cdr p) is the cons to delete
       (setcdr p (cdr cons))
diff --git a/lisp/frame.el b/lisp/frame.el
index e97b9903df..2c73737a54 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -786,25 +786,26 @@ When called from Lisp, returns the new frame."
       (make-frame)
     (select-frame (make-frame))))
 
-(defun clone-frame (&optional frame use-default-parameters)
-  "Make a new frame with the same parameters as FRAME.
-With a prefix arg (USE-DEFAULT-PARAMETERS), use
-`default-frame-alist' instead.
+(defun clone-frame (&optional frame no-windows)
+  "Make a new frame with the same parameters and windows as FRAME.
+With a prefix arg NO-WINDOWS, don't clone the window configuration.
 
 FRAME defaults to the selected frame.  The frame is created on the
 same terminal as FRAME.  If the terminal is a text-only terminal then
 also select the new frame."
-  (interactive "i\nP")
-  (if use-default-parameters
-      (make-frame-command)
-    (let* ((default-frame-alist (seq-filter
-                                 (lambda (elem)
-                                   (not (eq (car elem) 'name)))
-                                 (frame-parameters frame)))
-           (new-frame (make-frame)))
-      (unless (display-graphic-p)
-        (select-frame new-frame))
-      new-frame)))
+  (interactive (list (selected-frame) current-prefix-arg))
+  (let* ((frame (or frame (selected-frame)))
+         (windows (unless no-windows
+                    (window-state-get (frame-root-window frame))))
+         (default-frame-alist
+           (seq-remove (lambda (elem) (eq (car elem) 'name))
+                       (frame-parameters frame)))
+         (new-frame (make-frame)))
+    (when windows
+      (window-state-put windows (frame-root-window new-frame) 'safe))
+    (unless (display-graphic-p)
+      (select-frame new-frame))
+    new-frame))
 
 (defvar before-make-frame-hook nil
   "Functions to run before `make-frame' creates a new frame.")
diff --git a/lisp/frameset.el b/lisp/frameset.el
index cdbac0a48c..998f4fb4ca 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -1178,7 +1178,8 @@ FORCE-ONSCREEN can be:
           - a list (LEFT TOP WIDTH HEIGHT), describing the workarea.
           It must return non-nil to force the frame onscreen, nil otherwise.
 
-CLEANUP-FRAMES allows \"cleaning up\" the frame list after restoring a 
frameset:
+CLEANUP-FRAMES allows \"cleaning up\" the frame list after
+restoring a frameset:
   t        Delete all frames that were not created or restored upon.
   nil      Keep all frames.
   FUNC     A function called with two arguments:
diff --git a/lisp/gnus/gmm-utils.el b/lisp/gnus/gmm-utils.el
index bcf8dd014b..68a9098904 100644
--- a/lisp/gnus/gmm-utils.el
+++ b/lisp/gnus/gmm-utils.el
@@ -239,6 +239,7 @@ DEFAULT-MAP specifies the default key map for ICON-LIST."
   "Create function NAME.
 If FUNCTION exists, then NAME becomes an alias for FUNCTION.
 Otherwise, create function NAME with ARG-LIST and BODY."
+  (declare (indent defun))
   (let ((defined-p (fboundp function)))
     (if defined-p
         `(defalias ',name ',function)
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index 961965d928..20da295aca 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -475,17 +475,16 @@ manipulated as follows:
     (gnus-run-hooks 'gnus-agent-mode-hook
                    (intern (format "gnus-agent-%s-mode-hook" buffer)))))
 
-(defvar gnus-agent-group-mode-map (make-sparse-keymap))
-(gnus-define-keys gnus-agent-group-mode-map
-  "Ju" gnus-agent-fetch-groups
-  "Jc" gnus-enter-category-buffer
-  "Jj" gnus-agent-toggle-plugged
-  "Js" gnus-agent-fetch-session
-  "JY" gnus-agent-synchronize-flags
-  "JS" gnus-group-send-queue
-  "Ja" gnus-agent-add-group
-  "Jr" gnus-agent-remove-group
-  "Jo" gnus-agent-toggle-group-plugged)
+(defvar-keymap gnus-agent-group-mode-map
+  "Ju" #'gnus-agent-fetch-groups
+  "Jc" #'gnus-enter-category-buffer
+  "Jj" #'gnus-agent-toggle-plugged
+  "Js" #'gnus-agent-fetch-session
+  "JY" #'gnus-agent-synchronize-flags
+  "JS" #'gnus-group-send-queue
+  "Ja" #'gnus-agent-add-group
+  "Jr" #'gnus-agent-remove-group
+  "Jo" #'gnus-agent-toggle-group-plugged)
 
 (defun gnus-agent-group-make-menu-bar ()
   (unless (boundp 'gnus-agent-group-menu)
@@ -504,16 +503,15 @@ manipulated as follows:
        ["Synchronize flags" gnus-agent-synchronize-flags t]
        ))))
 
-(defvar gnus-agent-summary-mode-map (make-sparse-keymap))
-(gnus-define-keys gnus-agent-summary-mode-map
-  "Jj" gnus-agent-toggle-plugged
-  "Ju" gnus-agent-summary-fetch-group
-  "JS" gnus-agent-fetch-group
-  "Js" gnus-agent-summary-fetch-series
-  "J#" gnus-agent-mark-article
-  "J\M-#" gnus-agent-unmark-article
-  "@" gnus-agent-toggle-mark
-  "Jc" gnus-agent-catchup)
+(defvar-keymap gnus-agent-summary-mode-map
+  "Jj" #'gnus-agent-toggle-plugged
+  "Ju" #'gnus-agent-summary-fetch-group
+  "JS" #'gnus-agent-fetch-group
+  "Js" #'gnus-agent-summary-fetch-series
+  "J#" #'gnus-agent-mark-article
+  "J\M-#" #'gnus-agent-unmark-article
+  "@" #'gnus-agent-toggle-mark
+  "Jc" #'gnus-agent-catchup)
 
 (defun gnus-agent-summary-make-menu-bar ()
   (unless (boundp 'gnus-agent-summary-menu)
@@ -527,11 +525,10 @@ manipulated as follows:
        ["Fetch downloadable" gnus-agent-summary-fetch-group t]
        ["Catchup undownloaded" gnus-agent-catchup t]))))
 
-(defvar gnus-agent-server-mode-map (make-sparse-keymap))
-(gnus-define-keys gnus-agent-server-mode-map
-  "Jj" gnus-agent-toggle-plugged
-  "Ja" gnus-agent-add-server
-  "Jr" gnus-agent-remove-server)
+(defvar-keymap gnus-agent-server-mode-map
+  "Jj" #'gnus-agent-toggle-plugged
+  "Ja" #'gnus-agent-add-server
+  "Jr" #'gnus-agent-remove-server)
 
 (defun gnus-agent-server-make-menu-bar ()
   (unless (boundp 'gnus-agent-server-menu)
@@ -1323,7 +1320,7 @@ downloaded into the agent."
           (gnus-agent-set-local group agent-min (1- active-min)))))))
 
 (defun gnus-agent-save-group-info (method group active)
-  "Update a single group's active range in the agent's copy of the server's 
active file."
+  "Update single group's active range in agent's copy of server's active file."
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method (or method gnus-command-method))
           (coding-system-for-write nnheader-file-coding-system)
@@ -1356,7 +1353,7 @@ downloaded into the agent."
            (delete-char 1)))))))
 
 (defun gnus-agent-get-group-info (method group)
-  "Get a single group's active range in the agent's copy of the server's 
active file."
+  "Get single group's active range in agent's copy of server's active file."
   (when (gnus-agent-method-p method)
     (let* ((gnus-command-method (or method gnus-command-method))
           (coding-system-for-write nnheader-file-coding-system)
@@ -2597,25 +2594,20 @@ General format specifiers can also be used.  See Info 
node
 (defvar gnus-category-line-format-spec nil)
 (defvar gnus-category-mode-line-format-spec nil)
 
-(defvar gnus-category-mode-map nil)
-
-(unless gnus-category-mode-map
-  (setq gnus-category-mode-map (make-sparse-keymap))
-  (suppress-keymap gnus-category-mode-map)
-
-  (gnus-define-keys gnus-category-mode-map
-    "q" gnus-category-exit
-    "k" gnus-category-kill
-    "c" gnus-category-copy
-    "a" gnus-category-add
-    "e" gnus-agent-customize-category
-    "p" gnus-category-edit-predicate
-    "g" gnus-category-edit-groups
-    "s" gnus-category-edit-score
-    "l" gnus-category-list
-
-    "\C-c\C-i" gnus-info-find-node
-    "\C-c\C-b" gnus-bug))
+(defvar-keymap gnus-category-mode-map
+  :suppress t
+  "q" #'gnus-category-exit
+  "k" #'gnus-category-kill
+  "c" #'gnus-category-copy
+  "a" #'gnus-category-add
+  "e" #'gnus-agent-customize-category
+  "p" #'gnus-category-edit-predicate
+  "g" #'gnus-category-edit-groups
+  "s" #'gnus-category-edit-score
+  "l" #'gnus-category-list
+
+  "\C-c\C-i" #'gnus-info-find-node
+  "\C-c\C-b" #'gnus-bug)
 
 (defcustom gnus-category-menu-hook nil
   "Hook run after the creation of the menu."
@@ -3553,32 +3545,13 @@ articles in every agentized group? "))
       (when (and to-remove
                  (or gnus-expert-user
                      (gnus-y-or-n-p
-                      "gnus-agent-expire has identified local directories that 
are\
- not currently required by any agentized group.  Do you wish to consider\
- deleting them?")))
-        (while to-remove
-          (let ((dir (pop to-remove)))
-            (if (or gnus-expert-user
+                      "gnus-agent-expire has identified local directories that 
are
+not currently required by any agentized group.  Do you wish to consider
+deleting them?")))
+        (dolist (dir to-remove)
+          (when (or gnus-expert-user
                    (gnus-y-or-n-p (format "Delete %s? " dir)))
-                (let* (delete-recursive
-                      files f
-                       (delete-recursive
-                        (lambda (f-or-d)
-                          (ignore-errors
-                            (if (file-directory-p f-or-d)
-                                (condition-case nil
-                                    (delete-directory f-or-d)
-                                  (file-error
-                                   (setq files (directory-files f-or-d))
-                                   (while files
-                                     (setq f (pop files))
-                                     (or (member f '("." ".."))
-                                         (funcall delete-recursive
-                                                  (nnheader-concat
-                                                   f-or-d f))))
-                                   (delete-directory f-or-d)))
-                              (delete-file f-or-d))))))
-                  (funcall delete-recursive dir)))))))))
+            (delete-directory dir t)))))))
 
 ;;;###autoload
 (defun gnus-agent-batch ()
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index 7b6e15d6f8..89b4a63ad9 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -1167,6 +1167,19 @@ predicate.  See Info node `(gnus)Customizing Articles'."
   :link '(custom-manual "(gnus)Customizing Articles")
   :type gnus-article-treat-custom)
 
+(defcustom gnus-treat-emojize-symbols nil
+  "Display emoji versions of symbol.
+Some symbols have both a non-emoji presentation and an emoji
+presentation.  This treatment will make Gnus display the latter
+as emojis even when they weren't sent as such.
+
+Valid values are nil, t, `head', `first', `last', an integer or a
+predicate.  See Info node `(gnus)Customizing Articles'."
+  :version "29.1"
+  :group 'gnus-article-treat
+  :link '(custom-manual "(gnus)Customizing Articles")
+  :type gnus-article-treat-custom)
+
 (defcustom gnus-treat-unsplit-urls nil
   "Remove newlines from within URLs.
 Valid values are nil, t, `head', `first', `last', an integer or a
@@ -1650,6 +1663,7 @@ regexp."
 (defvar gnus-article-mime-handle-alist-1 nil)
 (defvar gnus-treatment-function-alist
   '((gnus-treat-strip-cr gnus-article-remove-cr)
+    (gnus-treat-emojize-symbols gnus-article-emojize-symbols)
     (gnus-treat-x-pgp-sig gnus-article-verify-x-pgp-sig)
     (gnus-treat-strip-banner gnus-article-strip-banner)
     (gnus-treat-strip-headers-in-body gnus-article-strip-headers-in-body)
@@ -2360,6 +2374,20 @@ fill width."
       (while (search-forward "\r" nil t)
        (replace-match "\n" t t)))))
 
+(defun article-emojize-symbols ()
+  "Display symbols (that have an emoji version) as emojis."
+  (interactive nil gnus-article-mode)
+  (when-let ((font (and (display-multi-font-p)
+                        (car (internal-char-font nil ?😀)))))
+    (save-excursion
+      (let ((inhibit-read-only t))
+        (goto-char (point-min))
+        (while (re-search-forward "[[:multibyte:]]" nil t)
+          ;; If there's already a grapheme cluster here, skip it.
+          (when (and (not (find-composition (point)))
+                     (font-has-char-p font (char-after (match-beginning 0))))
+            (insert "\N{VARIATION SELECTOR-16}")))))))
+
 (defun article-remove-trailing-blank-lines ()
   "Remove all trailing blank lines from the article."
   (interactive nil gnus-article-mode)
@@ -3933,8 +3961,8 @@ This format is defined by the `gnus-article-time-format' 
variable."
                      ;; No split name was found.
                      ((null split-name)
                       (read-file-name
-                       (concat prompt " (default "
-                               (file-name-nondirectory default-name) "): ")
+                        (format-prompt prompt
+                                       (file-name-nondirectory default-name))
                        (file-name-directory default-name)
                        default-name))
                      ;; A single group name is returned.
@@ -3943,8 +3971,8 @@ This format is defined by the `gnus-article-time-format' 
variable."
                             (funcall function split-name headers
                                      (symbol-value variable)))
                       (read-file-name
-                       (concat prompt " (default "
-                               (file-name-nondirectory default-name) "): ")
+                        (format-prompt prompt
+                                       (file-name-nondirectory default-name))
                        (file-name-directory default-name)
                        default-name))
                      ;; A single split name was found
@@ -3956,9 +3984,8 @@ This format is defined by the `gnus-article-time-format' 
variable."
                                          (file-name-as-directory name))
                                         ((file-exists-p name) name)
                                         (t gnus-article-save-directory))))
-                        (read-file-name
-                         (concat prompt " (default " name "): ")
-                         dir name)))
+                         (read-file-name (format-prompt prompt name)
+                                         dir name)))
                      ;; A list of splits was found.
                      (t
                       (setq split-name (nreverse split-name))
@@ -4342,6 +4369,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
            article-fill-long-lines
            article-capitalize-sentences
            article-remove-cr
+           article-emojize-symbols
            article-remove-leading-whitespace
            article-display-x-face
            article-display-face
@@ -4387,44 +4415,44 @@ If variable `gnus-use-long-file-name' is non-nil, it is
 ;;; Gnus article mode
 ;;;
 
-(set-keymap-parent gnus-article-mode-map button-buffer-map)
-
-(gnus-define-keys gnus-article-mode-map
-  " " gnus-article-goto-next-page
-  [?\S-\ ] gnus-article-goto-prev-page
-  "\177" gnus-article-goto-prev-page
-  [delete] gnus-article-goto-prev-page
-  "\C-c^" gnus-article-refer-article
-  "h" gnus-article-show-summary
-  "s" gnus-article-show-summary
-  "\C-c\C-m" gnus-article-mail
-  "?" gnus-article-describe-briefly
-  "<" beginning-of-buffer
-  ">" end-of-buffer
-  "\C-c\C-i" gnus-info-find-node
-  "\C-c\C-b" gnus-bug
-  "R" gnus-article-reply-with-original
-  "F" gnus-article-followup-with-original
-  "\C-hk" gnus-article-describe-key
-  "\C-hc" gnus-article-describe-key-briefly
-  "\C-hb" gnus-article-describe-bindings
-
-  "e" gnus-article-read-summary-keys
-  "\C-d" gnus-article-read-summary-keys
-  "\C-c\C-f" gnus-summary-mail-forward
-  "\M-*" gnus-article-read-summary-keys
-  "\M-#" gnus-article-read-summary-keys
-  "\M-^" gnus-article-read-summary-keys
-  "\M-g" gnus-article-read-summary-keys)
+(defvar gnus-article-send-map nil)
+
+(define-keymap :keymap gnus-article-mode-map :suppress t
+  :parent button-buffer-map
+  " " #'gnus-article-goto-next-page
+  [?\S-\ ] #'gnus-article-goto-prev-page
+  "\177" #'gnus-article-goto-prev-page
+  [delete] #'gnus-article-goto-prev-page
+  "\C-c^" #'gnus-article-refer-article
+  "h" #'gnus-article-show-summary
+  "s" #'gnus-article-show-summary
+  "\C-c\C-m" #'gnus-article-mail
+  "?" #'gnus-article-describe-briefly
+  "<" #'beginning-of-buffer
+  ">" #'end-of-buffer
+  "\C-c\C-i" #'gnus-info-find-node
+  "\C-c\C-b" #'gnus-bug
+  "R" #'gnus-article-reply-with-original
+  "F" #'gnus-article-followup-with-original
+  "\C-hk" #'gnus-article-describe-key
+  "\C-hc" #'gnus-article-describe-key-briefly
+  "\C-hb" #'gnus-article-describe-bindings
+
+  "e" #'gnus-article-read-summary-keys
+  "\C-d" #'gnus-article-read-summary-keys
+  "\C-c\C-f" #'gnus-summary-mail-forward
+  "\M-*" #'gnus-article-read-summary-keys
+  "\M-#" #'gnus-article-read-summary-keys
+  "\M-^" #'gnus-article-read-summary-keys
+  "\M-g" #'gnus-article-read-summary-keys
+
+  "S" (define-keymap :prefix 'gnus-article-send-map
+        "W" #'gnus-article-wide-reply-with-original
+        [t] #'gnus-article-read-summary-send-keys))
 
 (substitute-key-definition
  #'undefined #'gnus-article-read-summary-keys gnus-article-mode-map)
 
-(defvar gnus-article-send-map)
-(gnus-define-keys (gnus-article-send-map "S" gnus-article-mode-map)
-  "W" gnus-article-wide-reply-with-original
-  [t] gnus-article-read-summary-send-keys)
-
 (defun gnus-article-make-menu-bar ()
   (unless (boundp 'gnus-article-commands-menu)
     (gnus-summary-make-menu-bar))
@@ -4449,6 +4477,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        ["Treat overstrike" gnus-article-treat-overstrike t]
        ["Treat ANSI sequences" gnus-article-treat-ansi-sequences t]
        ["Remove carriage return" gnus-article-remove-cr t]
+       ["Emojize Symbols" gnus-article-emojize-symbols t]
        ["Remove leading whitespace" gnus-article-remove-leading-whitespace t]
        ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
        ["Remove base64" gnus-article-de-base64-unreadable t]
@@ -4507,6 +4536,10 @@ commands:
   (gnus-set-default-directory)
   (buffer-disable-undo)
   (setq show-trailing-whitespace nil)
+  ;; Arrange a callback from `mm-inline-message' if we're
+  ;; displaying a message/rfc822 part.
+  (setq-local mm-inline-message-prepare-function
+              #'gnus-mime--inline-message-function)
   (mm-enable-multibyte))
 
 (defun gnus-article-setup-buffer ()
@@ -6042,31 +6075,29 @@ If nil, don't show those extra buttons."
 (defun gnus-mime-display-mixed (handles)
   (mapcar #'gnus-mime-display-part handles))
 
+(defun gnus-mime--inline-message-function (handle charset)
+  (let ((handles
+         (let (gnus-article-mime-handles
+              ;; disable prepare hook
+              gnus-article-prepare-hook
+              (gnus-newsgroup-charset
+                ;; mm-uu might set it.
+               (unless (eq charset 'gnus-decoded)
+                 (or charset gnus-newsgroup-charset))))
+          (let ((gnus-original-article-buffer
+                  (mm-handle-buffer handle)))
+            (run-hooks 'gnus-article-decode-hook))
+          (gnus-article-prepare-display)
+           gnus-article-mime-handles)))
+    (when handles
+      (setq gnus-article-mime-handles
+           (mm-merge-handles gnus-article-mime-handles handles)))))
+
 (defun gnus-mime-display-single (handle)
   (let ((type (mm-handle-media-type handle))
        (ignored gnus-ignored-mime-types)
        (mm-inline-font-lock (gnus-visual-p 'article-highlight 'highlight))
        (not-attachment t)
-        ;; Arrange a callback from `mm-inline-message' if we're
-        ;; displaying a message/rfc822 part.
-        (mm-inline-message-prepare-function
-         (lambda (charset)
-           (let ((handles
-                  (let (gnus-article-mime-handles
-                       ;; disable prepare hook
-                       gnus-article-prepare-hook
-                       (gnus-newsgroup-charset
-                         ;; mm-uu might set it.
-                        (unless (eq charset 'gnus-decoded)
-                          (or charset gnus-newsgroup-charset))))
-                   (let ((gnus-original-article-buffer
-                           (mm-handle-buffer handle)))
-                     (run-hooks 'gnus-article-decode-hook))
-                   (gnus-article-prepare-display)
-                    gnus-article-mime-handles)))
-            (when handles
-              (setq gnus-article-mime-handles
-                    (mm-merge-handles gnus-article-mime-handles handles))))))
        display text
         gnus-displaying-mime)
     (catch 'ignored
@@ -6866,7 +6897,9 @@ KEY is a string or a vector."
               unread-command-events))
        (let ((cursor-in-echo-area t)
              gnus-pick-mode)
-         (describe-key (read-key-sequence nil t))))
+         (describe-key (cons (read-key-sequence nil t)
+                             (this-single-command-raw-keys))
+                       (current-buffer))))
     (describe-key key)))
 
 (defun gnus-article-describe-key-briefly (key &optional insert)
@@ -6889,7 +6922,9 @@ KEY is a string or a vector."
               unread-command-events))
        (let ((cursor-in-echo-area t)
              gnus-pick-mode)
-         (describe-key-briefly (read-key-sequence nil t) insert)))
+         (describe-key-briefly (cons (read-key-sequence nil t)
+                                     (this-single-command-raw-keys))
+                               insert (current-buffer))))
     (describe-key-briefly key insert)))
 
 ;;`gnus-agent-mode' in gnus-agent.el will define it.
@@ -7217,50 +7252,43 @@ other groups."
 
 (defvar gnus-article-edit-done-function nil)
 
-(defvar gnus-article-edit-mode-map nil)
-
-;; Should we be using derived.el for this?
-(unless gnus-article-edit-mode-map
-  (setq gnus-article-edit-mode-map (make-keymap))
-  (set-keymap-parent gnus-article-edit-mode-map text-mode-map)
-
-  (gnus-define-keys gnus-article-edit-mode-map
-    "\C-c?"    describe-mode
-    "\C-c\C-c" gnus-article-edit-done
-    "\C-c\C-k" gnus-article-edit-exit
-    "\C-c\C-f\C-t" message-goto-to
-    "\C-c\C-f\C-o" message-goto-from
-    "\C-c\C-f\C-b" message-goto-bcc
-    ;;"\C-c\C-f\C-w" message-goto-fcc
-    "\C-c\C-f\C-c" message-goto-cc
-    "\C-c\C-f\C-s" message-goto-subject
-    "\C-c\C-f\C-r" message-goto-reply-to
-    "\C-c\C-f\C-n" message-goto-newsgroups
-    "\C-c\C-f\C-d" message-goto-distribution
-    "\C-c\C-f\C-f" message-goto-followup-to
-    "\C-c\C-f\C-m" message-goto-mail-followup-to
-    "\C-c\C-f\C-k" message-goto-keywords
-    "\C-c\C-f\C-u" message-goto-summary
-    "\C-c\C-f\C-i" message-insert-or-toggle-importance
-    "\C-c\C-f\C-a" message-generate-unsubscribed-mail-followup-to
-    "\C-c\C-b" message-goto-body
-    "\C-c\C-i" message-goto-signature
-
-    "\C-c\C-t" message-insert-to
-    "\C-c\C-n" message-insert-newsgroups
-    "\C-c\C-o" message-sort-headers
-    "\C-c\C-e" message-elide-region
-    "\C-c\C-v" message-delete-not-region
-    "\C-c\C-z" message-kill-to-signature
-    "\M-\r" message-newline-and-reformat
-    "\C-c\C-a" mml-attach-file
-    "\C-a" message-beginning-of-line
-    "\t" message-tab
-    "\M-;" comment-region)
-
-  (gnus-define-keys (gnus-article-edit-wash-map
-                    "\C-c\C-w" gnus-article-edit-mode-map)
-    "f" gnus-article-edit-full-stops))
+(defvar-keymap gnus-article-edit-mode-map
+  :full t :parent text-mode-map
+  "\C-c?" #'describe-mode
+  "\C-c\C-c" #'gnus-article-edit-done
+  "\C-c\C-k" #'gnus-article-edit-exit
+  "\C-c\C-f\C-t" #'message-goto-to
+  "\C-c\C-f\C-o" #'message-goto-from
+  "\C-c\C-f\C-b" #'message-goto-bcc
+  ;;"\C-c\C-f\C-w" message-goto-fcc
+  "\C-c\C-f\C-c" #'message-goto-cc
+  "\C-c\C-f\C-s" #'message-goto-subject
+  "\C-c\C-f\C-r" #'message-goto-reply-to
+  "\C-c\C-f\C-n" #'message-goto-newsgroups
+  "\C-c\C-f\C-d" #'message-goto-distribution
+  "\C-c\C-f\C-f" #'message-goto-followup-to
+  "\C-c\C-f\C-m" #'message-goto-mail-followup-to
+  "\C-c\C-f\C-k" #'message-goto-keywords
+  "\C-c\C-f\C-u" #'message-goto-summary
+  "\C-c\C-f\C-i" #'message-insert-or-toggle-importance
+  "\C-c\C-f\C-a" #'message-generate-unsubscribed-mail-followup-to
+  "\C-c\C-b" #'message-goto-body
+  "\C-c\C-i" #'message-goto-signature
+
+  "\C-c\C-t" #'message-insert-to
+  "\C-c\C-n" #'message-insert-newsgroups
+  "\C-c\C-o" #'message-sort-headers
+  "\C-c\C-e" #'message-elide-region
+  "\C-c\C-v" #'message-delete-not-region
+  "\C-c\C-z" #'message-kill-to-signature
+  "\M-\r" #'message-newline-and-reformat
+  "\C-c\C-a" #'mml-attach-file
+  "\C-a" #'message-beginning-of-line
+  "\t" #'message-tab
+  "\M-;" #'comment-region
+
+  "\C-c\C-w" (define-keymap :prefix 'gnus-article-edit-wash-map
+               "f" #'gnus-article-edit-full-stops))
 
 (easy-menu-define
   gnus-article-edit-mode-field-menu gnus-article-edit-mode-map ""
diff --git a/lisp/gnus/gnus-bookmark.el b/lisp/gnus/gnus-bookmark.el
index 8c2a928ab9..171da9d17a 100644
--- a/lisp/gnus/gnus-bookmark.el
+++ b/lisp/gnus/gnus-bookmark.el
@@ -198,7 +198,9 @@ So the cdr of each bookmark is an alist too.")
 
 (defun gnus-bookmark-make-record
   (group message-id author date subject annotation)
-  "Return the record part of a new bookmark, given GROUP MESSAGE-ID AUTHOR 
DATE SUBJECT and ANNOTATION."
+  "Return the record part of a new bookmark.
+Arguments GROUP MESSAGE-ID AUTHOR DATE SUBJECT and ANNOTATION
+will be saved in the bookmark."
   (let ((the-record
         `((group . ,(substring-no-properties group))
           (message-id . ,(substring-no-properties message-id))
@@ -416,32 +418,29 @@ That is, all information but the name."
 
 (defvar gnus-bookmark-bmenu-bookmark-column nil)
 (defvar gnus-bookmark-bmenu-hidden-bookmarks ())
-(defvar gnus-bookmark-bmenu-mode-map nil)
-
-(if gnus-bookmark-bmenu-mode-map
-    nil
-  (setq gnus-bookmark-bmenu-mode-map (make-keymap))
-  (suppress-keymap gnus-bookmark-bmenu-mode-map t)
-  (define-key gnus-bookmark-bmenu-mode-map "q" 'quit-window)
-  (define-key gnus-bookmark-bmenu-mode-map "\C-m" 'gnus-bookmark-bmenu-select)
-  (define-key gnus-bookmark-bmenu-mode-map "v" 'gnus-bookmark-bmenu-select)
-  (define-key gnus-bookmark-bmenu-mode-map "d" 'gnus-bookmark-bmenu-delete)
-  (define-key gnus-bookmark-bmenu-mode-map "k" 'gnus-bookmark-bmenu-delete)
-  (define-key gnus-bookmark-bmenu-mode-map "\C-d" 
'gnus-bookmark-bmenu-delete-backwards)
-  (define-key gnus-bookmark-bmenu-mode-map "x" 
'gnus-bookmark-bmenu-execute-deletions)
-  (define-key gnus-bookmark-bmenu-mode-map " " 'next-line)
-  (define-key gnus-bookmark-bmenu-mode-map "n" 'next-line)
-  (define-key gnus-bookmark-bmenu-mode-map "p" 'previous-line)
-  (define-key gnus-bookmark-bmenu-mode-map "\177" 
'gnus-bookmark-bmenu-backup-unmark)
-  (define-key gnus-bookmark-bmenu-mode-map "?" 'describe-mode)
-  (define-key gnus-bookmark-bmenu-mode-map "u" 'gnus-bookmark-bmenu-unmark)
-  (define-key gnus-bookmark-bmenu-mode-map "m" 'gnus-bookmark-bmenu-mark)
-  (define-key gnus-bookmark-bmenu-mode-map "l" 'gnus-bookmark-bmenu-load)
-  (define-key gnus-bookmark-bmenu-mode-map "s" 'gnus-bookmark-bmenu-save)
-  (define-key gnus-bookmark-bmenu-mode-map "t" 
'gnus-bookmark-bmenu-toggle-infos)
-  (define-key gnus-bookmark-bmenu-mode-map "a" 
'gnus-bookmark-bmenu-show-details)
-  (define-key gnus-bookmark-bmenu-mode-map [mouse-2]
-    'gnus-bookmark-bmenu-select-by-mouse))
+
+(defvar-keymap gnus-bookmark-bmenu-mode-map
+  :full t
+  :suppress 'nodigits
+  "q" #'quit-window
+  "\C-m" #'gnus-bookmark-bmenu-select
+  "v" #'gnus-bookmark-bmenu-select
+  "d" #'gnus-bookmark-bmenu-delete
+  "k" #'gnus-bookmark-bmenu-delete
+  "\C-d" #'gnus-bookmark-bmenu-delete-backwards
+  "x" #'gnus-bookmark-bmenu-execute-deletions
+  " " #'next-line
+  "n" #'next-line
+  "p" #'previous-line
+  "\177" #'gnus-bookmark-bmenu-backup-unmark
+  "?" #'describe-mode
+  "u" #'gnus-bookmark-bmenu-unmark
+  "m" #'gnus-bookmark-bmenu-mark
+  "l" #'gnus-bookmark-bmenu-load
+  "s" #'gnus-bookmark-bmenu-save
+  "t" #'gnus-bookmark-bmenu-toggle-infos
+  "a" #'gnus-bookmark-bmenu-show-details
+  [mouse-2] #'gnus-bookmark-bmenu-select-by-mouse)
 
 ;; Bookmark Buffer Menu mode is suitable only for specially formatted
 ;; data.
diff --git a/lisp/gnus/gnus-cite.el b/lisp/gnus/gnus-cite.el
index 34947cece8..e9c912109e 100644
--- a/lisp/gnus/gnus-cite.el
+++ b/lisp/gnus/gnus-cite.el
@@ -839,7 +839,7 @@ See also the documentation for 
`gnus-article-highlight-citation'."
                 (setq current (car loop)
                       loop (cdr loop))
                 (setcdr current
-                         (seq-difference (cdr current) numbers #'eq)))))))))
+                        (gnus-set-difference (cdr current) numbers)))))))))
 
 (defun gnus-cite-parse-attributions ()
   (let (al-alist)
@@ -999,7 +999,7 @@ See also the documentation for 
`gnus-article-highlight-citation'."
                    loop (cdr loop))
              (if (eq current best)
                  ()
-                (setcdr current (seq-difference (cdr current) numbers #'eq))
+               (setcdr current (gnus-set-difference (cdr current) numbers))
                (when (null (cdr current))
                  (setq gnus-cite-loose-prefix-alist
                        (delq current gnus-cite-loose-prefix-alist)
diff --git a/lisp/gnus/gnus-dired.el b/lisp/gnus/gnus-dired.el
index e9eddae942..be46d3a341 100644
--- a/lisp/gnus/gnus-dired.el
+++ b/lisp/gnus/gnus-dired.el
@@ -53,12 +53,10 @@
 (autoload 'message-buffers "message")
 (autoload 'gnus-print-buffer "gnus-sum")
 
-(defvar gnus-dired-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\C-c\C-m\C-a" 'gnus-dired-attach)
-    (define-key map "\C-c\C-m\C-l" 'gnus-dired-find-file-mailcap)
-    (define-key map "\C-c\C-m\C-p" 'gnus-dired-print)
-    map))
+(defvar-keymap gnus-dired-mode-map
+  "\C-c\C-m\C-a" #'gnus-dired-attach
+  "\C-c\C-m\C-l" #'gnus-dired-find-file-mailcap
+  "\C-c\C-m\C-p" #'gnus-dired-print)
 
 ;; FIXME: Make it customizable, change the default to `mail-user-agent' when
 ;; this file is renamed (e.g. to `dired-mime.el').
diff --git a/lisp/gnus/gnus-draft.el b/lisp/gnus/gnus-draft.el
index 9a0f21359f..756e6d2d36 100644
--- a/lisp/gnus/gnus-draft.el
+++ b/lisp/gnus/gnus-draft.el
@@ -33,15 +33,12 @@
 
 ;;; Draft minor mode
 
-(defvar gnus-draft-mode-map
-  (let ((map (make-sparse-keymap)))
-    (gnus-define-keys map
-     "Dt" gnus-draft-toggle-sending
-     "e"  gnus-draft-edit-message ;; Use `B w' for `gnus-summary-edit-article'
-     "De" gnus-draft-edit-message
-     "Ds" gnus-draft-send-message
-     "DS" gnus-draft-send-all-messages)
-    map))
+(defvar-keymap gnus-draft-mode-map
+  "Dt" #'gnus-draft-toggle-sending
+  "e" #' gnus-draft-edit-message ;; Use `B w' for `gnus-summary-edit-article'
+  "De" #'gnus-draft-edit-message
+  "Ds" #'gnus-draft-send-message
+  "DS" #'gnus-draft-send-all-messages)
 
 (defun gnus-draft-make-menu-bar ()
   (unless (boundp 'gnus-draft-menu)
diff --git a/lisp/gnus/gnus-eform.el b/lisp/gnus/gnus-eform.el
index 3fd8bf51de..b0aa58f0f2 100644
--- a/lisp/gnus/gnus-eform.el
+++ b/lisp/gnus/gnus-eform.el
@@ -48,13 +48,10 @@
 (defvar gnus-edit-form-buffer "*Gnus edit form*")
 (defvar gnus-edit-form-done-function nil)
 
-(defvar gnus-edit-form-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map emacs-lisp-mode-map)
-    (gnus-define-keys map
-      "\C-c\C-c" gnus-edit-form-done
-      "\C-c\C-k" gnus-edit-form-exit)
-    map))
+(defvar-keymap gnus-edit-form-mode-map
+  :parent emacs-lisp-mode-map
+  "\C-c\C-c" #'gnus-edit-form-done
+  "\C-c\C-k" #'gnus-edit-form-exit)
 
 (defun gnus-edit-form-make-menu-bar ()
   (unless (boundp 'gnus-edit-form-menu)
diff --git a/lisp/gnus/gnus-fun.el b/lisp/gnus/gnus-fun.el
index 8bca4ffe38..0754d7aa7b 100644
--- a/lisp/gnus/gnus-fun.el
+++ b/lisp/gnus/gnus-fun.el
@@ -97,13 +97,14 @@ PNG format."
 
 ;;;###autoload
 (defun gnus--random-face-with-type (dir ext omit fun)
-  "Return file from DIR with extension EXT, omitting matches of OMIT, 
processed by FUN."
+  "Return file from DIR with extension EXT.
+Omit matches of OMIT, and process them by FUN."
   (when (file-exists-p dir)
     (let* ((files
             (remove nil (mapcar
                          (lambda (f) (unless (string-match (or omit "^$") f) 
f))
                          (directory-files dir t ext))))
-           (file (nth (random (length files)) files)))
+           (file (and files (seq-random-elt files))))
       (when file
         (funcall fun file)))))
 
@@ -315,7 +316,7 @@ colors of the displayed X-Faces."
   (let* ((possibilities '("%02x0000" "00%02x00" "0000%02x"
                          "%02x%02x00" "00%02x%02x" "%02x00%02x"))
         (format (concat "'#%02x%02x%02x' '#"
-                        (nth (random 6) possibilities)
+                         (seq-random-elt possibilities)
                         "'"))
         (values nil))
   (dotimes (i 255)
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 83c953515e..ddc819877c 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -573,209 +573,209 @@ simple manner."
 ;;; Gnus group mode
 ;;;
 
-(gnus-define-keys gnus-group-mode-map
-  " " gnus-group-read-group
-  "=" gnus-group-select-group
-  "\r" gnus-group-select-group
-  "\M-\r" gnus-group-quick-select-group
-  "\M- " gnus-group-visible-select-group
-  [(meta control return)] gnus-group-select-group-ephemerally
-  "j" gnus-group-jump-to-group
-  "n" gnus-group-next-unread-group
-  "p" gnus-group-prev-unread-group
-  "\177" gnus-group-prev-unread-group
-  [delete] gnus-group-prev-unread-group
-  "N" gnus-group-next-group
-  "P" gnus-group-prev-group
-  "\M-n" gnus-group-next-unread-group-same-level
-  "\M-p" gnus-group-prev-unread-group-same-level
-  "," gnus-group-best-unread-group
-  "." gnus-group-first-unread-group
-  "u" gnus-group-toggle-subscription-at-point
-  "U" gnus-group-toggle-subscription
-  "c" gnus-group-catchup-current
-  "C" gnus-group-catchup-current-all
-  "\M-c" gnus-group-clear-data
-  "l" gnus-group-list-groups
-  "L" gnus-group-list-all-groups
-  "m" gnus-group-mail
-  "i" gnus-group-news
-  "g" gnus-group-get-new-news
-  "\M-g" gnus-group-get-new-news-this-group
-  "R" gnus-group-restart
-  "r" gnus-group-read-init-file
-  "B" gnus-group-browse-foreign-server
-  "b" gnus-group-check-bogus-groups
-  "F" gnus-group-find-new-groups
-  "\C-c\C-d" gnus-group-describe-group
-  "\M-d" gnus-group-describe-all-groups
-  "\C-c\C-a" gnus-group-apropos
-  "\C-c\M-\C-a" gnus-group-description-apropos
-  "a" gnus-group-post-news
-  "\ek" gnus-group-edit-local-kill
-  "\eK" gnus-group-edit-global-kill
-  "\C-k" gnus-group-kill-group
-  "\C-y" gnus-group-yank-group
-  "\C-w" gnus-group-kill-region
-  "\C-x\C-t" gnus-group-transpose-groups
-  "\C-c\C-l" gnus-group-list-killed
-  "\C-c\C-x" gnus-group-expire-articles
-  "\C-c\M-\C-x" gnus-group-expire-all-groups
-  "V" gnus-version
-  "s" gnus-group-save-newsrc
-  "z" gnus-group-suspend
-  "q" gnus-group-exit
-  "Q" gnus-group-quit
-  "?" gnus-group-describe-briefly
-  "\C-c\C-i" gnus-info-find-node
-  "\M-e" gnus-group-edit-group-method
-  "^" gnus-group-enter-server-mode
-  [mouse-2] gnus-mouse-pick-group
-  [follow-link] mouse-face
-  "<" beginning-of-buffer
-  ">" end-of-buffer
-  "\C-c\C-b" gnus-bug
-  "\C-c\C-s" gnus-group-sort-groups
-  "t" gnus-topic-mode
-  "\C-c\M-g" gnus-activate-all-groups
-  "\M-&" gnus-group-universal-argument
-  "#" gnus-group-mark-group
-  "\M-#" gnus-group-unmark-group)
-
-(gnus-define-keys (gnus-group-cloud-map "~" gnus-group-mode-map)
-  "u" gnus-cloud-upload-all-data
-  "~" gnus-cloud-upload-all-data
-  "d" gnus-cloud-download-all-data
-  "\r" gnus-cloud-download-all-data)
-
-(gnus-define-keys (gnus-group-mark-map "M" gnus-group-mode-map)
-  "m" gnus-group-mark-group
-  "u" gnus-group-unmark-group
-  "w" gnus-group-mark-region
-  "b" gnus-group-mark-buffer
-  "r" gnus-group-mark-regexp
-  "U" gnus-group-unmark-all-groups)
-
-(gnus-define-keys (gnus-group-sieve-map "D" gnus-group-mode-map)
-  "u" gnus-sieve-update
-  "g" gnus-sieve-generate)
-
-(gnus-define-keys (gnus-group-group-map "G" gnus-group-mode-map)
-  "d" gnus-group-make-directory-group
-  "h" gnus-group-make-help-group
-  "u" gnus-group-make-useful-group
-  "l" gnus-group-nnimap-edit-acl
-  "m" gnus-group-make-group
-  "E" gnus-group-edit-group
-  "e" gnus-group-edit-group-method
-  "p" gnus-group-edit-group-parameters
-  "v" gnus-group-add-to-virtual
-  "V" gnus-group-make-empty-virtual
-  "D" gnus-group-enter-directory
-  "f" gnus-group-make-doc-group
-  "w" gnus-group-make-web-group
-  "G" gnus-group-read-ephemeral-search-group
-  "g" gnus-group-make-search-group
-  "M" gnus-group-read-ephemeral-group
-  "r" gnus-group-rename-group
-  "R" gnus-group-make-rss-group
-  "c" gnus-group-customize
-  "z" gnus-group-compact-group
-  "x" gnus-group-expunge-group
-  "\177" gnus-group-delete-group
-  [delete] gnus-group-delete-group)
-
-(gnus-define-keys (gnus-group-sort-map "S" gnus-group-group-map)
-  "s" gnus-group-sort-groups
-  "a" gnus-group-sort-groups-by-alphabet
-  "u" gnus-group-sort-groups-by-unread
-  "l" gnus-group-sort-groups-by-level
-  "v" gnus-group-sort-groups-by-score
-  "r" gnus-group-sort-groups-by-rank
-  "m" gnus-group-sort-groups-by-method
-  "n" gnus-group-sort-groups-by-real-name)
-
-(gnus-define-keys (gnus-group-sort-selected-map "P" gnus-group-group-map)
-  "s" gnus-group-sort-selected-groups
-  "a" gnus-group-sort-selected-groups-by-alphabet
-  "u" gnus-group-sort-selected-groups-by-unread
-  "l" gnus-group-sort-selected-groups-by-level
-  "v" gnus-group-sort-selected-groups-by-score
-  "r" gnus-group-sort-selected-groups-by-rank
-  "m" gnus-group-sort-selected-groups-by-method
-  "n" gnus-group-sort-selected-groups-by-real-name)
-
-(gnus-define-keys (gnus-group-list-map "A" gnus-group-mode-map)
-  "k" gnus-group-list-killed
-  "z" gnus-group-list-zombies
-  "s" gnus-group-list-groups
-  "u" gnus-group-list-all-groups
-  "A" gnus-group-list-active
-  "a" gnus-group-apropos
-  "d" gnus-group-description-apropos
-  "m" gnus-group-list-matching
-  "M" gnus-group-list-all-matching
-  "l" gnus-group-list-level
-  "c" gnus-group-list-cached
-  "?" gnus-group-list-dormant
-  "!" gnus-group-list-ticked)
-
-(gnus-define-keys (gnus-group-list-limit-map "/" gnus-group-list-map)
-  "k"  gnus-group-list-limit
-  "z"  gnus-group-list-limit
-  "s"  gnus-group-list-limit
-  "u"  gnus-group-list-limit
-  "A"  gnus-group-list-limit
-  "m"  gnus-group-list-limit
-  "M"  gnus-group-list-limit
-  "l"  gnus-group-list-limit
-  "c"  gnus-group-list-limit
-  "?"  gnus-group-list-limit
-  "!"  gnus-group-list-limit)
-
-(gnus-define-keys (gnus-group-list-flush-map "f" gnus-group-list-map)
-  "k"  gnus-group-list-flush
-  "z"  gnus-group-list-flush
-  "s"  gnus-group-list-flush
-  "u"  gnus-group-list-flush
-  "A"  gnus-group-list-flush
-  "m"  gnus-group-list-flush
-  "M"  gnus-group-list-flush
-  "l"  gnus-group-list-flush
-  "c"  gnus-group-list-flush
-  "?"  gnus-group-list-flush
-  "!"  gnus-group-list-flush)
-
-(gnus-define-keys (gnus-group-list-plus-map "p" gnus-group-list-map)
-  "k"  gnus-group-list-plus
-  "z"  gnus-group-list-plus
-  "s"  gnus-group-list-plus
-  "u"  gnus-group-list-plus
-  "A"  gnus-group-list-plus
-  "m"  gnus-group-list-plus
-  "M"  gnus-group-list-plus
-  "l"  gnus-group-list-plus
-  "c"  gnus-group-list-plus
-  "?"  gnus-group-list-plus
-  "!"  gnus-group-list-plus)
-
-(gnus-define-keys (gnus-group-score-map "W" gnus-group-mode-map)
-  "f" gnus-score-flush-cache
-  "e" gnus-score-edit-all-score)
-
-(gnus-define-keys (gnus-group-help-map "H" gnus-group-mode-map)
-  "d" gnus-group-describe-group
-  "v" gnus-version)
-
-(gnus-define-keys (gnus-group-sub-map "S" gnus-group-mode-map)
-  "l" gnus-group-set-current-level
-  "t" gnus-group-toggle-subscription-at-point
-  "s" gnus-group-toggle-subscription
-  "k" gnus-group-kill-group
-  "y" gnus-group-yank-group
-  "w" gnus-group-kill-region
-  "\C-k" gnus-group-kill-level
-  "z" gnus-group-kill-all-zombies)
+(define-keymap :keymap gnus-group-mode-map
+  " " #'gnus-group-read-group
+  "=" #'gnus-group-select-group
+  "\r" #'gnus-group-select-group
+  "\M-\r" #'gnus-group-quick-select-group
+  "\M- " #'gnus-group-visible-select-group
+  [(meta control return)] #'gnus-group-select-group-ephemerally
+  "j" #'gnus-group-jump-to-group
+  "n" #'gnus-group-next-unread-group
+  "p" #'gnus-group-prev-unread-group
+  "\177" #'gnus-group-prev-unread-group
+  [delete] #'gnus-group-prev-unread-group
+  "N" #'gnus-group-next-group
+  "P" #'gnus-group-prev-group
+  "\M-n" #'gnus-group-next-unread-group-same-level
+  "\M-p" #'gnus-group-prev-unread-group-same-level
+  "," #'gnus-group-best-unread-group
+  "." #'gnus-group-first-unread-group
+  "u" #'gnus-group-toggle-subscription-at-point
+  "U" #'gnus-group-toggle-subscription
+  "c" #'gnus-group-catchup-current
+  "C" #'gnus-group-catchup-current-all
+  "\M-c" #'gnus-group-clear-data
+  "l" #'gnus-group-list-groups
+  "L" #'gnus-group-list-all-groups
+  "m" #'gnus-group-mail
+  "i" #'gnus-group-news
+  "g" #'gnus-group-get-new-news
+  "\M-g" #'gnus-group-get-new-news-this-group
+  "R" #'gnus-group-restart
+  "r" #'gnus-group-read-init-file
+  "B" #'gnus-group-browse-foreign-server
+  "b" #'gnus-group-check-bogus-groups
+  "F" #'gnus-group-find-new-groups
+  "\C-c\C-d" #'gnus-group-describe-group
+  "\M-d" #'gnus-group-describe-all-groups
+  "\C-c\C-a" #'gnus-group-apropos
+  "\C-c\M-\C-a" #'gnus-group-description-apropos
+  "a" #'gnus-group-post-news
+  "\ek" #'gnus-group-edit-local-kill
+  "\eK" #'gnus-group-edit-global-kill
+  "\C-k" #'gnus-group-kill-group
+  "\C-y" #'gnus-group-yank-group
+  "\C-w" #'gnus-group-kill-region
+  "\C-x\C-t" #'gnus-group-transpose-groups
+  "\C-c\C-l" #'gnus-group-list-killed
+  "\C-c\C-x" #'gnus-group-expire-articles
+  "\C-c\M-\C-x" #'gnus-group-expire-all-groups
+  "V" #'gnus-version
+  "s" #'gnus-group-save-newsrc
+  "z" #'gnus-group-suspend
+  "q" #'gnus-group-exit
+  "Q" #'gnus-group-quit
+  "?" #'gnus-group-describe-briefly
+  "\C-c\C-i" #'gnus-info-find-node
+  "\M-e" #'gnus-group-edit-group-method
+  "^" #'gnus-group-enter-server-mode
+  [mouse-2] #'gnus-mouse-pick-group
+  [follow-link] 'mouse-face
+  "<" #'beginning-of-buffer
+  ">" #'end-of-buffer
+  "\C-c\C-b" #'gnus-bug
+  "\C-c\C-s" #'gnus-group-sort-groups
+  "t" #'gnus-topic-mode
+  "\C-c\M-g" #'gnus-activate-all-groups
+  "\M-&" #'gnus-group-universal-argument
+  "#" #'gnus-group-mark-group
+  "\M-#" #'gnus-group-unmark-group
+
+  "~" (define-keymap :prefix 'gnus-group-cloud-map
+        "u" #'gnus-cloud-upload-all-data
+        "~" #'gnus-cloud-upload-all-data
+        "d" #'gnus-cloud-download-all-data
+        "\r" #'gnus-cloud-download-all-data)
+
+  "M" (define-keymap :prefix 'gnus-group-mark-map
+        "m" #'gnus-group-mark-group
+        "u" #'gnus-group-unmark-group
+        "w" #'gnus-group-mark-region
+        "b" #'gnus-group-mark-buffer
+        "r" #'gnus-group-mark-regexp
+        "U" #'gnus-group-unmark-all-groups)
+
+  "D" (define-keymap :prefix 'gnus-group-sieve-map
+        "u" #'gnus-sieve-update
+        "g" #'gnus-sieve-generate)
+
+  "G" (define-keymap :prefix 'gnus-group-group-map
+        "d" #'gnus-group-make-directory-group
+        "h" #'gnus-group-make-help-group
+        "u" #'gnus-group-make-useful-group
+        "l" #'gnus-group-nnimap-edit-acl
+        "m" #'gnus-group-make-group
+        "E" #'gnus-group-edit-group
+        "e" #'gnus-group-edit-group-method
+        "p" #'gnus-group-edit-group-parameters
+        "v" #'gnus-group-add-to-virtual
+        "V" #'gnus-group-make-empty-virtual
+        "D" #'gnus-group-enter-directory
+        "f" #'gnus-group-make-doc-group
+        "w" #'gnus-group-make-web-group
+        "G" #'gnus-group-read-ephemeral-search-group
+        "g" #'gnus-group-make-search-group
+        "M" #'gnus-group-read-ephemeral-group
+        "r" #'gnus-group-rename-group
+        "R" #'gnus-group-make-rss-group
+        "c" #'gnus-group-customize
+        "z" #'gnus-group-compact-group
+        "x" #'gnus-group-expunge-group
+        "\177" #'gnus-group-delete-group
+        [delete] #'gnus-group-delete-group
+
+        "S" (define-keymap :prefix 'gnus-group-sort-map
+              "s" #'gnus-group-sort-groups
+              "a" #'gnus-group-sort-groups-by-alphabet
+              "u" #'gnus-group-sort-groups-by-unread
+              "l" #'gnus-group-sort-groups-by-level
+              "v" #'gnus-group-sort-groups-by-score
+              "r" #'gnus-group-sort-groups-by-rank
+              "m" #'gnus-group-sort-groups-by-method
+              "n" #'gnus-group-sort-groups-by-real-name)
+
+        "P" (define-keymap :prefix 'gnus-group-sort-selected-map
+              "s" #'gnus-group-sort-selected-groups
+              "a" #'gnus-group-sort-selected-groups-by-alphabet
+              "u" #'gnus-group-sort-selected-groups-by-unread
+              "l" #'gnus-group-sort-selected-groups-by-level
+              "v" #'gnus-group-sort-selected-groups-by-score
+              "r" #'gnus-group-sort-selected-groups-by-rank
+              "m" #'gnus-group-sort-selected-groups-by-method
+              "n" #'gnus-group-sort-selected-groups-by-real-name))
+
+  "A" (define-keymap :prefix 'gnus-group-list-map
+        "k" #'gnus-group-list-killed
+        "z" #'gnus-group-list-zombies
+        "s" #'gnus-group-list-groups
+        "u" #'gnus-group-list-all-groups
+        "A" #'gnus-group-list-active
+        "a" #'gnus-group-apropos
+        "d" #'gnus-group-description-apropos
+        "m" #'gnus-group-list-matching
+        "M" #'gnus-group-list-all-matching
+        "l" #'gnus-group-list-level
+        "c" #'gnus-group-list-cached
+        "?" #'gnus-group-list-dormant
+        "!" #'gnus-group-list-ticked
+
+        "/" (define-keymap :prefix 'gnus-group-list-limit-map
+              "k" #'gnus-group-list-limit
+              "z" #'gnus-group-list-limit
+              "s" #'gnus-group-list-limit
+              "u" #'gnus-group-list-limit
+              "A" #'gnus-group-list-limit
+              "m" #'gnus-group-list-limit
+              "M" #'gnus-group-list-limit
+              "l" #'gnus-group-list-limit
+              "c" #'gnus-group-list-limit
+              "?" #'gnus-group-list-limit
+              "!" #'gnus-group-list-limit)
+
+        "f" (define-keymap :prefix 'gnus-group-list-flush-map
+              "k" #'gnus-group-list-flush
+              "z" #'gnus-group-list-flush
+              "s" #'gnus-group-list-flush
+              "u" #'gnus-group-list-flush
+              "A" #'gnus-group-list-flush
+              "m" #'gnus-group-list-flush
+              "M" #'gnus-group-list-flush
+              "l" #'gnus-group-list-flush
+              "c" #'gnus-group-list-flush
+              "?" #'gnus-group-list-flush
+              "!" #'gnus-group-list-flush)
+
+        "p" (define-keymap :prefix 'gnus-group-list-plus-map
+              "k" #'gnus-group-list-plus
+              "z" #'gnus-group-list-plus
+              "s" #'gnus-group-list-plus
+              "u" #'gnus-group-list-plus
+              "A" #'gnus-group-list-plus
+              "m" #'gnus-group-list-plus
+              "M" #'gnus-group-list-plus
+              "l" #'gnus-group-list-plus
+              "c" #'gnus-group-list-plus
+              "?" #'gnus-group-list-plus
+              "!" #'gnus-group-list-plus))
+
+  "W" (define-keymap :prefix 'gnus-group-score-map
+        "f" #'gnus-score-flush-cache
+        "e" #'gnus-score-edit-all-score)
+
+  "H" (define-keymap :prefix 'gnus-group-help-map
+        "d" #'gnus-group-describe-group
+        "v" #'gnus-version)
+
+  "S" (define-keymap :prefix 'gnus-group-sub-map
+        "l" #'gnus-group-set-current-level
+        "t" #'gnus-group-toggle-subscription-at-point
+        "s" #'gnus-group-toggle-subscription
+        "k" #'gnus-group-kill-group
+        "y" #'gnus-group-yank-group
+        "w" #'gnus-group-kill-region
+        "\C-k" #'gnus-group-kill-level
+        "z" #'gnus-group-kill-all-zombies))
 
 (defun gnus-topic-mode-p ()
   "Return non-nil in `gnus-topic-mode'."
@@ -4062,7 +4062,8 @@ of groups killed."
     (if (< (length out) 2) (car out) (nreverse out))))
 
 (defun gnus-group-yank-group (&optional arg)
-  "Yank the last newsgroups killed with \\[gnus-group-kill-group], inserting 
it before the current newsgroup.
+  "Yank the last newsgroups killed with \\[gnus-group-kill-group], inserting it
+before the current newsgroup.
 The numeric ARG specifies how many newsgroups are to be yanked.  The
 name of the newsgroup yanked is returned, or (if several groups are
 yanked) a list of yanked groups is returned."
@@ -4473,7 +4474,7 @@ The hook `gnus-suspend-gnus-hook' is called before 
actually suspending."
        (gnus-kill-buffer buf)))
     (setq gnus-backlog-articles nil)
     (gnus-kill-gnus-frames)
-    ;; Closing all the backends is useful (for instance) when when the
+    ;; Closing all the backends is useful (for instance) when the
     ;; IP addresses have changed and you need to reconnect.
     (dolist (elem gnus-opened-servers)
       (gnus-close-server (car elem)))
@@ -4716,7 +4717,8 @@ or `gnus-group-catchup-group-hook'."
   (gnus-group-get-parameter group 'timestamp t))
 
 (defun gnus-group-timestamp-delta (group)
-  "Return the offset in seconds from the timestamp for GROUP to the current 
time, as a floating point number."
+  "Return the offset in seconds from the timestamp for GROUP to the current 
time.
+Return value is a floating point number."
   ;; FIXME: This should return a Lisp integer, not a Lisp float,
   ;; since it is always an integer.
   (let* ((time (or (gnus-group-timestamp group) 0))
diff --git a/lisp/gnus/gnus-html.el b/lisp/gnus/gnus-html.el
index be62bfd81f..c1815d3486 100644
--- a/lisp/gnus/gnus-html.el
+++ b/lisp/gnus/gnus-html.el
@@ -71,21 +71,17 @@ fit these criteria."
   :group 'gnus-art
   :type 'float)
 
-(defvar gnus-html-image-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "u" 'gnus-article-copy-string)
-    (define-key map "i" 'gnus-html-insert-image)
-    (define-key map "v" 'gnus-html-browse-url)
-    map))
-
-(defvar gnus-html-displayed-image-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" 'gnus-html-show-alt-text)
-    (define-key map "i" 'gnus-html-browse-image)
-    (define-key map "\r" 'gnus-html-browse-url)
-    (define-key map "u" 'gnus-article-copy-string)
-    (define-key map [tab] 'button-forward)
-    map))
+(defvar-keymap gnus-html-image-map
+  "u" #'gnus-article-copy-string
+  "i" #'gnus-html-insert-image
+  "v" #'gnus-html-browse-url)
+
+(defvar-keymap gnus-html-displayed-image-map
+  "a" #'gnus-html-show-alt-text
+  "i" #'gnus-html-browse-image
+  "\r" #'gnus-html-browse-url
+  "u" #'gnus-article-copy-string
+  [tab] #'forward-button)
 
 (defun gnus-html-encode-url (url)
   "Encode URL."
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index b6e5e7f786..81e46d7a51 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -194,7 +194,11 @@
                           (caddr event))))
 
     (cl-labels
-       ((attendee-role (prop) (plist-get (cadr prop) 'ROLE))
+       ((attendee-role (prop)
+                        ;; RFC5546: default ROLE is REQ-PARTICIPANT
+                        (and prop
+                             (or (plist-get (cadr prop) 'ROLE)
+                                 "REQ-PARTICIPANT")))
         (attendee-name
          (prop)
          (or (plist-get (cadr prop) 'CN)
@@ -225,7 +229,10 @@
                      (gnus-icalendar-event--find-attendee
                       ical attendee-name-or-email)))
          (attendee-names (gnus-icalendar-event--get-attendee-names ical))
-         (role (plist-get (cadr attendee) 'ROLE))
+         ;; RFC5546: default ROLE is REQ-PARTICIPANT
+         (role (and attendee
+                    (or (plist-get (cadr attendee) 'ROLE)
+                        "REQ-PARTICIPANT")))
          (participation-type (pcase role
                                ("REQ-PARTICIPANT" 'required)
                                ("OPT-PARTICIPANT" 'optional)
@@ -345,10 +352,16 @@ status will be retrieved from the first matching attendee 
record."
 
       (mapc #'process-event-line (split-string ical-request "\n"))
 
+      ;; RFC5546 refers to uninvited attendees as "party crashers".
+      ;; This situation is common if the invitation is sent to a group
+      ;; of people via a mailing list.
       (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x))
                                      reply-event-lines)
         (lwarn 'gnus-icalendar :warning
-               "Could not find an event attendee matching given identity"))
+               "Could not find an event attendee matching given identity")
+        (push (format "ATTENDEE;RSVP=TRUE;PARTSTAT=%s;CN=%s:MAILTO:%s"
+                      attendee-status user-full-name user-mail-address)
+              reply-event-lines))
 
       (mapconcat #'identity `("BEGIN:VEVENT"
                               ,@(nreverse reply-event-lines)
@@ -847,10 +860,14 @@ These will be used to retrieve the RSVP information from 
ical events."
        button t
        gnus-data ,data))))
 
-(defun gnus-icalendar-send-buffer-by-mail (buffer-name subject)
+(defun gnus-icalendar-send-buffer-by-mail (buffer-name subject organizer)
   (let ((message-signature nil))
     (with-current-buffer gnus-summary-buffer
       (gnus-summary-reply)
+      ;; Reply to the organizer, not to whoever sent the invitation. person
+      ;; Some calendar systems use specific email address as organizer to
+      ;; receive these responses.
+      (message-replace-header "To" organizer)
       (message-goto-body)
       (mml-insert-multipart "alternative")
       (mml-insert-empty-tag 'part 'type "text/plain")
@@ -866,7 +883,8 @@ These will be used to retrieve the RSVP information from 
ical events."
          (event (caddr data))
          (reply (gnus-icalendar-with-decoded-handle handle
                   (gnus-icalendar-event-reply-from-buffer
-                   (current-buffer) status (gnus-icalendar-identities)))))
+                   (current-buffer) status (gnus-icalendar-identities))))
+         (organizer (gnus-icalendar-event:organizer event)))
 
     (when reply
       (cl-labels
@@ -883,7 +901,7 @@ These will be used to retrieve the RSVP information from 
ical events."
             (delete-region (point-min) (point-max))
             (insert reply)
             (fold-icalendar-buffer)
-            (gnus-icalendar-send-buffer-by-mail (buffer-name) subject))
+            (gnus-icalendar-send-buffer-by-mail (buffer-name) subject 
organizer))
 
           ;; Back in article buffer
           (setq-local gnus-icalendar-reply-status status)
@@ -897,10 +915,16 @@ These will be used to retrieve the RSVP information from 
ical events."
   (gnus-icalendar-event:sync-to-org event gnus-icalendar-reply-status))
 
 (cl-defmethod gnus-icalendar-event:inline-reply-buttons ((event 
gnus-icalendar-event) handle)
-  (when (gnus-icalendar-event:rsvp event)
-    `(("Accept" gnus-icalendar-reply (,handle accepted ,event))
-      ("Tentative" gnus-icalendar-reply (,handle tentative ,event))
-      ("Decline" gnus-icalendar-reply (,handle declined ,event)))))
+  (let ((accept-btn "Accept")
+        (tentative-btn "Tentative")
+        (decline-btn "Decline"))
+    (unless (gnus-icalendar-event:rsvp event)
+      (setq accept-btn "Uninvited Accept"
+            tentative-btn "Uninvited Tentative"
+            decline-btn "Uninvited Decline"))
+    `((,accept-btn gnus-icalendar-reply (,handle accepted ,event))
+      (,tentative-btn gnus-icalendar-reply (,handle tentative ,event))
+      (,decline-btn gnus-icalendar-reply (,handle declined ,event)))))
 
 (cl-defmethod gnus-icalendar-event:inline-reply-buttons ((_event 
gnus-icalendar-event-reply) _handle)
   "No buttons for REPLY events."
@@ -1038,13 +1062,14 @@ These will be used to retrieve the RSVP information 
from ical events."
   (add-to-list 'mm-automatic-display "text/calendar")
   (add-to-list 'mm-inline-media-tests '("text/calendar" 
gnus-icalendar-mm-inline identity))
 
-  (gnus-define-keys (gnus-summary-calendar-map "i" gnus-summary-mode-map)
-    "a" gnus-icalendar-reply-accept
-    "t" gnus-icalendar-reply-tentative
-    "d" gnus-icalendar-reply-decline
-    "c" gnus-icalendar-event-check-agenda
-    "e" gnus-icalendar-event-export
-    "s" gnus-icalendar-event-show)
+  (define-key gnus-summary-mode-map "i"
+    (define-keymap :prefix 'gnus-summary-calendar-map
+      "a" #'gnus-icalendar-reply-accept
+      "t" #'gnus-icalendar-reply-tentative
+      "d" #'gnus-icalendar-reply-decline
+      "c" #'gnus-icalendar-event-check-agenda
+      "e" #'gnus-icalendar-event-export
+      "s" #'gnus-icalendar-event-show))
 
   (require 'gnus-art)
   (add-to-list 'gnus-mime-action-alist
diff --git a/lisp/gnus/gnus-kill.el b/lisp/gnus/gnus-kill.el
index 525823e72c..7e589c54e9 100644
--- a/lisp/gnus/gnus-kill.el
+++ b/lisp/gnus/gnus-kill.el
@@ -66,18 +66,15 @@ of time."
 ;;; Gnus Kill File Mode
 ;;;
 
-(defvar gnus-kill-file-mode-map
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map emacs-lisp-mode-map)
-    (gnus-define-keymap map
-      "\C-c\C-k\C-s" gnus-kill-file-kill-by-subject
-      "\C-c\C-k\C-a" gnus-kill-file-kill-by-author
-      "\C-c\C-k\C-t" gnus-kill-file-kill-by-thread
-      "\C-c\C-k\C-x" gnus-kill-file-kill-by-xref
-      "\C-c\C-a" gnus-kill-file-apply-buffer
-      "\C-c\C-e" gnus-kill-file-apply-last-sexp
-      "\C-c\C-c" gnus-kill-file-exit)
-    map))
+(defvar-keymap gnus-kill-file-mode-map
+  :parent emacs-lisp-mode-map
+  "\C-c\C-k\C-s" #'gnus-kill-file-kill-by-subject
+  "\C-c\C-k\C-a" #'gnus-kill-file-kill-by-author
+  "\C-c\C-k\C-t" #'gnus-kill-file-kill-by-thread
+  "\C-c\C-k\C-x" #'gnus-kill-file-kill-by-xref
+  "\C-c\C-a" #'gnus-kill-file-apply-buffer
+  "\C-c\C-e" #'gnus-kill-file-apply-last-sexp
+  "\C-c\C-c" #'gnus-kill-file-exit)
 
 (define-derived-mode gnus-kill-file-mode emacs-lisp-mode "Kill"
   "Major mode for editing kill files.
diff --git a/lisp/gnus/gnus-ml.el b/lisp/gnus/gnus-ml.el
index ee3abf2f7b..bf33194cf7 100644
--- a/lisp/gnus/gnus-ml.el
+++ b/lisp/gnus/gnus-ml.el
@@ -31,16 +31,13 @@
 
 ;;; Mailing list minor mode
 
-(defvar gnus-mailing-list-mode-map
-  (let ((map (make-sparse-keymap)))
-    (gnus-define-keys map
-      "\C-c\C-nh" gnus-mailing-list-help
-      "\C-c\C-ns" gnus-mailing-list-subscribe
-      "\C-c\C-nu" gnus-mailing-list-unsubscribe
-      "\C-c\C-np" gnus-mailing-list-post
-      "\C-c\C-no" gnus-mailing-list-owner
-      "\C-c\C-na" gnus-mailing-list-archive)
-    map))
+(defvar-keymap gnus-mailing-list-mode-map
+  "\C-c\C-nh" #'gnus-mailing-list-help
+  "\C-c\C-ns" #'gnus-mailing-list-subscribe
+  "\C-c\C-nu" #'gnus-mailing-list-unsubscribe
+  "\C-c\C-np" #'gnus-mailing-list-post
+  "\C-c\C-no" #'gnus-mailing-list-owner
+  "\C-c\C-na" #'gnus-mailing-list-archive)
 
 (defvar gnus-mailing-list-menu)
 
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index 8a3272042f..e88aa8f7d0 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -349,39 +349,39 @@ only affect the Gcc copy, but not the original message."
 ;;; Gnus Posting Functions
 ;;;
 
-(gnus-define-keys (gnus-summary-send-map "S" gnus-summary-mode-map)
-  "p" gnus-summary-post-news
-  "i" gnus-summary-news-other-window
-  "f" gnus-summary-followup
-  "F" gnus-summary-followup-with-original
-  "c" gnus-summary-cancel-article
-  "s" gnus-summary-supersede-article
-  "r" gnus-summary-reply
-  "y" gnus-summary-yank-message
-  "R" gnus-summary-reply-with-original
-  "L" gnus-summary-reply-to-list-with-original
-  "w" gnus-summary-wide-reply
-  "W" gnus-summary-wide-reply-with-original
-  "v" gnus-summary-very-wide-reply
-  "V" gnus-summary-very-wide-reply-with-original
-  "n" gnus-summary-followup-to-mail
-  "N" gnus-summary-followup-to-mail-with-original
-  "m" gnus-summary-mail-other-window
-  "u" gnus-uu-post-news
-  "A" gnus-summary-attach-article
-  "\M-c" gnus-summary-mail-crosspost-complaint
-  "Br" gnus-summary-reply-broken-reply-to
-  "BR" gnus-summary-reply-broken-reply-to-with-original
-  "om" gnus-summary-mail-forward
-  "op" gnus-summary-post-forward
-  "Om" gnus-uu-digest-mail-forward
-  "Op" gnus-uu-digest-post-forward)
-
-(gnus-define-keys (gnus-send-bounce-map "D" gnus-summary-send-map)
-  "b" gnus-summary-resend-bounced-mail
-  ;; "c" gnus-summary-send-draft
-  "r" gnus-summary-resend-message
-  "e" gnus-summary-resend-message-edit)
+(define-keymap :prefix 'gnus-summary-send-map
+  "p" #'gnus-summary-post-news
+  "i" #'gnus-summary-news-other-window
+  "f" #'gnus-summary-followup
+  "F" #'gnus-summary-followup-with-original
+  "c" #'gnus-summary-cancel-article
+  "s" #'gnus-summary-supersede-article
+  "r" #'gnus-summary-reply
+  "y" #'gnus-summary-yank-message
+  "R" #'gnus-summary-reply-with-original
+  "L" #'gnus-summary-reply-to-list-with-original
+  "w" #'gnus-summary-wide-reply
+  "W" #'gnus-summary-wide-reply-with-original
+  "v" #'gnus-summary-very-wide-reply
+  "V" #'gnus-summary-very-wide-reply-with-original
+  "n" #'gnus-summary-followup-to-mail
+  "N" #'gnus-summary-followup-to-mail-with-original
+  "m" #'gnus-summary-mail-other-window
+  "u" #'gnus-uu-post-news
+  "A" #'gnus-summary-attach-article
+  "\M-c" #'gnus-summary-mail-crosspost-complaint
+  "Br" #'gnus-summary-reply-broken-reply-to
+  "BR" #'gnus-summary-reply-broken-reply-to-with-original
+  "om" #'gnus-summary-mail-forward
+  "op" #'gnus-summary-post-forward
+  "Om" #'gnus-uu-digest-mail-forward
+  "Op" #'gnus-uu-digest-post-forward
+
+  "D" (define-keymap :prefix 'gnus-send-bounce-map
+        "b" #'gnus-summary-resend-bounced-mail
+        ;; "c" gnus-summary-send-draft
+        "r" #'gnus-summary-resend-message
+        "e" #'gnus-summary-resend-message-edit))
 
 ;;; Internal functions.
 
diff --git a/lisp/gnus/gnus-range.el b/lisp/gnus/gnus-range.el
index 7d12ae9fdc..a8f09b6371 100644
--- a/lisp/gnus/gnus-range.el
+++ b/lisp/gnus/gnus-range.el
@@ -40,10 +40,17 @@ If RANGE is a single range, return (RANGE).  Otherwise, 
return RANGE."
 
 (define-obsolete-function-alias 'gnus-copy-sequence 'copy-tree "27.1")
 
+;;; We could be using `seq-difference' here, but it's much slower
+;;; on these data sets.  See bug#50877.
 (defun gnus-set-difference (list1 list2)
   "Return a list of elements of LIST1 that do not appear in LIST2."
-  (declare (obsolete seq-difference "28.1"))
-  (seq-difference list1 list2 #'eq))
+  (let ((hash2 (make-hash-table :test 'eq))
+        (result nil))
+    (dolist (elt list2) (puthash elt t hash2))
+    (dolist (elt list1)
+      (unless (gethash elt hash2)
+        (setq result (cons elt result))))
+    (nreverse result)))
 
 (defun gnus-range-nconcat (&rest ranges)
   "Return a range comprising all the RANGES, which are pre-sorted.
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 9b76f98322..8ce88dc81e 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -990,9 +990,9 @@ Uses `gnus-registry-marks' to find what shortcuts to 
install."
                    gnus-registry-misc-menus)
              (gnus-message 9 "Defined mark handling function %s"
                            function-name))))))
-    (gnus-define-keys-1
-     '(gnus-registry-mark-map "M" gnus-summary-mark-map)
-     keys-plist)
+    (define-key gnus-summary-mark-map "M"
+      (apply #'define-keymap :prefix 'gnus-summary-mark-map
+             keys-plist))
     (add-hook 'gnus-summary-menu-hook
               (lambda ()
                 (easy-menu-add-item
@@ -1142,7 +1142,7 @@ non-nil."
            entry)
       (while (car-safe old)
         (cl-incf count)
-        ;; don't use progress reporters for backwards compatibility
+        ;; todo: use progress reporters.
         (when (and (< 0 expected)
                    (= 0 (mod count 100)))
           (message "importing: %d of %d (%.2f%%)"
diff --git a/lisp/gnus/gnus-salt.el b/lisp/gnus/gnus-salt.el
index dc81dfc5f6..8ffe4a4c57 100644
--- a/lisp/gnus/gnus-salt.el
+++ b/lisp/gnus/gnus-salt.el
@@ -64,15 +64,12 @@ It accepts the same format specs that 
`gnus-summary-line-format' does."
 
 ;;; Internal variables.
 
-(defvar gnus-pick-mode-map
-  (let ((map (make-sparse-keymap)))
-    (gnus-define-keys map
-      " " gnus-pick-next-page
-      "u" gnus-pick-unmark-article-or-thread
-      "." gnus-pick-article-or-thread
-      [down-mouse-2] gnus-pick-mouse-pick-region
-      "\r" gnus-pick-start-reading)
-    map))
+(defvar-keymap gnus-pick-mode-map
+  " " #'gnus-pick-next-page
+  "u" #'gnus-pick-unmark-article-or-thread
+  "." #'gnus-pick-article-or-thread
+  [down-mouse-2] #'gnus-pick-mouse-pick-region
+  "\r" #'gnus-pick-start-reading)
 
 (defun gnus-pick-make-menu-bar ()
   (unless (boundp 'gnus-pick-menu)
@@ -315,11 +312,8 @@ This must be bound to a button-down mouse event."
 (defvar gnus-binary-mode-hook nil
   "Hook run in summary binary mode buffers.")
 
-(defvar gnus-binary-mode-map
-  (let ((map (make-sparse-keymap)))
-    (gnus-define-keys map
-      "g" gnus-binary-show-article)
-    map))
+(defvar-keymap gnus-binary-mode-map
+  "g" #'gnus-binary-show-article)
 
 (defun gnus-binary-make-menu-bar ()
   (unless (boundp 'gnus-binary-menu)
@@ -424,21 +418,17 @@ Two predefined functions are available:
 (defvar gnus-tree-displayed-thread nil)
 (defvar gnus-tree-inhibit nil)
 
-(defvar gnus-tree-mode-map
-  (let ((map (make-keymap)))
-    (suppress-keymap map)
-    (gnus-define-keys
-        map
-      "\r" gnus-tree-select-article
-      [mouse-2] gnus-tree-pick-article
-      "\C-?" gnus-tree-read-summary-keys
-      "h" gnus-tree-show-summary
-
-      "\C-c\C-i" gnus-info-find-node)
-
-    (substitute-key-definition
-     'undefined 'gnus-tree-read-summary-keys map)
-    map))
+(defvar-keymap gnus-tree-mode-map
+  :full t :suppress t
+  "\r" #'gnus-tree-select-article
+  [mouse-2] #'gnus-tree-pick-article
+  "\C-?" #'gnus-tree-read-summary-keys
+  "h" #'gnus-tree-show-summary
+
+  "\C-c\C-i" #'gnus-info-find-node)
+
+(substitute-key-definition 'undefined #'gnus-tree-read-summary-keys
+                           gnus-tree-mode-map)
 
 (defun gnus-tree-make-menu-bar ()
   (unless (boundp 'gnus-tree-menu)
diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el
index 0626e8bde5..2ca2580295 100644
--- a/lisp/gnus/gnus-score.el
+++ b/lisp/gnus/gnus-score.el
@@ -502,19 +502,20 @@ of the last successful match.")
 
 ;;; Summary mode score maps.
 
-(gnus-define-keys (gnus-summary-score-map "V" gnus-summary-mode-map)
-  "s" gnus-summary-set-score
-  "S" gnus-summary-current-score
-  "c" gnus-score-change-score-file
-  "C" gnus-score-customize
-  "m" gnus-score-set-mark-below
-  "x" gnus-score-set-expunge-below
-  "R" gnus-summary-rescore
-  "e" gnus-score-edit-current-scores
-  "f" gnus-score-edit-file
-  "F" gnus-score-flush-cache
-  "t" gnus-score-find-trace
-  "w" gnus-score-find-favorite-words)
+(define-key gnus-summary-mode-map "V"
+  (define-keymap :prefix 'gnus-summary-score-map
+    "s" #'gnus-summary-set-score
+    "S" #'gnus-summary-current-score
+    "c" #'gnus-score-change-score-file
+    "C" #'gnus-score-customize
+    "m" #'gnus-score-set-mark-below
+    "x" #'gnus-score-set-expunge-below
+    "R" #'gnus-summary-rescore
+    "e" #'gnus-score-edit-current-scores
+    "f" #'gnus-score-edit-file
+    "F" #'gnus-score-flush-cache
+    "t" #'gnus-score-find-trace
+    "w" #'gnus-score-find-favorite-words))
 
 ;; Summary score file commands
 
@@ -3115,7 +3116,9 @@ If ADAPT, return the home adaptive file instead."
 ;;;
 
 (defun gnus-decay-score (score)
-  "Decay SCORE according to `gnus-score-decay-constant' and 
`gnus-score-decay-scale'."
+  "Decay SCORE according to decay variables.
+The decay variables are `gnus-score-decay-constant' and
+`gnus-score-decay-scale'."
   (floor (- score
            (* (if (< score 0) -1 1)
               (min (abs score)
diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el
index 9c83d5fa37..3157358804 100644
--- a/lisp/gnus/gnus-search.el
+++ b/lisp/gnus/gnus-search.el
@@ -1084,7 +1084,8 @@ Responsible for handling and, or, and parenthetical 
expressions.")
 Currently takes into account support for the LITERAL+ capability.
 Other capabilities could be tested here."
   (with-slots (literal-plus) engine
-    (when literal-plus
+    (when (and literal-plus
+               (string-match-p "\n" query))
       (setq query (split-string query "\n")))
     (cond
      ((consp query)
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index 115efa9805..f2ffb067b8 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -103,7 +103,43 @@ If nil, a faster, but more primitive, buffer is used 
instead."
 (defvar gnus-server-mode-line-format-spec nil)
 (defvar gnus-server-killed-servers nil)
 
-(defvar gnus-server-mode-map nil)
+(defvar-keymap gnus-server-mode-map
+  :full t :suppress t
+  " " #'gnus-server-read-server-in-server-buffer
+  "\r" #'gnus-server-read-server
+  [mouse-2] #'gnus-server-pick-server
+  "q" #'gnus-server-exit
+  "l" #'gnus-server-list-servers
+  "k" #'gnus-server-kill-server
+  "y" #'gnus-server-yank-server
+  "c" #'gnus-server-copy-server
+  "a" #'gnus-server-add-server
+  "e" #'gnus-server-edit-server
+  "S" #'gnus-server-show-server
+  "s" #'gnus-server-scan-server
+
+  "O" #'gnus-server-open-server
+  "\M-o" #'gnus-server-open-all-servers
+  "C" #'gnus-server-close-server
+  "\M-c" #'gnus-server-close-all-servers
+  "D" #'gnus-server-deny-server
+  "L" #'gnus-server-offline-server
+  "R" #'gnus-server-remove-denials
+
+  "n" #'next-line
+  "p" #'previous-line
+
+  "g" #'gnus-server-regenerate-server
+
+  "G" #'gnus-group-read-ephemeral-search-group
+
+  "z" #'gnus-server-compact-server
+
+  "i" #'gnus-server-toggle-cloud-server
+  "I" #'gnus-server-set-cloud-method-server
+
+  "\C-c\C-i" #'gnus-info-find-node
+  "\C-c\C-b" #'gnus-bug)
 
 (defcustom gnus-server-menu-hook nil
   "Hook run after the creation of the server mode menu."
@@ -145,47 +181,6 @@ If nil, a faster, but more primitive, buffer is used 
instead."
 
     (gnus-run-hooks 'gnus-server-menu-hook)))
 
-(unless gnus-server-mode-map
-  (setq gnus-server-mode-map (make-keymap))
-  (suppress-keymap gnus-server-mode-map)
-
-  (gnus-define-keys gnus-server-mode-map
-    " " gnus-server-read-server-in-server-buffer
-    "\r" gnus-server-read-server
-    [mouse-2] gnus-server-pick-server
-    "q" gnus-server-exit
-    "l" gnus-server-list-servers
-    "k" gnus-server-kill-server
-    "y" gnus-server-yank-server
-    "c" gnus-server-copy-server
-    "a" gnus-server-add-server
-    "e" gnus-server-edit-server
-    "S" gnus-server-show-server
-    "s" gnus-server-scan-server
-
-    "O" gnus-server-open-server
-    "\M-o" gnus-server-open-all-servers
-    "C" gnus-server-close-server
-    "\M-c" gnus-server-close-all-servers
-    "D" gnus-server-deny-server
-    "L" gnus-server-offline-server
-    "R" gnus-server-remove-denials
-
-    "n" next-line
-    "p" previous-line
-
-    "g" gnus-server-regenerate-server
-
-    "G" gnus-group-read-ephemeral-search-group
-
-    "z" gnus-server-compact-server
-
-    "i" gnus-server-toggle-cloud-server
-    "I" gnus-server-set-cloud-method-server
-
-    "\C-c\C-i" gnus-info-find-node
-    "\C-c\C-b" gnus-bug))
-
 (defface gnus-server-agent
   '((((class color) (background light)) (:foreground "PaleTurquoise" :bold t))
     (((class color) (background dark)) (:foreground "PaleTurquoise" :bold t))
@@ -570,7 +565,7 @@ The following commands are available:
   (when (assoc to gnus-server-alist)
     (error "%s already exists" to))
   (unless (gnus-server-to-method from)
-    (error "%s: no such server" from))
+    (error "%s: No such server" from))
   (let ((to-entry (cons from (copy-tree
                              (gnus-server-to-method from)))))
     (setcar to-entry to)
@@ -697,37 +692,31 @@ claim them."
                function
                (repeat function)))
 
-(defvar gnus-browse-mode-map nil)
-
-(unless gnus-browse-mode-map
-  (setq gnus-browse-mode-map (make-keymap))
-  (suppress-keymap gnus-browse-mode-map)
-
-  (gnus-define-keys
-      gnus-browse-mode-map
-    " " gnus-browse-read-group
-    "=" gnus-browse-select-group
-    "n" gnus-browse-next-group
-    "p" gnus-browse-prev-group
-    "\177" gnus-browse-prev-group
-    [delete] gnus-browse-prev-group
-    "N" gnus-browse-next-group
-    "P" gnus-browse-prev-group
-    "\M-n" gnus-browse-next-group
-    "\M-p" gnus-browse-prev-group
-    "\r" gnus-browse-select-group
-    "u" gnus-browse-toggle-subscription-at-point
-    "l" gnus-browse-exit
-    "L" gnus-browse-exit
-    "q" gnus-browse-exit
-    "Q" gnus-browse-exit
-    "d" gnus-browse-describe-group
-    [delete] gnus-browse-delete-group
-    "\C-c\C-c" gnus-browse-exit
-    "?" gnus-browse-describe-briefly
-
-    "\C-c\C-i" gnus-info-find-node
-    "\C-c\C-b" gnus-bug))
+(defvar-keymap gnus-browse-mode-map
+  :full t :suppress t
+  " " #'gnus-browse-read-group
+  "=" #'gnus-browse-select-group
+  "n" #'gnus-browse-next-group
+  "p" #'gnus-browse-prev-group
+  "\177" #'gnus-browse-prev-group
+  [delete] #'gnus-browse-prev-group
+  "N" #'gnus-browse-next-group
+  "P" #'gnus-browse-prev-group
+  "\M-n" #'gnus-browse-next-group
+  "\M-p" #'gnus-browse-prev-group
+  "\r" #'gnus-browse-select-group
+  "u" #'gnus-browse-toggle-subscription-at-point
+  "l" #'gnus-browse-exit
+  "L" #'gnus-browse-exit
+  "q" #'gnus-browse-exit
+  "Q" #'gnus-browse-exit
+  "d" #'gnus-browse-describe-group
+  [delete] #'gnus-browse-delete-group
+  "\C-c\C-c" #'gnus-browse-exit
+  "?" #'gnus-browse-describe-briefly
+
+  "\C-c\C-i" #'gnus-info-find-node
+  "\C-c\C-b" #'gnus-bug)
 
 (defun gnus-browse-make-menu-bar ()
   (gnus-turn-off-edit-menu 'browse)
@@ -1128,7 +1117,7 @@ Requesting compaction of %s... (this may take a long 
time)"
       (customize-set-variable 'gnus-cloud-method server)
       ;; Note we can't use `Custom-save' here.
       (when (gnus-yes-or-no-p
-             (format "The new cloud host server is %S now. Save it? " server))
+             (format "The new cloud host server is `%S' now.  Save it?" 
server))
         (customize-save-variable 'gnus-cloud-method server)))
     (when (gnus-yes-or-no-p (format "Upload Cloud data to %S now? " server))
       (gnus-message 1 "Uploading all data to Emacs Cloud server %S" server)
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index e32cfc0d61..606bd3a39a 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -663,6 +663,7 @@ the first newsgroup."
 (defvar mail-sources)
 (defvar nnmail-scan-directory-mail-source-once)
 (defvar nnmail-split-history)
+(defvar gnus-save-newsrc-file-last-timestamp nil)
 
 (defun gnus-close-all-servers ()
   "Close all servers."
@@ -707,6 +708,7 @@ the first newsgroup."
        gnus-current-select-method nil
        nnmail-split-history nil
        gnus-extended-servers nil
+        gnus-save-newsrc-file-last-timestamp nil
        gnus-ephemeral-servers nil)
   (gnus-shutdown 'gnus)
   ;; Kill the startup file.
@@ -2731,7 +2733,6 @@ The form should return either t or nil."
       'msdos-long-file-names
       (lambda () t))))
 
-(defvar gnus-save-newsrc-file-last-timestamp nil)
 (defun gnus-save-newsrc-file (&optional force)
   "Save .newsrc file.
 Use the group string names in `gnus-group-list' to pull info
@@ -2934,7 +2935,7 @@ SPECIFIC-VARIABLES, or those in `gnus-variable-list'."
     (nreverse olist)))
 
 (defun gnus-gnus-to-newsrc-format (&optional foreign-ok)
-  (interactive (list (gnus-y-or-n-p "write foreign groups too? ")))
+  (interactive (list (gnus-y-or-n-p "Write foreign groups too?")))
   ;; Generate and save the .newsrc file.
   (with-current-buffer (create-file-buffer gnus-current-startup-file)
     (let ((standard-output (current-buffer))
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index 2ddd3d2a7e..3beeace897 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -1907,485 +1907,483 @@ increase the score of each group you read."
 
 ;; Non-orthogonal keys
 
-(gnus-define-keys gnus-summary-mode-map
-  " " gnus-summary-next-page
-  [?\S-\ ] gnus-summary-prev-page
-  "\177" gnus-summary-prev-page
-  [delete] gnus-summary-prev-page
-  "\r" gnus-summary-scroll-up
-  "\M-\r" gnus-summary-scroll-down
-  "n" gnus-summary-next-unread-article
-  "p" gnus-summary-prev-unread-article
-  "N" gnus-summary-next-article
-  "P" gnus-summary-prev-article
-  "\M-\C-n" gnus-summary-next-same-subject
-  "\M-\C-p" gnus-summary-prev-same-subject
-  "\M-n" gnus-summary-next-unread-subject
-  "\M-p" gnus-summary-prev-unread-subject
-  "." gnus-summary-first-unread-article
-  "," gnus-summary-best-unread-article
-  "[" gnus-summary-prev-unseen-article
-  "]" gnus-summary-next-unseen-article
-  "\M-s\M-s" gnus-summary-search-article-forward
-  "\M-s\M-r" gnus-summary-search-article-backward
-  "\M-r" gnus-summary-search-article-backward
-  "\M-S" gnus-summary-repeat-search-article-forward
-  "\M-R" gnus-summary-repeat-search-article-backward
-  "<" gnus-summary-beginning-of-article
-  ">" gnus-summary-end-of-article
-  "j" gnus-summary-goto-article
-  "^" gnus-summary-refer-parent-article
-  "\M-^" gnus-summary-refer-article
-  "u" gnus-summary-tick-article-forward
-  "!" gnus-summary-tick-article-forward
-  "U" gnus-summary-tick-article-backward
-  "d" gnus-summary-mark-as-read-forward
-  "D" gnus-summary-mark-as-read-backward
-  "E" gnus-summary-mark-as-expirable
-  "\M-u" gnus-summary-clear-mark-forward
-  "\M-U" gnus-summary-clear-mark-backward
-  "k" gnus-summary-kill-same-subject-and-select
-  "\C-k" gnus-summary-kill-same-subject
-  "\M-\C-k" gnus-summary-kill-thread
-  "\M-\C-l" gnus-summary-lower-thread
-  "e" gnus-summary-edit-article
-  "#" gnus-summary-mark-as-processable
-  "\M-#" gnus-summary-unmark-as-processable
-  "\M-\C-t" gnus-summary-toggle-threads
-  "\M-\C-s" gnus-summary-show-thread
-  "\M-\C-h" gnus-summary-hide-thread
-  "\M-\C-f" gnus-summary-next-thread
-  "\M-\C-b" gnus-summary-prev-thread
-  [(meta down)] gnus-summary-next-thread
-  [(meta up)] gnus-summary-prev-thread
-  "\M-\C-u" gnus-summary-up-thread
-  "\M-\C-d" gnus-summary-down-thread
-  "&" gnus-summary-execute-command
-  "c" gnus-summary-catchup-and-exit
-  "\C-w" gnus-summary-mark-region-as-read
-  "\C-t" toggle-truncate-lines
-  "?" gnus-summary-mark-as-dormant
-  "\C-c\M-\C-s" gnus-summary-limit-include-expunged
-  "\C-c\C-s\C-n" gnus-summary-sort-by-number
-  "\C-c\C-s\C-m\C-n" gnus-summary-sort-by-most-recent-number
-  "\C-c\C-s\C-l" gnus-summary-sort-by-lines
-  "\C-c\C-s\C-c" gnus-summary-sort-by-chars
-  "\C-c\C-s\C-m\C-m" gnus-summary-sort-by-marks
-  "\C-c\C-s\C-a" gnus-summary-sort-by-author
-  "\C-c\C-s\C-t" gnus-summary-sort-by-recipient
-  "\C-c\C-s\C-s" gnus-summary-sort-by-subject
-  "\C-c\C-s\C-d" gnus-summary-sort-by-date
-  "\C-c\C-s\C-m\C-d" gnus-summary-sort-by-most-recent-date
-  "\C-c\C-s\C-i" gnus-summary-sort-by-score
-  "\C-c\C-s\C-o" gnus-summary-sort-by-original
-  "\C-c\C-s\C-r" gnus-summary-sort-by-random
-  "\C-c\C-s\C-u" gnus-summary-sort-by-newsgroups
-  "\C-c\C-s\C-x" gnus-summary-sort-by-extra
-  "=" gnus-summary-expand-window
-  "\C-x\C-s" gnus-summary-reselect-current-group
-  "\M-g" gnus-summary-rescan-group
-  "\C-c\C-r" gnus-summary-caesar-message
-  "f" gnus-summary-followup
-  "F" gnus-summary-followup-with-original
-  "C" gnus-summary-cancel-article
-  "r" gnus-summary-reply
-  "R" gnus-summary-reply-with-original
-  "\C-c\C-f" gnus-summary-mail-forward
-  "o" gnus-summary-save-article
-  "\C-o" gnus-summary-save-article-mail
-  "|" gnus-summary-pipe-output
-  "\M-k" gnus-summary-edit-local-kill
-  "\M-K" gnus-summary-edit-global-kill
+(define-keymap :keymap gnus-summary-mode-map
+  " " #'gnus-summary-next-page
+  [?\S-\ ] #'gnus-summary-prev-page
+  "\177" #'gnus-summary-prev-page
+  [delete] #'gnus-summary-prev-page
+  "\r" #'gnus-summary-scroll-up
+  "\M-\r" #'gnus-summary-scroll-down
+  "n" #'gnus-summary-next-unread-article
+  "p" #'gnus-summary-prev-unread-article
+  "N" #'gnus-summary-next-article
+  "P" #'gnus-summary-prev-article
+  "\M-\C-n" #'gnus-summary-next-same-subject
+  "\M-\C-p" #'gnus-summary-prev-same-subject
+  "\M-n" #'gnus-summary-next-unread-subject
+  "\M-p" #'gnus-summary-prev-unread-subject
+  "." #'gnus-summary-first-unread-article
+  "," #'gnus-summary-best-unread-article
+  "[" #'gnus-summary-prev-unseen-article
+  "]" #'gnus-summary-next-unseen-article
+  "\M-s\M-s" #'gnus-summary-search-article-forward
+  "\M-s\M-r" #'gnus-summary-search-article-backward
+  "\M-r" #'gnus-summary-search-article-backward
+  "\M-S" #'gnus-summary-repeat-search-article-forward
+  "\M-R" #'gnus-summary-repeat-search-article-backward
+  "<" #'gnus-summary-beginning-of-article
+  ">" #'gnus-summary-end-of-article
+  "j" #'gnus-summary-goto-article
+  "^" #'gnus-summary-refer-parent-article
+  "\M-^" #'gnus-summary-refer-article
+  "u" #'gnus-summary-tick-article-forward
+  "!" #'gnus-summary-tick-article-forward
+  "U" #'gnus-summary-tick-article-backward
+  "d" #'gnus-summary-mark-as-read-forward
+  "D" #'gnus-summary-mark-as-read-backward
+  "E" #'gnus-summary-mark-as-expirable
+  "\M-u" #'gnus-summary-clear-mark-forward
+  "\M-U" #'gnus-summary-clear-mark-backward
+  "k" #'gnus-summary-kill-same-subject-and-select
+  "\C-k" #'gnus-summary-kill-same-subject
+  "\M-\C-k" #'gnus-summary-kill-thread
+  "\M-\C-l" #'gnus-summary-lower-thread
+  "e" #'gnus-summary-edit-article
+  "#" #'gnus-summary-mark-as-processable
+  "\M-#" #'gnus-summary-unmark-as-processable
+  "\M-\C-t" #'gnus-summary-toggle-threads
+  "\M-\C-s" #'gnus-summary-show-thread
+  "\M-\C-h" #'gnus-summary-hide-thread
+  "\M-\C-f" #'gnus-summary-next-thread
+  "\M-\C-b" #'gnus-summary-prev-thread
+  [(meta down)] #'gnus-summary-next-thread
+  [(meta up)] #'gnus-summary-prev-thread
+  "\M-\C-u" #'gnus-summary-up-thread
+  "\M-\C-d" #'gnus-summary-down-thread
+  "&" #'gnus-summary-execute-command
+  "c" #'gnus-summary-catchup-and-exit
+  "\C-w" #'gnus-summary-mark-region-as-read
+  "\C-t" #'toggle-truncate-lines
+  "?" #'gnus-summary-mark-as-dormant
+  "\C-c\M-\C-s" #'gnus-summary-limit-include-expunged
+  "\C-c\C-s\C-n" #'gnus-summary-sort-by-number
+  "\C-c\C-s\C-m\C-n" #'gnus-summary-sort-by-most-recent-number
+  "\C-c\C-s\C-l" #'gnus-summary-sort-by-lines
+  "\C-c\C-s\C-c" #'gnus-summary-sort-by-chars
+  "\C-c\C-s\C-m\C-m" #'gnus-summary-sort-by-marks
+  "\C-c\C-s\C-a" #'gnus-summary-sort-by-author
+  "\C-c\C-s\C-t" #'gnus-summary-sort-by-recipient
+  "\C-c\C-s\C-s" #'gnus-summary-sort-by-subject
+  "\C-c\C-s\C-d" #'gnus-summary-sort-by-date
+  "\C-c\C-s\C-m\C-d" #'gnus-summary-sort-by-most-recent-date
+  "\C-c\C-s\C-i" #'gnus-summary-sort-by-score
+  "\C-c\C-s\C-o" #'gnus-summary-sort-by-original
+  "\C-c\C-s\C-r" #'gnus-summary-sort-by-random
+  "\C-c\C-s\C-u" #'gnus-summary-sort-by-newsgroups
+  "\C-c\C-s\C-x" #'gnus-summary-sort-by-extra
+  "=" #'gnus-summary-expand-window
+  "\C-x\C-s" #'gnus-summary-reselect-current-group
+  "\M-g" #'gnus-summary-rescan-group
+  "\C-c\C-r" #'gnus-summary-caesar-message
+  "f" #'gnus-summary-followup
+  "F" #'gnus-summary-followup-with-original
+  "C" #'gnus-summary-cancel-article
+  "r" #'gnus-summary-reply
+  "R" #'gnus-summary-reply-with-original
+  "\C-c\C-f" #'gnus-summary-mail-forward
+  "o" #'gnus-summary-save-article
+  "\C-o" #'gnus-summary-save-article-mail
+  "|" #'gnus-summary-pipe-output
+  "\M-k" #'gnus-summary-edit-local-kill
+  "\M-K" #'gnus-summary-edit-global-kill
   ;; "V" gnus-version
-  "\C-c\C-d" gnus-summary-describe-group
-  "\C-c\C-p" gnus-summary-make-group-from-search
-  "q" gnus-summary-exit
-  "Q" gnus-summary-exit-no-update
-  "\C-c\C-i" gnus-info-find-node
-  [mouse-2] gnus-mouse-pick-article
-  [follow-link] mouse-face
-  "m" gnus-summary-mail-other-window
-  "a" gnus-summary-post-news
-  "x" gnus-summary-limit-to-unread
-  "s" gnus-summary-isearch-article
-  "\t" gnus-summary-button-forward
-  [backtab] gnus-summary-button-backward
-  "w" gnus-summary-browse-url
-  "t" gnus-summary-toggle-header
-  "g" gnus-summary-show-article
-  "l" gnus-summary-goto-last-article
-  "\C-c\C-v\C-v" gnus-uu-decode-uu-view
-  "\C-d" gnus-summary-enter-digest-group
-  "\M-\C-d" gnus-summary-read-document
-  "\M-\C-e" gnus-summary-edit-parameters
-  "\M-\C-a" gnus-summary-customize-parameters
-  "\C-c\C-b" gnus-bug
-  "*" gnus-cache-enter-article
-  "\M-*" gnus-cache-remove-article
-  "\M-&" gnus-summary-universal-argument
-  "\C-l" gnus-recenter
-  "I" gnus-summary-increase-score
-  "L" gnus-summary-lower-score
-  "\M-i" gnus-symbolic-argument
-  "h" gnus-summary-select-article-buffer
-
-  "b" gnus-article-view-part
-  "\M-t" gnus-summary-toggle-display-buttonized
-
-  "V" gnus-summary-score-map
-  "X" gnus-uu-extract-map
-  "S" gnus-summary-send-map)
-
-;; Sort of orthogonal keymap
-(gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
-  "t" gnus-summary-tick-article-forward
-  "!" gnus-summary-tick-article-forward
-  "d" gnus-summary-mark-as-read-forward
-  "r" gnus-summary-mark-as-read-forward
-  "c" gnus-summary-clear-mark-forward
-  " " gnus-summary-clear-mark-forward
-  "e" gnus-summary-mark-as-expirable
-  "x" gnus-summary-mark-as-expirable
-  "?" gnus-summary-mark-as-dormant
-  "b" gnus-summary-set-bookmark
-  "B" gnus-summary-remove-bookmark
-  "#" gnus-summary-mark-as-processable
-  "\M-#" gnus-summary-unmark-as-processable
-  "S" gnus-summary-limit-include-expunged
-  "C" gnus-summary-catchup
-  "H" gnus-summary-catchup-to-here
-  "h" gnus-summary-catchup-from-here
-  "\C-c" gnus-summary-catchup-all
-  "k" gnus-summary-kill-same-subject-and-select
-  "K" gnus-summary-kill-same-subject
-  "P" gnus-uu-mark-map)
-
-(gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
-  "c" gnus-summary-clear-above
-  "u" gnus-summary-tick-above
-  "m" gnus-summary-mark-above
-  "k" gnus-summary-kill-below)
-
-(gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
-  "/" gnus-summary-limit-to-subject
-  "n" gnus-summary-limit-to-articles
-  "b" gnus-summary-limit-to-bodies
-  "h" gnus-summary-limit-to-headers
-  "w" gnus-summary-pop-limit
-  "s" gnus-summary-limit-to-subject
-  "a" gnus-summary-limit-to-author
-  "u" gnus-summary-limit-to-unread
-  "m" gnus-summary-limit-to-marks
-  "M" gnus-summary-limit-exclude-marks
-  "v" gnus-summary-limit-to-score
-  "*" gnus-summary-limit-include-cached
-  "D" gnus-summary-limit-include-dormant
-  "T" gnus-summary-limit-include-thread
-  "d" gnus-summary-limit-exclude-dormant
-  "t" gnus-summary-limit-to-age
-  "." gnus-summary-limit-to-unseen
-  "x" gnus-summary-limit-to-extra
-  "p" gnus-summary-limit-to-display-predicate
-  "E" gnus-summary-limit-include-expunged
-  "c" gnus-summary-limit-exclude-childless-dormant
-  "C" gnus-summary-limit-mark-excluded-as-read
-  "o" gnus-summary-insert-old-articles
-  "N" gnus-summary-insert-new-articles
-  "S" gnus-summary-limit-to-singletons
-  "r" gnus-summary-limit-to-replied
-  "R" gnus-summary-limit-to-recipient
-  "A" gnus-summary-limit-to-address)
-
-(gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
-  "n" gnus-summary-next-unread-article
-  "p" gnus-summary-prev-unread-article
-  "N" gnus-summary-next-article
-  "P" gnus-summary-prev-article
-  "\C-n" gnus-summary-next-same-subject
-  "\C-p" gnus-summary-prev-same-subject
-  "\M-n" gnus-summary-next-unread-subject
-  "\M-p" gnus-summary-prev-unread-subject
-  "f" gnus-summary-first-unread-article
-  "b" gnus-summary-best-unread-article
-  "u" gnus-summary-next-unseen-article
-  "U" gnus-summary-prev-unseen-article
-  "j" gnus-summary-goto-article
-  "g" gnus-summary-goto-subject
-  "l" gnus-summary-goto-last-article
-  "o" gnus-summary-pop-article)
-
-(gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
-  "k" gnus-summary-kill-thread
-  "E" gnus-summary-expire-thread
-  "l" gnus-summary-lower-thread
-  "i" gnus-summary-raise-thread
-  "T" gnus-summary-toggle-threads
-  "t" gnus-summary-rethread-current
-  "^" gnus-summary-reparent-thread
-  "\M-^" gnus-summary-reparent-children
-  "s" gnus-summary-show-thread
-  "S" gnus-summary-show-all-threads
-  "h" gnus-summary-hide-thread
-  "H" gnus-summary-hide-all-threads
-  "n" gnus-summary-next-thread
-  "p" gnus-summary-prev-thread
-  "u" gnus-summary-up-thread
-  "o" gnus-summary-top-thread
-  "d" gnus-summary-down-thread
-  "#" gnus-uu-mark-thread
-  "\M-#" gnus-uu-unmark-thread)
-
-(gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
-  "g" gnus-summary-prepare
-  "c" gnus-summary-insert-cached-articles
-  "d" gnus-summary-insert-dormant-articles
-  "t" gnus-summary-insert-ticked-articles)
-
-(gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
-  "c" gnus-summary-catchup-and-exit
-  "C" gnus-summary-catchup-all-and-exit
-  "E" gnus-summary-exit-no-update
-  "Q" gnus-summary-exit
-  "Z" gnus-summary-exit
-  "n" gnus-summary-catchup-and-goto-next-group
-  "p" gnus-summary-catchup-and-goto-prev-group
-  "R" gnus-summary-reselect-current-group
-  "G" gnus-summary-rescan-group
-  "N" gnus-summary-next-group
-  "s" gnus-summary-save-newsrc
-  "P" gnus-summary-prev-group)
-
-(gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
-  " " gnus-summary-next-page
-  "n" gnus-summary-next-page
-  [?\S-\ ] gnus-summary-prev-page
-  "\177" gnus-summary-prev-page
-  [delete] gnus-summary-prev-page
-  "p" gnus-summary-prev-page
-  "\r" gnus-summary-scroll-up
-  "\M-\r" gnus-summary-scroll-down
-  "<" gnus-summary-beginning-of-article
-  ">" gnus-summary-end-of-article
-  "b" gnus-summary-beginning-of-article
-  "e" gnus-summary-end-of-article
-  "^" gnus-summary-refer-parent-article
-  "r" gnus-summary-refer-parent-article
-  "C" gnus-summary-show-complete-article
-  "D" gnus-summary-enter-digest-group
-  "R" gnus-summary-refer-references
-  "T" gnus-summary-refer-thread
-  "W" gnus-warp-to-article
-  "g" gnus-summary-show-article
-  "s" gnus-summary-isearch-article
-  "\t" gnus-summary-button-forward
-  [backtab] gnus-summary-button-backward
-  "w" gnus-summary-browse-url
-  "P" gnus-summary-print-article
-  "S" gnus-sticky-article
-  "M" gnus-mailing-list-insinuate
-  "t" gnus-article-babel)
-
-(gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
-  "b" gnus-article-add-buttons
-  "B" gnus-article-add-buttons-to-head
-  "o" gnus-article-treat-overstrike
-  "e" gnus-article-emphasize
-  "w" gnus-article-fill-cited-article
-  "Q" gnus-article-fill-long-lines
-  "L" gnus-article-toggle-truncate-lines
-  "C" gnus-article-capitalize-sentences
-  "c" gnus-article-remove-cr
-  "q" gnus-article-de-quoted-unreadable
-  "6" gnus-article-de-base64-unreadable
-  "Z" gnus-article-decode-HZ
-  "A" gnus-article-treat-ansi-sequences
-  "h" gnus-article-wash-html
-  "u" gnus-article-unsplit-urls
-  "s" gnus-summary-force-verify-and-decrypt
-  "f" gnus-article-display-x-face
-  "l" gnus-summary-stop-page-breaking
-  "r" gnus-summary-caesar-message
-  "m" gnus-summary-morse-message
-  "t" gnus-summary-toggle-header
-  "g" gnus-treat-smiley
-  "v" gnus-summary-verbose-headers
-  "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
-  "p" gnus-article-verify-x-pgp-sig
-  "d" gnus-article-treat-smartquotes
-  "U" gnus-article-treat-non-ascii
-  "i" gnus-summary-idna-message)
-
-(gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
-  ;; mnemonic: deuglif*Y*
-  "u" gnus-article-outlook-unwrap-lines
-  "a" gnus-article-outlook-repair-attribution
-  "c" gnus-article-outlook-rearrange-citation
-  "f" gnus-article-outlook-deuglify-article) ;; mnemonic: full deuglify
-
-(gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
-  "a" gnus-article-hide
-  "h" gnus-article-hide-headers
-  "b" gnus-article-hide-boring-headers
-  "s" gnus-article-hide-signature
-  "c" gnus-article-hide-citation
-  "C" gnus-article-hide-citation-in-followups
-  "l" gnus-article-hide-list-identifiers
-  "B" gnus-article-strip-banner
-  "P" gnus-article-hide-pem
-  "\C-c" gnus-article-hide-citation-maybe)
-
-(gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
-  "a" gnus-article-highlight
-  "h" gnus-article-highlight-headers
-  "c" gnus-article-highlight-citation
-  "s" gnus-article-highlight-signature)
-
-(gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
-  "f" gnus-article-treat-fold-headers
-  "u" gnus-article-treat-unfold-headers
-  "n" gnus-article-treat-fold-newsgroups)
-
-(gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
-  "x" gnus-article-display-x-face
-  "d" gnus-article-display-face
-  "s" gnus-treat-smiley
-  "D" gnus-article-remove-images
-  "W" gnus-article-show-images
-  "F" gnus-article-toggle-fonts
-  "f" gnus-treat-from-picon
-  "m" gnus-treat-mail-picon
-  "n" gnus-treat-newsgroups-picon
-  "g" gnus-treat-from-gravatar
-  "h" gnus-treat-mail-gravatar)
-
-(gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
-  "w" gnus-article-decode-mime-words
-  "c" gnus-article-decode-charset
-  "h" gnus-mime-buttonize-attachments-in-header
-  "v" gnus-mime-view-all-parts
-  "b" gnus-article-view-part)
-
-(gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
-  "z" gnus-article-date-ut
-  "u" gnus-article-date-ut
-  "l" gnus-article-date-local
-  "p" gnus-article-date-english
-  "e" gnus-article-date-lapsed
-  "o" gnus-article-date-original
-  "i" gnus-article-date-iso8601
-  "s" gnus-article-date-user)
-
-(gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
-  "t" gnus-article-remove-trailing-blank-lines
-  "l" gnus-article-strip-leading-blank-lines
-  "m" gnus-article-strip-multiple-blank-lines
-  "a" gnus-article-strip-blank-lines
-  "A" gnus-article-strip-all-blank-lines
-  "s" gnus-article-strip-leading-space
-  "e" gnus-article-strip-trailing-space
-  "w" gnus-article-remove-leading-whitespace)
-
-(gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
-  "v" gnus-version
-  "d" gnus-summary-describe-group
-  "h" gnus-summary-describe-briefly
-  "i" gnus-info-find-node)
-
-(gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
-  "e" gnus-summary-expire-articles
-  "\M-\C-e" gnus-summary-expire-articles-now
-  "\177" gnus-summary-delete-article
-  [delete] gnus-summary-delete-article
-  [backspace] gnus-summary-delete-article
-  "m" gnus-summary-move-article
-  "r" gnus-summary-respool-article
-  "w" gnus-summary-edit-article
-  "c" gnus-summary-copy-article
-  "B" gnus-summary-crosspost-article
-  "q" gnus-summary-respool-query
-  "t" gnus-summary-respool-trace
-  "i" gnus-summary-import-article
-  "I" gnus-summary-create-article
-  "p" gnus-summary-article-posted-p)
-
-(gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
-  "o" gnus-summary-save-article
-  "m" gnus-summary-save-article-mail
-  "F" gnus-summary-write-article-file
-  "r" gnus-summary-save-article-rmail
-  "f" gnus-summary-save-article-file
-  "b" gnus-summary-save-article-body-file
-  "B" gnus-summary-write-article-body-file
-  "h" gnus-summary-save-article-folder
-  "v" gnus-summary-save-article-vm
-  "p" gnus-summary-pipe-output
-  "P" gnus-summary-muttprint)
-
-(gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
-  "b" gnus-summary-display-buttonized
-  "m" gnus-summary-repair-multipart
-  "v" gnus-article-view-part
-  "o" gnus-article-save-part
-  "O" gnus-article-save-part-and-strip
-  "r" gnus-article-replace-part
-  "d" gnus-article-delete-part
-  "t" gnus-article-view-part-as-type
-  "j" gnus-article-jump-to-part
-  "c" gnus-article-copy-part
-  "C" gnus-article-view-part-as-charset
-  "e" gnus-article-view-part-externally
-  "H" gnus-article-browse-html-article
-  "E" gnus-article-encrypt-body
-  "i" gnus-article-inline-part
-  "|" gnus-article-pipe-part)
-
-(gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
-  "p" gnus-summary-mark-as-processable
-  "u" gnus-summary-unmark-as-processable
-  "U" gnus-summary-unmark-all-processable
-  "v" gnus-uu-mark-over
-  "s" gnus-uu-mark-series
-  "r" gnus-uu-mark-region
-  "g" gnus-uu-unmark-region
-  "R" gnus-uu-mark-by-regexp
-  "G" gnus-uu-unmark-by-regexp
-  "t" gnus-uu-mark-thread
-  "T" gnus-uu-unmark-thread
-  "a" gnus-uu-mark-all
-  "b" gnus-uu-mark-buffer
-  "S" gnus-uu-mark-sparse
-  "k" gnus-summary-kill-process-mark
-  "y" gnus-summary-yank-process-mark
-  "w" gnus-summary-save-process-mark
-  "i" gnus-uu-invert-processable)
-
-(gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
-  ;;"x" gnus-uu-extract-any
-  "m" gnus-summary-save-parts
-  "u" gnus-uu-decode-uu
-  "U" gnus-uu-decode-uu-and-save
-  "s" gnus-uu-decode-unshar
-  "S" gnus-uu-decode-unshar-and-save
-  "o" gnus-uu-decode-save
-  "O" gnus-uu-decode-save
-  "b" gnus-uu-decode-binhex
-  "B" gnus-uu-decode-binhex
-  "Y" gnus-uu-decode-yenc
-  "p" gnus-uu-decode-postscript
-  "P" gnus-uu-decode-postscript-and-save)
-
-(gnus-define-keys
-    (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
-  "u" gnus-uu-decode-uu-view
-  "U" gnus-uu-decode-uu-and-save-view
-  "s" gnus-uu-decode-unshar-view
-  "S" gnus-uu-decode-unshar-and-save-view
-  "o" gnus-uu-decode-save-view
-  "O" gnus-uu-decode-save-view
-  "b" gnus-uu-decode-binhex-view
-  "B" gnus-uu-decode-binhex-view
-  "p" gnus-uu-decode-postscript-view
-  "P" gnus-uu-decode-postscript-and-save-view)
+  "\C-c\C-d" #'gnus-summary-describe-group
+  "\C-c\C-p" #'gnus-summary-make-group-from-search
+  "q" #'gnus-summary-exit
+  "Q" #'gnus-summary-exit-no-update
+  "\C-c\C-i" #'gnus-info-find-node
+  [mouse-2] #'gnus-mouse-pick-article
+  [follow-link] 'mouse-face
+  "m" #'gnus-summary-mail-other-window
+  "a" #'gnus-summary-post-news
+  "x" #'gnus-summary-limit-to-unread
+  "s" #'gnus-summary-isearch-article
+  "\t" #'gnus-summary-button-forward
+  [backtab] #'gnus-summary-button-backward
+  "w" #'gnus-summary-browse-url
+  "t" #'gnus-summary-toggle-header
+  "g" #'gnus-summary-show-article
+  "l" #'gnus-summary-goto-last-article
+  "\C-c\C-v\C-v" #'gnus-uu-decode-uu-view
+  "\C-d" #'gnus-summary-enter-digest-group
+  "\M-\C-d" #'gnus-summary-read-document
+  "\M-\C-e" #'gnus-summary-edit-parameters
+  "\M-\C-a" #'gnus-summary-customize-parameters
+  "\C-c\C-b" #'gnus-bug
+  "*" #'gnus-cache-enter-article
+  "\M-*" #'gnus-cache-remove-article
+  "\M-&" #'gnus-summary-universal-argument
+  "\C-l" #'gnus-recenter
+  "I" #'gnus-summary-increase-score
+  "L" #'gnus-summary-lower-score
+  "\M-i" #'gnus-symbolic-argument
+  "h" #'gnus-summary-select-article-buffer
+
+  "b" #'gnus-article-view-part
+  "\M-t" #'gnus-summary-toggle-display-buttonized
+
+  "S" #'gnus-summary-send-map
+
+  ;; Sort of orthogonal keymaps.
+  "M" (define-keymap :prefix 'gnus-summary-mark-map
+        "t" #'gnus-summary-tick-article-forward
+        "!" #'gnus-summary-tick-article-forward
+        "d" #'gnus-summary-mark-as-read-forward
+        "r" #'gnus-summary-mark-as-read-forward
+        "c" #'gnus-summary-clear-mark-forward
+        " " #'gnus-summary-clear-mark-forward
+        "e" #'gnus-summary-mark-as-expirable
+        "x" #'gnus-summary-mark-as-expirable
+        "?" #'gnus-summary-mark-as-dormant
+        "b" #'gnus-summary-set-bookmark
+        "B" #'gnus-summary-remove-bookmark
+        "#" #'gnus-summary-mark-as-processable
+        "\M-#" #'gnus-summary-unmark-as-processable
+        "S" #'gnus-summary-limit-include-expunged
+        "C" #'gnus-summary-catchup
+        "H" #'gnus-summary-catchup-to-here
+        "h" #'gnus-summary-catchup-from-here
+        "\C-c" #'gnus-summary-catchup-all
+        "k" #'gnus-summary-kill-same-subject-and-select
+        "K" #'gnus-summary-kill-same-subject
+
+        "P" (define-keymap :prefix 'gnus-uu-mark-map
+              "p" #'gnus-summary-mark-as-processable
+              "u" #'gnus-summary-unmark-as-processable
+              "U" #'gnus-summary-unmark-all-processable
+              "v" #'gnus-uu-mark-over
+              "s" #'gnus-uu-mark-series
+              "r" #'gnus-uu-mark-region
+              "g" #'gnus-uu-unmark-region
+              "R" #'gnus-uu-mark-by-regexp
+              "G" #'gnus-uu-unmark-by-regexp
+              "t" #'gnus-uu-mark-thread
+              "T" #'gnus-uu-unmark-thread
+              "a" #'gnus-uu-mark-all
+              "b" #'gnus-uu-mark-buffer
+              "S" #'gnus-uu-mark-sparse
+              "k" #'gnus-summary-kill-process-mark
+              "y" #'gnus-summary-yank-process-mark
+              "w" #'gnus-summary-save-process-mark
+              "i" #'gnus-uu-invert-processable)
+
+        "V" (define-keymap :prefix 'gnus-summary-mscore-map
+              "c" #'gnus-summary-clear-above
+              "u" #'gnus-summary-tick-above
+              "m" #'gnus-summary-mark-above
+              "k" #'gnus-summary-kill-below))
+
+  "/" (define-keymap :prefix 'gnus-summary-limit-map
+        "/" #'gnus-summary-limit-to-subject
+        "n" #'gnus-summary-limit-to-articles
+        "b" #'gnus-summary-limit-to-bodies
+        "h" #'gnus-summary-limit-to-headers
+        "w" #'gnus-summary-pop-limit
+        "s" #'gnus-summary-limit-to-subject
+        "a" #'gnus-summary-limit-to-author
+        "u" #'gnus-summary-limit-to-unread
+        "m" #'gnus-summary-limit-to-marks
+        "M" #'gnus-summary-limit-exclude-marks
+        "v" #'gnus-summary-limit-to-score
+        "*" #'gnus-summary-limit-include-cached
+        "D" #'gnus-summary-limit-include-dormant
+        "T" #'gnus-summary-limit-include-thread
+        "d" #'gnus-summary-limit-exclude-dormant
+        "t" #'gnus-summary-limit-to-age
+        "." #'gnus-summary-limit-to-unseen
+        "x" #'gnus-summary-limit-to-extra
+        "p" #'gnus-summary-limit-to-display-predicate
+        "E" #'gnus-summary-limit-include-expunged
+        "c" #'gnus-summary-limit-exclude-childless-dormant
+        "C" #'gnus-summary-limit-mark-excluded-as-read
+        "o" #'gnus-summary-insert-old-articles
+        "N" #'gnus-summary-insert-new-articles
+        "S" #'gnus-summary-limit-to-singletons
+        "r" #'gnus-summary-limit-to-replied
+        "R" #'gnus-summary-limit-to-recipient
+        "A" #'gnus-summary-limit-to-address)
+
+  "G" (define-keymap :prefix 'gnus-summary-goto-map
+        "n" #'gnus-summary-next-unread-article
+        "p" #'gnus-summary-prev-unread-article
+        "N" #'gnus-summary-next-article
+        "P" #'gnus-summary-prev-article
+        "\C-n" #'gnus-summary-next-same-subject
+        "\C-p" #'gnus-summary-prev-same-subject
+        "\M-n" #'gnus-summary-next-unread-subject
+        "\M-p" #'gnus-summary-prev-unread-subject
+        "f" #'gnus-summary-first-unread-article
+        "b" #'gnus-summary-best-unread-article
+        "u" #'gnus-summary-next-unseen-article
+        "U" #'gnus-summary-prev-unseen-article
+        "j" #'gnus-summary-goto-article
+        "g" #'gnus-summary-goto-subject
+        "l" #'gnus-summary-goto-last-article
+        "o" #'gnus-summary-pop-article)
+
+  "T" (define-keymap :prefix 'gnus-summary-thread-map
+        "k" #'gnus-summary-kill-thread
+        "E" #'gnus-summary-expire-thread
+        "l" #'gnus-summary-lower-thread
+        "i" #'gnus-summary-raise-thread
+        "T" #'gnus-summary-toggle-threads
+        "t" #'gnus-summary-rethread-current
+        "^" #'gnus-summary-reparent-thread
+        "\M-^" #'gnus-summary-reparent-children
+        "s" #'gnus-summary-show-thread
+        "S" #'gnus-summary-show-all-threads
+        "h" #'gnus-summary-hide-thread
+        "H" #'gnus-summary-hide-all-threads
+        "n" #'gnus-summary-next-thread
+        "p" #'gnus-summary-prev-thread
+        "u" #'gnus-summary-up-thread
+        "o" #'gnus-summary-top-thread
+        "d" #'gnus-summary-down-thread
+        "#" #'gnus-uu-mark-thread
+        "\M-#" #'gnus-uu-unmark-thread)
+
+  "Y" (define-keymap :prefix 'gnus-summary-buffer-map
+        "g" #'gnus-summary-prepare
+        "c" #'gnus-summary-insert-cached-articles
+        "d" #'gnus-summary-insert-dormant-articles
+        "t" #'gnus-summary-insert-ticked-articles)
+
+  "Z" (define-keymap :prefix 'gnus-summary-exit-map
+        "c" #'gnus-summary-catchup-and-exit
+        "C" #'gnus-summary-catchup-all-and-exit
+        "E" #'gnus-summary-exit-no-update
+        "Q" #'gnus-summary-exit
+        "Z" #'gnus-summary-exit
+        "n" #'gnus-summary-catchup-and-goto-next-group
+        "p" #'gnus-summary-catchup-and-goto-prev-group
+        "R" #'gnus-summary-reselect-current-group
+        "G" #'gnus-summary-rescan-group
+        "N" #'gnus-summary-next-group
+        "s" #'gnus-summary-save-newsrc
+        "P" #'gnus-summary-prev-group)
+
+  "A" (define-keymap :prefix 'gnus-summary-article-map
+        " " #'gnus-summary-next-page
+        "n" #'gnus-summary-next-page
+        [?\S-\ ] #'gnus-summary-prev-page
+        "\177" #'gnus-summary-prev-page
+        [delete] #'gnus-summary-prev-page
+        "p" #'gnus-summary-prev-page
+        "\r" #'gnus-summary-scroll-up
+        "\M-\r" #'gnus-summary-scroll-down
+        "<" #'gnus-summary-beginning-of-article
+        ">" #'gnus-summary-end-of-article
+        "b" #'gnus-summary-beginning-of-article
+        "e" #'gnus-summary-end-of-article
+        "^" #'gnus-summary-refer-parent-article
+        "r" #'gnus-summary-refer-parent-article
+        "C" #'gnus-summary-show-complete-article
+        "D" #'gnus-summary-enter-digest-group
+        "R" #'gnus-summary-refer-references
+        "T" #'gnus-summary-refer-thread
+        "W" #'gnus-warp-to-article
+        "g" #'gnus-summary-show-article
+        "s" #'gnus-summary-isearch-article
+        "\t" #'gnus-summary-button-forward
+        [backtab] #'gnus-summary-button-backward
+        "w" #'gnus-summary-browse-url
+        "P" #'gnus-summary-print-article
+        "S" #'gnus-sticky-article
+        "M" #'gnus-mailing-list-insinuate
+        "t" #'gnus-article-babel)
+
+  "W" (define-keymap :prefix 'gnus-summary-wash-map
+        "b" #'gnus-article-add-buttons
+        "B" #'gnus-article-add-buttons-to-head
+        "o" #'gnus-article-treat-overstrike
+        "e" #'gnus-article-emphasize
+        "w" #'gnus-article-fill-cited-article
+        "Q" #'gnus-article-fill-long-lines
+        "L" #'gnus-article-toggle-truncate-lines
+        "C" #'gnus-article-capitalize-sentences
+        "c" #'gnus-article-remove-cr
+        "q" #'gnus-article-de-quoted-unreadable
+        "6" #'gnus-article-de-base64-unreadable
+        "Z" #'gnus-article-decode-HZ
+        "A" #'gnus-article-treat-ansi-sequences
+        "h" #'gnus-article-wash-html
+        "u" #'gnus-article-unsplit-urls
+        "s" #'gnus-summary-force-verify-and-decrypt
+        "f" #'gnus-article-display-x-face
+        "l" #'gnus-summary-stop-page-breaking
+        "r" #'gnus-summary-caesar-message
+        "m" #'gnus-summary-morse-message
+        "t" #'gnus-summary-toggle-header
+        "g" #'gnus-treat-smiley
+        "v" #'gnus-summary-verbose-headers
+        "a" #'gnus-article-strip-headers-in-body ;; mnemonic: wash archive
+        "p" #'gnus-article-verify-x-pgp-sig
+        "d" #'gnus-article-treat-smartquotes
+        "U" #'gnus-article-treat-non-ascii
+        "i" #'gnus-summary-idna-message
+
+        "Y" (define-keymap :prefix 'gnus-summary-wash-deuglify-map
+              ;; mnemonic: deuglif*Y*
+              "u" #'gnus-article-outlook-unwrap-lines
+              "a" #'gnus-article-outlook-repair-attribution
+              "c" #'gnus-article-outlook-rearrange-citation
+              ;; mnemonic: full deuglify
+              "f" #'gnus-article-outlook-deuglify-article)
+
+        "W" (define-keymap :prefix 'gnus-summary-wash-hide-map
+              "a" #'gnus-article-hide
+              "h" #'gnus-article-hide-headers
+              "b" #'gnus-article-hide-boring-headers
+              "s" #'gnus-article-hide-signature
+              "c" #'gnus-article-hide-citation
+              "C" #'gnus-article-hide-citation-in-followups
+              "l" #'gnus-article-hide-list-identifiers
+              "B" #'gnus-article-strip-banner
+              "P" #'gnus-article-hide-pem
+              "\C-c" #'gnus-article-hide-citation-maybe)
+
+        "H" (define-keymap :prefix 'gnus-summary-wash-highlight-map
+              "a" #'gnus-article-highlight
+              "h" #'gnus-article-highlight-headers
+              "c" #'gnus-article-highlight-citation
+              "s" #'gnus-article-highlight-signature)
+
+        "G" (define-keymap :prefix 'gnus-summary-wash-header-map
+              "f" #'gnus-article-treat-fold-headers
+              "u" #'gnus-article-treat-unfold-headers
+              "n" #'gnus-article-treat-fold-newsgroups)
+
+        "D" (define-keymap :prefix 'gnus-summary-wash-display-map
+              "x" #'gnus-article-display-x-face
+              "d" #'gnus-article-display-face
+              "s" #'gnus-treat-smiley
+              "e" #'gnus-article-emojize-symbols
+              "D" #'gnus-article-remove-images
+              "W" #'gnus-article-show-images
+              "F" #'gnus-article-toggle-fonts
+              "f" #'gnus-treat-from-picon
+              "m" #'gnus-treat-mail-picon
+              "n" #'gnus-treat-newsgroups-picon
+              "g" #'gnus-treat-from-gravatar
+              "h" #'gnus-treat-mail-gravatar)
+
+        "M" (define-keymap :prefix 'gnus-summary-wash-mime-map
+              "w" #'gnus-article-decode-mime-words
+              "c" #'gnus-article-decode-charset
+              "h" #'gnus-mime-buttonize-attachments-in-header
+              "v" #'gnus-mime-view-all-parts
+              "b" #'gnus-article-view-part)
+
+        "T" (define-keymap :prefix 'gnus-summary-wash-time-map
+              "z" #'gnus-article-date-ut
+              "u" #'gnus-article-date-ut
+              "l" #'gnus-article-date-local
+              "p" #'gnus-article-date-english
+              "e" #'gnus-article-date-lapsed
+              "o" #'gnus-article-date-original
+              "i" #'gnus-article-date-iso8601
+              "s" #'gnus-article-date-user)
+
+        "E" (define-keymap :prefix 'gnus-summary-wash-empty-map
+              "t" #'gnus-article-remove-trailing-blank-lines
+              "l" #'gnus-article-strip-leading-blank-lines
+              "m" #'gnus-article-strip-multiple-blank-lines
+              "a" #'gnus-article-strip-blank-lines
+              "A" #'gnus-article-strip-all-blank-lines
+              "s" #'gnus-article-strip-leading-space
+              "e" #'gnus-article-strip-trailing-space
+              "w" #'gnus-article-remove-leading-whitespace))
+
+  "H" (define-keymap :prefix 'gnus-summary-help-map
+        "v" #'gnus-version
+        "d" #'gnus-summary-describe-group
+        "h" #'gnus-summary-describe-briefly
+        "i" #'gnus-info-find-node)
+
+  "B" (define-keymap :prefix 'gnus-summary-backend-map
+        "e" #'gnus-summary-expire-articles
+        "\M-\C-e" #'gnus-summary-expire-articles-now
+        "\177" #'gnus-summary-delete-article
+        [delete] #'gnus-summary-delete-article
+        [backspace] #'gnus-summary-delete-article
+        "m" #'gnus-summary-move-article
+        "r" #'gnus-summary-respool-article
+        "w" #'gnus-summary-edit-article
+        "c" #'gnus-summary-copy-article
+        "B" #'gnus-summary-crosspost-article
+        "q" #'gnus-summary-respool-query
+        "t" #'gnus-summary-respool-trace
+        "i" #'gnus-summary-import-article
+        "I" #'gnus-summary-create-article
+        "p" #'gnus-summary-article-posted-p)
+
+  "O" (define-keymap :prefix 'gnus-summary-save-map
+        "o" #'gnus-summary-save-article
+        "m" #'gnus-summary-save-article-mail
+        "F" #'gnus-summary-write-article-file
+        "r" #'gnus-summary-save-article-rmail
+        "f" #'gnus-summary-save-article-file
+        "b" #'gnus-summary-save-article-body-file
+        "B" #'gnus-summary-write-article-body-file
+        "h" #'gnus-summary-save-article-folder
+        "v" #'gnus-summary-save-article-vm
+        "p" #'gnus-summary-pipe-output
+        "P" #'gnus-summary-muttprint)
+
+  "K" (define-keymap :prefix 'gnus-summary-mime-map
+        "b" #'gnus-summary-display-buttonized
+        "m" #'gnus-summary-repair-multipart
+        "v" #'gnus-article-view-part
+        "o" #'gnus-article-save-part
+        "O" #'gnus-article-save-part-and-strip
+        "r" #'gnus-article-replace-part
+        "d" #'gnus-article-delete-part
+        "t" #'gnus-article-view-part-as-type
+        "j" #'gnus-article-jump-to-part
+        "c" #'gnus-article-copy-part
+        "C" #'gnus-article-view-part-as-charset
+        "e" #'gnus-article-view-part-externally
+        "H" #'gnus-article-browse-html-article
+        "E" #'gnus-article-encrypt-body
+        "i" #'gnus-article-inline-part
+        "|" #'gnus-article-pipe-part)
+
+  "X" (define-keymap :prefix 'gnus-uu-extract-map
+        ;;"x" gnus-uu-extract-any
+        "m" #'gnus-summary-save-parts
+        "u" #'gnus-uu-decode-uu
+        "U" #'gnus-uu-decode-uu-and-save
+        "s" #'gnus-uu-decode-unshar
+        "S" #'gnus-uu-decode-unshar-and-save
+        "o" #'gnus-uu-decode-save
+        "O" #'gnus-uu-decode-save
+        "b" #'gnus-uu-decode-binhex
+        "B" #'gnus-uu-decode-binhex
+        "Y" #'gnus-uu-decode-yenc
+        "p" #'gnus-uu-decode-postscript
+        "P" #'gnus-uu-decode-postscript-and-save
+
+        "v" (define-keymap :prefix 'gnus-uu-extract-view-map
+              "u" #'gnus-uu-decode-uu-view
+              "U" #'gnus-uu-decode-uu-and-save-view
+              "s" #'gnus-uu-decode-unshar-view
+              "S" #'gnus-uu-decode-unshar-and-save-view
+              "o" #'gnus-uu-decode-save-view
+              "O" #'gnus-uu-decode-save-view
+              "b" #'gnus-uu-decode-binhex-view
+              "B" #'gnus-uu-decode-binhex-view
+              "p" #'gnus-uu-decode-postscript-view
+              "P" #'gnus-uu-decode-postscript-and-save-view)))
 
 (defvar gnus-article-post-menu nil)
 
@@ -4357,7 +4355,8 @@ If SELECT-ARTICLES, only select those articles from 
GROUP."
     result))
 
 (defun gnus-sort-gathered-threads (threads)
-  "Sort subthreads inside each gathered thread by 
`gnus-sort-gathered-threads-function'."
+  "Sort subthreads inside each gathered thread.
+Sorting is done by `gnus-sort-gathered-threads-function'."
   (let ((result threads))
     (while threads
       (when (stringp (caar threads))
@@ -5173,7 +5172,7 @@ Unscored articles will be counted as having a score of 
zero."
   (gnus-article-sort-by-number h1 h2))
 
 (defun gnus-thread-sort-by-most-recent-number (h1 h2)
-  "Sort threads such that the thread with the most recently arrived article 
comes first."
+  "Sort threads such that the thread with most recently arrived article is 
first."
   (> (gnus-thread-highest-number h1) (gnus-thread-highest-number h2)))
 
 (defun gnus-thread-highest-number (thread)
@@ -5187,7 +5186,7 @@ Unscored articles will be counted as having a score of 
zero."
   (gnus-article-sort-by-date h1 h2))
 
 (defun gnus-thread-sort-by-most-recent-date (h1 h2)
-  "Sort threads such that the thread with the most recently dated article 
comes first."
+  "Sort threads such that the thread with most recently dated article is 
first."
   (> (gnus-thread-latest-date h1) (gnus-thread-latest-date h2)))
 
 (defsubst gnus-article-sort-by-newsgroups (h1 h2)
@@ -5651,7 +5650,7 @@ or a straight list of headers."
         gnus-list-identifiers)))
 
 (defun gnus-summary-remove-list-identifiers ()
-  "Remove list identifiers in `gnus-list-identifiers' from articles in the 
current group."
+  "Remove identifiers in `gnus-list-identifiers' from articles in current 
group."
   (let ((regexp (gnus-group-get-list-identifiers gnus-newsgroup-name))
         changed subject)
     (when regexp
@@ -8066,9 +8065,7 @@ Return nil if there are no unread articles."
 Return nil if there are no unread articles."
   (interactive nil gnus-summary-mode)
   (prog1
-      (when (gnus-summary-first-subject t)
-       (gnus-summary-show-thread)
-       (gnus-summary-first-subject t))
+      (gnus-summary--goto-and-possibly-unhide t)
     (gnus-summary-position-point)))
 
 (defun gnus-summary-next-unseen-article (&optional backward)
@@ -8102,23 +8099,27 @@ Return nil if there are no unread articles."
 Return nil if there are no unseen articles."
   (interactive nil gnus-summary-mode)
   (prog1
-      (when (gnus-summary-first-subject nil nil t)
-       (gnus-summary-show-thread)
-       (gnus-summary-first-subject nil nil t))
+      (gnus-summary--goto-and-possibly-unhide)
     (gnus-summary-position-point)))
 
+(defun gnus-summary--goto-and-possibly-unhide (&optional unread undownloaded
+                                                         unseen)
+  (let ((first (gnus-summary-first-subject unread undownloaded unseen)))
+    (if (and first
+             (not (= first (gnus-summary-article-number))))
+        (progn
+          (gnus-summary-show-thread)
+          (gnus-summary-first-subject unread undownloaded unseen))
+      first)))
+
 (defun gnus-summary-first-unseen-or-unread-subject ()
   "Place the point on the subject line of the first unseen and unread article.
 If all articles have been seen, on the subject line of the first unread
 article."
   (interactive nil gnus-summary-mode)
   (prog1
-      (unless (when (gnus-summary-first-subject nil nil t)
-               (gnus-summary-show-thread)
-               (gnus-summary-first-subject nil nil t))
-       (when (gnus-summary-first-subject t)
-         (gnus-summary-show-thread)
-         (gnus-summary-first-subject t)))
+      (unless (gnus-summary--goto-and-possibly-unhide nil nil t)
+        (gnus-summary-first-subject t))
     (gnus-summary-position-point)))
 
 (defun gnus-summary-first-article ()
@@ -8589,9 +8590,8 @@ If UNREPLIED (the prefix), limit to unreplied articles."
   (interactive "P" gnus-summary-mode)
   (if unreplied
       (gnus-summary-limit
-       (seq-difference gnus-newsgroup-articles
-                       gnus-newsgroup-replied
-                       #'eq))
+       (gnus-set-difference gnus-newsgroup-articles
+       gnus-newsgroup-replied))
     (gnus-summary-limit gnus-newsgroup-replied))
   (gnus-summary-position-point))
 
diff --git a/lisp/gnus/gnus-topic.el b/lisp/gnus/gnus-topic.el
index c8bcccdfdd..e78dd1542c 100644
--- a/lisp/gnus/gnus-topic.el
+++ b/lisp/gnus/gnus-topic.el
@@ -1056,63 +1056,56 @@ articles in the topic and its subtopics."
 
 ;;; Topic mode, commands and keymap.
 
-(defvar gnus-topic-mode-map nil)
-(defvar gnus-group-topic-map nil)
-
-(unless gnus-topic-mode-map
-  (setq gnus-topic-mode-map (make-sparse-keymap))
-
+(defvar-keymap gnus-topic-mode-map
   ;; Override certain group mode keys.
-  (gnus-define-keys gnus-topic-mode-map
-    "=" gnus-topic-select-group
-    "\r" gnus-topic-select-group
-    " " gnus-topic-read-group
-    "\C-c\C-x" gnus-topic-expire-articles
-    "c" gnus-topic-catchup-articles
-    "\C-k" gnus-topic-kill-group
-    "\C-y" gnus-topic-yank-group
-    "\M-g" gnus-topic-get-new-news-this-topic
-    "AT" gnus-topic-list-active
-    "Gp" gnus-topic-edit-parameters
-    "#" gnus-topic-mark-topic
-    "\M-#" gnus-topic-unmark-topic
-    [tab] gnus-topic-indent
-    [(meta tab)] gnus-topic-unindent
-    "\C-i" gnus-topic-indent
-    "\M-\C-i" gnus-topic-unindent
-    [mouse-2] gnus-mouse-pick-topic)
-
-  ;; Define a new submap.
-  (gnus-define-keys (gnus-group-topic-map "T" gnus-group-mode-map)
-    "#" gnus-topic-mark-topic
-    "\M-#" gnus-topic-unmark-topic
-    "n" gnus-topic-create-topic
-    "m" gnus-topic-move-group
-    "D" gnus-topic-remove-group
-    "c" gnus-topic-copy-group
-    "h" gnus-topic-hide-topic
-    "s" gnus-topic-show-topic
-    "j" gnus-topic-jump-to-topic
-    "M" gnus-topic-move-matching
-    "C" gnus-topic-copy-matching
-    "\M-p" gnus-topic-goto-previous-topic
-    "\M-n" gnus-topic-goto-next-topic
-    "\C-i" gnus-topic-indent
-    [tab] gnus-topic-indent
-    "r" gnus-topic-rename
-    "\177" gnus-topic-delete
-    [delete] gnus-topic-delete
-    "H" gnus-topic-toggle-display-empty-topics)
-
-  (gnus-define-keys (gnus-topic-sort-map "S" gnus-group-topic-map)
-    "s" gnus-topic-sort-groups
-    "a" gnus-topic-sort-groups-by-alphabet
-    "u" gnus-topic-sort-groups-by-unread
-    "l" gnus-topic-sort-groups-by-level
-    "e" gnus-topic-sort-groups-by-server
-    "v" gnus-topic-sort-groups-by-score
-    "r" gnus-topic-sort-groups-by-rank
-    "m" gnus-topic-sort-groups-by-method))
+  "=" #'gnus-topic-select-group
+  "\r" #'gnus-topic-select-group
+  " " #'gnus-topic-read-group
+  "\C-c\C-x" #'gnus-topic-expire-articles
+  "c" #'gnus-topic-catchup-articles
+  "\C-k" #'gnus-topic-kill-group
+  "\C-y" #'gnus-topic-yank-group
+  "\M-g" #'gnus-topic-get-new-news-this-topic
+  "AT" #'gnus-topic-list-active
+  "Gp" #'gnus-topic-edit-parameters
+  "#" #'gnus-topic-mark-topic
+  "\M-#" #'gnus-topic-unmark-topic
+  [tab] #'gnus-topic-indent
+  [(meta tab)] #'gnus-topic-unindent
+  "\C-i" #'gnus-topic-indent
+  "\M-\C-i" #'gnus-topic-unindent
+  [mouse-2] #'gnus-mouse-pick-topic
+
+  "T" (define-keymap :prefix 'gnus-group-topic-map
+        "#" #'gnus-topic-mark-topic
+        "\M-#" #'gnus-topic-unmark-topic
+        "n" #'gnus-topic-create-topic
+        "m" #'gnus-topic-move-group
+        "D" #'gnus-topic-remove-group
+        "c" #'gnus-topic-copy-group
+        "h" #'gnus-topic-hide-topic
+        "s" #'gnus-topic-show-topic
+        "j" #'gnus-topic-jump-to-topic
+        "M" #'gnus-topic-move-matching
+        "C" #'gnus-topic-copy-matching
+        "\M-p" #'gnus-topic-goto-previous-topic
+        "\M-n" #'gnus-topic-goto-next-topic
+        "\C-i" #'gnus-topic-indent
+        [tab] #'gnus-topic-indent
+        "r" #'gnus-topic-rename
+        "\177" #'gnus-topic-delete
+        [delete] #'gnus-topic-delete
+        "H" #'gnus-topic-toggle-display-empty-topics
+
+        "S" (define-keymap :prefix 'gnus-topic-sort-map
+              "s" #'gnus-topic-sort-groups
+              "a" #'gnus-topic-sort-groups-by-alphabet
+              "u" #'gnus-topic-sort-groups-by-unread
+              "l" #'gnus-topic-sort-groups-by-level
+              "e" #'gnus-topic-sort-groups-by-server
+              "v" #'gnus-topic-sort-groups-by-score
+              "r" #'gnus-topic-sort-groups-by-rank
+              "m" #'gnus-topic-sort-groups-by-method)))
 
 (defun gnus-topic-make-menu-bar ()
   (unless (boundp 'gnus-topic-menu)
diff --git a/lisp/gnus/gnus-undo.el b/lisp/gnus/gnus-undo.el
index 64ed2bbad6..0717a7ccfb 100644
--- a/lisp/gnus/gnus-undo.el
+++ b/lisp/gnus/gnus-undo.el
@@ -75,15 +75,12 @@
 
 ;;; Minor mode definition.
 
-(defvar gnus-undo-mode-map
-  (let ((map (make-sparse-keymap)))
-    (gnus-define-keys map
-      "\M-\C-_"     gnus-undo
-      "\C-_"        gnus-undo
-      "\C-xu"       gnus-undo
-      ;; many people are used to type `C-/' on X terminals and get `C-_'.
-      [(control /)] gnus-undo)
-    map))
+(defvar-keymap gnus-undo-mode-map
+  "\M-\C-_" #'gnus-undo
+  "\C-_" #'gnus-undo
+  "\C-xu" #'gnus-undo
+  ;; many people are used to type `C-/' on GUI frames and get `C-_'.
+  [(control /)] #'gnus-undo)
 
 (defun gnus-undo-make-menu-bar ()
   ;; This is disabled for the time being.
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index fb285962d6..a777157f89 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -300,25 +300,26 @@ Symbols are also allowed; their print names are used 
instead."
 
 (defmacro gnus-local-set-keys (&rest plist)
   "Set the keys in PLIST in the current keymap."
-  (declare (indent 1))
+  (declare (obsolete define-keymap "29.1") (indent 1))
   `(gnus-define-keys-1 (current-local-map) ',plist))
 
 (defmacro gnus-define-keys (keymap &rest plist)
   "Define all keys in PLIST in KEYMAP."
-  (declare (indent 1))
+  (declare (obsolete define-keymap "29.1") (indent 1))
   `(gnus-define-keys-1 ,(if (symbolp keymap) keymap `',keymap) (quote ,plist)))
 
 (defmacro gnus-define-keys-safe (keymap &rest plist)
   "Define all keys in PLIST in KEYMAP without overwriting previous 
definitions."
-  (declare (indent 1))
+  (declare (obsolete define-keymap "29.1") (indent 1))
   `(gnus-define-keys-1 (quote ,keymap) (quote ,plist) t))
 
 (defmacro gnus-define-keymap (keymap &rest plist)
   "Define all keys in PLIST in KEYMAP."
-  (declare (indent 1))
+  (declare (obsolete define-keymap "29.1") (indent 1))
   `(gnus-define-keys-1 ,keymap (quote ,plist)))
 
 (defun gnus-define-keys-1 (keymap plist &optional safe)
+  (declare (obsolete define-keymap "29.1"))
   (when (null keymap)
     (error "Can't set keys in a null keymap"))
   (cond ((symbolp keymap) (error "First arg should be a keymap object"))
@@ -1310,9 +1311,7 @@ SPEC is a predicate specifier that contains stuff like 
`or', `and',
                                     initial-input history def)
   "Call `gnus-completing-read-function'."
   (funcall gnus-completing-read-function
-           (concat prompt (when def
-                            (concat " (default " def ")"))
-                   ": ")
+           (format-prompt prompt def)
            collection require-match initial-input history def))
 
 (defun gnus-emacs-completing-read (prompt collection &optional require-match
diff --git a/lisp/gnus/gnus-uu.el b/lisp/gnus/gnus-uu.el
index f7b761ee33..778a8a3ea0 100644
--- a/lisp/gnus/gnus-uu.el
+++ b/lisp/gnus/gnus-uu.el
@@ -579,7 +579,7 @@ didn't work, and overwrite existing files.  Otherwise, ask 
each time."
 (defun gnus-new-processable (unmarkp articles)
   (if unmarkp
       (nreverse (seq-intersection gnus-newsgroup-processable articles #'eq))
-    (seq-difference articles gnus-newsgroup-processable #'eq)))
+    (gnus-set-difference articles gnus-newsgroup-processable)))
 
 (defun gnus-uu-mark-by-regexp (regexp &optional unmark)
   "Set the process mark on articles whose subjects match REGEXP.
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index f558360361..9b3181fd4d 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -2537,7 +2537,7 @@ are always t.")
      ;; Only used in gnus-util, which has an autoload.
      ("rmailsum" rmail-update-summary)
      ("gnus-xmas" gnus-xmas-splash)
-     ("score-mode" :interactive t gnus-score-mode)
+     ("score-mode" :interactive t gnus-score-mode gnus-score-edit-all-score)
      ("gnus-mh" gnus-summary-save-article-folder
       gnus-Folder-save-name gnus-folder-save-name)
      ("gnus-mh" :interactive (gnus-summary-mode) gnus-summary-save-in-folder)
@@ -2609,7 +2609,11 @@ are always t.")
       gnus-uu-decode-uu-and-save-view gnus-uu-decode-unshar-view
       gnus-uu-decode-unshar-and-save-view gnus-uu-decode-save-view
       gnus-uu-decode-binhex-view gnus-uu-unmark-thread
-      gnus-uu-mark-over gnus-uu-post-news gnus-uu-invert-processable)
+      gnus-uu-mark-over gnus-uu-post-news gnus-uu-invert-processable
+      gnus-uu-decode-postscript-and-save-view
+      gnus-uu-decode-postscript-view gnus-uu-decode-postscript-and-save
+      gnus-uu-decode-yenc gnus-uu-unmark-by-regexp gnus-uu-unmark-region
+      gnus-uu-decode-postscript)
      ("gnus-uu" gnus-uu-delete-work-dir gnus-uu-unmark-thread)
      ("gnus-msg" (gnus-summary-send-map keymap)
       gnus-article-mail gnus-copy-article-buffer gnus-extended-version)
@@ -2656,6 +2660,7 @@ are always t.")
       gnus-article-hide-headers gnus-article-hide-boring-headers
       gnus-article-treat-overstrike
       gnus-article-remove-cr gnus-article-remove-trailing-blank-lines
+      gnus-article-emojize-symbols
       gnus-article-display-x-face gnus-article-de-quoted-unreadable
       gnus-article-de-base64-unreadable
       gnus-article-decode-HZ
@@ -2667,7 +2672,34 @@ are always t.")
       gnus-article-edit-mode gnus-article-edit-article
       gnus-article-edit-done gnus-article-decode-encoded-words
       gnus-start-date-timer gnus-stop-date-timer
-      gnus-mime-view-all-parts)
+      gnus-mime-view-all-parts gnus-article-pipe-part
+      gnus-article-inline-part gnus-article-encrypt-body
+      gnus-article-browse-html-article gnus-article-view-part-externally
+      gnus-article-view-part-as-charset gnus-article-copy-part
+      gnus-article-jump-to-part gnus-article-view-part-as-type
+      gnus-article-delete-part gnus-article-replace-part
+      gnus-article-save-part-and-strip gnus-article-save-part
+      gnus-article-remove-leading-whitespace gnus-article-strip-trailing-space
+      gnus-article-strip-leading-space gnus-article-strip-all-blank-lines
+      gnus-article-strip-blank-lines gnus-article-strip-multiple-blank-lines
+      gnus-article-date-user gnus-article-date-iso8601
+      gnus-article-date-english gnus-article-date-ut
+      gnus-article-decode-charset gnus-article-decode-mime-words
+      gnus-article-toggle-fonts gnus-article-show-images
+      gnus-article-remove-images gnus-article-display-face
+      gnus-article-treat-fold-newsgroups gnus-article-treat-unfold-headers
+      gnus-article-treat-fold-headers gnus-article-highlight-signature
+      gnus-article-highlight-headers gnus-article-highlight
+      gnus-article-strip-banner gnus-article-hide-list-identifiers
+      gnus-article-hide gnus-article-outlook-rearrange-citation
+      gnus-article-treat-non-ascii gnus-article-treat-smartquotes
+      gnus-article-verify-x-pgp-sig gnus-article-strip-headers-in-body
+      gnus-treat-smiley gnus-article-treat-ansi-sequences
+      gnus-article-capitalize-sentences gnus-article-toggle-truncate-lines
+      gnus-article-fill-long-lines gnus-article-emphasize
+      gnus-article-add-buttons-to-head gnus-article-add-button
+      gnus-article-babel gnus-sticky-article gnus-article-view-part
+      gnus-article-add-buttons)
      ("gnus-int" gnus-request-type)
      ("gnus-start" gnus-newsrc-parse-options gnus-1 gnus-no-server-1
       gnus-dribble-enter gnus-read-init-file gnus-dribble-touch
@@ -3754,6 +3786,8 @@ just the host name."
          (setq foreign server
                group (substring group (+ 1 colon))))
        (setq foreign (concat foreign ":")))
+      ;; Remove braces from name (common in IMAP groups).
+      (setq group (replace-regexp-in-string "[][]+" "" group))
       ;; Collapse group name leaving LEVELS uncollapsed elements
       (let* ((slist (split-string group "/"))
             (slen (length slist))
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 4a754b9856..77e8fcdfd1 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -48,6 +48,8 @@
 (require 'puny)
 (require 'rmc)                          ; read-multiple-choice
 (require 'subr-x)
+(require 'yank-media)
+(require 'mailcap)
 
 (autoload 'mailclient-send-it "mailclient")
 
@@ -2395,6 +2397,8 @@ If VERBATIM, use slrn style verbatim marks (\"#v+\" and 
\"#v-\")."
   (save-excursion
     ;; add to the end of the region first, otherwise end would be invalid
     (goto-char end)
+    (unless (bolp)
+      (insert "\n"))
     (insert (if verbatim "#v-\n" message-mark-insert-end))
     (goto-char beg)
     (insert (if verbatim "#v+\n" message-mark-insert-begin))))
@@ -2868,84 +2872,78 @@ Consider adding this function to 
`message-header-setup-hook'"
 
 ;;; Set up keymap.
 
-(defvar message-mode-map nil)
-
-(unless message-mode-map
-  (setq message-mode-map (make-keymap))
-  (set-keymap-parent message-mode-map text-mode-map)
-  (define-key message-mode-map "\C-c?" #'describe-mode)
-
-  (define-key message-mode-map "\C-c\C-f\C-t" #'message-goto-to)
-  (define-key message-mode-map "\C-c\C-f\C-o" #'message-goto-from)
-  (define-key message-mode-map "\C-c\C-f\C-b" #'message-goto-bcc)
-  (define-key message-mode-map "\C-c\C-f\C-w" #'message-goto-fcc)
-  (define-key message-mode-map "\C-c\C-f\C-c" #'message-goto-cc)
-  (define-key message-mode-map "\C-c\C-f\C-s" #'message-goto-subject)
-  (define-key message-mode-map "\C-c\C-f\C-r" #'message-goto-reply-to)
-  (define-key message-mode-map "\C-c\C-f\C-n" #'message-goto-newsgroups)
-  (define-key message-mode-map "\C-c\C-f\C-d" #'message-goto-distribution)
-  (define-key message-mode-map "\C-c\C-f\C-f" #'message-goto-followup-to)
-  (define-key message-mode-map "\C-c\C-f\C-m" #'message-goto-mail-followup-to)
-  (define-key message-mode-map "\C-c\C-f\C-k" #'message-goto-keywords)
-  (define-key message-mode-map "\C-c\C-f\C-u" #'message-goto-summary)
-  (define-key message-mode-map "\C-c\C-f\C-i"
-    #'message-insert-or-toggle-importance)
-  (define-key message-mode-map "\C-c\C-f\C-a"
-    #'message-generate-unsubscribed-mail-followup-to)
+(defvar-keymap message-mode-map
+  :full t :parent text-mode-map
+  :doc "Message Mode keymap."
+  "\C-c?" #'describe-mode
+
+  "\C-c\C-f\C-t" #'message-goto-to
+  "\C-c\C-f\C-o" #'message-goto-from
+  "\C-c\C-f\C-b" #'message-goto-bcc
+  "\C-c\C-f\C-w" #'message-goto-fcc
+  "\C-c\C-f\C-c" #'message-goto-cc
+  "\C-c\C-f\C-s" #'message-goto-subject
+  "\C-c\C-f\C-r" #'message-goto-reply-to
+  "\C-c\C-f\C-n" #'message-goto-newsgroups
+  "\C-c\C-f\C-d" #'message-goto-distribution
+  "\C-c\C-f\C-f" #'message-goto-followup-to
+  "\C-c\C-f\C-m" #'message-goto-mail-followup-to
+  "\C-c\C-f\C-k" #'message-goto-keywords
+  "\C-c\C-f\C-u" #'message-goto-summary
+  "\C-c\C-f\C-i" #'message-insert-or-toggle-importance
+  "\C-c\C-f\C-a" #'message-generate-unsubscribed-mail-followup-to
 
   ;; modify headers (and insert notes in body)
-  (define-key message-mode-map "\C-c\C-fs"    #'message-change-subject)
+  "\C-c\C-fs"    #'message-change-subject
   ;;
-  (define-key message-mode-map "\C-c\C-fx"    #'message-cross-post-followup-to)
+  "\C-c\C-fx"    #'message-cross-post-followup-to
   ;; prefix+message-cross-post-followup-to = same w/o cross-post
-  (define-key message-mode-map "\C-c\C-ft"    #'message-reduce-to-to-cc)
-  (define-key message-mode-map "\C-c\C-fa"    #'message-add-archive-header)
+  "\C-c\C-ft"    #'message-reduce-to-to-cc
+  "\C-c\C-fa"    #'message-add-archive-header
   ;; mark inserted text
-  (define-key message-mode-map "\C-c\M-m" #'message-mark-inserted-region)
-  (define-key message-mode-map "\C-c\M-f" #'message-mark-insert-file)
-
-  (define-key message-mode-map "\C-c\C-b" #'message-goto-body)
-  (define-key message-mode-map "\C-c\C-i" #'message-goto-signature)
-
-  (define-key message-mode-map "\C-c\C-t" #'message-insert-to)
-  (define-key message-mode-map "\C-c\C-fw" #'message-insert-wide-reply)
-  (define-key message-mode-map "\C-c\C-n" #'message-insert-newsgroups)
-  (define-key message-mode-map "\C-c\C-l" #'message-to-list-only)
-  (define-key message-mode-map "\C-c\C-f\C-e" #'message-insert-expires)
-
-  (define-key message-mode-map "\C-c\C-u" 
#'message-insert-or-toggle-importance)
-  (define-key message-mode-map "\C-c\M-n"
-    #'message-insert-disposition-notification-to)
-
-  (define-key message-mode-map "\C-c\C-y" #'message-yank-original)
-  (define-key message-mode-map "\C-c\M-\C-y" #'message-yank-buffer)
-  (define-key message-mode-map "\C-c\C-q" #'message-fill-yanked-message)
-  (define-key message-mode-map "\C-c\C-w" #'message-insert-signature)
-  (define-key message-mode-map "\C-c\M-h" #'message-insert-headers)
-  (define-key message-mode-map "\C-c\C-r" #'message-caesar-buffer-body)
-  (define-key message-mode-map "\C-c\C-o" #'message-sort-headers)
-  (define-key message-mode-map "\C-c\M-r" #'message-rename-buffer)
-
-  (define-key message-mode-map "\C-c\C-c" #'message-send-and-exit)
-  (define-key message-mode-map "\C-c\C-s" #'message-send)
-  (define-key message-mode-map "\C-c\C-k" #'message-kill-buffer)
-  (define-key message-mode-map "\C-c\C-d" #'message-dont-send)
-  (define-key message-mode-map "\C-c\n" #'gnus-delay-article)
-
-  (define-key message-mode-map "\C-c\M-k" #'message-kill-address)
-  (define-key message-mode-map "\C-c\C-e" #'message-elide-region)
-  (define-key message-mode-map "\C-c\C-v" #'message-delete-not-region)
-  (define-key message-mode-map "\C-c\C-z" #'message-kill-to-signature)
-  (define-key message-mode-map "\M-\r" #'message-newline-and-reformat)
-  (define-key message-mode-map [remap split-line]  #'message-split-line)
-
-  (define-key message-mode-map "\C-c\C-a" #'mml-attach-file)
-  (define-key message-mode-map "\C-c\C-p" #'message-insert-screenshot)
-
-  (define-key message-mode-map "\C-a" #'message-beginning-of-line)
-  (define-key message-mode-map "\t" #'message-tab)
-
-  (define-key message-mode-map "\M-n" #'message-display-abbrev))
+  "\C-c\M-m" #'message-mark-inserted-region
+  "\C-c\M-f" #'message-mark-insert-file
+
+  "\C-c\C-b" #'message-goto-body
+  "\C-c\C-i" #'message-goto-signature
+
+  "\C-c\C-t" #'message-insert-to
+  "\C-c\C-fw" #'message-insert-wide-reply
+  "\C-c\C-n" #'message-insert-newsgroups
+  "\C-c\C-l" #'message-to-list-only
+  "\C-c\C-f\C-e" #'message-insert-expires
+  "\C-c\C-u" #'message-insert-or-toggle-importance
+  "\C-c\M-n" #'message-insert-disposition-notification-to
+
+  "\C-c\C-y" #'message-yank-original
+  "\C-c\M-\C-y" #'message-yank-buffer
+  "\C-c\C-q" #'message-fill-yanked-message
+  "\C-c\C-w" #'message-insert-signature
+  "\C-c\M-h" #'message-insert-headers
+  "\C-c\C-r" #'message-caesar-buffer-body
+  "\C-c\C-o" #'message-sort-headers
+  "\C-c\M-r" #'message-rename-buffer
+
+  "\C-c\C-c" #'message-send-and-exit
+  "\C-c\C-s" #'message-send
+  "\C-c\C-k" #'message-kill-buffer
+  "\C-c\C-d" #'message-dont-send
+  "\C-c\n" #'gnus-delay-article
+
+  "\C-c\M-k" #'message-kill-address
+  "\C-c\C-e" #'message-elide-region
+  "\C-c\C-v" #'message-delete-not-region
+  "\C-c\C-z" #'message-kill-to-signature
+  "\M-\r" #'message-newline-and-reformat
+  [remap split-line]  #'message-split-line
+
+  "\C-c\C-a" #'mml-attach-file
+  "\C-c\C-p" #'message-insert-screenshot
+
+  "\C-a" #'message-beginning-of-line
+  "\t" #'message-tab
+
+  "\M-n" #'message-display-abbrev)
 
 (easy-menu-define
   message-mode-menu message-mode-map "Message Menu."
@@ -3159,6 +3157,7 @@ Like `text-mode', but with these additional commands:
   (setq-local message-checksum nil)
   (setq-local message-mime-part 0)
   (message-setup-fill-variables)
+  (yank-media-handler "image/.*" #'message--yank-media-image-handler)
   (when message-fill-column
     (setq fill-column message-fill-column)
     (turn-on-auto-fill))
@@ -3572,8 +3571,18 @@ Prefix arg means justify as well."
     (when (looking-at message-cite-prefix-regexp)
       (setq quoted (match-string 0))
       (goto-char (match-end 0))
-      (looking-at "[ \t]*")
-      (setq leading-space (match-string 0)))
+      (let ((after (point)))
+        ;; This is a line with no text after the cite prefix.  In that
+        ;; case, the trailing space is commonly not present, so look
+        ;; around for other lines that have some data.
+        (when (looking-at-p "\n")
+          (let ((regexp (concat "^" message-cite-prefix-regexp "[ \t]")))
+            (when (or (re-search-backward regexp nil t)
+                      (re-search-forward regexp nil t))
+              (goto-char (1- (match-end 0))))))
+        (looking-at "[ \t]*")
+        (setq leading-space (match-string 0))
+        (goto-char after)))
     (if (and quoted
             (not not-break)
             (not bolp)
@@ -3590,7 +3599,7 @@ Prefix arg means justify as well."
                      (equal quoted (match-string 0)))
            (goto-char (match-end 0))
            (looking-at "[ \t]*")
-           (when (< (length leading-space) (length (match-string 0)))
+           (when (> (length leading-space) (length (match-string 0)))
              (setq leading-space (match-string 0)))
            (forward-line 1))
          (setq end (point))
@@ -5346,7 +5355,7 @@ Otherwise, generate and save a value for 
`canlock-password' first."
                   (zerop
                    (length
                     (setq to (completing-read
-                              "Followups to (default no Followup-To header): "
+                               (format-prompt "Followups to" "no Followup-To 
header")
                               (mapcar #'list
                                       (cons "poster"
                                             (message-tokenize-header
@@ -8867,24 +8876,29 @@ used to take the screenshot."
                  (car message-screenshot-command) nil (current-buffer) nil
                  (cdr message-screenshot-command))
           (buffer-string))))
-    (set-mark (point))
-    (insert-image
-     (create-image image 'png t
-                  :max-width (truncate (* (frame-pixel-width) 0.8))
-                  :max-height (truncate (* (frame-pixel-height) 0.8))
-                  :scale 1)
-     (format "<#part type=\"image/png\" disposition=inline 
data-encoding=base64 raw=t>\n%s\n<#/part>"
-            ;; Get a base64 version of the image -- this avoids later
-            ;; complications if we're auto-saving the buffer and
-            ;; restoring from a file.
-            (with-temp-buffer
-              (set-buffer-multibyte nil)
-              (insert image)
-              (base64-encode-region (point-min) (point-max) t)
-              (buffer-string))))
-    (insert "\n\n")
+    (message--yank-media-image-handler 'image/png image)
     (message "")))
 
+(defun message--yank-media-image-handler (type image)
+  (set-mark (point))
+  (insert-image
+   (create-image image (mailcap-mime-type-to-extension type) t
+                :max-width (truncate (* (frame-pixel-width) 0.8))
+                :max-height (truncate (* (frame-pixel-height) 0.8))
+                :scale 1)
+   (format "<#part type=\"%s\" disposition=inline data-encoding=base64 
raw=t>\n%s\n<#/part>"
+           type
+          ;; Get a base64 version of the image -- this avoids later
+          ;; complications if we're auto-saving the buffer and
+          ;; restoring from a file.
+          (with-temp-buffer
+            (set-buffer-multibyte nil)
+            (insert image)
+            (base64-encode-region (point-min) (point-max) t)
+            (buffer-string)))
+   nil nil t)
+  (insert "\n\n"))
+
 (declare-function gnus-url-unhex-string "gnus-util")
 
 (defun message-parse-mailto-url (url)
diff --git a/lisp/gnus/mm-uu.el b/lisp/gnus/mm-uu.el
index 494221adee..a52613a092 100644
--- a/lisp/gnus/mm-uu.el
+++ b/lisp/gnus/mm-uu.el
@@ -145,6 +145,14 @@ This can be either \"inline\" or \"attachment\".")
      ,#'mm-uu-pgp-key-extract
      ,#'mm-uu-gpg-key-skip-to-last
      nil)
+    (markdown-emacs-sources
+     "^```\\(?:elisp\\|emacs-lisp\\|\n(\\)"
+     "^```$"
+     ,#'mm-uu-emacs-sources-extract)
+    (markdown-diff ;; this should be higher than `git-format-patch'
+     "^```\\(?:diff\\|patch\\|\ndiff --git \\)"
+     "^```$"
+     ,#'mm-uu-diff-extract)
     (emacs-sources
      "^;;;?[ \t]*[^ \t]+\\.el[ \t]*--"
      "^;;;?[ \t]*\\([^ \t]+\\.el\\)[ \t]+ends here"
diff --git a/lisp/gnus/mm-view.el b/lisp/gnus/mm-view.el
index 129295474f..d2a6d2cf5d 100644
--- a/lisp/gnus/mm-view.el
+++ b/lisp/gnus/mm-view.el
@@ -50,9 +50,7 @@
     (w3m . mm-inline-text-html-render-with-w3m)
     (w3m-standalone . mm-inline-text-html-render-with-w3m-standalone)
     (gnus-w3m . gnus-article-html)
-    (links mm-inline-render-with-file
-          mm-links-remove-leading-blank
-          "links" "-dump" file)
+    (links . mm-inline-render-with-links)
     (lynx mm-inline-render-with-stdin nil
          "lynx" "-dump" "-force_html" "-stdin" "-nolist")
     (html2text mm-inline-render-with-function html2text))
@@ -264,6 +262,7 @@ This is only used if `mm-inline-large-images' is set to
     (mm-inline-render-with-stdin handle nil "w3m" "-dump" "-T" "text/html")))
 
 (defun mm-links-remove-leading-blank ()
+  (declare (obsolete nil "28.1"))
   ;; Delete the annoying three spaces preceding each line of links
   ;; output.
   (goto-char (point-min))
@@ -271,6 +270,7 @@ This is only used if `mm-inline-large-images' is set to
     (delete-region (match-beginning 0) (match-end 0))))
 
 (defun mm-inline-wash-with-file (post-func cmd &rest args)
+  (declare (obsolete nil "28.1"))
   (with-suppressed-warnings ((lexical file))
     (dlet ((file (make-temp-file
                  (expand-file-name "mm" mm-tmp-directory))))
@@ -290,12 +290,41 @@ This is only used if `mm-inline-large-images' is set to
   (and post-func (funcall post-func)))
 
 (defun mm-inline-render-with-file (handle post-func cmd &rest args)
+  (declare (obsolete nil "28.1"))
   (let ((source (mm-get-part handle)))
     (mm-insert-inline
      handle
      (mm-with-unibyte-buffer
        (insert source)
-       (apply #'mm-inline-wash-with-file post-func cmd args)
+       (with-suppressed-warnings ((obsolete mm-inline-wash-with-file))
+         (apply #'mm-inline-wash-with-file post-func cmd args))
+       (buffer-string)))))
+
+(defun mm-inline-render-with-links (handle)
+  (let ((source (mm-get-part handle))
+        file charset)
+    (mm-insert-inline
+     handle
+     (with-temp-buffer
+       (setq charset (mail-content-type-get (mm-handle-type handle) 'charset))
+       (insert source)
+       (unwind-protect
+           (progn
+             (setq file (make-temp-file (expand-file-name
+                                         "mm" mm-tmp-directory)))
+             (let ((coding-system-for-write 'binary))
+               (write-region (point-min) (point-max) file nil 'silent))
+             (delete-region (point-min) (point-max))
+             (if charset
+                 (with-environment-variables (("LANG" (format "en-US.%s"
+                                                              charset)))
+                  (call-process "links" nil t nil "-dump" file))
+               (call-process "links" nil t nil "-dump" file))
+             (goto-char (point-min))
+             (while (re-search-forward "^   " nil t)
+               (delete-region (match-beginning 0) (match-end 0))))
+         (when (and file (file-exists-p file))
+           (delete-file file)))
        (buffer-string)))))
 
 (defun mm-inline-render-with-stdin (handle post-func cmd &rest args)
@@ -422,7 +451,7 @@ This is only used if `mm-inline-large-images' is set to
 
 (defvar mm-inline-message-prepare-function nil
   "Function called by `mm-inline-message' to do client specific setup.
-It is called with one parameter -- the charset.")
+It is called with two parameters -- the MIME handle and the charset.")
 
 (defun mm-inline-message (handle)
   "Insert HANDLE (a message/rfc822 part) into the current buffer.
@@ -442,7 +471,7 @@ after inserting the part."
        (narrow-to-region b b)
        (mm-insert-part handle)
         (when mm-inline-message-prepare-function
-         (funcall mm-inline-message-prepare-function charset))
+         (funcall mm-inline-message-prepare-function handle charset))
        (goto-char (point-min))
        (unless bolp
          (insert "\n"))
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index b49793509f..f72d76ac02 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -238,7 +238,7 @@ You can also customize or set `mml-signencrypt-style-alist' 
instead."
             (goto-char (match-end 0))
             (apply #'mml-insert-tag 'part (cons (if sign 'sign 'encrypt)
                                                (cons method tags))))
-           (t (error "The message is corrupted. No mail header separator"))))))
+            (t (error "The message is corrupted.  No mail header 
separator"))))))
 
 (defvar mml-secure-method
   (if (equal mml-default-encrypt-method mml-default-sign-method)
@@ -328,7 +328,7 @@ either an error is raised or not."
            (unless (yes-or-no-p "Message for encryption contains Bcc header.\
   This may give away all Bcc'ed identities to all recipients.\
   Are you sure that this is safe?\
-  (Customize `mml-secure-safe-bcc-list' to avoid this warning.) ")
+  (Customize `mml-secure-safe-bcc-list' to avoid this warning.)")
              (error "Aborted"))))))))
 
 ;; defuns that add the proper <#secure ...> tag to the top of the message body
@@ -352,7 +352,7 @@ either an error is raised or not."
               (apply #'mml-insert-tag
                      'secure 'method method 'mode mode tags)))
            (t (error
-               "The message is corrupted. No mail header separator"))))
+                "The message is corrupted.  No mail header separator"))))
     (when (eql insert-loc (point))
       (forward-line 1))))
 
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 5f35e73cd7..079c1b5122 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -1409,6 +1409,13 @@ to specify options."
   :version "22.1" ;; Gnus 5.10.9
   :group 'message)
 
+(defcustom mml-attach-file-at-the-end nil
+  "If non-nil, \\[mml-attach-file] attaches files at the end of the message.
+If nil, files are attached at point."
+  :type 'boolean
+  :version "29.1"
+  :group 'message)
+
 ;;;###autoload
 (defun mml-attach-file (file &optional type description disposition)
   "Attach a file to the outgoing MIME message.
@@ -1423,6 +1430,8 @@ specifies how the attachment is intended to be displayed. 
 It can
 be either \"inline\" (displayed automatically within the message
 body) or \"attachment\" (separate from the body).
 
+Also see the `mml-attach-file-at-the-end' variable.
+
 If given a prefix interactively, no prompting will be done for
 the TYPE, DESCRIPTION or DISPOSITION values.  Instead defaults
 will be computed and used."
@@ -1440,8 +1449,11 @@ will be computed and used."
                         (mml-minibuffer-read-disposition type nil file))))
      (list file type description disposition)))
   ;; If in the message header, attach at the end and leave point unchanged.
-  (let ((head (unless (message-in-body-p) (point))))
-    (if head (goto-char (point-max)))
+  (let ((at-end (and (or (not (message-in-body-p))
+                         mml-attach-file-at-the-end)
+                     (point))))
+    (when at-end
+      (goto-char (point-max)))
     (mml-insert-empty-tag 'part
                          'type type
                          ;; icicles redefines read-file-name and returns a
@@ -1451,13 +1463,13 @@ will be computed and used."
                          'description description)
     ;; When using Mail mode, make sure it does the mime encoding
     ;; when you send the message.
-    (or (eq mail-user-agent 'message-user-agent)
-       (setq mail-encode-mml t))
-    (when head
+    (unless (eq mail-user-agent 'message-user-agent)
+      (setq mail-encode-mml t))
+    (when at-end
       (unless (pos-visible-in-window-p)
        (message "The file \"%s\" has been attached at the end of the message"
                 (file-name-nondirectory file)))
-      (goto-char head))))
+      (goto-char at-end))))
 
 (defun mml-dnd-attach-file (uri _action)
   "Attach a drag and drop file.
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 8a48cd87db..b7082696b2 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -429,8 +429,18 @@ during splitting, which may be slow."
                       now
                       (nnimap-last-command-time nnimap-object))))
             (with-local-quit
-              (ignore-errors          ;E.g. "buffer foo has no process".
-                (nnimap-send-command "NOOP")))))))))
+              (ignore-errors        ;E.g. "buffer foo has no process".
+                (nnimap-send-command "NOOP"))
+              ;; If our connection has died in the meantime, clean it
+              ;; and its buffer up.
+              (unless (process-live-p (get-buffer-process buffer))
+               (setq nnimap-process-buffers
+                     (delq buffer nnimap-process-buffers))
+               (setq nnimap-connection-alist
+                     (seq-filter (lambda (elt)
+                                   (null (eq buffer (cdr elt))))
+                                 nnimap-connection-alist))
+               (kill-buffer buffer)))))))))
 
 (defun nnimap-open-connection (buffer)
   ;; Be backwards-compatible -- the earlier value of nnimap-stream was
@@ -662,10 +672,17 @@ during splitting, which may be slow."
 
 (deffoo nnimap-close-server (&optional server defs)
   (when (nnoo-change-server 'nnimap server defs)
-    (ignore-errors
-      (delete-process (get-buffer-process (nnimap-buffer))))
-    (nnoo-close-server 'nnimap server)
-    t))
+    (let ((buf (nnimap-buffer)))
+      (ignore-errors
+        (delete-process (get-buffer-process buf)))
+      (setq nnimap-process-buffers
+            (delq buf nnimap-process-buffers)
+            nnimap-connection-alist
+           (seq-filter (lambda (elt)
+                         (null (eq buf (cdr elt))))
+                       nnimap-connection-alist))
+      (nnoo-close-server 'nnimap server)
+      t)))
 
 (deffoo nnimap-request-close ()
   t)
@@ -1638,15 +1655,13 @@ If LIMIT, first try to limit the search to the N last 
articles."
              (setq start-article 1))
            (let* ((unread
                    (gnus-compress-sequence
-                     (seq-difference
-                      (seq-difference
+                    (gnus-set-difference
+                     (gnus-set-difference
                       existing
                       (gnus-sorted-union
                        (cdr (assoc '%Seen flags))
-                        (cdr (assoc '%Deleted flags)))
-                       #'eq)
-                      (cdr (assoc '%Flagged flags))
-                      #'eq)))
+                       (cdr (assoc '%Deleted flags))))
+                     (cdr (assoc '%Flagged flags)))))
                   (read (gnus-range-difference
                          (cons start-article high) unread)))
              (when (> start-article 1)
@@ -1939,10 +1954,13 @@ Return the server's response to the SELECT or EXAMINE 
command."
     (when entry
       (if (and (buffer-live-p (cadr entry))
               (get-buffer-process (cadr entry))
-              (memq (process-status (get-buffer-process (cadr entry)))
-                    '(open run)))
+              (process-live-p (get-buffer-process (cadr entry))))
          (get-buffer-process (cadr entry))
-       (setq nnimap-connection-alist (delq entry nnimap-connection-alist))
+       (setq nnimap-connection-alist (delq entry nnimap-connection-alist)
+              nnimap-process-buffers
+             (delq (cadr entry) nnimap-process-buffers))
+       (when (buffer-live-p (cadr entry))
+         (kill-buffer (cadr entry)))
        nil))))
 
 ;; Leave room for `open-network-stream' to issue a couple of IMAP
@@ -2289,7 +2307,7 @@ Return the server's response to the SELECT or EXAMINE 
command."
          nnimap-incoming-split-list)))
 
 (defun nnimap-make-thread-query (header)
-  (let* ((id  (mail-header-id header))
+  (let* ((id (substring-no-properties (mail-header-id header)))
         (refs (split-string
                (or (mail-header-references header)
                    "")))
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 171f0813b3..690761a2d6 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -194,7 +194,15 @@ This variable is set by `nnmaildir-request-article'.")
         (article-file (concat curdir prefix suffix))
         (new-name (concat curdir prefix new-suffix)))
     (unless (file-exists-p article-file)
-      (error "Couldn't find article file %s" article-file))
+      (let ((possible (file-expand-wildcards (concat curdir prefix "*"))))
+       (cond ((length= possible 1)
+              (unless (string-match-p "\\`\\(.+\\):2,.*?\\'" (car possible))
+                (error "Couldn't find updated article file %s" article-file))
+              (setq article-file (car possible)))
+             ((length> possible 1)
+              (error "Couldn't determine exact article file %s" article-file))
+             ((null possible)
+              (error "Couldn't find article file %s" article-file)))))
     (rename-file article-file new-name 'replace)
     (setf (nnmaildir--art-suffix article) new-suffix)))
 
diff --git a/lisp/gnus/nnrss.el b/lisp/gnus/nnrss.el
index 97c9f18a60..0ac57e9e17 100644
--- a/lisp/gnus/nnrss.el
+++ b/lisp/gnus/nnrss.el
@@ -715,7 +715,7 @@ Read the file and attempt to subscribe to each Feed in the 
file."
        (when (and xmlurl
                  (not (string-match "\\`[\t ]*\\'" xmlurl))
                  (prog1
-                     (y-or-n-p (format "Subscribe to %s " xmlurl))
+                      (y-or-n-p (format "Subscribe to %s?" xmlurl))
                    (message "")))
         (condition-case err
             (progn
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index 615a3c931b..25289655bf 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -331,9 +331,7 @@ retried once before actually displaying the error report."
     (when nntp-record-commands
       (nntp-record-command "*** CALLED nntp-report ***"))
 
-    (nnheader-report 'nntp args)
-
-    (apply #'error args)))
+    (nnheader-report 'nntp args)))
 
 (defsubst nntp-copy-to-buffer (buffer start end)
   "Copy string from unibyte current buffer to multibyte buffer."
diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el
index 03a0ff296f..41a2da958a 100644
--- a/lisp/gnus/nnvirtual.el
+++ b/lisp/gnus/nnvirtual.el
@@ -382,7 +382,10 @@ It is computed from the marks of individual component 
groups.")
 
 
 (defun nnvirtual-update-xref-header (group article prefix sysname)
-  "Edit current NOV header in current buffer to have an xref to the component 
group, and also server prefix any existing xref lines."
+  "Edit current NOV header to have xref to component group and correct prefix.
+This function edits the current NOV header in current buffer so that it
+has an xref to the component group, and also ensures any existing xref
+lines have the correct component server prefix."
   ;; Move to beginning of Xref field, creating a slot if needed.
   (beginning-of-line)
   (looking-at
@@ -569,7 +572,9 @@ If UPDATE-P is not nil, call gnus-group-update-group on the 
components."
 ;; unique reverse mapping.
 
 (defun nnvirtual-map-article (article)
-  "Return a cons of the component group and article corresponding to the given 
virtual ARTICLE."
+  "Return the component group and article corresponding to virtual ARTICLE.
+Value is a cons of the component group and article corresponding to the given
+virtual ARTICLE."
   (let ((table nnvirtual-mapping-table)
        entry group-pos)
     (while (and table
@@ -590,7 +595,7 @@ If UPDATE-P is not nil, call gnus-group-update-group on the 
components."
 
 
 (defun nnvirtual-reverse-map-article (group article)
-  "Return the virtual article number corresponding to the given component 
GROUP and ARTICLE."
+  "Return virtual article number corresponding to component GROUP and ARTICLE."
   (when (numberp article)
     (let ((table nnvirtual-mapping-table)
          (group-pos 0)
diff --git a/lisp/gnus/spam.el b/lisp/gnus/spam.el
index 3f978918b9..cfef69f103 100644
--- a/lisp/gnus/spam.el
+++ b/lisp/gnus/spam.el
@@ -663,13 +663,13 @@ order for SpamAssassin to recognize the new registered 
spam."
 
 ;;; Key bindings for spam control.
 
-(gnus-define-keys gnus-summary-mode-map
-  "St" spam-generic-score
-  "Sx" gnus-summary-mark-as-spam
-  "Mst" spam-generic-score
-  "Msx" gnus-summary-mark-as-spam
-  "\M-d" gnus-summary-mark-as-spam
-  "$" gnus-summary-mark-as-spam)
+(define-keymap :keymap gnus-summary-mode-map
+  "St" #'spam-generic-score
+  "Sx" #'gnus-summary-mark-as-spam
+  "Mst" #'spam-generic-score
+  "Msx" #'gnus-summary-mark-as-spam
+  "\M-d" #'gnus-summary-mark-as-spam
+  "$" #'gnus-summary-mark-as-spam)
 
 (defvar spam-cache-lookups t
   "Whether spam.el will try to cache lookups using `spam-caches'.")
@@ -710,8 +710,16 @@ finds ham or spam.")
 (defun spam-set-difference (list1 list2)
   "Return a set difference of LIST1 and LIST2.
 When either list is nil, the other is returned."
-  (declare (obsolete seq-difference "28.1"))
-  (seq-difference list1 list2 #'eq))
+  (if (and list1 list2)
+      ;; we have two non-nil lists
+      (progn
+        (dolist (item (append list1 list2))
+          (when (and (memq item list1) (memq item list2))
+            (setq list1 (delq item list1))
+            (setq list2 (delq item list2))))
+        (append list1 list2))
+    ;; if either of the lists was nil, return the other one
+    (if list1 list1 list2)))
 
 (defun spam-group-ham-mark-p (group mark &optional spam)
   "Checks if MARK is considered a ham mark in GROUP."
@@ -1319,7 +1327,7 @@ In the case of mover backends, checks the setting of
              (new-articles (spam-list-articles
                             gnus-newsgroup-articles
                             classification))
-             (changed-articles (seq-difference new-articles old-articles 
#'eq)))
+             (changed-articles (spam-set-difference new-articles 
old-articles)))
         ;; now that we have the changed articles, we go through the processors
         (dolist (backend (spam-backend-list))
           (let (unregister-list)
diff --git a/lisp/help-at-pt.el b/lisp/help-at-pt.el
index 233c50504b..8eb397bc82 100644
--- a/lisp/help-at-pt.el
+++ b/lisp/help-at-pt.el
@@ -229,11 +229,11 @@ this option, or use \"In certain situations\" and specify 
no text
 properties, to enable buffer local values."
                         never))
   :initialize 'custom-initialize-default
-  :set #'(lambda (variable value)
-          (set-default variable value)
-          (if (eq value 'never)
-              (help-at-pt-cancel-timer)
-            (help-at-pt-set-timer)))
+  :set (lambda (variable value)
+         (set-default variable value)
+         (if (eq value 'never)
+             (help-at-pt-cancel-timer)
+           (help-at-pt-set-timer)))
   :set-after '(help-at-pt-timer-delay)
   :require 'help-at-pt)
 
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 6be5cd4a50..17fabe4f63 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -176,8 +176,11 @@ with the current prefix.  The files are chosen according to
           completions))
 
 (defun help--symbol-completion-table (string pred action)
-  (if (and completions-detailed (eq action 'metadata))
-      '(metadata (affixation-function . 
help--symbol-completion-table-affixation))
+  (if (eq action 'metadata)
+      `(metadata
+        ,@(when completions-detailed
+            '((affixation-function . 
help--symbol-completion-table-affixation)))
+        (category . symbol-help))
     (when help-enable-completion-autoload
       (let ((prefixes (radix-tree-prefixes (help-definition-prefixes) string)))
         (help--load-prefixes prefixes)))
@@ -820,7 +823,7 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
                            ;; Advised & aliased function.
                            (and advised (symbolp real-function)
                                 (not (eq 'autoload (car-safe def))))
-                           (and (subrp def)
+                           (and (subrp def) (symbolp function)
                                 (not (string= (subr-name def)
                                               (symbol-name function)))))))
         (real-def (cond
@@ -1558,7 +1561,7 @@ If FRAME is omitted or nil, use the selected frame."
                  (:fontset . "Fontset")
                   (:extend . "Extend")
                  (:inherit . "Inherit")))
-        (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x)))
+         (max-width (apply #'max (mapcar (lambda (x) (length (cdr x)))
                                         attrs))))
     (dolist (a attrs)
       (let ((attr (face-attribute face (car a) frame)))
diff --git a/lisp/help-mode.el b/lisp/help-mode.el
index 551cf7e1a3..792f2e5af3 100644
--- a/lisp/help-mode.el
+++ b/lisp/help-mode.el
@@ -35,6 +35,8 @@
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map (make-composed-keymap button-buffer-map
                                                  special-mode-map))
+    (define-key map "n" 'help-goto-next-page)
+    (define-key map "p" 'help-goto-previous-page)
     (define-key map "l" 'help-go-back)
     (define-key map "r" 'help-go-forward)
     (define-key map "\C-c\C-b" 'help-go-back)
@@ -224,6 +226,11 @@ The format is (FUNCTION ARGS...).")
   'help-function #'info
   'help-echo (purecopy "mouse-2, RET: read this Info node"))
 
+(define-button-type 'help-man
+  :supertype 'help-xref
+  'help-function #'man
+  'help-echo (purecopy "mouse-2, RET: read this man page"))
+
 (define-button-type 'help-customization-group
   :supertype 'help-xref
   'help-function #'customize-group
@@ -268,6 +275,10 @@ The format is (FUNCTION ARGS...).")
             (when (or (< position (point-min))
                       (> position (point-max)))
               (widen))
+            ;; Save mark for the old location, unless the point is not
+            ;; actually going to move.
+            (unless (= (point) position)
+              (push-mark nil t))
             (goto-char position))
         (message "Unable to find location in file")))))
 
@@ -367,6 +378,13 @@ The format is (FUNCTION ARGS...).")
     (view-buffer-other-window (find-file-noselect file))
     (goto-char pos))
   'help-echo (purecopy "mouse-2, RET: show corresponding NEWS announcement"))
+
+;;;###autoload
+(defun help-mode--add-function-link (str fun)
+  (make-text-button (copy-sequence str) nil
+                    'type 'help-function
+                    'help-args (list fun)))
+
 
 (defvar bookmark-make-record-function)
 (defvar help-mode--current-data nil)
@@ -438,6 +456,11 @@ when help commands related to multilingual environment 
(e.g.,
    "\\<[Ii]nfo[ \t\n]+\\(node\\|anchor\\)[ \t\n]+['`‘]\\([^'’]+\\)['’]")
   "Regexp matching doc string references to an Info node.")
 
+(defconst help-xref-man-regexp
+  (purecopy
+   "\\<[Mm]an[ \t\n]+page[ \t\n]+\\(?:for[ 
\t\n]+\\)?['`‘\"]\\([^'’\"]+\\)['’\"]")
+  "Regexp matching doc string references to a man page.")
+
 (defconst help-xref-customization-group-regexp
   (purecopy "\\<[Cc]ustomization[ \t\n]+[Gg]roup[ \t\n]+['`‘]\\([^'’]+\\)['’]")
   "Regexp matching doc string references to a customization group.")
@@ -548,6 +571,10 @@ that."
                        (setq data ;; possible newlines if para filled
                              (replace-regexp-in-string "[ \t\n]+" " " data t 
t)))
                       (help-xref-button 2 'help-info data))))
+                ;; Man references
+                (save-excursion
+                  (while (re-search-forward help-xref-man-regexp nil t)
+                    (help-xref-button 1 'help-man (match-string 1))))
                 ;; Customization groups.
                 (save-excursion
                   (while (re-search-forward
@@ -617,34 +644,7 @@ that."
                           "\\<M-x\\s-+\\(\\sw\\(\\sw\\|\\s_\\)*\\sw\\)" nil t)
                     (let ((sym (intern-soft (match-string 1))))
                       (if (fboundp sym)
-                          (help-xref-button 1 'help-function sym)))))
-                ;; Look for commands in whole keymap substitutions:
-                (save-excursion
-                  ;; Make sure to find the first keymap.
-                  (goto-char (point-min))
-                  ;; Find a header and the column at which the command
-                  ;; name will be found.
-
-                  ;; If the keymap substitution isn't the last thing in
-                  ;; the doc string, and if there is anything on the same
-                  ;; line after it, this code won't recognize the end of it.
-                  (while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n"
-                                            nil t)
-                    (let ((col (- (match-end 1) (match-beginning 1))))
-                      (while
-                          (and (not (eobp))
-                               ;; Stop at a pair of blank lines.
-                               (not (looking-at-p "\n\\s-*\n")))
-                        ;; Skip a single blank line.
-                        (and (eolp) (forward-line))
-                        (end-of-line)
-                        (skip-chars-backward "^ \t\n")
-                        (if (and (>= (current-column) col)
-                                 (looking-at "\\(\\sw\\|\\s_\\)+$"))
-                            (let ((sym (intern-soft (match-string 0))))
-                              (if (fboundp sym)
-                                  (help-xref-button 0 'help-function sym))))
-                        (forward-line))))))
+                          (help-xref-button 1 'help-function sym))))))
             (set-syntax-table stab))
           ;; Delete extraneous newlines at the end of the docstring
           (goto-char (point-max))
@@ -781,6 +781,26 @@ See `help-make-xrefs'."
       (help-xref-go-forward (current-buffer))
     (user-error "No next help buffer")))
 
+(defun help-goto-next-page ()
+  "Go to the next page (if any) in the current buffer.
+The help buffers are divided into \"pages\" by the ^L character."
+  (interactive nil help-mode)
+  (push-mark)
+  (forward-page)
+  (unless (eobp)
+    (forward-line 1)))
+
+(defun help-goto-previous-page ()
+  "Go to the previous page (if any) in the current buffer.
+(If not at the start of a page, go to the start of the current page.)
+
+The help buffers are divided into \"pages\" by the ^L character."
+  (interactive nil help-mode)
+  (push-mark)
+  (backward-page (if (looking-back "\f\n" (- (point) 5)) 2 1))
+  (unless (bobp)
+    (forward-line 1)))
+
 (defun help-view-source ()
   "View the source of the current help item."
   (interactive nil help-mode)
diff --git a/lisp/help.el b/lisp/help.el
index 8f77167040..b2772f4389 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -561,11 +561,13 @@ To record all your input, use `open-dribble-file'."
               'font-lock-face 'help-key-binding
               'face 'help-key-binding))
 
-(defcustom describe-bindings-outline nil
+(defcustom describe-bindings-outline t
   "Non-nil enables outlines in the output buffer of `describe-bindings'."
   :type 'boolean
   :group 'help
-  :version "28.1")
+  :version "29.1")
+
+(declare-function outline-hide-subtree "outline")
 
 (defun describe-bindings (&optional prefix buffer)
   "Display a buffer showing a list of all defined keys, and their definitions.
@@ -581,8 +583,6 @@ or a buffer name."
   (help-setup-xref (list #'describe-bindings prefix buffer)
                   (called-interactively-p 'interactive))
   (with-help-window (help-buffer)
-    ;; Be aware that `describe-buffer-bindings' puts its output into
-    ;; the current buffer.
     (with-current-buffer (help-buffer)
       (describe-buffer-bindings buffer prefix)
 
@@ -592,18 +592,18 @@ or a buffer name."
         (setq-local outline-level (lambda () 1))
         (setq-local outline-minor-mode-cycle t
                     outline-minor-mode-highlight t)
+        (setq-local outline-minor-mode-use-buttons t)
         (outline-minor-mode 1)
         (save-excursion
+          (goto-char (point-min))
           (let ((inhibit-read-only t))
-            (goto-char (point-min))
-            (insert (substitute-command-keys
-                     (concat "\\<outline-minor-mode-cycle-map>Type "
-                             "\\[outline-cycle] or \\[outline-cycle-buffer] "
-                             "on headings to cycle their visibility.\n\n")))
-            ;; Hide the longest body
-            (when (and (re-search-forward "Key translations" nil t)
-                       (fboundp 'outline-cycle))
-              (outline-cycle))))))))
+            ;; Hide the longest body.
+            (when (re-search-forward "Key translations" nil t)
+              (outline-hide-subtree))
+            ;; Hide ^Ls.
+            (while (search-forward "\n\f\n" nil t)
+              (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
+                                 'invisible t))))))))
 
 (defun where-is (definition &optional insert)
   "Print message listing key sequences that invoke the command DEFINITION.
@@ -677,9 +677,11 @@ If INSERT (the prefix arg) is non-nil, insert the message 
in the buffer."
 (defun help--binding-undefined-p (defn)
   (or (null defn) (integerp defn) (equal defn 'undefined)))
 
-(defun help--analyze-key (key untranslated)
+(defun help--analyze-key (key untranslated &optional buffer)
   "Get information about KEY its corresponding UNTRANSLATED events.
-Returns a list of the form (BRIEF-DESC DEFN EVENT MOUSE-MSG)."
+Returns a list of the form (BRIEF-DESC DEFN EVENT MOUSE-MSG).
+When BUFFER is nil, it defaults to the buffer displayed
+in the selected window."
   (if (numberp untranslated)
       (error "Missing `untranslated'!"))
   (let* ((event (when (> (length key) 0)
@@ -695,7 +697,18 @@ Returns a list of the form (BRIEF-DESC DEFN EVENT 
MOUSE-MSG)."
         (mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers)
                            (memq 'drag modifiers))
                         " at that spot" ""))
-        (defn (key-binding key t)))
+         ;; Use `mouse-set-point' to handle the case when a menu item
+         ;; is selected from the context menu that should describe KEY
+         ;; at the position of mouse click that opened the context menu.
+         ;; When no mouse was involved, don't use `mouse-set-point'.
+         (defn (if (or buffer
+                       ;; Clicks on the menu bar produce "event" that
+                       ;; is just '(menu-bar)', for which
+                       ;; `mouse-set-point' is not useful.
+                       (and (not (windowp (posn-window (event-start event))))
+                            (not (framep (posn-window (event-start event))))))
+                   (key-binding key t)
+                 (save-excursion (mouse-set-point event) (key-binding key 
t)))))
     ;; Handle the case where we faked an entry in "Select and Paste" menu.
     (when (and (eq defn nil)
               (stringp (aref key (1- (length key))))
@@ -725,7 +738,7 @@ Returns a list of the form (BRIEF-DESC DEFN EVENT 
MOUSE-MSG)."
    ;; If nothing left, then keep one (the last one).
    (last info-list)))
 
-(defun describe-key-briefly (&optional key-list insert untranslated)
+(defun describe-key-briefly (&optional key-list insert buffer)
   "Print the name of the functions KEY-LIST invokes.
 KEY-LIST is a list of pairs (SEQ . RAW-SEQ) of key sequences, where
 RAW-SEQ is the untranslated form of the key sequence SEQ.
@@ -733,8 +746,10 @@ If INSERT (the prefix arg) is non-nil, insert the message 
in the buffer.
 
 While reading KEY-LIST interactively, this command temporarily enables
 menu items or tool-bar buttons that are disabled to allow getting help
-on them."
-  (declare (advertised-calling-convention (key-list &optional insert) "27.1"))
+on them.
+
+BUFFER is the buffer in which to lookup those keys; it defaults to the
+current buffer."
   (interactive
    ;; Ignore mouse movement events because it's too easy to miss the
    ;; message while moving the mouse.
@@ -742,15 +757,13 @@ on them."
      `(,key-list ,current-prefix-arg)))
   (when (arrayp key-list)
     ;; Old calling convention, changed
-    (setq key-list (list (cons key-list
-                               (if (numberp untranslated)
-                                   (this-single-command-raw-keys)
-                                 untranslated)))))
-  (let* ((info-list (mapcar (lambda (kr)
-                              (help--analyze-key (car kr) (cdr kr)))
-                            key-list))
-         (msg (mapconcat #'car (help--filter-info-list info-list 1) "\n")))
-    (if insert (insert msg) (message "%s" msg))))
+    (setq key-list (list (cons key-list nil))))
+  (with-current-buffer (if (buffer-live-p buffer) buffer (current-buffer))
+    (let* ((info-list (mapcar (lambda (kr)
+                                (help--analyze-key (car kr) (cdr kr) buffer))
+                              key-list))
+           (msg (mapconcat #'car (help--filter-info-list info-list 1) "\n")))
+      (if insert (insert msg) (message "%s" msg)))))
 
 (defun help--key-binding-keymap (key &optional accept-default no-remap 
position)
   "Return a keymap holding a binding for KEY within current keymaps.
@@ -910,7 +923,7 @@ current buffer."
              (mapcar (lambda (x)
                        (pcase-let* ((`(,seq . ,raw-seq) x)
                                     (`(,brief-desc ,defn ,event ,_mouse-msg)
-                                     (help--analyze-key seq raw-seq))
+                                     (help--analyze-key seq raw-seq buffer))
                                     (locus
                                      (help--binding-locus
                                       seq (event-start event))))
@@ -952,8 +965,11 @@ current buffer."
            (describe-function-1 defn)))))))
 
 (defun search-forward-help-for-help ()
-  "Search forward \"help window\"."
+  "Search forward in the help-for-help window.
+This command is meant to be used after issuing the `C-h C-h' command."
   (interactive)
+  (unless (get-buffer help-for-help-buffer-name)
+    (error "No %s buffer; use `C-h C-h' first" help-for-help-buffer-name))
   ;; Move cursor to the "help window".
   (pop-to-buffer help-for-help-buffer-name)
   ;; Do incremental search forward.
@@ -1048,6 +1064,14 @@ is currently activated with completion."
     result))
 
 
+(defcustom help-link-key-to-documentation t
+  "Non-nil means link keys to their command in *Help* buffers.
+This affects \\\\=\\[command] substitutions in documentation
+strings done by `substitute-command-keys'."
+  :type 'boolean
+  :version "29.1"
+  :group 'help)
+
 (defun substitute-command-keys (string)
   "Substitute key descriptions for command names in STRING.
 Each substring of the form \\\\=[COMMAND] is replaced by either a
@@ -1135,7 +1159,14 @@ Otherwise, return a new string."
                         (delete-char 1))
                     ;; Function is on a key.
                     (delete-char (- end-point (point)))
-                    (insert (help--key-description-fontified key)))))
+                    (let ((key (help--key-description-fontified key)))
+                      (insert (if (and help-link-key-to-documentation
+                                       (functionp fun))
+                                  ;; The `fboundp' fixes bootstrap.
+                                  (if (fboundp 'help-mode--add-function-link)
+                                      (help-mode--add-function-link key fun)
+                                    key)
+                                key))))))
                ;; 1D. \{foo} is replaced with a summary of the keymap
                ;;            (symbol-value foo).
                ;;     \<foo> just sets the keymap used for \[cmd].
@@ -1217,15 +1248,12 @@ If NOMENU is non-nil, then omit menu-bar commands.
 If TRANSL is non-nil, the definitions are actually key
 translations so print strings and vectors differently.
 
-If ALWAYS_TITLE is non-nil, print the title even if there are no
+If ALWAYS-TITLE is non-nil, print the title even if there are no
 maps to look through.
 
-If MENTION_SHADOW is non-nil, then when something is shadowed by
+If MENTION-SHADOW is non-nil, then when something is shadowed by
 SHADOW, don't omit it; instead, mention it but say it is
-shadowed.
-
-Any inserted text ends in two newlines (used by
-`help-make-xrefs')."
+shadowed."
   (let* ((amaps (accessible-keymaps startmap prefix))
          (orig-maps (if no-menu
                         (progn
@@ -1242,17 +1270,8 @@ Any inserted text ends in two newlines (used by
                             result))
                       amaps))
          (maps orig-maps)
-         (print-title (or maps always-title)))
-    ;; Print title.
-    (when print-title
-      (insert (concat (if title
-                          (concat title
-                                  (if prefix
-                                      (concat " Starting With "
-                                              (help--key-description-fontified 
prefix)))
-                                  ":\n"))
-                      "key             binding\n"
-                      "---             -------\n")))
+         (print-title (or maps always-title))
+         (start-point (point)))
     ;; Describe key bindings.
     (setq help--keymaps-seen nil)
     (while (consp maps)
@@ -1277,8 +1296,24 @@ Any inserted text ends in two newlines (used by
           (describe-map (cdr elt) elt-prefix transl partial
                         sub-shadows no-menu mention-shadow)))
       (setq maps (cdr maps)))
-    (when print-title
-      (insert "\n"))))
+    ;; Print title...
+    (when (and print-title
+               ;; ... unless the keymap was empty.
+               (/= (point) start-point))
+      (save-excursion
+        (goto-char start-point)
+        (when (eolp)
+          (delete-region (point) (1+ (point))))
+        (insert
+         (concat
+          (if title
+              (concat title
+                      (if prefix
+                          (concat " Starting With "
+                                  (help--key-description-fontified prefix)))
+                      ":\n"))
+          "\nKey             Binding\n"
+          (make-separator-line)))))))
 
 (defun help--shadow-lookup (keymap key accept-default remap)
   "Like `lookup-key', but with command remapping.
@@ -1291,48 +1326,34 @@ Return nil if the key sequence is too long."
                value))
           (t value))))
 
-(defvar help--previous-description-column 0)
-(defun help--describe-command (definition)
-  ;; Converted from describe_command in keymap.c.
-  ;; If column 16 is no good, go to col 32;
-  ;; but don't push beyond that--go to next line instead.
-  (let* ((column (current-column))
-         (description-column (cond ((> column 30)
-                                    (insert "\n")
-                                    32)
-                                   ((or (> column 14)
-                                        (and (> column 10)
-                                             (= 
help--previous-description-column 32)))
-                                    32)
-                                   (t 16))))
-    ;; Avoid using the `help-keymap' face.
-    (let ((op (point)))
-      (indent-to description-column 1)
-      (set-text-properties op (point) '( face nil
-                                         font-lock-face nil)))
-    (setq help--previous-description-column description-column)
-    (cond ((symbolp definition)
-           (insert (symbol-name definition) "\n"))
-          ((or (stringp definition) (vectorp definition))
-           (insert "Keyboard Macro\n"))
-          ((keymapp definition)
-           (insert "Prefix Command\n"))
-          (t (insert "??\n")))))
-
-(defun help--describe-translation (definition)
-  ;; Converted from describe_translation in keymap.c.
-  ;; Avoid using the `help-keymap' face.
-  (let ((op (point)))
-    (indent-to 16 1)
-    (set-text-properties op (point) '( face nil
-                                      font-lock-face nil)))
+(defun help--describe-command (definition &optional translation)
   (cond ((symbolp definition)
-         (insert (symbol-name definition) "\n"))
+         (insert-text-button (symbol-name definition)
+                             'type 'help-function
+                             'help-args (list definition))
+         (insert "\n"))
         ((or (stringp definition) (vectorp definition))
-         (insert (key-description definition nil) "\n"))
+         (if translation
+             (insert (key-description definition nil) "\n")
+           (insert "Keyboard Macro\n")))
         ((keymapp definition)
          (insert "Prefix Command\n"))
-        (t (insert "??\n"))))
+        ((byte-code-function-p definition)
+         (insert "[%s]\n" (buttonize "byte-code" #'disassemble definition)))
+        ((and (consp definition)
+              (memq (car definition) '(closure lambda)))
+         (insert (format "[%s]\n"
+                         (buttonize
+                          (symbol-name (car definition))
+                          (lambda (_)
+                            (pp-display-expression
+                             definition "*Help Source*" t))
+                          nil "View definition"))))
+        (t
+         (insert "??\n"))))
+
+(define-obsolete-function-alias 'help--describe-translation
+  #'help--describe-command "29.1")
 
 (defun help--describe-map-compare (a b)
   (let ((a (car a))
@@ -1346,7 +1367,8 @@ Return nil if the key sequence is too long."
            (string-version-lessp (symbol-name a) (symbol-name b)))
           (t nil))))
 
-(defun describe-map (map prefix transl partial shadow nomenu mention-shadow)
+(defun describe-map (map &optional prefix transl partial shadow
+                         nomenu mention-shadow)
   "Describe the contents of keymap MAP.
 Assume that this keymap itself is reached by the sequence of
 prefix keys PREFIX (a string or vector).
@@ -1358,14 +1380,22 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as 
in
          (map (keymap-canonicalize map))
          (tail map)
          (first t)
-         (describer (if transl
-                        #'help--describe-translation
-                      #'help--describe-command))
          done vect)
     (while (and (consp tail) (not done))
       (cond ((or (vectorp (car tail)) (char-table-p (car tail)))
-             (help--describe-vector (car tail) prefix describer partial
-                                shadow map mention-shadow))
+             (let ((columns ()))
+               (help--describe-vector
+                (car tail) prefix
+                (lambda (def)
+                  (let ((start-line (line-beginning-position))
+                        (end-key (point))
+                        (column (current-column)))
+                    (help--describe-command def transl)
+                    (push (list column start-line end-key (1- (point)))
+                          columns)))
+                partial shadow map mention-shadow)
+               (when columns
+                 (describe-map--align-section columns))))
             ((consp (car tail))
              (let ((event (caar tail))
                    definition this-shadowed)
@@ -1408,7 +1438,9 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
                  (push (cons tail prefix) help--keymaps-seen)))))
       (setq tail (cdr tail)))
     ;; If we found some sparse map events, sort them.
-    (let ((vect (sort vect 'help--describe-map-compare)))
+    (let ((vect (sort vect 'help--describe-map-compare))
+          (columns ())
+          line-start key-end column)
       ;; Now output them in sorted order.
       (while vect
         (let* ((elem (car vect))
@@ -1416,10 +1448,6 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as in
                (definition (cadr elem))
                (shadowed (caddr elem))
                (end start))
-          (when first
-            (setq help--previous-description-column 0)
-            (insert "\n")
-            (setq first nil))
           ;; Find consecutive chars that are identically defined.
           (when (fixnump start)
             (while (and (cdr vect)
@@ -1434,26 +1462,80 @@ TRANSL, PARTIAL, SHADOW, NOMENU, MENTION-SHADOW are as 
in
                                (eq this-shadowed next-shadowed))))
               (setq vect (cdr vect))
               (setq end (caar vect))))
-          ;; Now START .. END is the range to describe next.
-          ;; Insert the string to describe the event START.
-          (insert (help--key-description-fontified (vector start) prefix))
-          (when (not (eq start end))
-            (insert " .. " (help--key-description-fontified (vector end) 
prefix)))
-          ;; Print a description of the definition of this character.
-          ;; Called function will take care of spacing out far enough
-          ;; for alignment purposes.
-          (if transl
-              (help--describe-translation definition)
-            (help--describe-command definition))
-          ;; Print a description of the definition of this character.
-          ;; elt_describer will take care of spacing out far enough for
-          ;; alignment purposes.
-          (when shadowed
-            (goto-char (max (1- (point)) (point-min)))
-            (insert "\n  (this binding is currently shadowed)")
-            (goto-char (min (1+ (point)) (point-max)))))
+          (when (or (not (eq start end))
+                    ;; Don't output keymap prefixes.
+                    (not (keymapp definition)))
+            (when first
+              (insert "\n")
+              (setq first nil))
+            ;; Now START .. END is the range to describe next.
+            ;; Insert the string to describe the event START.
+            (setq line-start (point))
+            (insert (help--key-description-fontified (vector start) prefix))
+            (when (not (eq start end))
+              (insert " .. " (help--key-description-fontified (vector end)
+                                                              prefix)))
+            (setq key-end (point)
+                  column (current-column))
+            ;; Print a description of the definition of this character.
+            ;; Called function will take care of spacing out far enough
+            ;; for alignment purposes.
+            (help--describe-command definition transl)
+            (push (list column line-start key-end (1- (point))) columns)
+            ;; Print a description of the definition of this character.
+            ;; elt_describer will take care of spacing out far enough for
+            ;; alignment purposes.
+            (when shadowed
+              (goto-char (max (1- (point)) (point-min)))
+              (insert "\n  (this binding is currently shadowed)")
+              (goto-char (min (1+ (point)) (point-max))))))
         ;; Next item in list.
-        (setq vect (cdr vect))))))
+        (setq vect (cdr vect)))
+      (when columns
+        (describe-map--align-section columns)))))
+
+(defun describe-map--align-section (columns)
+  (save-excursion
+    (let ((max-key (apply #'max (mapcar #'car columns))))
+      (cond
+       ;; It's fine to use the minimum, so just do it, but quantize to
+       ;; two different widths, because having each block align slightly
+       ;; differently looks untidy.
+       ((< max-key 16)
+        (describe-map--fill-columns columns 16))
+       ((< max-key 24)
+        (describe-map--fill-columns columns 24))
+       ((< max-key 32)
+        (describe-map--fill-columns columns 32))
+       ;; We have some really wide ones in this block.
+       (t
+        (let ((window-width (window-width))
+              (max-def (apply #'max (mapcar
+                                     (lambda (elem)
+                                       (- (nth 3 elem) (nth 2 elem)))
+                                     columns))))
+          (if (< (+ max-def (max 16 max-key)) window-width)
+              ;; Can we do the block without continuation lines?  Then do that.
+              (describe-map--fill-columns columns (1+ (max 16 max-key)))
+            ;; No, do continuation lines for some definitions.
+            (dolist (elem columns)
+              (goto-char (caddr elem))
+              (if (< (+ (car elem) (- (nth 3 elem) (nth 2 elem))) window-width)
+                  ;; Indent.
+                  (insert-char ?\s (- (1+ max-key) (car elem)))
+                ;; Continuation.
+                (insert "\n")
+                (insert-char ?\t 2))))))))))
+
+(defun describe-map--fill-columns (columns width)
+  (dolist (elem columns)
+    (goto-char (caddr elem))
+    (let ((tabs (- (/ width tab-width)
+                   (/ (car elem) tab-width))))
+      (insert-char ?\t tabs)
+      (insert-char ?\s (if (zerop tabs)
+                           (- width (car elem))
+                         (mod width tab-width))))))
 
 ;;;; This Lisp version is 100 times slower than its C equivalent:
 ;;
@@ -1589,10 +1671,16 @@ and some others."
       (add-hook 'temp-buffer-show-hook 'resize-temp-buffer-window 'append)
     (remove-hook 'temp-buffer-show-hook 'resize-temp-buffer-window)))
 
+(defvar resize-temp-buffer-window-inhibit nil
+  "Non-nil means `resize-temp-buffer-window' should not resize.")
+
 (defun resize-temp-buffer-window (&optional window)
   "Resize WINDOW to fit its contents.
 WINDOW must be a live window and defaults to the selected one.
-Do not resize if WINDOW was not created by `display-buffer'.
+Do not resize if WINDOW was not created by `display-buffer'.  Do
+not resize either if a `window-height', `window-width' or
+`window-size' entry in `display-buffer-alist' prescribes some
+alternative resizing for WINDOW's buffer.
 
 If WINDOW is part of a vertical combination, restrain its new
 size by `temp-buffer-max-height' and do not resize if its minimum
@@ -1607,27 +1695,33 @@ provided `fit-frame-to-buffer' is non-nil.
 This function may call `preserve-window-size' to preserve the
 size of WINDOW."
   (setq window (window-normalize-window window t))
-  (let ((height (if (functionp temp-buffer-max-height)
+  (let* ((buffer (window-buffer window))
+         (height (if (functionp temp-buffer-max-height)
+                    (with-selected-window window
+                      (funcall temp-buffer-max-height buffer))
+                  temp-buffer-max-height))
+        (width (if (functionp temp-buffer-max-width)
                    (with-selected-window window
-                     (funcall temp-buffer-max-height (window-buffer)))
-                 temp-buffer-max-height))
-       (width (if (functionp temp-buffer-max-width)
-                  (with-selected-window window
-                    (funcall temp-buffer-max-width (window-buffer)))
-                temp-buffer-max-width))
-       (quit-cadr (cadr (window-parameter window 'quit-restore))))
-    ;; Resize WINDOW iff it was made by `display-buffer'.
+                     (funcall temp-buffer-max-width buffer))
+                 temp-buffer-max-width))
+        (quit-cadr (cadr (window-parameter window 'quit-restore))))
+    ;; Resize WINDOW only if it was made by `display-buffer'.
     (when (or (and (eq quit-cadr 'window)
                   (or (and (window-combined-p window)
                            (not (eq fit-window-to-buffer-horizontally
                                     'only))
-                           (pos-visible-in-window-p (point-min) window))
+                           (pos-visible-in-window-p
+                             (with-current-buffer buffer (point-min))
+                             window)
+                            (not resize-temp-buffer-window-inhibit))
                       (and (window-combined-p window t)
-                           fit-window-to-buffer-horizontally)))
+                           fit-window-to-buffer-horizontally
+                            (not resize-temp-buffer-window-inhibit))))
              (and (eq quit-cadr 'frame)
                    fit-frame-to-buffer
-                   (eq window (frame-root-window window))))
-       (fit-window-to-buffer window height nil width nil t))))
+                   (eq window (frame-root-window window))
+                   (not resize-temp-buffer-window-inhibit)))
+      (fit-window-to-buffer window height nil width nil t))))
 
 ;;; Help windows.
 (defcustom help-window-select nil
diff --git a/lisp/hilit-chg.el b/lisp/hilit-chg.el
index 8919e98238..d9fab6b875 100644
--- a/lisp/hilit-chg.el
+++ b/lisp/hilit-chg.el
@@ -444,7 +444,7 @@ This is the opposite of `hilit-chg-hide-changes'."
          ;; We set the change property so we can tell this is one
          ;; of our overlays (so we don't delete someone else's).
           (overlay-put ov 'hilit-chg t))
-      (error "hilit-chg-make-ov: no face for prop: %s" prop))))
+      (error "hilit-chg-make-ov: No face for prop: %s" prop))))
 
 (defun hilit-chg-hide-changes (&optional beg end)
   "Remove face information for Highlight Changes mode.
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index 7c95baf8cd..5b69a878e2 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1210,7 +1210,7 @@ Interactively, prompt for NAME, and use the current 
filters."
     (_
      (let ((type (assq (car qualifier) ibuffer-filtering-alist)))
        (unless qualifier
-         (error "Ibuffer: bad qualifier %s" qualifier))
+         (error "Ibuffer: Bad qualifier %s" qualifier))
        (concat " [" (cadr type) ": " (format "%s]" (cdr qualifier)))))))
 
 (defun ibuffer-list-buffer-modes (&optional include-parents)
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 6c0180590b..233127b011 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -1079,7 +1079,8 @@ a new window in the current frame, splitting vertically."
   ;; Make sure that redisplay is performed, otherwise there can be a
   ;; bad interaction with code in the window-scroll-functions hook
   (redisplay t)
-  (when (buffer-local-value 'ibuffer-auto-mode (window-buffer))
+  (when (with-current-buffer (window-buffer)
+          (eq major-mode 'ibuffer-mode))
     (fit-window-to-buffer
      nil (and owin
               (/ (frame-height)
@@ -2483,6 +2484,7 @@ Other commands:
   `\\[ibuffer-update]' - Regenerate the list of all buffers.
           Prefix arg means to toggle whether buffers that match
           `ibuffer-maybe-show-predicates' should be displayed.
+  `\\[ibuffer-auto-mode]' - Toggle automatic updates.
 
   `\\[ibuffer-switch-format]' - Change the current display format.
   `\\[forward-line]' - Move point to the next line.
diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index 01033474d3..a61c9d6354 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -716,11 +716,6 @@ See `icomplete-mode' and `minibuffer-setup-hook'."
             (delete-region (overlay-start rfn-eshadow-overlay)
                            (overlay-end rfn-eshadow-overlay)))
           (let* ((field-string (icomplete--field-string))
-                 ;; Not sure why, but such requests seem to come
-                 ;; every once in a while.  It's not fully
-                 ;; deterministic but `C-x C-f M-DEL M-DEL ...'
-                 ;; seems to trigger it fairly often!
-                 (while-no-input-ignore-events '(selection-request))
                  (text (while-no-input
                          (icomplete-completions
                           field-string
diff --git a/lisp/ido.el b/lisp/ido.el
index 7c2d2eb0d7..6767d66988 100644
--- a/lisp/ido.el
+++ b/lisp/ido.el
@@ -354,8 +354,8 @@ The following values are possible:
 
 Setting this variable directly does not take effect;
 use either \\[customize] or the function `ido-mode'."
-  :set #'(lambda (_symbol value)
-           (ido-mode (or value 0)))
+  :set (lambda (_symbol value)
+         (ido-mode (or value 0)))
   :initialize #'custom-initialize-default
   :require 'ido
   :link '(emacs-commentary-link "ido.el")
@@ -620,9 +620,9 @@ hosts on first use of UNC path."
                 (function-item :tag "Use `NET VIEW'"
                                :value ido-unc-hosts-net-view)
                 (function :tag "Your own function"))
-  :set #'(lambda (symbol value)
-          (set symbol value)
-          (setq ido-unc-hosts-cache t)))
+  :set (lambda (symbol value)
+         (set symbol value)
+         (setq ido-unc-hosts-cache t)))
 
 (defcustom ido-downcase-unc-hosts t
   "Non-nil if UNC host names should be downcased."
diff --git a/lisp/image-dired.el b/lisp/image-dired.el
index 3ca47300a9..a2c37f00f2 100644
--- a/lisp/image-dired.el
+++ b/lisp/image-dired.el
@@ -1,7 +1,7 @@
 ;;; image-dired.el --- use dired to browse and manipulate your images -*- 
lexical-binding: t -*-
-;;
+
 ;; Copyright (C) 2005-2021 Free Software Foundation, Inc.
-;;
+
 ;; Version: 0.4.11
 ;; Keywords: multimedia
 ;; Author: Mathias Dahl <mathias.rem0veth1s.dahl@gmail.com>
@@ -22,7 +22,7 @@
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
-;;
+
 ;; BACKGROUND
 ;; ==========
 ;;
@@ -45,7 +45,7 @@
 ;; currently keep all my 2000+ images in the same directory) and
 ;; browsing the thumbnail buffer was slow too.  image-dired.el will not
 ;; create thumbnails until they are needed and the browsing is done
-;; quickly and easily in dired.  I copied a great deal of ideas and
+;; quickly and easily in Dired.  I copied a great deal of ideas and
 ;; code from there though... :)
 ;;
 ;;  `image-dired' stores the thumbnail files in `image-dired-dir'
@@ -59,19 +59,22 @@
 ;; PREREQUISITES
 ;; =============
 ;;
-;; * The ImageMagick package.  Currently, `convert' and `mogrify' are
-;; used.  Find it here: https://www.imagemagick.org.
+;; * The GraphicsMagick or ImageMagick package; Image-Dired uses
+;;   whichever is available.
+;;
+;;   A) For GraphicsMagick, `gm' is used.
+;;      Find it here:  http://www.graphicsmagick.org/
+;;
+;;   B) For ImageMagick, `convert' and `mogrify' are used.
+;;      Find it here:  https://www.imagemagick.org.
 ;;
 ;; * For non-lossy rotation of JPEG images, the JpegTRAN program is
-;; needed.
+;;   needed.
 ;;
-;; * For `image-dired-get-exif-data' and `image-dired-set-exif-data' to work,
-;; the command line tool `exiftool' is needed.  It can be found here:
-;; https://exiftool.org/.  These two functions are, among other
-;; things, used for writing comments to image files using
-;; `image-dired-thumbnail-set-image-description' and to create
-;; "unique" file names using `image-dired-get-exif-file-name' (used by
-;; `image-dired-copy-with-exif-file-name').
+;; * For `image-dired-set-exif-data' to work, the command line tool `exiftool' 
is
+;;   needed.  It can be found here: https://exiftool.org/.  This
+;;   function is, among other things, used for writing comments to
+;;   image files using `image-dired-thumbnail-set-image-description'.
 ;;
 ;;
 ;; USAGE
@@ -89,24 +92,22 @@
 ;; ===========
 ;;
 ;; * Supports all image formats that Emacs and convert supports, but
-;; the thumbnails are hard-coded to JPEG format.
+;;   the thumbnails are hard-coded to JPEG or PNG format.  It uses
+;;   JPEG by default, but can optionally follow the Thumbnail Managing
+;;   Standard (v0.9.0, Dec 2020), which mandates PNG.  See the user
+;;   option `image-dired-thumbnail-storage'.
 ;;
 ;; * WARNING: The "database" format used might be changed so keep a
-;; backup of `image-dired-db-file' when testing new versions.
-;;
-;; * `image-dired-display-image-mode' does not support animation
+;;   backup of `image-dired-db-file' when testing new versions.
 ;;
 ;; TODO
 ;; ====
 ;;
-;; * Support gallery creation when using per-directory thumbnail
-;; storage.
-;;
 ;; * Some sort of auto-rotate function based on rotate info in the
-;; EXIF data.
+;;   EXIF data.
 ;;
 ;; * Investigate if it is possible to also write the tags to the image
-;; files.
+;;   files.
 ;;
 ;; * From thumbs.el: Add an option for clean-up/max-size functionality
 ;;   for thumbnail directory.
@@ -119,149 +120,149 @@
 ;; * From thumbs.el: Add the "modify" commands (emboss, negate,
 ;;   monochrome etc).
 ;;
-;; * Add `image-dired-display-thumbs-ring' and functions to cycle that.  Find
-;; out which is best, saving old batch just before inserting new, or
-;; saving the current batch in the ring when inserting it.  Adding it
-;; probably needs rewriting `image-dired-display-thumbs' to be more general.
+;; * Add `image-dired-display-thumbs-ring' and functions to cycle that.  Find 
out
+;;   which is best, saving old batch just before inserting new, or
+;;   saving the current batch in the ring when inserting it.  Adding
+;;   it probably needs rewriting `image-dired-display-thumbs' to be more 
general.
 ;;
 ;; * Find some way of toggling on and off really nice keybindings in
-;; dired (for example, using C-n or <down> instead of C-S-n).  Richard
-;; suggested that we could keep C-t as prefix for image-dired commands
-;; as it is currently not used in dired.  He also suggested that
-;; `dired-next-line' and `dired-previous-line' figure out if
-;; image-dired is enabled in the current buffer and, if it is, call
-;; `image-dired-dired-next-line' and
-;; `image-dired-dired-previous-line', respectively.  Update: This is
-;; partly done; some bindings have now been added to dired.
-;;
-;; * Enhanced gallery creation with basic CSS-support and pagination
-;; of tag pages with many pictures.
-;;
-;; * Rewrite `image-dired-modify-mark-on-thumb-original-file' to be
-;; less ugly.
+;;   Dired (for example, using C-n or <down> instead of C-S-n).
+;;   Richard suggested that we could keep C-t as prefix for
+;;   image-dired commands as it is currently not used in Dired.  He
+;;   also suggested that `dired-next-line' and `dired-previous-line'
+;;   figure out if image-dired is enabled in the current buffer and,
+;;   if it is, call `image-dired-dired-next-line' and 
`image-dired-dired-previous-line',
+;;   respectively.  Update: This is partly done; some bindings have
+;;   now been added to Dired.
 ;;
 ;; * In some way keep track of buffers and windows and stuff so that
-;; it works as the user expects.
-;;
-;; * More/better documentation
-;;
+;;   it works as the user expects.
 ;;
+;; * More/better documentation.
+
 ;;; Code:
 
 (require 'dired)
+(require 'exif)
 (require 'image-mode)
 (require 'widget)
+(require 'xdg)
 
 (eval-when-compile
   (require 'cl-lib)
   (require 'wid-edit))
 
+
+;;; Customizable variables
+
 (defgroup image-dired nil
-  "Use dired to browse your images as thumbnails, and more."
+  "Use Dired to browse your images as thumbnails, and more."
   :prefix "image-dired-"
   :link '(info-link "(emacs) Image-Dired")
   :group 'multimedia)
 
 (defcustom image-dired-dir (locate-user-emacs-file "image-dired/")
-  "Directory where thumbnail images are stored."
+  "Directory where thumbnail images are stored.
+
+The value of this option will be ignored if Image-Dired is
+customized to use the Thumbnail Managing Standard; they will be
+saved in \"$XDG_CACHE_HOME/thumbnails/\" instead.  See
+`image-dired-thumbnail-storage'."
   :type 'directory)
 
 (defcustom image-dired-thumbnail-storage 'use-image-dired-dir
-  "How to store image-dired's thumbnail files.
-Image-Dired can store thumbnail files in one of two ways and this is
-controlled by this variable.  \"Use image-dired dir\" means that the
-thumbnails are stored in a central directory.  \"Per directory\"
-means that each thumbnail is stored in a subdirectory called
-\".image-dired\" in the same directory where the image file is.
-\"Thumbnail Managing Standard\" means that the thumbnails are
-stored and generated according to the Thumbnail Managing Standard
-that allows sharing of thumbnails across different programs."
+  "How `image-dired' stores thumbnail files.
+There are two ways that Image-Dired can store and generate
+thumbnails.  If you set this variable to one of the two following
+values, they will be stored in the JPEG format:
+
+- `use-image-dired-dir' means that the thumbnails are stored in a
+  central directory.
+
+- `per-directory' means that each thumbnail is stored in a
+  subdirectory called \".image-dired\" in the same directory
+  where the image file is.
+
+It can also use the \"Thumbnail Managing Standard\", which allows
+sharing of thumbnails across different programs.  Thumbnails will
+be stored in \"$XDG_CACHE_HOME/thumbnails/\" instead of in
+`image-dired-dir'.  Thumbnails are saved in the PNG format, and
+can be one of the following sizes:
+
+- `standard' means use thumbnails sized 128x128.
+- `standard-large' means use thumbnails sized 256x256.
+- `standard-x-large' means use thumbnails sized 512x512.
+- `standard-xx-large' means use thumbnails sized 1024x1024.
+
+For more information on the Thumbnail Managing Standard, see:
+https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html";
   :type '(choice :tag "How to store thumbnail files"
                  (const :tag "Use image-dired-dir" use-image-dired-dir)
-                 (const :tag "Thumbnail Managing Standard (normal 128x128)" 
standard)
-                 (const :tag "Thumbnail Managing Standard (large 256x256)" 
standard-large)
-                 (const :tag "Per-directory" per-directory)))
+                 (const :tag "Thumbnail Managing Standard (normal 128x128)"
+                        standard)
+                 (const :tag "Thumbnail Managing Standard (large 256x256)"
+                        standard-large)
+                 (const :tag "Thumbnail Managing Standard (larger 512x512)"
+                        standard-x-large)
+                 (const :tag "Thumbnail Managing Standard (extra large 
1024x1024)"
+                        standard-xx-large)
+                 (const :tag "Per-directory" per-directory))
+  :version "29.1")
+
+(defconst image-dired--thumbnail-standard-sizes
+  '( standard standard-large
+     standard-x-large standard-xx-large)
+  "List of symbols representing thumbnail sizes in Thumbnail Managing 
Standard.")
 
 (defcustom image-dired-db-file
   (expand-file-name ".image-dired_db" image-dired-dir)
   "Database file where file names and their associated tags are stored."
   :type 'file)
 
-(defcustom image-dired-temp-image-file
-  (expand-file-name ".image-dired_temp" image-dired-dir)
-  "Name of temporary image file used by various commands."
-  :type 'file)
-
-(defcustom image-dired-gallery-dir
-  (expand-file-name ".image-dired_gallery" image-dired-dir)
-  "Directory to store generated gallery html pages.
-This path needs to be \"shared\" to the public so that it can access
-the index.html page that image-dired creates."
-  :type 'directory)
-
-(defcustom image-dired-gallery-image-root-url
-"https://your.own.server/image-diredpics";
-  "URL where the full size images are to be found.
-Note that this path has to be configured in your web server.  Image-Dired
-expects to find pictures in this directory."
-  :type 'string)
-
-(defcustom image-dired-gallery-thumb-image-root-url
-"https://your.own.server/image-diredthumbs";
-  "URL where the thumbnail images are to be found.
-Note that this path has to be configured in your web server.  Image-Dired
-expects to find pictures in this directory."
-  :type 'string)
-
 (defcustom image-dired-cmd-create-thumbnail-program
-  "convert"
+  (if (executable-find "gm") "gm" "convert")
   "Executable used to create thumbnail.
 Used together with `image-dired-cmd-create-thumbnail-options'."
-  :type 'file)
+  :type 'file
+  :version "29.1")
 
 (defcustom image-dired-cmd-create-thumbnail-options
-  '("-size" "%wx%h" "%f[0]" "-resize" "%wx%h>" "-strip" "jpeg:%t")
+  (let ((opts '("-size" "%wx%h" "%f[0]"
+                "-resize" "%wx%h>"
+                "-strip" "jpeg:%t")))
+    (if (executable-find "gm") (cons "convert" opts) opts))
   "Options of command used to create thumbnail image.
 Used with `image-dired-cmd-create-thumbnail-program'.
 Available format specifiers are: %w which is replaced by
 `image-dired-thumb-width', %h which is replaced by `image-dired-thumb-height',
 %f which is replaced by the file name of the original image and %t
 which is replaced by the file name of the thumbnail file."
-  :version "26.1"
-  :type '(repeat (string :tag "Argument")))
-
-(defcustom image-dired-cmd-create-temp-image-program "convert"
-  "Executable used to create temporary image.
-Used together with `image-dired-cmd-create-temp-image-options'."
-  :type 'file)
-
-(defcustom image-dired-cmd-create-temp-image-options
-  '("-size" "%wx%h" "%f[0]" "-resize" "%wx%h>" "-strip" "jpeg:%t")
-  "Options of command used to create temporary image for display window.
-Used together with `image-dired-cmd-create-temp-image-program',
-Available format specifiers are: %w and %h which are replaced by
-the calculated max size for width and height in the image display window,
-%f which is replaced by the file name of the original image and %t which
-is replaced by the file name of the temporary file."
-  :version "26.1"
+  :version "29.1"
   :type '(repeat (string :tag "Argument")))
 
 (defcustom image-dired-cmd-pngnq-program
-  (or (executable-find "pngnq")
-      (executable-find "pngnq-s9"))
-  "The file name of the `pngnq' program.
+  ;; Prefer pngquant to pngnq-s9 as it is faster on my machine.
+  ;;   The project also seems more active than the alternatives.
+  ;; Prefer pngnq-s9 to pngnq as it fixes bugs in pngnq.
+  ;; The pngnq project seems dead (?) since 2011 or so.
+  (or (executable-find "pngquant")
+      (executable-find "pngnq-s9")
+      (executable-find "pngnq"))
+  "The file name of the `pngquant' or `pngnq' program.
 It quantizes colors of PNG images down to 256 colors or fewer
 using the NeuQuant algorithm."
-  :version "26.1"
+  :version "29.1"
   :type '(choice (const :tag "Not Set" nil) file))
 
 (defcustom image-dired-cmd-pngnq-options
-  '("-f" "%t")
+  (if (executable-find "pngquant")
+      '("--ext" "-nq8.png" "%t") ; same extension as "pngnq"
+    '("-f" "%t"))
   "Arguments to pass `image-dired-cmd-pngnq-program'.
 Available format specifiers are the same as in
 `image-dired-cmd-create-thumbnail-options'."
-  :version "26.1"
-  :type '(repeat (string :tag "Argument")))
+  :type '(repeat (string :tag "Argument"))
+  :version "29.1")
 
 (defcustom image-dired-cmd-pngcrush-program (executable-find "pngcrush")
   "The file name of the `pngcrush' program.
@@ -316,23 +317,6 @@ Available format specifiers are the same as in
   :version "26.1"
   :type '(repeat (string :tag "Argument")))
 
-(defcustom image-dired-cmd-rotate-thumbnail-program
-  "mogrify"
-  "Executable used to rotate thumbnail.
-Used together with `image-dired-cmd-rotate-thumbnail-options'."
-  :type 'file)
-
-(defcustom image-dired-cmd-rotate-thumbnail-options
-  '("-rotate" "%d" "%t")
-  "Arguments of command used to rotate thumbnail image.
-Used with `image-dired-cmd-rotate-thumbnail-program'.
-Available format specifiers are: %d which is replaced by the
-number of (positive) degrees to rotate the image, normally 90 or 270
-\(for 90 degrees right and left), %t which is replaced by the file name
-of the thumbnail file."
-  :version "26.1"
-  :type '(repeat (string :tag "Argument")))
-
 (defcustom image-dired-cmd-rotate-original-program
   "jpegtran"
   "Executable used to rotate original image.
@@ -378,35 +362,20 @@ which is replaced by the tag value."
   :version "26.1"
   :type '(repeat (string :tag "Argument")))
 
-(defcustom image-dired-cmd-read-exif-data-program
-  "exiftool"
-  "Program used to read EXIF data to image.
-Used together with `image-dired-cmd-read-exif-data-options'."
-  :type 'file)
-
-(defcustom image-dired-cmd-read-exif-data-options
-  '("-s" "-s" "-s" "-%t" "%f")
-  "Arguments of command used to read EXIF data.
-Used with `image-dired-cmd-read-exif-data-program'.
-Available format specifiers are: %f which is replaced
-by the image file name and %t which is replaced by the tag name."
-  :version "26.1"
-  :type '(repeat (string :tag "Argument")))
-
-(defcustom image-dired-gallery-hidden-tags
-  (list "private" "hidden" "pending")
-  "List of \"hidden\" tags.
-Used by `image-dired-gallery-generate' to leave out \"hidden\" images."
-  :type '(repeat string))
-
 (defcustom image-dired-thumb-size
   (cond
    ((eq 'standard image-dired-thumbnail-storage) 128)
    ((eq 'standard-large image-dired-thumbnail-storage) 256)
+   ((eq 'standard-x-large image-dired-thumbnail-storage) 512)
+   ((eq 'standard-xx-large image-dired-thumbnail-storage) 1024)
    (t 100))
   "Size of thumbnails, in pixels.
 This is the default size for both `image-dired-thumb-width'
-and `image-dired-thumb-height'."
+and `image-dired-thumb-height'.
+
+The value of this option will be ignored if Image-Dired is
+customized to use the Thumbnail Managing Standard; the standard
+sizes will be used instead.  See `image-dired-thumbnail-storage'."
   :type 'integer)
 
 (defcustom image-dired-thumb-width image-dired-thumb-size
@@ -427,17 +396,28 @@ This is where you see the cursor."
   :type 'integer)
 
 (defcustom image-dired-thumb-visible-marks t
-  "Make marks visible in thumbnail buffer.
+  "Make marks and flags visible in thumbnail buffer.
 If non-nil, apply the `image-dired-thumb-mark' face to marked
-images."
+images and `image-dired-thumb-flagged' to images flagged for
+deletion."
   :type 'boolean
   :version "28.1")
 
 (defface image-dired-thumb-mark
-  '((t (:background "orange")))
-  "Background-color for marked images in thumbnail buffer."
-  :group 'image-dired
-  :version "28.1")
+  '((((class color) (min-colors 16)) :background "DarkOrange")
+    (((class color)) :foreground "yellow"))
+  "Face for marked images in thumbnail buffer."
+  :version "29.1")
+
+(defface image-dired-thumb-flagged
+  '((((class color) (min-colors 88) (background light)) :background "Red3")
+    (((class color) (min-colors 88) (background dark))  :background "Pink")
+    (((class color) (min-colors 16) (background light)) :background "Red3")
+    (((class color) (min-colors 16) (background dark))  :background "Pink")
+    (((class color) (min-colors 8)) :background "red")
+    (t :inverse-video t))
+  "Face for images flagged for deletion in thumbnail buffer."
+  :version "29.1")
 
 (defcustom image-dired-line-up-method 'dynamic
   "Default method for line-up of thumbnails in thumbnail buffer.
@@ -456,18 +436,6 @@ and No line-up means that no automatic line-up will be 
done."
   "Number of thumbnails to display per row in thumb buffer."
   :type 'integer)
 
-(defcustom image-dired-display-window-width-correction 1
-  "Number to be used to correct image display window width.
-Change if the default (1) does not work (i.e. if the image does not
-completely fit)."
-  :type 'integer)
-
-(defcustom image-dired-display-window-height-correction 0
-  "Number to be used to correct image display window height.
-Change if the default (0) does not work (i.e. if the image does not
-completely fit)."
-  :type 'integer)
-
 (defcustom image-dired-track-movement t
   "The current state of the tracking and mirroring.
 For more information, see the documentation for
@@ -485,18 +453,18 @@ This value can be toggled using 
`image-dired-toggle-append-browsing'."
   :type 'boolean)
 
 (defcustom image-dired-dired-disp-props t
-  "If non-nil, display properties for dired file when browsing.
+  "If non-nil, display properties for Dired file when browsing.
 Used by `image-dired-next-line-and-display',
 `image-dired-previous-line-and-display' and 
`image-dired-mark-and-display-next'.
 If the database file is large, this can slow down image browsing in
-dired and you might want to turn it off."
+Dired and you might want to turn it off."
   :type 'boolean)
 
 (defcustom image-dired-display-properties-format "%b: %f (%t): %c"
   "Display format for thumbnail properties.
-%b is replaced with associated dired buffer name, %f with file name
-\(without path) of original image file, %t with the list of tags and %c
-with the comment."
+%b is replaced with associated Dired buffer name, %f with file
+name (without path) of original image file, %t with the list of
+tags and %c with the comment."
   :type 'string)
 
 (defcustom image-dired-external-viewer
@@ -504,23 +472,43 @@ with the comment."
   ;; dired-view-command-alist.
   (cond ((executable-find "display"))
         ((executable-find "xli"))
-        ((executable-find "qiv") "qiv -t"))
+        ((executable-find "qiv") "qiv -t")
+        ((executable-find "feh") "feh"))
   "Name of external viewer.
 Including parameters.  Used when displaying original image from
 `image-dired-thumbnail-mode'."
-  :version "27.1"
+  :version "28.1"
   :type '(choice string
                  (const :tag "Not Set" nil)))
 
-(defcustom image-dired-main-image-directory "~/pics/"
+(defcustom image-dired-main-image-directory
+  (or (xdg-user-dir "PICTURES") "~/pics/")
   "Name of main image directory, if any.
 Used by `image-dired-copy-with-exif-file-name'."
-  :type 'string)
+  :type 'string
+  :version "29.1")
 
-(defcustom image-dired-show-all-from-dir-max-files 50
-  "Maximum number of files to show using `image-dired-show-all-from-dir'
-before warning."
-  :type 'integer)
+(defcustom image-dired-show-all-from-dir-max-files 500
+  "Maximum number of files in directory before prompting.
+
+If there are more image files than this in a selected directory,
+the `image-dired-show-all-from-dir' command will ask for
+confirmation before creating the thumbnail buffer.  If this
+variable is nil, it will never ask."
+  :type '(choice integer
+                 (const :tag "Disable warning" nil))
+  :version "29.1")
+
+
+;;; Util functions
+
+(defvar image-dired-debug nil
+  "Non-nil means enable debug messages.")
+
+(defun image-dired-debug-message (&rest args)
+  "Display debug message ARGS when `image-dired-debug' is non-nil."
+  (when image-dired-debug
+    (apply #'message args)))
 
 (defmacro image-dired--with-db-file (&rest body)
   "Run BODY in a temp buffer containing `image-dired-db-file'.
@@ -537,7 +525,8 @@ Create the thumbnails directory if it does not exist."
   (let ((image-dired-dir (file-name-as-directory
                     (expand-file-name image-dired-dir))))
     (unless (file-directory-p image-dired-dir)
-      (make-directory image-dired-dir t)
+      (with-file-modes #o700
+        (make-directory image-dired-dir t))
       (message "Creating thumbnails directory"))
     image-dired-dir))
 
@@ -560,11 +549,7 @@ Create the thumbnails directory if it does not exist."
                           (file-attribute-modification-time
                            (file-attributes file))))
       (image-dired-create-thumb file thumb-file))
-    (create-image thumb-file)
-;;     (list 'image :type 'jpeg
-;;           :file thumb-file
-;;       :relief image-dired-thumb-relief :margin image-dired-thumb-margin)
-    ))
+    (create-image thumb-file)))
 
 (defun image-dired-insert-thumbnail (file original-file-name
                                      associated-dired-buffer)
@@ -572,13 +557,19 @@ Create the thumbnails directory if it does not exist."
 Add text properties ORIGINAL-FILE-NAME and ASSOCIATED-DIRED-BUFFER."
   (let (beg end)
     (setq beg (point))
-    (image-dired-insert-image file
-                        ;; TODO: this should depend on the real file type
-                        (if (memq image-dired-thumbnail-storage
-                                  '(standard standard-large))
-                            'png 'jpeg)
-                        image-dired-thumb-relief
-                        image-dired-thumb-margin)
+    (image-dired-insert-image
+     file
+     ;; Thumbnails are created asynchronously, so we might not yet
+     ;; have a file.  But if it exists, it might have been cached from
+     ;; before and we should use it instead of our current settings.
+     (or (and (file-exists-p file)
+              (image-type-from-file-header file))
+         (and (memq image-dired-thumbnail-storage
+                    image-dired--thumbnail-standard-sizes)
+              'png)
+         'jpeg)
+     image-dired-thumb-relief
+     image-dired-thumb-margin)
     (setq end (point))
     (add-text-properties
      beg end
@@ -590,35 +581,39 @@ Add text properties ORIGINAL-FILE-NAME and 
ASSOCIATED-DIRED-BUFFER."
            'comment (image-dired-get-comment original-file-name)))))
 
 (defun image-dired-thumb-name (file)
-  "Return thumbnail file name for FILE.
-Depending on the value of `image-dired-thumbnail-storage', the file
-name will vary.  For central thumbnail file storage, make a
-MD5-hash of the image file's directory name and add that to make
-the thumbnail file name unique.  For per-directory storage, just
-add a subdirectory.  For standard storage, produce the file name
-according to the Thumbnail Managing Standard."
-  (cond ((memq image-dired-thumbnail-storage '(standard standard-large))
-         (let* ((xdg (getenv "XDG_CACHE_HOME"))
-                (dir (if (and xdg (file-name-absolute-p xdg))
-                         xdg "~/.cache"))
-                (thumbdir (cl-case image-dired-thumbnail-storage
-                            (standard "thumbnails/normal")
-                            (standard-large "thumbnails/large"))))
+  "Return absolute file name for thumbnail FILE.
+Depending on the value of `image-dired-thumbnail-storage', the
+file name of the thumbnail will vary:
+- For `use-image-dired-dir', make a SHA1-hash of the image file's
+  directory name and add that to make the thumbnail file name
+  unique.
+- For `per-directory' storage, just add a subdirectory.
+- For `standard' storage, produce the file name according to the
+  Thumbnail Managing Standard.  Among other things, an MD5-hash
+  of the image file's directory name will be added to the
+  filename.
+See also `image-dired-thumbnail-storage'."
+  (cond ((memq image-dired-thumbnail-storage
+               image-dired--thumbnail-standard-sizes)
+         (let ((thumbdir (cl-case image-dired-thumbnail-storage
+                           (standard "thumbnails/normal")
+                           (standard-large "thumbnails/large")
+                           (standard-x-large "thumbnails/x-large")
+                           (standard-xx-large "thumbnails/xx-large"))))
            (expand-file-name
+            ;; MD5 is mandated by the Thumbnail Managing Standard.
             (concat (md5 (concat "file://" (expand-file-name file))) ".png")
-            (expand-file-name thumbdir dir))))
+            (expand-file-name thumbdir (xdg-cache-home)))))
         ((eq 'use-image-dired-dir image-dired-thumbnail-storage)
          (let* ((f (expand-file-name file))
-                (md5-hash
-                 ;; Is MD5 hashes fast enough? The checksum of a
-                 ;; thumbnail file name need not be that
-                 ;; "cryptographically" good so a faster one could
-                 ;; be used here.
-                 (md5 (file-name-as-directory (file-name-directory f)))))
+                (hash
+                 ;; SHA1 is slightly faster than MD5, so let's use it.
+                 ;; (We don't need anything crytographically strong.)
+                 (sha1 (file-name-as-directory (file-name-directory f)))))
            (format "%s%s%s.thumb.%s"
                    (file-name-as-directory (expand-file-name 
(image-dired-dir)))
                    (file-name-base f)
-                   (if md5-hash (concat "_" md5-hash) "")
+                   (if hash (concat "_" hash) "")
                    (file-name-extension f))))
         ((eq 'per-directory image-dired-thumbnail-storage)
          (let ((f (expand-file-name file)))
@@ -631,16 +626,24 @@ according to the Thumbnail Managing Standard."
   (unless (executable-find (symbol-value executable))
     (error "Executable %S not found" executable)))
 
+
+;;; Creating thumbnails
+
 (defun image-dired-thumb-size (dimension)
   "Return thumb size depending on `image-dired-thumbnail-storage'.
 DIMENSION should be either the symbol `width' or `height'."
   (cond
    ((eq 'standard image-dired-thumbnail-storage) 128)
    ((eq 'standard-large image-dired-thumbnail-storage) 256)
+   ((eq 'standard-x-large image-dired-thumbnail-storage) 512)
+   ((eq 'standard-xx-large image-dired-thumbnail-storage) 1024)
    (t (cl-ecase dimension
         (width image-dired-thumb-width)
         (height image-dired-thumb-height)))))
 
+(defvar image-dired--generate-thumbs-start nil
+  "Time when `display-thumbs' was called.")
+
 (defvar image-dired-queue nil
   "List of items in the queue.
 Each item has the form (ORIGINAL-FILE TARGET-FILE).")
@@ -648,11 +651,12 @@ Each item has the form (ORIGINAL-FILE TARGET-FILE).")
 (defvar image-dired-queue-active-jobs 0
   "Number of active jobs in `image-dired-queue'.")
 
-(defvar image-dired-queue-active-limit 2
+(defvar image-dired-queue-active-limit (min 4 (max 2 (/ (num-processors) 2)))
   "Maximum number of concurrent jobs permitted for generating images.
-Increase at own risk.")
-
-(defvar image-dired-tag-history nil "Variable holding the tag history.")
+Increase at own risk.  If you want to experiment with this,
+consider setting `image-dired-debug' to a non-nil value to see
+the time spent on generating thumbnails.  Run `image-clear-cache'
+and remove the cached thumbnail files between each trial run.")
 
 (defun image-dired-pngnq-thumb (spec)
   "Quantize thumbnail described by format SPEC with pngnq(1)."
@@ -751,7 +755,7 @@ Increase at own risk.")
                  (mapcar
                   (lambda (arg) (format-spec arg spec))
                   (if (memq image-dired-thumbnail-storage
-                            '(standard standard-large))
+                            image-dired--thumbnail-standard-sizes)
                       image-dired-cmd-create-standard-thumbnail-options
                     image-dired-cmd-create-thumbnail-options))))
 
@@ -760,6 +764,12 @@ Increase at own risk.")
             ;; Trigger next in queue once a thumbnail has been created
             (cl-decf image-dired-queue-active-jobs)
             (image-dired-thumb-queue-run)
+            (when (= image-dired-queue-active-jobs 0)
+              (image-dired-debug-message
+               (format-time-string
+                "Generated thumbnails in %s.%3N seconds"
+                (time-subtract (current-time)
+                               image-dired--generate-thumbs-start))))
             (if (not (and (eq (process-status process) 'exit)
                           (zerop (process-exit-status process))))
                 (message "Thumb could not be created for %s: %s"
@@ -770,7 +780,7 @@ Increase at own risk.")
               ;; PNG thumbnail has been created since we are
               ;; following the XDG thumbnail spec, so try to optimize
               (when (memq image-dired-thumbnail-storage
-                          '(standard standard-large))
+                          image-dired--thumbnail-standard-sizes)
                 (cond
                  ((and image-dired-cmd-pngnq-program
                        (executable-find image-dired-cmd-pngnq-program))
@@ -793,7 +803,8 @@ Queued items live in `image-dired-queue'."
     (apply #'image-dired-create-thumb-1 (pop image-dired-queue))))
 
 (defun image-dired-create-thumb (original-file thumbnail-file)
-  "Add a job for generating thumbnail to `image-dired-queue'."
+  "Add a job for generating ORIGINAL-FILE thumbnail to `image-dired-queue'.
+The new file will be named THUMBNAIL-FILE."
   (setq image-dired-queue
         (nconc image-dired-queue
                (list (list original-file thumbnail-file))))
@@ -817,7 +828,7 @@ thumbnail."
 
 ;;;###autoload
 (defun image-dired-dired-toggle-marked-thumbs (&optional arg)
-  "Toggle thumbnails in front of file names in the dired buffer.
+  "Toggle thumbnails in front of file names in the Dired buffer.
 If no marked file could be found, insert or hide thumbnails on the
 current line.  ARG, if non-nil, specifies the files to use instead
 of the marked files.  If ARG is an integer, use the next ARG (or
@@ -848,7 +859,7 @@ previous -ARG, if ARG<0) files."
             'image-dired-dired-after-readin-hook nil t))
 
 (defun image-dired-dired-after-readin-hook ()
-  "Relocate existing thumbnail overlays in dired buffer after reverting.
+  "Relocate existing thumbnail overlays in Dired buffer after reverting.
 Move them to their corresponding files if they still exist.
 Otherwise, delete overlays."
   (mapc (lambda (overlay)
@@ -861,7 +872,7 @@ Otherwise, delete overlays."
         (overlays-in (point-min) (point-max))))
 
 (defun image-dired-next-line-and-display ()
-  "Move to next dired line and display thumbnail image."
+  "Move to next Dired line and display thumbnail image."
   (interactive)
   (dired-next-line 1)
   (image-dired-display-thumbs
@@ -870,7 +881,7 @@ Otherwise, delete overlays."
       (image-dired-dired-display-properties)))
 
 (defun image-dired-previous-line-and-display ()
-  "Move to previous dired line and display thumbnail image."
+  "Move to previous Dired line and display thumbnail image."
   (interactive)
   (dired-previous-line 1)
   (image-dired-display-thumbs
@@ -883,13 +894,13 @@ Otherwise, delete overlays."
   (interactive)
   (setq image-dired-append-when-browsing
         (not image-dired-append-when-browsing))
-  (message "Append browsing %s."
+  (message "Append browsing %s"
            (if image-dired-append-when-browsing
                "on"
              "off")))
 
 (defun image-dired-mark-and-display-next ()
-  "Mark current file in dired and display next thumbnail image."
+  "Mark current file in Dired and display next thumbnail image."
   (interactive)
   (dired-mark 1)
   (image-dired-display-thumbs
@@ -922,15 +933,6 @@ Otherwise, delete overlays."
 (defvar image-dired-display-image-buffer "*image-dired-display-image*"
   "Where larger versions of the images are display.")
 
-(defun image-dired-create-display-image-buffer ()
-  "Create image display buffer and set `image-dired-display-image-mode'."
-  (let ((buf (get-buffer-create image-dired-display-image-buffer)))
-    (with-current-buffer buf
-      (setq buffer-read-only t)
-      (if (not (eq major-mode 'image-dired-display-image-mode))
-          (image-dired-display-image-mode)))
-    buf))
-
 (defvar image-dired-saved-window-configuration nil
   "Saved window configuration.")
 
@@ -940,12 +942,12 @@ Otherwise, delete overlays."
 
 Convenience command that:
 
- - Opens dired in folder DIR
+ - Opens Dired in folder DIR
  - Splits windows in most useful (?) way
- - Set `truncate-lines' to t
+ - Sets `truncate-lines' to t
 
 After the command has finished, you would typically mark some
-image files in dired and type
+image files in Dired and type
 \\[image-dired-display-thumbs] (`image-dired-display-thumbs').
 
 If called with prefix argument ARG, skip splitting of windows.
@@ -954,7 +956,7 @@ The current window configuration is saved and can be 
restored by
 calling `image-dired-restore-window-configuration'."
   (interactive "DDirectory: \nP")
   (let ((buf (image-dired-create-thumbnail-buffer))
-        (buf2 (image-dired-create-display-image-buffer)))
+        (buf2 (get-buffer-create image-dired-display-image-buffer)))
     (setq image-dired-saved-window-configuration
           (current-window-configuration))
     (dired dir)
@@ -973,7 +975,7 @@ calling `image-dired-restore-window-configuration'."
   "Restore window configuration.
 Restore any changes to the window configuration made by calling
 `image-dired-dired-with-window-configuration'."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (if image-dired-saved-window-configuration
       (set-window-configuration image-dired-saved-window-configuration)
     (message "No saved window configuration")))
@@ -1000,7 +1002,7 @@ point (this is useful if you have marked some files but 
want to show
 another one).
 
 Recommended usage is to split the current frame horizontally so that
-you have the dired buffer in the left window and the
+you have the Dired buffer in the left window and the
 `image-dired-thumbnail-buffer' buffer in the right window.
 
 With optional argument APPEND, append thumbnail to thumbnail buffer
@@ -1013,6 +1015,7 @@ used or not.  If non-nil, use `display-buffer' instead of
 `image-dired-previous-line-and-display' where we do not want the
 thumbnail buffer to be selected."
   (interactive "P")
+  (setq image-dired--generate-thumbs-start  (current-time))
   (let ((buf (image-dired-create-thumbnail-buffer))
         thumb-name files dired-buf)
     (if arg
@@ -1036,30 +1039,38 @@ thumbnail buffer to be selected."
 
 ;;;###autoload
 (defun image-dired-show-all-from-dir (dir)
-  "Make a preview buffer for all images in DIR and display it.
-If the number of files in DIR matching `image-file-name-regexp'
-exceeds `image-dired-show-all-from-dir-max-files', a warning will be
-displayed."
-  (interactive "DImage Dired: ")
+  "Make a thumbnail buffer for all images in DIR and display it.
+Any file matching `image-file-name-regexp' is considered an image
+file.
+
+If the number of image files in DIR exceeds
+`image-dired-show-all-from-dir-max-files', ask for confirmation
+before creating the thumbnail buffer.  If that variable is nil,
+never ask for confirmation."
+  (interactive "DImage-Dired: ")
   (dired dir)
   (dired-mark-files-regexp (image-file-name-regexp))
-  (let ((files (dired-get-marked-files)))
-    (if (or (<= (length files) image-dired-show-all-from-dir-max-files)
-            (and (> (length files) image-dired-show-all-from-dir-max-files)
-                 (y-or-n-p
-                  (format
-                   "Directory contains more than %d image files.  Proceed? "
-                   image-dired-show-all-from-dir-max-files))))
-        (progn
-          (image-dired-display-thumbs)
-          (pop-to-buffer image-dired-thumbnail-buffer))
-      (message "Canceled."))))
+  (let ((files (dired-get-marked-files nil nil nil t)))
+    (cond ((and (null (cdr files)))
+           (message "No image files in directory"))
+          ((or (not image-dired-show-all-from-dir-max-files)
+               (<= (length (cdr files)) 
image-dired-show-all-from-dir-max-files)
+               (and (> (length (cdr files)) 
image-dired-show-all-from-dir-max-files)
+                    (y-or-n-p
+                     (format
+                      "Directory contains more than %d image files.  Proceed?"
+                      image-dired-show-all-from-dir-max-files))))
+           (image-dired-display-thumbs)
+           (pop-to-buffer image-dired-thumbnail-buffer)
+           (setq default-directory dir)
+           (image-dired-unmark-all-marks))
+          (t (message "Image-Dired canceled")))))
 
 ;;;###autoload
 (defalias 'image-dired 'image-dired-show-all-from-dir)
 
-;;;###autoload
-(define-obsolete-function-alias 'tumme 'image-dired "24.4")
+
+;;; Tags
 
 (defun image-dired-sane-db-file ()
   "Check if `image-dired-db-file' exists.
@@ -1069,14 +1080,18 @@ Signal error if there are problems creating it."
       (let (dir buf)
         (unless (file-directory-p (setq dir (file-name-directory
                                              image-dired-db-file)))
-          (make-directory dir t))
+          (with-file-modes #o700
+            (make-directory dir t)))
         (with-current-buffer (setq buf (create-file-buffer
                                         image-dired-db-file))
-          (write-file image-dired-db-file))
+          (with-file-modes #o600
+            (write-file image-dired-db-file)))
         (kill-buffer buf)
         (file-exists-p image-dired-db-file))
       (error "Could not create %s" image-dired-db-file)))
 
+(defvar image-dired-tag-history nil "Variable holding the tag history.")
+
 (defun image-dired-write-tags (file-tags)
   "Write file tags to database.
 Write each file and tag in FILE-TAGS to the database.
@@ -1147,7 +1162,7 @@ FILE-TAGS is an alist in the following form:
 
 ;;;###autoload
 (defun image-dired-tag-files (arg)
-  "Tag marked file(s) in dired.  With prefix ARG, tag file at point."
+  "Tag marked file(s) in Dired.  With prefix ARG, tag file at point."
   (interactive "P")
   (let ((tag (completing-read
               "Tags to add (separate tags with a semicolon): "
@@ -1197,6 +1212,9 @@ With prefix argument ARG, remove tag from file at point."
      (image-dired-update-property
       'tags (image-dired-list-tags (image-dired-original-file-name))))))
 
+
+;;; Thumbnail mode (cont.)
+
 (defun image-dired-original-file-name ()
   "Get original file name for thumbnail or display image at point."
   (get-text-property (point) 'original-file-name))
@@ -1208,7 +1226,7 @@ With prefix argument ARG, remove tag from file at point."
       (abbreviate-file-name f))))
 
 (defun image-dired-associated-dired-buffer ()
-  "Get associated dired buffer at point."
+  "Get associated Dired buffer at point."
   (get-text-property (point) 'associated-dired-buffer))
 
 (defun image-dired-get-buffer-window (buf)
@@ -1219,7 +1237,7 @@ With prefix argument ARG, remove tag from file at point."
    nil t))
 
 (defun image-dired-track-original-file ()
-  "Track the original file in the associated dired buffer.
+  "Track the original file in the associated Dired buffer.
 See documentation for `image-dired-toggle-movement-tracking'.
 Interactive use only useful if `image-dired-track-movement' is nil."
   (interactive)
@@ -1234,16 +1252,16 @@ Interactive use only useful if 
`image-dired-track-movement' is nil."
 
 (defun image-dired-toggle-movement-tracking ()
   "Turn on and off `image-dired-track-movement'.
-Tracking of the movements between thumbnail and dired buffer so that
+Tracking of the movements between thumbnail and Dired buffer so that
 they are \"mirrored\" in the dired buffer.  When this is on, moving
 around in the thumbnail or dired buffer will find the matching
 position in the other buffer."
   (interactive)
   (setq image-dired-track-movement (not image-dired-track-movement))
-  (message "Tracking %s" (if image-dired-track-movement "on" "off")))
+  (message "Movement tracking %s" (if image-dired-track-movement "on" "off")))
 
 (defun image-dired-track-thumbnail ()
-  "Track current dired file's thumb in `image-dired-thumbnail-buffer'.
+  "Track current Dired file's thumb in `image-dired-thumbnail-buffer'.
 This is almost the same as what `image-dired-track-original-file' does,
 but the other way around."
   (let ((file (dired-get-filename))
@@ -1282,51 +1300,59 @@ With prefix argument, move ARG lines."
   (if image-dired-track-movement
       (image-dired-track-thumbnail)))
 
-(defun image-dired-forward-image (&optional arg)
+(defun image-dired--display-thumb-properties-fun ()
+  (let ((old-buf (current-buffer))
+        (old-point (point)))
+    (lambda ()
+      (when (and (equal (current-buffer) old-buf)
+                 (= (point) old-point))
+        (ignore-errors
+          (image-dired-display-thumb-properties))))))
+
+(defun image-dired-forward-image (&optional arg wrap-around)
   "Move to next image and display properties.
-Optional prefix ARG says how many images to move; default is one
-image."
+Optional prefix ARG says how many images to move; the default is
+one image.  Negative means move backwards.
+On reaching end or beginning of buffer, stop and show a message.
+
+If optional argument WRAP-AROUND is non-nil, wrap around: if
+point is on the last image, move to the last one and vice versa."
   (interactive "p")
-  (let (pos (steps (or arg 1)))
-    (dotimes (_ steps)
-      (if (and (not (eobp))
+  (setq arg (or arg 1))
+  (let (pos)
+    (dotimes (_ (abs arg))
+      (if (and (not (if (> arg 0) (eobp) (bobp)))
                (save-excursion
-                 (forward-char)
-                 (while (and (not (eobp))
+                 (forward-char (if (> arg 0) 1 -1))
+                 (while (and (not (if (> arg 0) (eobp) (bobp)))
                              (not (image-dired-image-at-point-p)))
-                   (forward-char))
+                   (forward-char (if (> arg 0) 1 -1)))
                  (setq pos (point))
                  (image-dired-image-at-point-p)))
-          (goto-char pos)
-        (error "At last image"))))
+          (progn (goto-char pos)
+                 (image-dired-display-thumb-properties))
+        (if wrap-around
+            (progn (goto-char (if (> arg 0)
+                                  (point-min)
+                                ;; There are two spaces after the last image.
+                                (- (point-max) 2)))
+                   (image-dired-display-thumb-properties))
+          (message "At %s image" (if (> arg 0) "last" "first"))
+          (run-at-time 1 nil (image-dired--display-thumb-properties-fun))))))
   (when image-dired-track-movement
-    (image-dired-track-original-file))
-  (image-dired-display-thumb-properties))
+    (image-dired-track-original-file)))
 
 (defun image-dired-backward-image (&optional arg)
   "Move to previous image and display properties.
-Optional prefix ARG says how many images to move; default is one
-image."
+Optional prefix ARG says how many images to move; the default is
+one image.  Negative means move forward.
+On reaching end or beginning of buffer, stop and show a message."
   (interactive "p")
-  (let (pos (steps (or arg 1)))
-    (dotimes (_ steps)
-      (if (and (not (bobp))
-               (save-excursion
-                 (backward-char)
-                 (while (and (not (bobp))
-                             (not (image-dired-image-at-point-p)))
-                   (backward-char))
-                 (setq pos (point))
-                 (image-dired-image-at-point-p)))
-          (goto-char pos)
-        (error "At first image"))))
-  (when image-dired-track-movement
-    (image-dired-track-original-file))
-  (image-dired-display-thumb-properties))
+  (image-dired-forward-image (- (or arg 1))))
 
 (defun image-dired-next-line ()
   "Move to next line and display properties."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (let ((goal-column (current-column)))
     (forward-line 1)
     (move-to-column goal-column))
@@ -1340,7 +1366,7 @@ image."
 
 (defun image-dired-previous-line ()
   "Move to previous line and display properties."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (let ((goal-column (current-column)))
     (forward-line -1)
     (move-to-column goal-column))
@@ -1354,9 +1380,31 @@ image."
       (image-dired-track-original-file))
   (image-dired-display-thumb-properties))
 
+(defun image-dired-beginning-of-buffer ()
+  "Move to the first image in the buffer and display properties."
+  (interactive nil image-dired-thumbnail-mode)
+  (goto-char (point-min))
+  (while (and (not (image-at-point-p))
+              (not (eobp)))
+    (forward-char 1))
+  (when image-dired-track-movement
+    (image-dired-track-original-file))
+  (image-dired-display-thumb-properties))
+
+(defun image-dired-end-of-buffer ()
+  "Move to the last image in the buffer and display properties."
+  (interactive nil image-dired-thumbnail-mode)
+  (goto-char (point-max))
+  (while (and (not (image-at-point-p))
+              (not (bobp)))
+    (forward-char -1))
+  (when image-dired-track-movement
+    (image-dired-track-original-file))
+  (image-dired-display-thumb-properties))
+
 (defun image-dired-format-properties-string (buf file props comment)
   "Format display properties.
-BUF is the associated dired buffer, FILE is the original image file
+BUF is the associated Dired buffer, FILE is the original image file
 name, PROPS is a stringified list of tags and COMMENT is the image file's
 comment."
   (format-spec
@@ -1383,61 +1431,76 @@ comment."
               props
               comment))))))
 
-(defun image-dired-dired-file-marked-p ()
-  "Check whether file on current line is marked or not."
+(defun image-dired-dired-file-marked-p (&optional marker)
+  "In Dired, return t if file on current line is marked.
+If optional argument MARKER is non-nil, it is a character to look
+for.  The default is to look for `dired-marker-char'."
+  (setq marker (or marker dired-marker-char))
   (save-excursion
     (beginning-of-line)
-    (looking-at-p dired-re-mark)))
-
-(defun image-dired-modify-mark-on-thumb-original-file (command)
-  "Modify mark in dired buffer.
-COMMAND is one of `mark' for marking file in dired, `unmark' for
-unmarking file in dired or `flag' for flagging file for delete in
-dired."
-  (let ((file-name (image-dired-original-file-name))
-        (dired-buf (image-dired-associated-dired-buffer)))
-    (if (not (and dired-buf file-name))
-        (message "No image, or image with correct properties, at point.")
-    (with-current-buffer dired-buf
-        (message "%s" file-name)
-        (when (dired-goto-file file-name)
-          (cond ((eq command 'mark) (dired-mark 1))
-                ((eq command 'unmark) (dired-unmark 1))
-                ((eq command 'toggle)
-                 (if (image-dired-dired-file-marked-p)
-                     (dired-unmark 1)
-                   (dired-mark 1)))
-                ((eq command 'flag) (dired-flag-file-deletion 1)))
-          (image-dired-thumb-update-marks))))))
+    (and (looking-at dired-re-mark)
+         (= (aref (match-string 0) 0) marker))))
+
+(defun image-dired-dired-file-flagged-p ()
+  "In Dired, return t if file on current line is flagged for deletion."
+  (image-dired-dired-file-marked-p dired-del-marker))
+
+(defmacro image-dired--on-file-in-dired-buffer (&rest body)
+  "Run BODY with point on file at point in Dired buffer.
+Should be called from commands in `image-dired-thumbnail-mode'."
+  (declare (indent defun)
+           (debug 1))
+  `(let ((file-name (image-dired-original-file-name))
+         (dired-buf (image-dired-associated-dired-buffer)))
+     (if (not (and dired-buf file-name))
+         (message "No image, or image with correct properties, at point.")
+       (with-current-buffer dired-buf
+         (when (dired-goto-file file-name)
+           ,@body
+           (image-dired-thumb-update-marks))))))
 
 (defun image-dired-mark-thumb-original-file ()
-  "Mark original image file in associated dired buffer."
-  (interactive)
-  (image-dired-modify-mark-on-thumb-original-file 'mark)
+  "Mark original image file in associated Dired buffer."
+  (interactive nil image-dired-thumbnail-mode)
+  (image-dired--on-file-in-dired-buffer
+    (dired-mark 1))
   (image-dired-forward-image))
 
 (defun image-dired-unmark-thumb-original-file ()
-  "Unmark original image file in associated dired buffer."
-  (interactive)
-  (image-dired-modify-mark-on-thumb-original-file 'unmark)
+  "Unmark original image file in associated Dired buffer."
+  (interactive nil image-dired-thumbnail-mode)
+  (image-dired--on-file-in-dired-buffer
+    (dired-unmark 1))
   (image-dired-forward-image))
 
 (defun image-dired-flag-thumb-original-file ()
-  "Flag original image file for deletion in associated dired buffer."
-  (interactive)
-  (image-dired-modify-mark-on-thumb-original-file 'flag)
+  "Flag original image file for deletion in associated Dired buffer."
+  (interactive nil image-dired-thumbnail-mode)
+  (image-dired--on-file-in-dired-buffer
+    (dired-flag-file-deletion 1))
   (image-dired-forward-image))
 
 (defun image-dired-toggle-mark-thumb-original-file ()
-  "Toggle mark on original image file in associated dired buffer."
-  (interactive)
-  (image-dired-modify-mark-on-thumb-original-file 'toggle))
+  "Toggle mark on original image file in associated Dired buffer."
+  (interactive nil image-dired-thumbnail-mode)
+  (image-dired--on-file-in-dired-buffer
+    (if (image-dired-dired-file-marked-p)
+        (dired-unmark 1)
+      (dired-mark 1))))
+
+(defun image-dired-unmark-all-marks ()
+  "Remove all marks from all files in associated Dired buffer.
+Also update the marks in the thumbnail buffer."
+  (interactive nil image-dired-thumbnail-mode)
+  (with-current-buffer (image-dired-associated-dired-buffer)
+    (dired-unmark-all-marks))
+  (image-dired-thumb-update-marks))
 
 (defun image-dired-jump-original-dired-buffer ()
-  "Jump to the dired buffer associated with the current image file.
+  "Jump to the Dired buffer associated with the current image file.
 You probably want to use this together with
 `image-dired-track-original-file'."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (let ((buf (image-dired-associated-dired-buffer))
         window frame)
     (setq window (image-dired-get-buffer-window buf))
@@ -1492,10 +1555,16 @@ You probably want to use this together with
     (define-key map "\C-p" 'image-dired-previous-line)
     (define-key map "\C-n" 'image-dired-next-line)
 
+    (define-key map "<" #'image-dired-beginning-of-buffer)
+    (define-key map ">" #'image-dired-end-of-buffer)
+    (define-key map (kbd "M-<") #'image-dired-beginning-of-buffer)
+    (define-key map (kbd "M->") #'image-dired-end-of-buffer)
+
     (define-key map "d" 'image-dired-flag-thumb-original-file)
     (define-key map [delete] 'image-dired-flag-thumb-original-file)
     (define-key map "m" 'image-dired-mark-thumb-original-file)
     (define-key map "u" 'image-dired-unmark-thumb-original-file)
+    (define-key map "U" 'image-dired-unmark-all-marks)
     (define-key map "." 'image-dired-track-original-file)
     (define-key map [tab] 'image-dired-jump-original-dired-buffer)
 
@@ -1507,8 +1576,6 @@ You probably want to use this together with
     (define-key map "\C-m" 'image-dired-display-thumbnail-original-image)
     (define-key map [C-return] 'image-dired-thumbnail-display-external)
 
-    (define-key map "l" 'image-dired-rotate-thumbnail-left)
-    (define-key map "r" 'image-dired-rotate-thumbnail-right)
     (define-key map "L" 'image-dired-rotate-original-left)
     (define-key map "R" 'image-dired-rotate-original-right)
 
@@ -1521,6 +1588,15 @@ You probably want to use this together with
     ;; Mouse
     (define-key map [mouse-2] 'image-dired-mouse-display-image)
     (define-key map [mouse-1] 'image-dired-mouse-select-thumbnail)
+    (define-key map [mouse-3] #'image-dired-mouse-select-thumbnail)
+    (define-key map [down-mouse-1] #'image-dired-mouse-select-thumbnail)
+    (define-key map [down-mouse-2] #'image-dired-mouse-select-thumbnail)
+    (define-key map [down-mouse-3] #'image-dired-mouse-select-thumbnail)
+    ;; Let's disable mouse dragging, as it currently doesn't do
+    ;; anything useful.
+    (define-key map [drag-mouse-1] #'ignore)
+    (define-key map [drag-mouse-2] #'ignore)
+    (define-key map [drag-mouse-3] #'ignore)
     ;; Seems I must first set C-down-mouse-1 to undefined, or else it
     ;; will trigger the buffer menu. If I try to instead bind
     ;; C-down-mouse-1 to `image-dired-mouse-toggle-mark', I get a message
@@ -1528,111 +1604,78 @@ You probably want to use this together with
     ;; probably do not completely understand mouse events.
     (define-key map [C-down-mouse-1] 'undefined)
     (define-key map [C-mouse-1] 'image-dired-mouse-toggle-mark)
-
-    ;; Menu
-    (easy-menu-define nil map
-      "Menu for `image-dired-thumbnail-mode'."
-      '("Image-Dired"
-        ["Quit" quit-window]
-        ["Delete thumbnail from buffer" image-dired-delete-char]
-        ["Delete marked images" image-dired-delete-marked]
-        ["Remove tag from current or marked thumbnails"
-         image-dired-tag-thumbnail-remove]
-        ["Tag current or marked thumbnails" image-dired-tag-thumbnail]
-        ["Comment thumbnail" image-dired-comment-thumbnail]
-        ["Refresh thumb" image-dired-refresh-thumb]
-        ["Dynamic line up" image-dired-line-up-dynamic]
-        ["Line up thumbnails" image-dired-line-up]
-
-        ["Rotate thumbnail left" image-dired-rotate-thumbnail-left]
-        ["Rotate thumbnail right" image-dired-rotate-thumbnail-right]
-        ["Rotate original left" image-dired-rotate-original-left]
-        ["Rotate original right" image-dired-rotate-original-right]
-
-        ["Toggle movement tracking on/off" 
image-dired-toggle-movement-tracking]
-
-        ["Jump to dired buffer" image-dired-jump-original-dired-buffer]
-        ["Track original" image-dired-track-original-file]
-
-        ["Flag original for deletion" image-dired-flag-thumb-original-file]
-        ["Unmark original" image-dired-unmark-thumb-original-file]
-        ["Mark original" image-dired-mark-thumb-original-file]
-
-        ["Display in external viewer" image-dired-thumbnail-display-external]
-        ["Display image" image-dired-display-thumbnail-original-image]))
     map)
   "Keymap for `image-dired-thumbnail-mode'.")
 
+(easy-menu-define image-dired-thumbnail-mode-menu 
image-dired-thumbnail-mode-map
+  "Menu for `image-dired-thumbnail-mode'."
+  '("Image-Dired"
+    ["Display image" image-dired-display-thumbnail-original-image]
+    ["Display in external viewer" image-dired-thumbnail-display-external]
+    "---"
+    ["Mark original" image-dired-mark-thumb-original-file]
+    ["Unmark original" image-dired-unmark-thumb-original-file]
+    ["Flag original for deletion" image-dired-flag-thumb-original-file]
+    "---"
+    ["Track original" image-dired-track-original-file]
+    ["Jump to dired buffer" image-dired-jump-original-dired-buffer]
+    ["Toggle movement tracking on/off" image-dired-toggle-movement-tracking
+     :style toggle
+     :selected image-dired-track-movement]
+    "---"
+    ["Rotate original right" image-dired-rotate-original-right]
+    ["Rotate original left" image-dired-rotate-original-left]
+    "---"
+    ["Line up thumbnails" image-dired-line-up]
+    ["Dynamic line up" image-dired-line-up-dynamic]
+    ["Refresh thumb" image-dired-refresh-thumb]
+    "---"
+    ["Comment thumbnail" image-dired-comment-thumbnail]
+    ["Tag current or marked thumbnails" image-dired-tag-thumbnail]
+    "---"
+    ["Remove tag from current or marked thumbnails"
+     image-dired-tag-thumbnail-remove]
+    ["Unmark all marks" image-dired-unmark-all-marks]
+    ["Delete marked images" image-dired-delete-marked]
+    ["Delete thumbnail from buffer" image-dired-delete-char]
+    "---"
+    ["Quit" quit-window]))
+
 (defvar image-dired-display-image-mode-map
   (let ((map (make-sparse-keymap)))
-    ;; `image-mode-map' has bindings that do not make sense in image-dired
-    ;; (set-keymap-parent map image-mode-map)
-    (define-key map "f" 'image-dired-display-current-image-full)
-    (define-key map "s" 'image-dired-display-current-image-sized)
-    (define-key map "g" nil)
-
-    ;; Useful bindings from `image-mode-map'
-    (define-key map [remap forward-char] 'image-forward-hscroll)
-    (define-key map [remap backward-char] 'image-backward-hscroll)
-    (define-key map [remap right-char] 'image-forward-hscroll)
-    (define-key map [remap left-char] 'image-backward-hscroll)
-    (define-key map [remap previous-line] 'image-previous-line)
-    (define-key map [remap next-line] 'image-next-line)
-    (define-key map [remap scroll-up] 'image-scroll-up)
-    (define-key map [remap scroll-down] 'image-scroll-down)
-    (define-key map [remap scroll-up-command] 'image-scroll-up)
-    (define-key map [remap scroll-down-command] 'image-scroll-down)
-    (define-key map [remap scroll-left] 'image-scroll-left)
-    (define-key map [remap scroll-right] 'image-scroll-right)
-    (define-key map [remap move-beginning-of-line] 'image-bol)
-    (define-key map [remap move-end-of-line] 'image-eol)
-    (define-key map [remap beginning-of-buffer] 'image-bob)
-    (define-key map [remap end-of-buffer] 'image-eob)
-
-    (easy-menu-define nil map
-      "Menu for `image-dired-display-image-mode-map'."
-      '("Image-Dired"
-        ["Quit" quit-window]
-        ["Display original, sized to fit" 
image-dired-display-current-image-sized]
-        ["Display original, full size" 
image-dired-display-current-image-full]))
+    ;; Disable keybindings from `image-mode-map' that doesn't make sense here.
+    (define-key map "o" nil) ; image-save
+    (define-key map "n" nil) ; image-next-file
+    (define-key map "p" nil) ; image-previous-file
+    ;; FIXME: Should be replaced with image-dired commands.
+    (define-key map (kbd "DEL") nil) ; image-next-file
+    (define-key map (kbd "SPC") nil) ; image-next-file
+    ;; FIXME: Should be replaced with image-dired commands.
+    (define-key map "m" nil) ; image-mode-mark-file
+    (define-key map "u" nil) ; image-mode-unmark-file
     map)
   "Keymap for `image-dired-display-image-mode'.")
 
-(defun image-dired-display-current-image-full ()
-  "Display current image in full size."
-  (interactive)
-  (let ((file (image-dired-original-file-name)))
-    (if file
-        (progn
-          (image-dired-display-image file t)
-          (message "Full size image displayed"))
-      (error "No original file name at point"))))
-
-(defun image-dired-display-current-image-sized ()
-  "Display current image in sized to fit window dimensions."
-  (interactive)
-  (let ((file (image-dired-original-file-name)))
-    (if file
-        (progn
-          (image-dired-display-image file)
-          (message "Fitted image displayed"))
-      (error "No original file name at point"))))
-
 (define-derived-mode image-dired-thumbnail-mode
   special-mode "image-dired-thumbnail"
-  "Browse and manipulate thumbnail images using dired.
+  "Browse and manipulate thumbnail images using Dired.
 Use `image-dired-minor-mode' to get a nice setup."
   (buffer-disable-undo)
-  (add-hook 'file-name-at-point-functions 'image-dired-file-name-at-point nil 
t))
+  (add-hook 'file-name-at-point-functions 'image-dired-file-name-at-point nil 
t)
+  (setq-local window-resize-pixelwise t)
+  (setq-local bookmark-make-record-function #'image-dired-bookmark-make-record)
+  ;; Use approximately as much vertical spacing as horizontal.
+  (setq-local line-spacing (frame-char-width)))
+
+
+;;; Display image mode
 
 (define-derived-mode image-dired-display-image-mode
-  special-mode "image-dired-image-display"
+  image-mode "image-dired-image-display"
   "Mode for displaying and manipulating original image.
 Resized or in full-size."
-  (buffer-disable-undo)
-  (image-mode-setup-winprops)
-  (setq cursor-type nil)
-  (add-hook 'file-name-at-point-functions 'image-dired-file-name-at-point nil 
t))
+  :interactive nil
+  (add-hook 'file-name-at-point-functions #'image-dired-file-name-at-point nil 
t))
 
 (defvar image-dired-minor-mode-map
   (let ((map (make-sparse-keymap)))
@@ -1656,48 +1699,49 @@ Resized or in full-size."
     (define-key map "\C-t." 'image-dired-display-thumb)
     (define-key map "\C-tc" 'image-dired-dired-comment-files)
     (define-key map "\C-tf" 'image-dired-mark-tagged-files)
-
-    ;; Menu for dired
-    (easy-menu-define nil map
-      "Menu for `image-dired-minor-mode'."
-      '("Image-dired"
-        ["Copy with EXIF file name" image-dired-copy-with-exif-file-name]
-        ["Comment files" image-dired-dired-comment-files]
-        ["Mark tagged files" image-dired-mark-tagged-files]
-        ["Jump to thumbnail buffer" image-dired-jump-thumbnail-buffer]
-
-        ["Toggle movement tracking" image-dired-toggle-movement-tracking]
-        ["Toggle append browsing" image-dired-toggle-append-browsing]
-        ["Toggle display properties" 
image-dired-toggle-dired-display-properties]
-
-        ["Display in external viewer" image-dired-dired-display-external]
-        ["Display image" image-dired-dired-display-image]
-        ["Display this thumbnail" image-dired-display-thumb]
-        ["Display thumbnails append" image-dired-display-thumbs-append]
-
-        ["Create thumbnails for marked files" image-dired-create-thumbs]
-
-        ["Mark and display next" image-dired-mark-and-display-next]
-        ["Display thumb for previous file" 
image-dired-previous-line-and-display]
-        ["Display thumb for next file" image-dired-next-line-and-display]))
     map)
   "Keymap for `image-dired-minor-mode'.")
 
+(easy-menu-define image-dired-minor-mode-menu image-dired-minor-mode-map
+  "Menu for `image-dired-minor-mode'."
+  '("Image-dired"
+    ["Display thumb for next file" image-dired-next-line-and-display]
+    ["Display thumb for previous file" image-dired-previous-line-and-display]
+    ["Mark and display next" image-dired-mark-and-display-next]
+    "---"
+    ["Create thumbnails for marked files" image-dired-create-thumbs]
+    "---"
+    ["Display thumbnails append" image-dired-display-thumbs-append]
+    ["Display this thumbnail" image-dired-display-thumb]
+    ["Display image" image-dired-dired-display-image]
+    ["Display in external viewer" image-dired-dired-display-external]
+    "---"
+    ["Toggle display properties" image-dired-toggle-dired-display-properties
+     :style toggle
+     :selected image-dired-dired-disp-props]
+    ["Toggle append browsing" image-dired-toggle-append-browsing
+     :style toggle
+     :selected image-dired-append-when-browsing]
+    ["Toggle movement tracking" image-dired-toggle-movement-tracking
+     :style toggle
+     :selected image-dired-track-movement]
+    "---"
+    ["Jump to thumbnail buffer" image-dired-jump-thumbnail-buffer]
+    ["Mark tagged files" image-dired-mark-tagged-files]
+    ["Comment files" image-dired-dired-comment-files]
+    ["Copy with EXIF file name" image-dired-copy-with-exif-file-name]))
+
 ;;;###autoload
 (define-minor-mode image-dired-minor-mode
-  "Setup easy-to-use keybindings for the commands to be used in dired mode.
+  "Setup easy-to-use keybindings for the commands to be used in Dired mode.
 Note that n, p and <down> and <up> will be hijacked and bound to
-`image-dired-dired-x-line'."
+`image-dired-dired-next-line' and `image-dired-dired-previous-line'."
   :keymap image-dired-minor-mode-map)
 
-;;;###autoload
-(define-obsolete-function-alias 'image-dired-setup-dired-keybindings 
'image-dired-minor-mode
-  "26.1")
-
 (declare-function clear-image-cache "image.c" (&optional filter))
 
 (defun image-dired-create-thumbs (&optional arg)
-  "Create thumbnail images for all marked files in dired.
+  "Create thumbnail images for all marked files in Dired.
 With prefix argument ARG, create thumbnails even if they already exist
 \(i.e. use this to refresh your thumbnails)."
   (interactive "P")
@@ -1713,6 +1757,9 @@ With prefix argument ARG, create thumbnails even if they 
already exist
                 arg)
         (image-dired-create-thumb curr-file thumb-name)))))
 
+
+;;; Slideshow.
+
 (defvar image-dired-slideshow-timer nil
   "Slideshow timer.")
 
@@ -1750,9 +1797,12 @@ Ask user for number of images to show and the delay in 
between."
   (interactive)
   (cancel-timer image-dired-slideshow-timer))
 
+
+;;; Thumbnail mode (cont. 3)
+
 (defun image-dired-delete-char ()
   "Remove current thumbnail from thumbnail buffer and line up."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (let ((inhibit-read-only t))
     (delete-char 1)
     (when (= (following-char) ?\s)
@@ -1785,18 +1835,26 @@ See also `image-dired-line-up-dynamic'."
                   (not (eobp)))
         (delete-char 1)))
     (goto-char (point-min))
-    (let ((count 0))
+    (let ((seen 0)
+          (thumb-prev-pos 0)
+          (thumb-width-chars
+           (ceiling (/ (+ (* 2 image-dired-thumb-relief)
+                          (* 2 image-dired-thumb-margin)
+                          (image-dired-thumb-size 'width))
+                       (float (frame-char-width))))))
       (while (not (eobp))
         (forward-char)
         (if (= image-dired-thumbs-per-row 1)
             (insert "\n")
-          (insert " ")
-          (setq count (1+ count))
-          (when (and (= count (- image-dired-thumbs-per-row 1))
+          (cl-incf thumb-prev-pos thumb-width-chars)
+          (insert (propertize " " 'display `(space :align-to ,thumb-prev-pos)))
+          (cl-incf seen)
+          (when (and (= seen (- image-dired-thumbs-per-row 1))
                     (not (eobp)))
             (forward-char)
             (insert "\n")
-            (setq count 0)))))
+            (setq seen 0)
+            (setq thumb-prev-pos 0)))))
     (goto-char (point-min))))
 
 (defun image-dired-line-up-dynamic ()
@@ -1846,11 +1904,6 @@ Ask user how many thumbnails should be displayed per 
row."
   "Calculate WINDOW width in pixels."
     (* (window-width window) (frame-char-width)))
 
-(defun image-dired-window-height-pixels (window)
-  "Calculate WINDOW height in pixels."
-  ;; Note: The mode-line consumes one line
-    (* (- (window-height window) 1) (frame-char-height)))
-
 (defun image-dired-display-window ()
   "Return window where `image-dired-display-image-buffer' is visible."
   (get-window-with-predicate
@@ -1866,7 +1919,7 @@ Ask user how many thumbnails should be displayed per row."
    nil t))
 
 (defun image-dired-associated-dired-buffer-window ()
-  "Return window where associated dired buffer is visible."
+  "Return window where associated Dired buffer is visible."
   (let (buf)
     (if (image-dired-image-at-point-p)
         (progn
@@ -1876,59 +1929,24 @@ Ask user how many thumbnails should be displayed per 
row."
              (equal (window-buffer window) buf))))
       (error "No thumbnail image at point"))))
 
-(defun image-dired-display-window-width (window)
-  "Return width, in pixels, of WINDOW."
-  (- (image-dired-window-width-pixels window)
-     image-dired-display-window-width-correction))
-
-(defun image-dired-display-window-height (window)
-  "Return height, in pixels, of WINDOW."
-  (- (image-dired-window-height-pixels window)
-     image-dired-display-window-height-correction))
-
-(defun image-dired-display-image (file &optional original-size)
+(defun image-dired-display-image (file &optional _ignored)
   "Display image FILE in image buffer.
-Use this when you want to display the image, semi sized, in a new
-window.  The image is sized to fit the display window (using a
-temporary file, don't worry).  Because of this, it will not be as
-quick as opening it directly, but on most modern systems it
-should feel snappy enough.
-
-If optional argument ORIGINAL-SIZE is non-nil, display image in its
-original size."
-  (image-dired--check-executable-exists
-   'image-dired-cmd-create-temp-image-program)
-  (let ((new-file (expand-file-name image-dired-temp-image-file))
-        (window (image-dired-display-window))
-        (image-type 'jpeg))
-    (setq file (expand-file-name file))
-    (if (not original-size)
-        (let* ((spec
-                (list
-                 (cons ?p image-dired-cmd-create-temp-image-program)
-                 (cons ?w (image-dired-display-window-width window))
-                 (cons ?h (image-dired-display-window-height window))
-                 (cons ?f file)
-                 (cons ?t new-file)))
-               (ret
-                (apply #'call-process
-                       image-dired-cmd-create-temp-image-program nil nil nil
-                       (mapcar
-                        (lambda (arg) (format-spec arg spec))
-                        image-dired-cmd-create-temp-image-options))))
-          (when (not (zerop ret))
-            (error "Could not resize image")))
-      (setq image-type (image-type-from-file-name file))
-      (copy-file file new-file t))
-    (with-current-buffer (image-dired-create-display-image-buffer)
-      (let ((inhibit-read-only t))
-        (erase-buffer)
-        (clear-image-cache)
-        (image-dired-insert-image image-dired-temp-image-file image-type 0 0)
-        (goto-char (point-min))
-        (set-window-vscroll window 0)
-        (set-window-hscroll window 0)
-        (image-dired-update-property 'original-file-name file)))))
+Use this when you want to display the image, in a new window.
+The window will use `image-dired-display-image-mode' which is
+based on `image-mode'."
+  (declare (advertised-calling-convention (file) "29.1"))
+  (setq file (expand-file-name file))
+  (when (not (file-exists-p file))
+    (error "No such file: %s" file))
+  (let ((buf (get-buffer image-dired-display-image-buffer))
+        (cur-win (selected-window)))
+    (when buf
+      (kill-buffer buf))
+    (when-let ((buf (find-file-other-window file)))
+      (display-buffer buf)
+      (rename-buffer image-dired-display-image-buffer)
+      (image-dired-display-image-mode)
+      (select-window cur-win))))
 
 (defun image-dired-display-thumbnail-original-image (&optional arg)
   "Display current thumbnail's original image in display buffer.
@@ -1942,8 +1960,6 @@ With prefix argument ARG, display image in its original 
size."
           (message "No thumbnail at point")
         (if (not file)
             (message "No original file name found")
-         (image-dired-create-display-image-buffer)
-          (display-buffer image-dired-display-image-buffer)
           (image-dired-display-image file arg))))))
 
 
@@ -1953,41 +1969,15 @@ With prefix argument ARG, display image in its original 
size."
 See documentation for `image-dired-display-image' for more information.
 With prefix argument ARG, display image in its original size."
   (interactive "P")
-  (image-dired-create-display-image-buffer)
-  (display-buffer image-dired-display-image-buffer)
   (image-dired-display-image (dired-get-filename) arg))
 
 (defun image-dired-image-at-point-p ()
   "Return non-nil if there is an `image-dired' thumbnail at point."
   (get-text-property (point) 'image-dired-thumbnail))
 
-(defun image-dired-rotate-thumbnail (degrees)
-  "Rotate thumbnail DEGREES degrees."
-  (image-dired--check-executable-exists
-   'image-dired-cmd-rotate-thumbnail-program)
-  (if (not (image-dired-image-at-point-p))
-      (message "No thumbnail at point")
-    (let* ((file (image-dired-thumb-name (image-dired-original-file-name)))
-           (thumb (expand-file-name file))
-           (spec (list (cons ?d degrees) (cons ?t thumb))))
-      (apply #'call-process image-dired-cmd-rotate-thumbnail-program nil nil 
nil
-             (mapcar (lambda (arg) (format-spec arg spec))
-                     image-dired-cmd-rotate-thumbnail-options))
-      (clear-image-cache thumb))))
-
-(defun image-dired-rotate-thumbnail-left ()
-  "Rotate thumbnail left (counter clockwise) 90 degrees."
-  (interactive)
-  (image-dired-rotate-thumbnail "270"))
-
-(defun image-dired-rotate-thumbnail-right ()
-  "Rotate thumbnail counter right (clockwise) 90 degrees."
-  (interactive)
-  (image-dired-rotate-thumbnail "90"))
-
 (defun image-dired-refresh-thumb ()
   "Force creation of new image for current thumbnail."
-  (interactive)
+  (interactive nil image-dired-thumbnail-mode)
   (let* ((file (image-dired-original-file-name))
          (thumb (expand-file-name (image-dired-thumb-name file))))
     (clear-image-cache (expand-file-name thumb))
@@ -2040,6 +2030,9 @@ overwritten.  This confirmation can be turned off using
   (interactive)
   (image-dired-rotate-original "90"))
 
+
+;;; EXIF support
+
 (defun image-dired-get-exif-file-name (file)
   "Use the image's EXIF information to return a unique file name.
 The file name should be unique as long as you do not take more than
@@ -2054,8 +2047,8 @@ YYYY_MM_DD_HH_MM_DD_ORIG_FILE_NAME.jpg.  Used from
                     "%Y:%m:%d %H:%M:%S"
                     (file-attribute-modification-time
                      (file-attributes (expand-file-name file)))))
-      (setq data (image-dired-get-exif-data (expand-file-name file)
-                                            "DateTimeOriginal")))
+      (setq data (exif-field 'date-time (exif-parse-file
+                                         (expand-file-name file)))))
     (while (string-match "[ :]" data)
       (setq data (replace-match "_" nil nil data)))
     (format "%s%s%s" data
@@ -2072,7 +2065,7 @@ default value at the prompt."
   (if (not (image-dired-image-at-point-p))
       (message "No thumbnail at point")
     (let* ((file (image-dired-original-file-name))
-           (old-value (image-dired-get-exif-data file "ImageDescription")))
+           (old-value (or (exif-field 'description (exif-parse-file file)) 
"")))
       (if (eq 0
               (image-dired-set-exif-data file "ImageDescription"
                                    (read-string "Value of ImageDescription: "
@@ -2093,33 +2086,9 @@ default value at the prompt."
            (mapcar (lambda (arg) (format-spec arg spec))
                    image-dired-cmd-write-exif-data-options))))
 
-(defun image-dired-get-exif-data (file tag-name)
-  "From FILE, return EXIF tag TAG-NAME."
-  (image-dired--check-executable-exists
-   'image-dired-cmd-read-exif-data-program)
-  (let ((buf (get-buffer-create "*image-dired-get-exif-data*"))
-        (spec (list (cons ?f file) (cons ?t tag-name)))
-        tag-value)
-    (with-current-buffer buf
-      (delete-region (point-min) (point-max))
-      (if (not (eq (apply #'call-process image-dired-cmd-read-exif-data-program
-                          nil t nil
-                          (mapcar
-                           (lambda (arg) (format-spec arg spec))
-                           image-dired-cmd-read-exif-data-options))
-                   0))
-          (error "Could not get EXIF tag")
-        (goto-char (point-min))
-        ;; Clean buffer from newlines and carriage returns before
-        ;; getting final info
-        (while (search-forward-regexp "[\n\r]" nil t)
-          (replace-match "" nil t))
-        (setq tag-value (buffer-substring (point-min) (point-max)))))
-    tag-value))
-
 (defun image-dired-copy-with-exif-file-name ()
   "Copy file with unique name to main image directory.
-Copy current or all marked files in dired to a new file in your
+Copy current or all marked files in Dired to a new file in your
 main image directory, using a file name generated by
 `image-dired-get-exif-file-name'.  A typical usage for this if when
 copying images from a digital camera into the image directory.
@@ -2144,18 +2113,24 @@ function.  The result is a couple of new files in
        (copy-file curr-file new-name))
      files)))
 
-(defun image-dired-display-next-thumbnail-original ()
-  "In thumbnail buffer, move to next thumbnail and display the image."
-  (interactive)
-  (image-dired-forward-image)
-  (image-dired-display-thumbnail-original-image))
+;;; Thumbnail mode (cont.)
 
-(defun image-dired-display-previous-thumbnail-original ()
-  "Move to previous thumbnail and display image."
-  (interactive)
-  (image-dired-backward-image)
+(defun image-dired-display-next-thumbnail-original (&optional arg)
+  "In thumbnail buffer, move to next thumbnail and display the image.
+With prefix ARG, move that many thumbnails."
+  (interactive "p" image-dired-thumbnail-mode)
+  (image-dired-forward-image arg t)
   (image-dired-display-thumbnail-original-image))
 
+(defun image-dired-display-previous-thumbnail-original (arg)
+  "In thumbnail buffer, move to previous thumbnail and display image.
+With prefix ARG, move that many thumbnails."
+  (interactive "p" image-dired-thumbnail-mode)
+  (image-dired-display-next-thumbnail-original (- arg)))
+
+
+;;; Image Comments
+
 (defun image-dired-write-comments (file-comments)
   "Write file comments to database.
 Write file comments to one or more files.
@@ -2203,7 +2178,7 @@ FILE-COMMENTS is an alist on the following form:
 
 ;;;###autoload
 (defun image-dired-dired-comment-files ()
-  "Add comment to current or marked files in dired."
+  "Add comment to current or marked files in Dired."
   (interactive)
   (let ((comment (image-dired-read-comment)))
     (image-dired-write-comments
@@ -2255,7 +2230,7 @@ A `tag' is a keyword, a piece of meta data, associated 
with an
 image file and stored in image-dired's database file.  This command
 lets you input a regexp and this will be matched against all tags
 on all image files in the database file.  The files that have a
-matching tag will be marked in the dired buffer."
+matching tag will be marked in the Dired buffer."
   (interactive)
   (image-dired-sane-db-file)
   (let ((tag (read-string "Mark tagged files (regexp): "))
@@ -2282,50 +2257,69 @@ matching tag will be marked in the dired buffer."
          (dired-mark 1))))
     (message "%d files with matching tag marked." hits)))
 
+
+
+;;; Mouse support
+
 (defun image-dired-mouse-display-image (event)
   "Use mouse EVENT, call `image-dired-display-image' to display image.
-Track this in associated dired buffer if `image-dired-track-movement' is
+Track this in associated Dired buffer if `image-dired-track-movement' is
 non-nil."
   (interactive "e")
   (mouse-set-point event)
   (goto-char (posn-point (event-end event)))
+  (unless (image-at-point-p)
+    (image-dired-backward-image))
   (let ((file (image-dired-original-file-name)))
     (when file
       (if image-dired-track-movement
          (image-dired-track-original-file))
-      (image-dired-create-display-image-buffer)
-      (display-buffer image-dired-display-image-buffer)
       (image-dired-display-image file))))
 
 (defun image-dired-mouse-select-thumbnail (event)
   "Use mouse EVENT to select thumbnail image.
-Track this in associated dired buffer if `image-dired-track-movement' is
+Track this in associated Dired buffer if `image-dired-track-movement' is
 non-nil."
   (interactive "e")
   (mouse-set-point event)
   (goto-char (posn-point (event-end event)))
+  (unless (image-at-point-p)
+    (image-dired-backward-image))
   (if image-dired-track-movement
       (image-dired-track-original-file))
   (image-dired-display-thumb-properties))
 
-(defun image-dired-thumb-file-marked-p ()
-  "Check if file is marked in associated dired buffer."
+
+
+;;; Dired marks and tags
+
+(defun image-dired-thumb-file-marked-p (&optional flagged)
+  "Check if file is marked in associated Dired buffer.
+If optional argument FLAGGED is non-nil, check if file is flagged
+for deletion instead."
   (let ((file-name (image-dired-original-file-name))
         (dired-buf (image-dired-associated-dired-buffer)))
     (when (and dired-buf file-name)
       (with-current-buffer dired-buf
-        (when (dired-goto-file file-name)
-          (image-dired-dired-file-marked-p))))))
+        (save-excursion
+          (when (dired-goto-file file-name)
+            (if flagged
+                (image-dired-dired-file-flagged-p)
+              (image-dired-dired-file-marked-p))))))))
+
+(defun image-dired-thumb-file-flagged-p ()
+  "Check if file is flagged for deletion in associated Dired buffer."
+  (image-dired-thumb-file-marked-p t))
 
 (defun image-dired-delete-marked ()
   "Delete current or marked thumbnails and associated images."
   (interactive)
-  (with-current-buffer (image-dired-associated-dired-buffer)
-    (dired-do-delete))
   (image-dired--with-marked
    (image-dired-delete-char)
    (backward-char))
-  (image-dired--line-up-with-method))
+  (image-dired--line-up-with-method)
+  (with-current-buffer (image-dired-associated-dired-buffer)
+    (dired-do-delete)))
 
 (defun image-dired-thumb-update-marks ()
   "Update the marks in the thumbnail buffer."
@@ -2336,26 +2330,29 @@ non-nil."
         (let ((inhibit-read-only t))
           (while (not (eobp))
             (with-silent-modifications
-              (if (image-dired-thumb-file-marked-p)
-                  (add-face-text-property (point) (1+ (point))
-                                          'image-dired-thumb-mark)
-                (remove-text-properties (point) (1+ (point))
-                                        '(face image-dired-thumb-mark))))
+              (cond ((image-dired-thumb-file-marked-p)
+                     (add-face-text-property (point) (1+ (point))
+                                             'image-dired-thumb-mark))
+                    ((image-dired-thumb-file-flagged-p)
+                     (add-face-text-property (point) (1+ (point))
+                                             'image-dired-thumb-flagged))
+                    (t (remove-text-properties (point) (1+ (point))
+                                               '(face 
image-dired-thumb-mark)))))
             (forward-char)))))))
 
 (defun image-dired-mouse-toggle-mark-1 ()
-  "Toggle dired mark for current thumbnail.
-Track this in associated dired buffer if `image-dired-track-movement' is
-non-nil."
+  "Toggle Dired mark for current thumbnail.
+Track this in associated Dired buffer if
+`image-dired-track-movement' is non-nil."
   (when image-dired-track-movement
     (image-dired-track-original-file))
   (image-dired-toggle-mark-thumb-original-file))
 
 (defun image-dired-mouse-toggle-mark (event)
-  "Use mouse EVENT to toggle dired mark for thumbnail.
+  "Use mouse EVENT to toggle Dired mark for thumbnail.
 Toggle marks of all thumbnails in region, if it's active.
-Track this in associated dired buffer if `image-dired-track-movement' is
-non-nil."
+Track this in associated Dired buffer if
+`image-dired-track-movement' is non-nil."
   (interactive "e")
   (if (use-region-p)
       (let ((end (region-end)))
@@ -2371,7 +2368,7 @@ non-nil."
   (image-dired-thumb-update-marks))
 
 (defun image-dired-dired-display-properties ()
-  "Display properties for dired file in the echo area."
+  "Display properties for Dired file in the echo area."
   (interactive)
   (let* ((file (dired-get-filename))
          (file-name (file-name-nondirectory file))
@@ -2387,6 +2384,53 @@ non-nil."
           props
           comment)))))
 
+
+
+;;; Gallery support
+
+;; TODO:
+;; * Support gallery creation when using per-directory thumbnail
+;;   storage.
+;; * Enhanced gallery creation with basic CSS-support and pagination
+;;   of tag pages with many pictures.
+
+(defgroup image-dired-gallery nil
+  "Image-Dired support for generating a HTML gallery."
+  :prefix "image-dired-"
+  :group 'image-dired
+  :version "29.1")
+
+(defcustom image-dired-gallery-dir
+  (expand-file-name ".image-dired_gallery" image-dired-dir)
+  "Directory to store generated gallery html pages.
+The name of this directory needs to be \"shared\" to the public
+so that it can access the index.html page that image-dired creates."
+  :type 'directory)
+
+(defcustom image-dired-gallery-image-root-url
+  "https://example.org/image-diredpics";
+  "URL where the full size images are to be found on your web server.
+Note that this URL has to be configured on your web server.
+Image-Dired expects to find pictures in this directory.
+This is used by `image-dired-gallery-generate'."
+  :type 'string
+  :version "29.1")
+
+(defcustom image-dired-gallery-thumb-image-root-url
+  "https://example.org/image-diredthumbs";
+  "URL where the thumbnail images are to be found on your web server.
+Note that URL path has to be configured on your web server.
+Image-Dired expects to find pictures in this directory.
+This is used by `image-dired-gallery-generate'."
+  :type 'string
+  :version "29.1")
+
+(defcustom image-dired-gallery-hidden-tags
+  (list "private" "hidden" "pending")
+  "List of \"hidden\" tags.
+Used by `image-dired-gallery-generate' to leave out \"hidden\" images."
+  :type '(repeat string))
+
 (defvar image-dired-tag-file-list nil
   "List to store tag-file structure.")
 
@@ -2396,19 +2440,8 @@ non-nil."
 (defvar image-dired-file-comment-list nil
   "List to store file comments.")
 
-(defun image-dired-add-to-tag-file-list (tag file)
-  "Add relation between TAG and FILE."
-  (let (curr)
-    (if image-dired-tag-file-list
-        (if (setq curr (assoc tag image-dired-tag-file-list))
-            (if (not (member file curr))
-                (setcdr curr (cons file (cdr curr))))
-          (setcdr image-dired-tag-file-list
-                  (cons (list tag file) (cdr image-dired-tag-file-list))))
-      (setq image-dired-tag-file-list (list (list tag file))))))
-
-(defun image-dired-add-to-tag-file-lists (tag file)
-  "Helper function used from `image-dired-create-gallery-lists'.
+(defun image-dired--add-to-tag-file-lists (tag file)
+  "Helper function used from `image-dired--create-gallery-lists'.
 
 Add TAG to FILE in one list and FILE to TAG in the other.
 
@@ -2442,8 +2475,8 @@ image-dired-tag-file-list:
                   (cons (list tag file) (cdr image-dired-tag-file-list))))
       (setq image-dired-tag-file-list (list (list tag file))))))
 
-(defun image-dired-add-to-file-comment-list (file comment)
-  "Helper function used from `image-dired-create-gallery-lists'.
+(defun image-dired--add-to-file-comment-list (file comment)
+  "Helper function used from `image-dired--create-gallery-lists'.
 
 For FILE, add COMMENT to list.
 
@@ -2461,7 +2494,7 @@ image-dired-file-comment-list:
                         (cdr image-dired-file-comment-list))))
     (setq image-dired-file-comment-list (list (cons file comment)))))
 
-(defun image-dired-create-gallery-lists ()
+(defun image-dired--create-gallery-lists ()
   "Create temporary lists used by `image-dired-gallery-generate'."
   (image-dired-sane-db-file)
   (image-dired--with-db-file
@@ -2482,15 +2515,15 @@ image-dired-file-comment-list:
        (setq file (car row-tags))
        (dolist (x (cdr row-tags))
         (if (not (string-match "^comment:\\(.*\\)" x))
-            (image-dired-add-to-tag-file-lists x file)
-          (image-dired-add-to-file-comment-list file (match-string 1 x)))))))
+             (image-dired--add-to-tag-file-lists x file)
+           (image-dired--add-to-file-comment-list file (match-string 1 x)))))))
   ;; Sort tag-file list
   (setq image-dired-tag-file-list
         (sort image-dired-tag-file-list
               (lambda (x y)
                 (string< (car x) (car y))))))
 
-(defun image-dired-hidden-p (file)
+(defun image-dired--hidden-p (file)
   "Return t if image FILE has a \"hidden\" tag."
   (cl-loop for tag in (cdr (assoc file image-dired-file-tag-list))
            if (member tag image-dired-gallery-hidden-tags) return t))
@@ -2504,7 +2537,7 @@ it easier to generate, then HTML-files are created in
   (if (eq 'per-directory image-dired-thumbnail-storage)
       (error "Currently, gallery generation is not supported \
 when using per-directory thumbnail file storage"))
-  (image-dired-create-gallery-lists)
+  (image-dired--create-gallery-lists)
   (let ((tags image-dired-tag-file-list)
        (index-file (format "%s/index.html" image-dired-gallery-dir))
         count tag tag-file
@@ -2513,6 +2546,7 @@ when using per-directory thumbnail file storage"))
     (if (file-exists-p image-dired-gallery-dir)
         (if (not (file-directory-p image-dired-gallery-dir))
             (error "Variable image-dired-gallery-dir is not a directory"))
+      ;; FIXME: Should we set umask to 077 here, as we do for thumbnails?
       (make-directory image-dired-gallery-dir))
     ;; Open index file
     (with-temp-file index-file
@@ -2585,6 +2619,9 @@ when using per-directory thumbnail file storage"))
       (insert "  </body>\n")
       (insert "</html>"))))
 
+
+;;; Tag support
+
 (defvar image-dired-widget-list nil
   "List to keep track of meta data in edit buffer.")
 
@@ -2686,6 +2723,272 @@ tags to their respective image file.  Internal function 
used by
        (dolist (tag tag-list)
          (push (cons file tag) lst))))))
 
+
+;;; bookmark.el support
+
+(declare-function bookmark-make-record-default
+                  "bookmark" (&optional no-file no-context posn))
+(declare-function bookmark-prop-get "bookmark" (bookmark prop))
+
+(defun image-dired-bookmark-name ()
+  "Create a default bookmark name for the current EWW buffer."
+  (file-name-nondirectory
+   (directory-file-name
+    (file-name-directory (image-dired-original-file-name)))))
+
+(defun image-dired-bookmark-make-record ()
+  "Create a bookmark for the current EWW buffer."
+  `(,(image-dired-bookmark-name)
+    ,@(bookmark-make-record-default t)
+    (location . ,(file-name-directory (image-dired-original-file-name)))
+    (image-dired-file . ,(file-name-nondirectory 
(image-dired-original-file-name)))
+    (handler . image-dired-bookmark-jump)))
+
+;;;###autoload
+(defun image-dired-bookmark-jump (bookmark)
+  "Default bookmark handler for Image-Dired buffers."
+  ;; User already cached thumbnails, so disable any checking.
+  (let ((image-dired-show-all-from-dir-max-files nil))
+    (image-dired (bookmark-prop-get bookmark 'location))
+    ;; TODO: Go to the bookmarked file, if it exists.
+    ;; (bookmark-prop-get bookmark 'image-dired-file)
+    (goto-char (point-min))))
+
+
+;;; Obsolete
+
+;;;###autoload
+(define-obsolete-function-alias 'tumme #'image-dired "24.4")
+
+;;;###autoload
+(define-obsolete-function-alias 'image-dired-setup-dired-keybindings
+  #'image-dired-minor-mode "26.1")
+
+(defcustom image-dired-temp-image-file
+  (expand-file-name ".image-dired_temp" image-dired-dir)
+  "Name of temporary image file used by various commands."
+  :type 'file)
+(make-obsolete-variable 'image-dired-temp-image-file
+                        "no longer used." "29.1")
+
+(defcustom image-dired-cmd-create-temp-image-program
+  (if (executable-find "gm") "gm" "convert")
+  "Executable used to create temporary image.
+Used together with `image-dired-cmd-create-temp-image-options'."
+  :type 'file
+  :version "29.1")
+(make-obsolete-variable 'image-dired-cmd-create-temp-image-program
+                        "no longer used." "29.1")
+
+(defcustom image-dired-cmd-create-temp-image-options
+  (let ((opts '("-size" "%wx%h" "%f[0]"
+                "-resize" "%wx%h>"
+                "-strip" "jpeg:%t")))
+    (if (executable-find "gm") (cons "convert" opts) opts))
+  "Options of command used to create temporary image for display window.
+Used together with `image-dired-cmd-create-temp-image-program',
+Available format specifiers are: %w and %h which are replaced by
+the calculated max size for width and height in the image display window,
+%f which is replaced by the file name of the original image and %t which
+is replaced by the file name of the temporary file."
+  :version "29.1"
+  :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'image-dired-cmd-create-temp-image-options
+                        "no longer used." "29.1")
+
+(defcustom image-dired-display-window-width-correction 1
+  "Number to be used to correct image display window width.
+Change if the default (1) does not work (i.e. if the image does not
+completely fit)."
+  :type 'integer)
+(make-obsolete-variable 'image-dired-display-window-width-correction
+                        "no longer used." "29.1")
+
+(defcustom image-dired-display-window-height-correction 0
+  "Number to be used to correct image display window height.
+Change if the default (0) does not work (i.e. if the image does not
+completely fit)."
+  :type 'integer)
+(make-obsolete-variable 'image-dired-display-window-height-correction
+                        "no longer used." "29.1")
+
+(defun image-dired-display-window-width (window)
+  "Return width, in pixels, of WINDOW."
+  (declare (obsolete nil "29.1"))
+  (- (image-dired-window-width-pixels window)
+     image-dired-display-window-width-correction))
+
+(defun image-dired-display-window-height (window)
+  "Return height, in pixels, of WINDOW."
+  (declare (obsolete nil "29.1"))
+  (- (image-dired-window-height-pixels window)
+     image-dired-display-window-height-correction))
+
+(defun image-dired-window-height-pixels (window)
+  "Calculate WINDOW height in pixels."
+  (declare (obsolete nil "29.1"))
+  ;; Note: The mode-line consumes one line
+    (* (- (window-height window) 1) (frame-char-height)))
+
+(defcustom image-dired-cmd-read-exif-data-program "exiftool"
+  "Program used to read EXIF data to image.
+Used together with `image-dired-cmd-read-exif-data-options'."
+  :type 'file)
+(make-obsolete-variable 'image-dired-cmd-read-exif-data-program
+                        "use `exif-parse-file' and `exif-field' instead." 
"29.1")
+
+(defcustom image-dired-cmd-read-exif-data-options '("-s" "-s" "-s" "-%t" "%f")
+  "Arguments of command used to read EXIF data.
+Used with `image-dired-cmd-read-exif-data-program'.
+Available format specifiers are: %f which is replaced
+by the image file name and %t which is replaced by the tag name."
+  :version "26.1"
+  :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'image-dired-cmd-read-exif-data-options
+                        "use `exif-parse-file' and `exif-field' instead." 
"29.1")
+
+(defun image-dired-get-exif-data (file tag-name)
+  "From FILE, return EXIF tag TAG-NAME."
+  (declare (obsolete "use `exif-parse-file' and `exif-field' instead."  
"29.1"))
+  (image-dired--check-executable-exists
+   'image-dired-cmd-read-exif-data-program)
+  (let ((buf (get-buffer-create "*image-dired-get-exif-data*"))
+        (spec (list (cons ?f file) (cons ?t tag-name)))
+        tag-value)
+    (with-current-buffer buf
+      (delete-region (point-min) (point-max))
+      (if (not (eq (apply #'call-process image-dired-cmd-read-exif-data-program
+                          nil t nil
+                          (mapcar
+                           (lambda (arg) (format-spec arg spec))
+                           image-dired-cmd-read-exif-data-options))
+                   0))
+          (error "Could not get EXIF tag")
+        (goto-char (point-min))
+        ;; Clean buffer from newlines and carriage returns before
+        ;; getting final info
+        (while (search-forward-regexp "[\n\r]" nil t)
+          (replace-match "" nil t))
+        (setq tag-value (buffer-substring (point-min) (point-max)))))
+    tag-value))
+
+(defcustom image-dired-cmd-rotate-thumbnail-program
+  (if (executable-find "gm") "gm" "mogrify")
+  "Executable used to rotate thumbnail.
+Used together with `image-dired-cmd-rotate-thumbnail-options'."
+  :type 'file
+  :version "29.1")
+(make-obsolete-variable 'image-dired-cmd-rotate-thumbnail-program nil "29.1")
+
+(defcustom image-dired-cmd-rotate-thumbnail-options
+  (let ((opts '("-rotate" "%d" "%t")))
+    (if (executable-find "gm") (cons "mogrify" opts) opts))
+  "Arguments of command used to rotate thumbnail image.
+Used with `image-dired-cmd-rotate-thumbnail-program'.
+Available format specifiers are: %d which is replaced by the
+number of (positive) degrees to rotate the image, normally 90 or 270
+\(for 90 degrees right and left), %t which is replaced by the file name
+of the thumbnail file."
+  :version "29.1"
+  :type '(repeat (string :tag "Argument")))
+(make-obsolete-variable 'image-dired-cmd-rotate-thumbnail-options nil "29.1")
+
+(defun image-dired-rotate-thumbnail (degrees)
+  "Rotate thumbnail DEGREES degrees."
+  (declare (obsolete image-dired-refresh-thumb "29.1"))
+  (image-dired--check-executable-exists
+   'image-dired-cmd-rotate-thumbnail-program)
+  (if (not (image-dired-image-at-point-p))
+      (message "No thumbnail at point")
+    (let* ((file (image-dired-thumb-name (image-dired-original-file-name)))
+           (thumb (expand-file-name file))
+           (spec (list (cons ?d degrees) (cons ?t thumb))))
+      (apply #'call-process image-dired-cmd-rotate-thumbnail-program nil nil 
nil
+             (mapcar (lambda (arg) (format-spec arg spec))
+                     image-dired-cmd-rotate-thumbnail-options))
+      (clear-image-cache thumb))))
+
+(defun image-dired-rotate-thumbnail-left ()
+  "Rotate thumbnail left (counter clockwise) 90 degrees."
+  (declare (obsolete image-dired-refresh-thumb "29.1"))
+  (interactive)
+  (with-suppressed-warnings ((obsolete image-dired-rotate-thumbnail))
+    (image-dired-rotate-thumbnail "270")))
+
+(defun image-dired-rotate-thumbnail-right ()
+  "Rotate thumbnail counter right (clockwise) 90 degrees."
+  (declare (obsolete image-dired-refresh-thumb "29.1"))
+  (interactive)
+  (with-suppressed-warnings ((obsolete image-dired-rotate-thumbnail))
+    (image-dired-rotate-thumbnail "90")))
+
+(defun image-dired-modify-mark-on-thumb-original-file (command)
+  "Modify mark in Dired buffer.
+COMMAND is one of `mark' for marking file in Dired, `unmark' for
+unmarking file in Dired or `flag' for flagging file for delete in
+Dired."
+  (declare (obsolete image-dired--on-file-in-dired-buffer "29.1"))
+  (let ((file-name (image-dired-original-file-name))
+        (dired-buf (image-dired-associated-dired-buffer)))
+    (if (not (and dired-buf file-name))
+        (message "No image, or image with correct properties, at point.")
+    (with-current-buffer dired-buf
+        (message "%s" file-name)
+        (when (dired-goto-file file-name)
+          (cond ((eq command 'mark) (dired-mark 1))
+                ((eq command 'unmark) (dired-unmark 1))
+                ((eq command 'toggle)
+                 (if (image-dired-dired-file-marked-p)
+                     (dired-unmark 1)
+                   (dired-mark 1)))
+                ((eq command 'flag) (dired-flag-file-deletion 1)))
+          (image-dired-thumb-update-marks))))))
+
+(defun image-dired-display-current-image-full ()
+  "Display current image in full size."
+  (declare (obsolete image-transform-original "29.1"))
+  (interactive nil image-dired-thumbnail-mode)
+  (let ((file (image-dired-original-file-name)))
+    (if file
+        (progn
+          (image-dired-display-image file)
+          (with-current-buffer image-dired-display-image-buffer
+            (image-transform-original)))
+      (error "No original file name at point"))))
+
+(defun image-dired-display-current-image-sized ()
+  "Display current image in sized to fit window dimensions."
+  (declare (obsolete image-mode-fit-frame "29.1"))
+  (interactive nil image-dired-thumbnail-mode)
+  (let ((file (image-dired-original-file-name)))
+    (if file
+        (progn
+          (image-dired-display-image file))
+      (error "No original file name at point"))))
+
+(defun image-dired-add-to-tag-file-list (tag file)
+  "Add relation between TAG and FILE."
+  (declare (obsolete nil "29.1"))
+  (let (curr)
+    (if image-dired-tag-file-list
+        (if (setq curr (assoc tag image-dired-tag-file-list))
+            (if (not (member file curr))
+                (setcdr curr (cons file (cdr curr))))
+          (setcdr image-dired-tag-file-list
+                  (cons (list tag file) (cdr image-dired-tag-file-list))))
+      (setq image-dired-tag-file-list (list (list tag file))))))
+
+(define-obsolete-function-alias 'image-dired-create-display-image-buffer
+  #'ignore "29.1")
+(define-obsolete-function-alias 'image-dired-create-gallery-lists
+  #'image-dired--create-gallery-lists "29.1")
+(define-obsolete-function-alias 'image-dired-add-to-file-comment-list
+  #'image-dired--add-to-file-comment-list "29.1")
+(define-obsolete-function-alias 'image-dired-add-to-tag-file-lists
+  #'image-dired--add-to-tag-file-lists "29.1")
+(define-obsolete-function-alias 'image-dired-hidden-p
+  #'image-dired--hidden-p "29.1")
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;; TEST-SECTION ;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2717,23 +3020,6 @@ tags to their respective image file.  Internal function 
used by
 ;;       (setq dirsize (- dirsize (car (cdar files))))
 ;;       (setq files (cdr files)))))
 
-;;;;;;;;;;;;;;;;;;;;;;,
-
-;; (defun dired-speedbar-buttons (dired-buffer)
-;;   (when (and (boundp 'image-dired-use-speedbar)
-;;          image-dired-use-speedbar)
-;;     (let ((filename (with-current-buffer dired-buffer
-;;                   (dired-get-filename))))
-;;       (when (and (not (string-equal filename (buffer-string)))
-;;              (string-match (image-file-name-regexp) filename))
-;;     (erase-buffer)
-;;     (insert (propertize
-;;              filename
-;;              'display
-;;              (image-dired-get-thumbnail-image filename)))))))
-
-;; (setq image-dired-use-speedbar t)
-
 (provide 'image-dired)
 
 ;;; image-dired.el ends here
diff --git a/lisp/image-file.el b/lisp/image-file.el
index fbc9eaaf94..6df43f737d 100644
--- a/lisp/image-file.el
+++ b/lisp/image-file.el
@@ -37,7 +37,7 @@
 
 ;;;###autoload
 (defcustom image-file-name-extensions
-  (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" 
"ppm" "pnm" "svg"))
+  (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" 
"ppm" "pnm" "svg" "webp"))
   "A list of image-file filename extensions.
 Filenames having one of these extensions are considered image files,
 in addition to those matching `image-file-name-regexps'.
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 4a326cdc69..624c852cb8 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -58,16 +58,29 @@ It is called with one argument, the initial WINPROPS.")
   "Non-nil to resize the image upon first display.
 Its value should be one of the following:
  - nil, meaning no resizing.
- - t, meaning to fit the image to the window height and width.
+ - t, meaning to scale the image down to fit in the window.
+ - `fit-window', meaning to fit the image to the window.
  - `fit-height', meaning to fit the image to the window height.
  - `fit-width', meaning to fit the image to the window width.
- - A number, which is a scale factor (the default size is 1)."
+ - A number, which is a scale factor (the default size is 1).
+
+Resizing will always preserve the aspect ratio of the image."
   :type '(choice (const :tag "No resizing" nil)
-                 (other :tag "Fit height and width" t)
-                 (const :tag "Fit height" fit-height)
-                 (const :tag "Fit width" fit-width)
+                 (const :tag "Fit to window" fit-window)
+                 (const :tag "Fit to window height" fit-height)
+                 (const :tag "Fit to window width" fit-width)
+                 (other :tag "Scale down to fit window" t)
                  (number :tag "Scale factor" 1))
-  :version "27.1"
+  :version "29.1"
+  :group 'image)
+
+(defcustom image-auto-resize-max-scale-percent nil
+  "Max size (in percent) to scale up to when `image-auto-resize' is 
`fit-window'.
+Can be either a number larger than 100, or nil, which means no
+max size."
+  :type '(choice (const nil "No max")
+                 natnum)
+  :version "29.1"
   :group 'image)
 
 (defcustom image-auto-resize-on-window-resize 1
@@ -82,12 +95,16 @@ resizing according to the value specified in 
`image-auto-resize'."
 
 (defvar-local image-transform-resize nil
   "The image resize operation.
+Non-nil to resize the image upon first display.
 Its value should be one of the following:
  - nil, meaning no resizing.
- - t, meaning to fit the image to the window height and width.
+ - t, meaning to scale the image down to fit in the window.
+ - `fit-window', meaning to fit the image to the window.
  - `fit-height', meaning to fit the image to the window height.
  - `fit-width', meaning to fit the image to the window width.
- - A number, which is a scale factor (the default size is 1).")
+ - A number, which is a scale factor (the default size is 1).
+
+Resizing will always preserve the aspect ratio of the image.")
 
 (defvar-local image-transform-scale 1.0
   "The scale factor of the image being displayed.")
@@ -455,8 +472,9 @@ call."
 
     ;; Transformation keys
     (define-key map "sf" 'image-mode-fit-frame)
+    (define-key map "sw" 'image-transform-fit-to-window)
     (define-key map "sh" 'image-transform-fit-to-height)
-    (define-key map "sw" 'image-transform-fit-to-width)
+    (define-key map "si" 'image-transform-fit-to-width)
     (define-key map "sb" 'image-transform-fit-both)
     (define-key map "ss" 'image-transform-set-scale)
     (define-key map "sr" 'image-transform-set-rotation)
@@ -511,12 +529,10 @@ call."
        "--"
        ["Fit Frame to Image" image-mode-fit-frame :active t
         :help "Resize frame to match image"]
-       ["Fit Image to Window (Best Fit)" image-transform-fit-both
-        :help "Resize image to match the window height and width"]
-       ["Fit to Window Height" image-transform-fit-to-height
-        :help "Resize image to match the window height"]
-       ["Fit to Window Width" image-transform-fit-to-width
-        :help "Resize image to match the window width"]
+        ["Fit Image to Window" image-transform-fit-to-window
+         :help "Resize image to match the window height and width"]
+        ["Fit Image to Window (Scale down only)" image-transform-fit-both
+         :help "Scale image down to match the window height and width"]
        ["Zoom In" image-increase-size
         :help "Enlarge the image"]
        ["Zoom Out" image-decrease-size
@@ -803,6 +819,21 @@ Remove text properties that display the image."
 (defvar tar-superior-buffer)
 (declare-function image-flush "image.c" (spec &optional frame))
 
+(defun image--scale-within-limits-p (image)
+  "Return t if `fit-window' will scale image within the customized limits.
+The limits are given by the user option
+`image-auto-resize-max-scale-percent'."
+  (or (not image-auto-resize-max-scale-percent)
+      (let ((scale (/ image-auto-resize-max-scale-percent 100))
+            (mw (plist-get (cdr image) :max-width))
+            (mh (plist-get (cdr image) :max-height))
+            ;; Note: `image-size' looks up and thus caches the
+            ;; untransformed image.  There's no easy way to
+            ;; prevent that.
+            (size (image-size image t)))
+        (or (<= mw (* (car size) scale))
+            (<= mh (* (cdr size) scale))))))
+
 (defun image-toggle-display-image ()
   "Show the image of the image file.
 Turn the image data into a real image, but only if the whole file
@@ -837,7 +868,8 @@ was inserted."
            filename))
         ;; If we have a `fit-width' or a `fit-height', don't limit
         ;; the size of the image to the window size.
-        (edges (when (eq image-transform-resize t)
+         (edges (when (or (eq image-transform-resize t)
+                          (eq image-transform-resize 'fit-window))
                  (window-inside-pixel-edges (get-buffer-window))))
         (max-width (when edges
                      (- (nth 2 edges) (nth 0 edges))))
@@ -884,6 +916,14 @@ was inserted."
                                 ;; Type hint.
                                 :format (and filename data-p))))
 
+    ;; Handle `fit-window'.
+    (when (and (eq image-transform-resize 'fit-window)
+               (image--scale-within-limits-p image))
+      (setq image
+            (cons (car image)
+                  (plist-put (cdr image) :width
+                             (plist-get (cdr image) :max-width)))))
+
     ;; Discard any stale image data before looking it up again.
     (image-flush image)
     (setq image (append image (image-transform-properties image)))
@@ -1494,21 +1534,29 @@ return value is suitable for appending to an image 
spec."
 (defun image-transform-fit-to-height ()
   "Fit the current image to the height of the current window."
   (interactive)
+  (declare (obsolete nil "29.1"))
   (setq image-transform-resize 'fit-height)
   (image-toggle-display-image))
 
 (defun image-transform-fit-to-width ()
   "Fit the current image to the width of the current window."
+  (declare (obsolete nil "29.1"))
   (interactive)
   (setq image-transform-resize 'fit-width)
   (image-toggle-display-image))
 
 (defun image-transform-fit-both ()
-  "Fit the current image both to the height and width of the current window."
+  "Scale the current image down to fit in the current window."
   (interactive)
   (setq image-transform-resize t)
   (image-toggle-display-image))
 
+(defun image-transform-fit-to-window ()
+  "Fit the current image to the height and width of the current window."
+  (interactive)
+  (setq image-transform-resize 'fit-window)
+  (image-toggle-display-image))
+
 (defun image-transform-set-rotation (rotation)
   "Prompt for an angle ROTATION, and rotate the image by that amount.
 ROTATION should be in degrees."
diff --git a/lisp/image.el b/lisp/image.el
index 6e1dbbdf5c..a149caa1a9 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -48,6 +48,7 @@ static \\(unsigned \\)?char \\1_bits" . xbm)
     ("\\`\\(?:MM\0\\*\\|II\\*\0\\)" . tiff)
     ("\\`[\t\n\r ]*%!PS" . postscript)
     ("\\`\xff\xd8" . jpeg)    ; used to be (image-jpeg-p . jpeg)
+    ("\\`RIFF....WEBPVP8" . webp)
     (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
             (comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\r\n]*<\\)")))
        (concat "\\(?:<\\?xml[ \t\r\n]+[^>]*>\\)?[ \t\r\n]*<"
@@ -67,6 +68,7 @@ a non-nil value, TYPE is the image's type.")
   '(("\\.png\\'" . png)
     ("\\.gif\\'" . gif)
     ("\\.jpe?g\\'" . jpeg)
+    ("\\.webp\\'" . webp)
     ("\\.bmp\\'" . bmp)
     ("\\.xpm\\'" . xpm)
     ("\\.pbm\\'" . pbm)
@@ -92,6 +94,7 @@ be of image type IMAGE-TYPE.")
     (jpeg . maybe)
     (tiff . maybe)
     (svg . maybe)
+    (webp . maybe)
     (postscript . nil))
   "Alist of (IMAGE-TYPE . AUTODETECT) pairs used to auto-detect image files.
 \(See `image-type-auto-detected-p').
@@ -556,7 +559,12 @@ If VALUE is nil, PROPERTY is removed from IMAGE."
   (declare (gv-setter image--set-property))
   (plist-get (cdr image) property))
 
-(defun image-compute-scaling-factor (scaling)
+(defun image-compute-scaling-factor (&optional scaling)
+  "Compute the scaling factor based on SCALING.
+If a number, use that.  If it's `auto', compute the factor.
+If nil, use the `image-scaling-factor' variable."
+  (unless scaling
+    (setq scaling image-scaling-factor))
   (cond
    ((numberp scaling) scaling)
    ((eq scaling 'auto)
@@ -600,7 +608,7 @@ means display it in the right marginal area."
 
 
 ;;;###autoload
-(defun insert-image (image &optional string area slice)
+(defun insert-image (image &optional string area slice inhibit-isearch)
   "Insert IMAGE into current buffer at point.
 IMAGE is displayed by inserting STRING into the current buffer
 with a `display' property whose value is the image.
@@ -617,7 +625,11 @@ SLICE specifies slice of IMAGE to insert.  SLICE nil or 
omitted
 means insert whole image.  SLICE is a list (X Y WIDTH HEIGHT)
 specifying the X and Y positions and WIDTH and HEIGHT of image area
 to insert.  A float value 0.0 - 1.0 means relative to the width or
-height of the image; integer values are taken as pixel values."
+height of the image; integer values are taken as pixel values.
+
+Normally `isearch' is able to search for STRING in the buffer
+even if it's hidden behind a displayed image.  If INHIBIT-ISEARCH
+is non-nil, this is inhibited."
   ;; Use a space as least likely to cause trouble when it's a hidden
   ;; character in the buffer.
   (unless string (setq string " "))
@@ -641,6 +653,7 @@ height of the image; integer values are taken as pixel 
values."
                                        (list (cons 'slice slice) image)
                                      image)
                                    rear-nonsticky t
+                                  inhibit-isearch ,inhibit-isearch
                                    keymap ,image-map))))
 
 
@@ -791,7 +804,7 @@ Example:
 
    (defimage test-image ((:type xpm :file \"~/test1.xpm\")
                          (:type xbm :file \"~/test1.xbm\")))"
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   `(defvar ,symbol (find-image ',specs) ,doc))
 
 
@@ -1137,6 +1150,13 @@ default is 20%."
       (error "No image under point"))
     image))
 
+;;;###autoload
+(defun image-at-point-p ()
+  "Return non-nil if there is an image at point."
+  (condition-case nil
+      (prog1 t (image--get-image))
+    (error nil)))
+
 (defun image--get-imagemagick-and-warn (&optional position)
   (declare-function image-transforms-p "image.c" (&optional frame))
   (unless (or (fboundp 'imagemagick-types) (image-transforms-p))
diff --git a/lisp/image/exif.el b/lisp/image/exif.el
index c2cf234640..372e2d2555 100644
--- a/lisp/image/exif.el
+++ b/lisp/image/exif.el
@@ -58,6 +58,9 @@
 ;;  (:tag 306 :tag-name date-time :format 2 :format-type ascii
 ;;   :value "2019:09:21 16:22:13")
 ;;   ...)
+;;
+;; (exif-field 'date-time (exif-parse-file "test.jpg")) =>
+;; "2022:09:14 18:46:19"
 
 ;;; Code:
 
@@ -65,6 +68,7 @@
 
 (defvar exif-tag-alist
   '((11 processing-software)
+    (270 description)
     (271 make)
     (272 model)
     (274 orientation)
@@ -73,7 +77,8 @@
     (296 resolution-unit)
     (305 software)
     (306 date-time)
-    (315 artist))
+    (315 artist)
+    (33432 copyright))
   "Alist of tag values and their names.")
 
 (defconst exif--orientation
@@ -122,13 +127,20 @@ If the data is invalid, an `exif-error' is signaled."
         (when-let ((app1 (cdr (assq #xffe1 (exif--parse-jpeg)))))
           (exif--parse-exif-chunk app1))))))
 
+(defun exif-field (field data)
+  "Return raw FIELD from EXIF.
+If FIELD is not present in the data, return nil.
+FIELD is a symbol in the cdr of `exif-tag-alist'.
+DATA is the result of calling `exif-parse-file'."
+  (plist-get (seq-find (lambda (e)
+                         (eq field (plist-get e :tag-name)))
+                       data)
+             :value))
+
 (defun exif-orientation (exif)
   "Return the orientation (in degrees) in EXIF.
 If the orientation isn't present in the data, return nil."
-  (let ((code (plist-get (cl-find 'orientation exif
-                                  :key (lambda (e)
-                                         (plist-get e :tag-name)))
-                         :value)))
+  (let ((code (exif-field 'orientation exif)))
     (cadr (assq code exif--orientation))))
 
 (defun exif--parse-jpeg ()
diff --git a/lisp/info-look.el b/lisp/info-look.el
index 7cc5462dd4..4812035919 100644
--- a/lisp/info-look.el
+++ b/lisp/info-look.el
@@ -124,6 +124,14 @@ OTHER-MODES is a list of cross references to other help 
modes.")
 (defsubst info-lookup->mode-value (topic mode)
   (assoc mode (info-lookup->topic-value topic)))
 
+(defun info-lookup--expand-info (info)
+  ;; We have a dynamic doc-spec function.
+  (when (and (null (nth 3 info))
+             (nth 6 info))
+    (setf (nth 3 info) (funcall (nth 6 info))
+          (nth 6 info) nil))
+  info)
+
 (defsubst info-lookup->regexp (topic mode)
   (nth 1 (info-lookup->mode-value topic mode)))
 
@@ -146,7 +154,11 @@ Function arguments are specified as keyword/argument pairs:
     (KEYWORD . ARGUMENT)
 
 KEYWORD is either `:topic', `:mode', `:regexp', `:ignore-case',
- `:doc-spec', `:parse-rule', or `:other-modes'.
+ `:doc-spec', `:parse-rule', `:other-modes' or `:doc-spec-function'.
+  `:doc-spec-function' is used to compute a `:doc-spec', but instead of
+  doing so at load time, this is done when the user asks for info on
+  the mode in question.
+
 ARGUMENT has a value as explained in the documentation of the
  variable `info-lookup-alist'.
 
@@ -162,7 +174,8 @@ for more details."
 
 (defun info-lookup-add-help* (maybe &rest arg)
   (let (topic mode regexp ignore-case doc-spec
-             parse-rule other-modes keyword value)
+             parse-rule other-modes keyword value
+              doc-spec-function)
     (setq topic 'symbol
          mode major-mode
          regexp "\\w+")
@@ -185,6 +198,8 @@ for more details."
             (setq ignore-case value))
            ((eq keyword :doc-spec)
             (setq doc-spec value))
+           ((eq keyword :doc-spec-function)
+            (setq doc-spec-function value))
            ((eq keyword :parse-rule)
             (setq parse-rule value))
            ((eq keyword :other-modes)
@@ -192,7 +207,8 @@ for more details."
            (t
             (error "Unknown keyword \"%S\"" keyword))))
     (or (and maybe (info-lookup->mode-value topic mode))
-       (let* ((data (list regexp ignore-case doc-spec parse-rule other-modes))
+       (let* ((data (list regexp ignore-case doc-spec parse-rule other-modes
+                           doc-spec-function))
               (topic-cell (or (assoc topic info-lookup-alist)
                               (car (setq info-lookup-alist
                                          (cons (cons topic nil)
@@ -342,11 +358,22 @@ If optional argument QUERY is non-nil, query for the help 
mode."
        (error "No %s help available for `%s'" topic mode))
     (setq info-lookup-mode mode)))
 
+(defun info-lookup--item-to-mode (item mode)
+  (let ((spec (cons mode (car (split-string (if (stringp item)
+                                                item
+                                              (symbol-name item))
+                                            "-")))))
+    (if (assoc spec (cdr (assq 'symbol info-lookup-alist)))
+        spec
+      mode)))
+
 (defun info-lookup (topic item mode)
   "Display the documentation of a help item."
   (or mode (setq mode (info-lookup-select-mode)))
-  (or (info-lookup->mode-value topic mode)
-      (error "No %s help available for `%s'" topic mode))
+  (setq mode (info-lookup--item-to-mode item mode))
+  (if-let ((info (info-lookup->mode-value topic mode)))
+      (info-lookup--expand-info info)
+    (error "No %s help available for `%s'" topic mode))
   (let* ((completions (info-lookup->completions topic mode))
          (ignore-case (info-lookup->ignore-case topic mode))
          (entry (or (assoc (if ignore-case (downcase item) item) completions)
@@ -725,6 +752,8 @@ Return nil if there is nothing appropriate in the buffer 
near point."
 (defun info-complete (topic mode)
   "Try to complete a help item."
   (barf-if-buffer-read-only)
+  (when-let ((info (info-lookup->mode-value topic mode)))
+    (info-lookup--expand-info info))
   (let ((data (info-lookup-completions-at-point topic mode)))
     (if (null data)
         (error "No %s completion available for `%s' at point" topic mode)
@@ -907,11 +936,14 @@ Return nil if there is nothing appropriate in the buffer 
near point."
  :mode 'python-mode
  ;; Debian includes Python info files, but they're version-named
  ;; instead of having a symlink.
- :doc-spec `((,(cl-loop for version from 20 downto 7
-                        for name = (format "python3.%d" version)
-                        if (Info-find-file name t)
-                        return (format "(%s)Index" name)
-                        finally return "(python)Index"))))
+ :doc-spec-function (lambda ()
+                      (list
+                       (list
+                        (cl-loop for version from 20 downto 7
+                                 for name = (format "python3.%d" version)
+                                 if (Info-find-file name t)
+                                 return (format "(%s)Index" name)
+                                 finally return "(python)Index")))))
 
 (info-lookup-maybe-add-help
  :mode 'cperl-mode
@@ -949,6 +981,67 @@ Return nil if there is nothing appropriate in the buffer 
near point."
              ("(cl)Function Index"    nil "^ -+ .*: " "\\( \\|$\\)")
              ("(cl)Variable Index"    nil "^ -+ .*: " "\\( \\|$\\)")))
 
+(mapc
+ (lambda (elem)
+   (let* ((prefix (car elem)))
+     (info-lookup-add-help
+      :mode (cons 'emacs-lisp-mode prefix)
+      :regexp (concat "\\b" prefix "-[^][()`'‘’,\" \t\n]+")
+      :doc-spec (cl-loop for node in (cdr elem)
+                         collect
+                         (list (if (string-match-p "^(" node)
+                                   node
+                                 (format "(%s)%s" prefix node))
+                               nil "^ -+ .*: " "\\( \\|$\\)")))))
+ ;; Below we have a list of prefixes (used to match on symbols in
+ ;; `emacs-lisp-mode') and the nodes where the function/variable
+ ;; indices live.  If the prefix is different than the name of the
+ ;; manual, then the full "(manual)Node" name has to be used.
+ '(("auth" "Function Index" "Variable Index")
+   ("autotype" "Command Index" "Variable Index")
+   ("calc" "Lisp Function Index" "Variable Index")
+   ;;("cc-mode" "Variable Index" "Command and Function Index")
+   ("dbus" "Index")
+   ("ediff" "Index")
+   ("eieio" "Function Index")
+   ("gnutls" "(emacs-gnutls)Variable Index" "(emacs-gnutls)Function Index")
+   ("mm" "(emacs-mime)Index")
+   ("epa" "Variable Index" "Function Index")
+   ("ert" "Index")
+   ("eshell" "Function and Variable Index")
+   ("eudc" "Index")
+   ("eww" "Variable Index" "Lisp Function Index")
+   ("flymake" "Index")
+   ("forms" "Index")
+   ("gnus" "Index")
+   ("htmlfontify" "Functions" "Variables & Customization")
+   ("idlwave" "Index")
+   ("ido" "Variable Index" "Function Index")
+   ("info" "Index")
+   ("mairix" "(mairix-el)Variable Index" "(mairix-el)Function Index")
+   ("message" "Index")
+   ("mh" "(mh-e)Option Index" "(mh-e)Command Index")
+   ("newsticker" "Index")
+   ("octave" "(octave-mode)Variable Index" "(octave-mode)Lisp Function Index")
+   ("org" "Variable Index" "Command and Function Index")
+   ("pgg" "Variable Index" "Function Index")
+   ("rcirc" "Variable Index" "Index")
+   ("reftex" "Index")
+   ("sasl" "Variable Index" "Function Index")
+   ("sc" "Variable Index")
+   ("semantic" "Index")
+   ("ses" "Index")
+   ("sieve" "Index")
+   ("smtpmail" "Function and Variable Index")
+   ("srecode" "Index")
+   ("tramp" "Variable Index" "Function Index")
+   ("url" "Variable Index" "Function Index")
+   ("vhdl" "(vhdl-mode)Variable Index" "(vhdl-mode)Command Index")
+   ("viper" "Variable Index" "Function Index")
+   ("widget" "Index")
+   ("wisent" "Index")
+   ("woman" "Variable Index" "Command Index")))
+
 ;; docstrings talk about elisp, so have apropos-mode follow emacs-lisp-mode
 (info-lookup-maybe-add-help
  :mode 'apropos-mode
diff --git a/lisp/info.el b/lisp/info.el
index 8c08eaec3c..41889d6de1 100644
--- a/lisp/info.el
+++ b/lisp/info.el
@@ -2604,12 +2604,9 @@ new buffer."
      (if (eq (length completions) 1)
          (setq default (car completions)))
      (if completions
-        (let ((input (completing-read (if default
-                                          (concat
-                                           "Follow reference named (default "
-                                           default "): ")
-                                        "Follow reference named: ")
-                                      completions nil t)))
+         (let ((input (completing-read (format-prompt "Follow reference named"
+                                                      default)
+                                       completions nil t)))
           (list (if (equal input "")
                     default input)
                  current-prefix-arg))
diff --git a/lisp/international/ccl.el b/lisp/international/ccl.el
index 9be4d1ee95..883b0b60fc 100644
--- a/lisp/international/ccl.el
+++ b/lisp/international/ccl.el
@@ -510,7 +510,7 @@ If READ-FLAG is non-nil, this statement has the form
            (arg (nth 2 condition)))
        (ccl-check-register rrr cmd)
        (or (integerp op)
-           (error "CCL: invalid operator: %s" (nth 1 condition)))
+            (error "CCL: Invalid operator: %s" (nth 1 condition)))
        (if (integerp arg)
            (progn
              (ccl-embed-code (if read-flag 'read-jump-cond-expr-const
@@ -862,7 +862,7 @@ is a list of CCL-BLOCKs."
                                       rrr RRR 0)
           (ccl-embed-symbol Rrr 'translation-hash-table-id))
          (t
-          (error "CCL: non-constant table: %s" cmd)
+           (error "CCL: Non-constant table: %s" cmd)
           ;; not implemented:
           (ccl-check-register Rrr cmd)
           (ccl-embed-extended-command 'lookup-int rrr RRR 0))))
@@ -882,7 +882,7 @@ is a list of CCL-BLOCKs."
                                       rrr RRR 0)
           (ccl-embed-symbol Rrr 'translation-hash-table-id))
          (t
-          (error "CCL: non-constant table: %s" cmd)
+           (error "CCL: Non-constant table: %s" cmd)
           ;; not implemented:
           (ccl-check-register Rrr cmd)
           (ccl-embed-extended-command 'lookup-char rrr RRR 0))))
@@ -1553,7 +1553,7 @@ MAP :=
 MAP-IDs := MAP-ID ...
 MAP-SET := MAP-IDs | (MAP-IDs) MAP-SET
 MAP-ID := integer"
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   `(let ((prog ,(unwind-protect
                    (progn
                      ;; To make ,(charset-id CHARSET) works well.
diff --git a/lisp/international/characters.el b/lisp/international/characters.el
index e08dc27549..5aefda2328 100644
--- a/lisp/international/characters.el
+++ b/lisp/international/characters.el
@@ -116,11 +116,11 @@ Base characters (Unicode General Category L,N,P,S,Zs)")
 Combining diacritic or mark (Unicode General Category M)")
 
 ;; bidi types
-(define-category ?R "Right-to-left (strong)
+(define-category ?R "Strong R2L
 Characters with \"strong\" right-to-left directionality, i.e.
 with R, AL, RLE, or RLO Unicode bidi character type.")
 
-(define-category ?L "Left-to-right (strong)
+(define-category ?L "Strong L2R
 Characters with \"strong\" left-to-right directionality, i.e.
 with L, LRE, or LRO Unicode bidi character type.")
 
@@ -1540,6 +1540,9 @@ option `glyphless-char-display'."
            ((eq target 'c1-control)
             (glyphless-set-char-table-range glyphless-char-display
                                             #x80 #x9F method))
+           ((eq target 'variation-selectors)
+            (glyphless-set-char-table-range glyphless-char-display
+                                            #xFE00 #xFE0F method))
            ((eq target 'format-control)
             (when unicode-category-table
               (map-char-table
@@ -1575,6 +1578,7 @@ option `glyphless-char-display'."
 ;;; Control of displaying glyphless characters.
 (defcustom glyphless-char-display-control
   '((format-control . thin-space)
+    (variation-selectors . thin-space)
     (no-font . hex-code))
   "List of directives to control display of glyphless characters.
 
@@ -1590,6 +1594,9 @@ GROUP must be one of these symbols:
                     such as U+200C (ZWNJ), U+200E (LRM), but
                     excluding characters that have graphic images,
                     such as U+00AD (SHY).
+  `variation-selectors': U+FE00..U+FE0F, used for choosing between
+                         glyph variations (e.g. Emoji vs Text
+                         presentation).
   `no-font':        characters for which no suitable font is found.
                     For character terminals, characters that cannot
                     be encoded by `terminal-coding-system'.
@@ -1607,7 +1614,7 @@ Do not set its value directly from Lisp; the value takes 
effect
 only via a custom `:set'
 function (`update-glyphless-char-display'), which updates
 `glyphless-char-display'."
-  :version "24.1"
+  :version "28.1"
   :type '(alist :key-type (symbol :tag "Character Group")
                :value-type (symbol :tag "Display Method"))
   :options '((c0-control
@@ -1628,6 +1635,12 @@ function (`update-glyphless-char-display'), which updates
                      (const :tag "Display as empty box" empty-box)
                      (const :tag "Display acronym" acronym)
                      (const :tag "Display hex code in a box" hex-code)))
+            (variation-selectors
+             (choice (const :tag "Don't display" zero-width)
+                     (const :tag "Display as thin space" thin-space)
+                     (const :tag "Display as empty box" empty-box)
+                     (const :tag "Display acronym" acronym)
+                     (const :tag "Display hex code in a box" hex-code)))
             (no-font
              (choice (const :tag "Don't display" zero-width)
                      (const :tag "Display as thin space" thin-space)
diff --git a/lisp/international/emoji.el b/lisp/international/emoji.el
new file mode 100644
index 0000000000..d2570e9911
--- /dev/null
+++ b/lisp/international/emoji.el
@@ -0,0 +1,647 @@
+;;; emoji.el --- Inserting emojis  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@gnus.org>
+;; Keywords: fun
+
+;; Package-Requires: ((emacs "28.0") (transient "0.3.7"))
+;; Package-Version: 0.1
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'cl-extra)
+(require 'transient)
+
+(defgroup emoji nil
+  "Inserting Emojis."
+  :version "29.1"
+  :group 'play)
+
+(defface emoji-list-header
+  '((default :weight bold :inherit variable-pitch))
+  "Face for emoji list headers."
+  :version "29.1")
+
+(defface emoji
+  '((t :height 2.0))
+  "Face used when displaying an emoji."
+  :version "29.1")
+
+(defface emoji-with-derivations
+  '((((background dark))
+     (:background "#202020" :inherit emoji))
+    (((background light))
+     (:background "#e0e0e0" :inherit emoji)))
+  "Face for emojis that have derivations."
+  :version "29.1")
+
+(defvar emoji--labels nil)
+(defvar emoji--all-bases nil)
+(defvar emoji--derived nil)
+(defvar emoji--names (make-hash-table :test #'equal))
+(defvar emoji--done-derived nil)
+(defvar emoji--recent (list "😀" "😖"))
+(defvar emoji--insert-buffer)
+
+;;;###autoload
+(defun emoji-insert (&optional text)
+  "Choose and insert an emoji glyph.
+If TEXT (interactively, the prefix), use a textual search instead
+of a visual interface."
+  (interactive "*P")
+  (emoji--init)
+  (if text
+      (emoji--choose-emoji)
+    (unless (fboundp 'emoji--command-Emoji)
+      (emoji--define-transient))
+    (funcall (intern "emoji--command-Emoji"))))
+
+;;;###autoload
+(defun emoji-recent ()
+  "Choose and insert a recently used emoji glyph."
+  (interactive "*")
+  (emoji--init)
+  (unless (fboundp 'emoji--command-Emoji)
+    (emoji--define-transient))
+  (funcall (emoji--define-transient
+            (cons "Recent" emoji--recent) t)))
+
+;;;###autoload
+(defun emoji-search ()
+  "Choose and insert an emoji glyph by searching for an emoji name."
+  (interactive "*")
+  (emoji--init)
+  (emoji--choose-emoji))
+
+;;;###autoload
+(defun emoji-list ()
+  "List emojis and insert the one that's selected.
+The character will be inserted into the buffer that was selected
+when the command was issued."
+  (interactive "*")
+  (let ((buf (current-buffer)))
+    (emoji--init)
+    (switch-to-buffer (get-buffer-create "*Emoji*"))
+    ;; Don't regenerate the buffer if it already exists -- this will
+    ;; leave point where it was the last time it was used.
+    (when (zerop (buffer-size))
+      (let ((inhibit-read-only t))
+        (emoji-list-mode)
+        (setq-local emoji--insert-buffer buf)
+        (emoji--list-generate nil (cons nil emoji--labels))
+        (goto-char (point-min))))))
+
+;;;###autoload
+(defun emoji-describe (glyph &optional interactive)
+  "Say what the name of the composed grapheme cluster GLYPH is.
+If it's not known, this function returns nil.
+
+Interactively, it will message what the name of the emoji (or
+character) under point is."
+  (interactive
+   (list (if (eobp)
+             (error "No glyph under point")
+           (let ((comp (find-composition (point) (1+ (point)))))
+             (if comp
+                 (buffer-substring-no-properties (car comp) (cadr comp))
+               (buffer-substring-no-properties (point) (1+ (point))))))
+         t))
+  (require 'emoji-labels)
+  (if (not interactive)
+      ;; Don't return a name for non-compositions when called
+      ;; non-interactively.
+      (gethash glyph emoji--names)
+    ;; Give a name for (pretty much) any glyph, including non-emojis.
+    (let ((name (emoji--name glyph)))
+      (if (not name)
+          (message "No known name for \"%s\"" glyph)
+        (message "The name of \"%s\" is \"%s\"" glyph name)))))
+
+(defun emoji--list-generate (name alist)
+  (let ((width (/ (window-width) 5))
+        (mname (pop alist)))
+    (if (consp (car alist))
+        ;; Recurse.
+        (mapcar (lambda (elem)
+                  (emoji--list-generate (if name
+                                            (concat name " > " mname)
+                                          mname)
+                                        elem))
+                alist)
+      ;; Output this block of emojis.
+      (insert (propertize
+               (if (zerop (length name))
+                   mname
+                 (concat name " > " mname))
+               'face 'emoji-list-header)
+              "\n\n")
+      (cl-loop for i from 0
+               for glyph in alist
+               do
+               (when (and (cl-plusp i)
+                          (zerop (mod i width)))
+                 (insert "\n"))
+               (insert
+                (propertize
+                 (emoji--fontify-glyph glyph)
+                 'emoji-glyph glyph
+                 'help-echo (emoji--name glyph))))
+      (insert "\n\n"))))
+
+(defun emoji--fontify-glyph (glyph &optional inhibit-derived)
+  (propertize glyph 'face
+              (if (and (not inhibit-derived)
+                       (or (null emoji--done-derived)
+                           (not (gethash glyph emoji--done-derived)))
+                       (gethash glyph emoji--derived))
+                  ;; If this emoji has derivations, use a special face
+                  ;; to tell the user.
+                  'emoji-with-derivations
+                ;; Normal emoji.
+                'emoji)))
+
+(defun emoji--name (glyph)
+  (or (gethash glyph emoji--names)
+      (get-char-code-property (aref glyph 0) 'name)))
+
+(defvar-keymap emoji-list-mode-map
+  ["RET"] #'emoji-list-select
+  ["<mouse-2>"] #'emoji-list-select
+  "h" #'emoji-list-help
+  [follow-link] 'mouse-face)
+
+(define-derived-mode emoji-list-mode special-mode "Emoji"
+  "Mode to display emojis."
+  :interactive nil
+  (setq-local truncate-lines t))
+
+(defun emoji-list-select (event)
+  "Select the emoji under point."
+  (interactive (list last-nonmenu-event) emoji-list-mode)
+  (mouse-set-point event)
+  (let ((glyph (get-text-property (point) 'emoji-glyph)))
+    (unless glyph
+      (error "No emoji under point"))
+    (let ((derived (gethash glyph emoji--derived))
+          (end-func
+           (lambda ()
+             (let ((buf emoji--insert-buffer))
+               (quit-window)
+               (if (buffer-live-p buf)
+                   (switch-to-buffer buf)
+                 (error "Buffer disappeared"))))))
+      (if (not derived)
+          ;; Glyph without derivations.
+          (progn
+            (emoji--add-recent glyph)
+            (funcall end-func)
+            (insert glyph))
+        ;; Pop up a transient to choose between derivations.
+        (let ((emoji--done-derived (make-hash-table :test #'equal)))
+          (setf (gethash glyph emoji--done-derived) t)
+          (funcall
+           (emoji--define-transient (cons "Choose Emoji" (cons glyph derived))
+                                    nil end-func)))))))
+
+(defun emoji-list-help ()
+  "Say what the emoji under point is."
+  (interactive nil emoji-list-mode)
+  (let ((glyph (get-text-property (point) 'emoji-glyph)))
+    (unless glyph
+      (error "No emoji under point"))
+    (let ((name (emoji--name glyph)))
+      (if (not name)
+          (error "Unknown name")
+        (message "%s" name)))))
+
+(defun emoji--init (&optional force inhibit-adjust)
+  (when (or (not emoji--labels)
+            force)
+    (unless force
+      (ignore-errors (require 'emoji-labels)))
+    ;; The require should define the variable, but in case the .el
+    ;; file doesn't exist (yet), parse the file now.
+    (when (or force
+              (not emoji--labels))
+      (setq emoji--derived (make-hash-table :test #'equal))
+      (emoji--parse-emoji-test)))
+  (when (and (not inhibit-adjust)
+             (not emoji--all-bases))
+    (setq emoji--all-bases (make-hash-table :test #'equal))
+    (emoji--adjust-displayable (cons "Emoji" emoji--labels))))
+
+(defvar emoji--font nil)
+
+(defun emoji--adjust-displayable (alist)
+  "Remove glyphs we don't have fonts for."
+  (let ((emoji--font nil))
+    (emoji--adjust-displayable-1 alist)))
+
+(defun emoji--adjust-displayable-1 (alist)
+  (if (consp (caddr alist))
+      (dolist (child (cdr alist))
+        (emoji--adjust-displayable-1 child))
+    (while (cdr alist)
+      (let ((glyph (cadr alist)))
+        ;; Store all the emojis for later retrieval by
+        ;; the search feature.
+        (when-let ((name (emoji--name glyph)))
+          (setf (gethash (downcase name) emoji--all-bases) glyph))
+        (if (display-graphic-p)
+            ;; Remove glyphs we don't have in graphical displays.
+            (if (let ((char (elt glyph 0)))
+                  (if emoji--font
+                      (font-has-char-p emoji--font char)
+                    (when-let ((font (car (internal-char-font nil char))))
+                      (setq emoji--font font))))
+                (setq alist (cdr alist))
+              ;; Remove the element.
+              (setcdr alist (cddr alist)))
+          ;; We don't have font info on non-graphical displays.
+          (if (let ((char (elt glyph 0)))
+                ;; FIXME.  Some grapheme clusters display more or less
+                ;; correctly in the terminal, but we don't really know
+                ;; which ones.  None of these display totally
+                ;; correctly, though, so should they be filtered out?
+                (char-displayable-p char))
+              (setq alist (cdr alist))
+            ;; Remove the element.
+            (setcdr alist (cddr alist))))))))
+
+(defun emoji--parse-emoji-test ()
+  (setq emoji--labels nil)
+  (with-temp-buffer
+    (insert-file-contents (expand-file-name "../admin/unidata/emoji-test.txt"
+                                            data-directory))
+    (unless (re-search-forward "^# +group:" nil t)
+      (error "Can't find start of data"))
+    (beginning-of-line)
+    (setq emoji--names (make-hash-table :test #'equal))
+    (let ((derivations (make-hash-table :test #'equal))
+          (case-fold-search t)
+          group subgroup)
+      (while (not (eobp))
+        (cond
+         ((looking-at "# +group: \\(.*\\)")
+          (setq group (match-string 1)
+                subgroup nil))
+         ((looking-at "# +subgroup: \\(.*\\)")
+          (setq subgroup (match-string 1)))
+         ((looking-at
+           "\\([[:xdigit:] \t]+\\); *\\([^ \t]+\\)[ \t]+#.*?E[.0-9]+ 
+\\(.*\\)")
+          (let* ((codes (match-string 1))
+                 (qualification (match-string 2))
+                 (name (match-string 3))
+                 (base (emoji--base-name name derivations))
+                 (glyph (mapconcat
+                         (lambda (code)
+                           (string (string-to-number code 16)))
+                         (split-string codes))))
+            ;; Special-case flags.
+            (when (equal base "flag")
+              (setq base name))
+            ;; Register all glyphs to that we can look up their names
+            ;; later.
+            (setf (gethash glyph emoji--names) name)
+            ;; For the interface, we only care about the fully qualified
+            ;; emojis.
+            (when (equal qualification "fully-qualified")
+              (when (equal base name)
+                (emoji--add-to-group group subgroup glyph))
+              ;; Create mapping from base glyph name to name of
+              ;; derived glyphs.
+              (setf (gethash base derivations)
+                    (nconc (gethash base derivations) (list glyph)))))))
+        (forward-line 1))
+      ;; Finally create the mapping from the base glyphs to derived ones.
+      (setq emoji--derived (make-hash-table :test #'equal))
+      (maphash (lambda (_k v)
+                 (setf (gethash (car v) emoji--derived)
+                       (cdr v)))
+               derivations))))
+
+(defun emoji--add-to-group (group subgroup glyph)
+  ;; "People & Body" is very large; split it up.
+  (cond
+   ((equal group "People & Body")
+    (if (or (string-match "\\`person" subgroup)
+            (equal subgroup "family"))
+        (emoji--add-glyph glyph "People"
+                          (if (equal subgroup "family")
+                              (list subgroup)
+                            ;; Avoid "Person person".
+                            (cdr (emoji--split-subgroup subgroup))))
+      (emoji--add-glyph glyph "Body" (emoji--split-subgroup subgroup))))
+   ;; "Smileys & Emotion" also seems sub-optimal.
+   ((equal group "Smileys & Emotion")
+    (if (equal subgroup "emotion")
+        (emoji--add-glyph glyph "Emotion" nil)
+      (let ((subs (emoji--split-subgroup subgroup)))
+        ;; Remove one level of menus in the face case.
+        (when (equal (car subs) "face")
+          (pop subs))
+        (emoji--add-glyph glyph "Smileys" subs))))
+   ;; Don't modify the rest.
+   (t
+    (emoji--add-glyph glyph group (emoji--split-subgroup subgroup)))))
+
+(defun emoji--generate-file (&optional file)
+  "Generate an .el file with emoji mapping data and write it to FILE."
+  ;; Running from Makefile.
+  (unless file
+    (setq file (pop command-line-args-left)))
+  (emoji--init t t)
+  ;; Weed out the elements that are empty.
+  (let ((glyphs nil))
+    (maphash (lambda (k v)
+               (unless v
+                 (push k glyphs)))
+             emoji--derived)
+    (dolist (glyph glyphs)
+      (remhash glyph emoji--derived)))
+  (with-temp-buffer
+    (insert ";; Generated file -- do not edit.   -*- lexical-binding:t -*-
+;; Copyright © 1991-2021 Unicode, Inc.
+;; Generated from Unicode data files by emoji.el.
+;; The source for this file is found in the admin/unidata/emoji-test.txt
+;; file in the Emacs sources.  The Unicode data files are used under the
+;; Unicode Terms of Use, as contained in the file copyright.html in that
+;; same directory.\n\n")
+    (dolist (var '(emoji--labels emoji--derived emoji--names))
+      (insert (format "(defconst %s '" var))
+      (pp (symbol-value var) (current-buffer))
+      (insert (format "\n) ;; End %s\n\n" var)))
+    (insert ";; Local" " Variables:
+;; coding: utf-8
+;; version-control: never
+;; no-byte-"
+            ;; Obfuscate to not inhibit compilation of this file, too.
+            "compile: t
+;; no-update-autoloads: t
+;; End:
+
+(provide 'emoji-labels)
+
+;;; emoji-labels.el ends here\n")
+    (write-region (point-min) (point-max) file)))
+
+(defun emoji--base-name (name derivations)
+  (let* ((base (replace-regexp-in-string ":.*" "" name))
+         (non-binary (replace-regexp-in-string "\\`\\(man\\|woman\\) " ""
+                                               base)))
+    ;; If we have (for instance) "person golfing", and we're adding
+    ;; "man golfing", make the latter a derivation of the former.
+    (if (or (gethash (concat "person " non-binary) derivations)
+            (gethash non-binary derivations))
+        non-binary
+      base)))
+
+(defun emoji--split-subgroup (subgroup)
+  (let ((prefixes '("face" "hand" "person" "animal" "plant"
+                    "food" "place")))
+    (cond
+     ((string-match (concat "\\`" (regexp-opt prefixes) "-") subgroup)
+      ;; Split these subgroups into hierarchies.
+      (list (substring subgroup 0 (1- (match-end 0)))
+            (substring subgroup (match-end 0))))
+     ((equal subgroup "person")
+      (list "person" "age"))
+     (t
+      (list subgroup)))))
+
+(defun emoji--add-glyph (glyph main subs)
+  (let (parent elem)
+    ;; Useless category.
+    (unless (member main '("Component"))
+      (unless (setq parent (assoc main emoji--labels))
+        (setq emoji--labels (append emoji--labels
+                                    (list (setq parent (list main))))))
+      (setq elem parent)
+      (while subs
+        (unless (setq elem (assoc (car subs) parent))
+          (nconc parent (list (setq elem (list (car subs))))))
+        (pop subs)
+        (setq parent elem))
+      (nconc elem (list glyph)))))
+
+(defun emoji--define-transient (&optional alist inhibit-derived
+                                          end-function)
+  (unless alist
+    (setq alist (cons "Emoji" emoji--labels)))
+  (let* ((mname (pop alist))
+         (name (intern (format "emoji--command-%s" mname)))
+         (emoji--done-derived (or emoji--done-derived
+                                  (make-hash-table :test #'equal)))
+         (has-subs (consp (cadr alist)))
+         (layout
+          (if has-subs
+              ;; Define sub-maps.
+              (cl-loop for entry in
+                       (emoji--compute-prefix
+                        (if (equal mname "Emoji")
+                            (cons (list "Recent") alist)
+                          alist))
+                       collect (list
+                                (car entry)
+                                (emoji--compute-name (cdr entry))
+                                (if (equal (cadr entry) "Recent")
+                                    (emoji--recent-transient end-function)
+                                  (emoji--define-transient
+                                   (cons (concat mname " > " (cadr entry))
+                                         (cddr entry))))))
+            ;; Insert an emoji.
+            (cl-loop for glyph in alist
+                     for i in (append (number-sequence ?a ?z)
+                                      (number-sequence ?A ?Z)
+                                      (number-sequence ?0 ?9)
+                                      (number-sequence ?! ?/))
+                     collect (let ((this-glyph glyph))
+                               (list
+                                (string i)
+                                (emoji--fontify-glyph
+                                 glyph inhibit-derived)
+                                (let ((derived
+                                       (and (not inhibit-derived)
+                                            (not (gethash glyph
+                                                          emoji--done-derived))
+                                            (gethash glyph emoji--derived))))
+                                  (if derived
+                                      ;; We have a derived glyph, so add
+                                      ;; another level.
+                                      (progn
+                                        (setf (gethash glyph
+                                                       emoji--done-derived)
+                                              t)
+                                        (emoji--define-transient
+                                         (cons (concat mname " " glyph)
+                                               (cons glyph derived))
+                                         t end-function))
+                                    ;; Insert the emoji.
+                                    (lambda ()
+                                      (interactive)
+                                      ;; Allow switching to the correct
+                                      ;; buffer.
+                                      (when end-function
+                                        (funcall end-function))
+                                      (emoji--add-recent this-glyph)
+                                      (insert this-glyph)))))))))
+         (args (apply #'vector mname
+                      (emoji--columnize layout
+                                        (if has-subs 2 8)))))
+    ;; There's probably a better way to do this...
+    (setf (symbol-function name)
+          (lambda ()
+            (interactive)
+            (transient-setup name)))
+    (pcase-let ((`(,class ,slots ,suffixes ,docstr ,_body)
+                 (transient--expand-define-args (list args))))
+       (put name 'interactive-only t)
+       (put name 'function-documentation docstr)
+       (put name 'transient--prefix
+            (apply (or class 'transient-prefix) :command name
+                   (cons :variable-pitch (cons t slots))))
+       (put name 'transient--layout
+            (cl-mapcan (lambda (s) (transient--parse-child name s))
+                       suffixes)))
+    name))
+
+(defun emoji--recent-transient (end-function)
+  "Create a function to display a dynamically generated menu."
+  (lambda ()
+    (interactive)
+    (funcall (emoji--define-transient
+              (cons "Recent" emoji--recent) t end-function))))
+
+(defun emoji--add-recent (glyph)
+  "Add GLYPH to the set of recently used emojis."
+  (setq emoji--recent (delete glyph emoji--recent))
+  (push glyph emoji--recent)
+  ;; Shorten the list.
+  (when-let ((tail (nthcdr 30 emoji--recent)))
+    (setcdr tail nil)))
+
+(defun emoji--columnize (list columns)
+  "Split LIST into COLUMN columns."
+  (cl-loop with length = (ceiling (/ (float (length list)) columns))
+           for i upto columns
+           for part on list by (lambda (l) (nthcdr length l))
+           collect (apply #'vector (seq-take part length))))
+
+(defun emoji--compute-prefix (alist)
+  "Compute characters to use for entries in ALIST.
+We prefer the earliest unique letter."
+  (cl-loop with taken = (make-hash-table)
+           for entry in alist
+           for name = (car entry)
+           collect (cons (cl-loop for char across (concat
+                                                   (downcase name)
+                                                   (upcase name))
+                                  while (gethash char taken)
+                                  finally (progn
+                                            (setf (gethash char taken) t)
+                                            (cl-return (string char))))
+                         entry)))
+
+(defun emoji--compute-name (entry)
+  "Add example emojis to the name."
+  (let* ((name (concat (car entry) " "))
+         (children (emoji--flatten entry))
+         (length (length name))
+         (max 30))
+    (cl-loop for i from 0 upto 20
+             ;; Choose from all the children.
+             while (< length max)
+             do (cl-loop for child in children
+                         for glyph = (elt child i)
+                         while (< length max)
+                         when glyph
+                         do (setq name (concat name glyph)
+                                  length (+ length 2))))
+    (if (= (length name) max)
+        ;; Make an ellipsis signal that we've not exhausted the
+        ;; possibilities.
+        (concat name "…")
+      name)))
+
+(defun emoji--flatten (alist)
+  (pop alist)
+  (if (consp (cadr alist))
+      (cl-loop for child in alist
+               append (emoji--flatten child))
+    (list alist)))
+
+(defun emoji--split-long-lists (alist)
+  (let ((whole alist))
+    (pop alist)
+    (if (consp (cadr alist))
+        ;; Descend.
+        (cl-loop for child in alist
+                 do (emoji--split-long-lists child))
+      ;; We have a list.
+      (when (length> alist 77)
+        (setcdr whole
+                (cl-loop for prefix from ?a
+                         for bit on alist by (lambda (l) (nthcdr 77 l))
+                         collect (cons (concat (string prefix) "-group")
+                                       (seq-take bit 77))))))))
+
+(defun emoji--choose-emoji ()
+  ;; Use the list of names.
+  (let ((name
+         (completing-read
+          "Insert emoji: "
+          (lambda (string pred action)
+           (if (eq action 'metadata)
+               (list 'metadata
+                     (cons
+                       'affixation-function
+                       ;; Add the glyphs to the start of the displayed
+                       ;; strings when TAB-ing.
+                       (lambda (strings)
+                         (mapcar
+                          (lambda (name)
+                            (list name
+                                  (concat
+                                   (or (gethash name emoji--all-bases) " ")
+                                   "\t")
+                                  ""))
+                          strings))))
+             (complete-with-action action emoji--all-bases string pred)))
+          nil t)))
+    (when (cl-plusp (length name))
+      (let* ((glyph (gethash name emoji--all-bases))
+             (derived (gethash glyph emoji--derived)))
+        (if (not derived)
+            ;; Simple glyph with no derivations.
+            (progn
+              (emoji--add-recent glyph)
+              (insert glyph))
+          ;; Choose a derived version.
+          (let ((emoji--done-derived (make-hash-table :test #'equal)))
+            (setf (gethash glyph emoji--done-derived) t)
+            (funcall
+             (emoji--define-transient
+              (cons "Choose Emoji" (cons glyph derived))))))))))
+
+(provide 'emoji)
+
+;;; emoji.el ends here
diff --git a/lisp/international/fontset.el b/lisp/international/fontset.el
index 4ec641dca8..7c3a7cd1a9 100644
--- a/lisp/international/fontset.el
+++ b/lisp/international/fontset.el
@@ -157,7 +157,9 @@
        (armenian #x531)
        (hebrew #x5D0)
        (vai #xA500)
-       (arabic #x628)
+        ;; U+06C1 prevents us from using bad fonts, like DejaVu Sans,
+        ;; for Arabic text.
+       (arabic #x628 #x6C1)
        (syriac #x710)
        (thaana #x78C)
        (devanagari #x915)
@@ -279,7 +281,7 @@
        (ottoman-siyaq-number #x1ed01)
        (mahjong-tile #x1F000)
        (domino-tile #x1F030)
-        (emoji #x1F300 #x1F600 #xFE0F)))
+        (emoji #x1F300 #x1F600)))
 
 (defvar otf-script-alist)
 
@@ -814,11 +816,16 @@
                           (#x1D7EC #x1D7F5 mathematical-sans-serif-bold)
                           (#x1D7F6 #x1D7FF mathematical-monospace)))
     (let ((slot (assq (nth 2 math-subgroup) script-representative-chars)))
+      ;; Add both ends of each subgroup to help filter out some
+      ;; incomplete fonts, e.g. those that cover MATHEMATICAL SCRIPT
+      ;; CAPITAL glyphs but not MATHEMATICAL SCRIPT SMALL ones.
       (if slot
-         (if (vectorp (cdr slot))
-             (setcdr slot (vconcat (cdr slot) (vector (car math-subgroup))))
-           (setcdr slot (vector (cadr slot) (car math-subgroup))))
-       (setq slot (list (nth 2 math-subgroup) (car math-subgroup)))
+          (setcdr slot (append (list (nth 0 math-subgroup)
+                                     (nth 1 math-subgroup))
+                               (cdr slot)))
+        (setq slot (list (nth 2 math-subgroup)
+                         (nth 0 math-subgroup)
+                         (nth 1 math-subgroup)))
        (nconc script-representative-chars (list slot))))
     (set-fontset-font
      "fontset-default"
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index a0a6557c95..089decb83c 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -2665,6 +2665,20 @@ For example, translate \"swedish\" into 
\"sv_SE.ISO8859-1\"."
           locale))
     locale))
 
+(defvar current-locale-environment nil
+  "The currently set locale environment.")
+
+(defmacro with-locale-environment (locale-name &rest body)
+  "Execute BODY with the locale set to LOCALE-NAME."
+  (declare (indent 1) (debug (sexp def-body)))
+  (let ((current (gensym)))
+    `(let ((,current current-locale-environment))
+       (unwind-protect
+           (progn
+             (set-locale-environment ,locale-name)
+             ,@body)
+         (set-locale-environment ,current)))))
+
 (defun set-locale-environment (&optional locale-name frame)
   "Set up multilingual environment for using LOCALE-NAME.
 This sets the language environment, the coding system priority,
@@ -2690,6 +2704,10 @@ If FRAME is non-nil, only set the keyboard coding system 
and the
 terminal coding system for the terminal of that frame, and don't
 touch session-global parameters like the language environment.
 
+This function sets the `current-locale-environment' variable.  To
+change the locale temporarily, `with-locale-environment' can be
+used.
+
 See also `locale-charset-language-names', `locale-language-names',
 `locale-preferred-coding-systems' and `locale-coding-system'."
   (interactive (list (completing-read "Set environment for locale: "
@@ -2723,6 +2741,7 @@ See also `locale-charset-language-names', 
`locale-language-names',
 
     (when locale
       (setq locale (locale-translate locale))
+      (setq current-locale-environment locale)
 
       ;; Leave the system locales alone if the caller did not specify
       ;; an explicit locale name, as their defaults are set from
@@ -2927,6 +2946,7 @@ Optional 3rd argument DOCSTRING is a documentation string 
of the property.
 
 See also the documentation of `get-char-code-property' and
 `put-char-code-property'."
+  (declare (indent defun))
   (or (symbolp name)
       (error "Not a symbol: %s" name))
   (if (char-table-p table)
@@ -3238,5 +3258,116 @@ as names, not numbers."
 
 (define-obsolete-function-alias 'ucs-insert 'insert-char "24.3")
 (define-key ctl-x-map "8\r" 'insert-char)
+(define-key ctl-x-map "8e"
+            (define-keymap
+              "e" #'emoji-insert
+              "i" #'emoji-insert
+              "s" #'emoji-search
+              "d" #'emoji-describe
+              "r" #'emoji-recent
+              "l" #'emoji-list))
+
+(defface confusingly-reordered
+  '((((supports :underline (:style wave)))
+     :underline (:style wave :color "Red1"))
+    (t
+     :inherit warning))
+  "Face for highlighting text that was bidi-reordered in confusing ways."
+  :version "29.1")
+
+(defvar reorder-starters "[\u202A\u202B\u202D\u202E\u2066-\u2068]+"
+  "Regular expression for characters that start forced-reordered text.")
+(defvar reorder-enders "[\u202C\u2069]+\\|\n"
+  "Regular expression for characters that end forced-reordered text.")
+
+(autoload 'text-property-search-forward "text-property-search")
+(autoload 'prop-match-beginning "text-property-search")
+(autoload 'prop-match-end "text-property-search")
+
+(defun highlight-confusing-reorderings (beg end &optional remove)
+  "Highlight text in region that might be bidi-reordered in suspicious ways.
+This command find and highlights segments of buffer text that could have
+been reordered on display by using directional control characters, such
+as RLO and LRI, in a way that their display is deliberately meant to
+confuse the reader.  These techniques can be used for obfuscating
+malicious source code.  The suspicious stretches of buffer text are
+highlighted using the `confusingly-reordered' face.
+
+If the region is active, check the text inside the region.  Otherwise
+check the entire buffer.  When called from Lisp, pass BEG and END to
+specify the portion of the buffer to check.
+
+Optional argument REMOVE, if non-nil (interactively, prefix argument),
+means remove the highlighting from the region between BEG and END,
+or the active region if that is set."
+  (interactive
+   (if (use-region-p)
+       (list (region-beginning) (region-end) current-prefix-arg)
+     (list (point-min) (point-max) current-prefix-arg)))
+  (save-excursion
+    (if remove
+        (let (prop-match)
+          (goto-char beg)
+          (while (and
+                  (setq prop-match
+                        (text-property-search-forward 'font-lock-face
+                                                      'confusingly-reordered 
t))
+                  (< (prop-match-beginning prop-match) end))
+            (with-silent-modifications
+              (remove-list-of-text-properties (prop-match-beginning prop-match)
+                                              (prop-match-end prop-match)
+                                              '(font-lock-face face mouse-face
+                                                               help-echo)))))
+      (let ((count 0)
+            next)
+        (goto-char beg)
+        (while (setq next
+                     (bidi-find-overridden-directionality
+                      (point) end nil
+                      (current-bidi-paragraph-direction)))
+          (goto-char next)
+          ;; We detect the problematic parts by watching directional
+          ;; properties of strong L2R and R2L characters.  But
+          ;; malicious reordering in source buffers can, and usuually
+          ;; does, include syntactically-important punctuation
+          ;; characters.  Those have "weak" directionality, so we
+          ;; cannot easily detect when they are affected in malicious
+          ;; ways.  Therefore, once we find a strong directional
+          ;; character whose directionality was tweaked, we highlight
+          ;; the text around it, between the first bidi control
+          ;; character we find before it that starts an
+          ;; override/embedding/isolate, and the first control after
+          ;; it that ends these.  This could sometimes highlight only
+          ;; part of the affected text.  An alternative would be to
+          ;; find the first "starter" following BOL and the last
+          ;; "ender" before EOL, and highlight everything in between
+          ;; them -- this could sometimes highlight too much.
+          (let ((start
+                 (save-excursion
+                   (re-search-backward reorder-starters nil t)))
+                (finish
+                 (save-excursion
+                   (let ((fin (re-search-forward reorder-enders nil t)))
+                     (if fin (1- fin)
+                       (point-max))))))
+            (with-silent-modifications
+              (add-text-properties start finish
+                                   '(font-lock-face
+                                     confusingly-reordered
+                                     face confusingly-reordered
+                                     mouse-face highlight
+                                     help-echo "\
+This text is reordered on display in a way that could change its semantics;
+use \\[forward-char] and \\[backward-char] to see the actual order of 
characters.")))
+            (goto-char finish)
+            (setq count (1+ count))))
+        (message
+         (if (> count 0)
+             (ngettext
+              "Highlighted %d confusingly-reordered text string"
+              "Highlighted %d confusingly-reordered text strings"
+              count)
+           "No confusingly-reordered text strings were found")
+         count)))))
 
 ;;; mule-cmds.el ends here
diff --git a/lisp/international/mule-conf.el b/lisp/international/mule-conf.el
index 2d36dab632..ec027e9a93 100644
--- a/lisp/international/mule-conf.el
+++ b/lisp/international/mule-conf.el
@@ -148,6 +148,7 @@
 (defmacro define-iso-single-byte-charset (symbol iso-symbol name nickname
                                                 iso-ir iso-final
                                                 emacs-mule-id map)
+  (declare (indent defun))
   `(progn
      (define-charset ,symbol
        ,name
@@ -1679,6 +1680,7 @@ for decoding and encoding files, process I/O, etc."
 
 (defcustom password-word-equivalents
   '("password" "passcode" "passphrase" "pass phrase" "pin"
+    "decryption key" "encryption key" ; From ccrypt.
     ; These are sorted according to the GNU en_US locale.
     "암호"               ; ko
     "パスワード"    ; ja
diff --git a/lisp/international/mule-diag.el b/lisp/international/mule-diag.el
index 862c577bd5..5cc73e4367 100644
--- a/lisp/international/mule-diag.el
+++ b/lisp/international/mule-diag.el
@@ -833,7 +833,7 @@ The IGNORED argument is ignored."
   "Display information about a font whose name is FONTNAME."
   (interactive
    (list (completing-read
-          "Font name (default current choice for ASCII chars): "
+          (format-prompt "Font name" "current choice for ASCII chars")
           (and window-system
                ;; Implied by `window-system'.
                (fboundp 'x-list-fonts)
@@ -1004,7 +1004,7 @@ This shows which font is used for which character(s)."
                          (mapcar 'cdr fontset-alias-alist)))
           (completion-ignore-case t))
        (list (completing-read
-             "Fontset (default used by the current frame): "
+              (format-prompt "Fontset" "used by the current frame")
              fontset-list nil t)))))
   (if (= (length fontset) 0)
       (setq fontset (face-attribute 'default :fontset))
diff --git a/lisp/international/mule-util.el b/lisp/international/mule-util.el
index 38d29cb238..c2f91e77e7 100644
--- a/lisp/international/mule-util.el
+++ b/lisp/international/mule-util.el
@@ -67,10 +67,15 @@ decide whether the selected frame can display that Unicode 
character."
                                      ellipsis-text-property)
   "Truncate string STR to end at column END-COLUMN.
 The optional 3rd arg START-COLUMN, if non-nil, specifies the starting
-column; that means to return the characters occupying columns
-START-COLUMN ... END-COLUMN of STR.  Both END-COLUMN and START-COLUMN
-are specified in terms of character display width in the current
-buffer; see also `char-width'.
+column (default: zero); that means to return the characters occupying
+columns START-COLUMN ... END-COLUMN of STR.  Both END-COLUMN and
+START-COLUMN are specified in terms of character display width in the
+current buffer; see `char-width'.
+
+Since character composition on display can produce glyphs whose
+width is smaller than the sum of `char-width' values of the
+composed characters, this function can produce inaccurate results
+when used in such cases.
 
 The optional 4th arg PADDING, if non-nil, specifies a padding
 character (which should have a display width of 1) to add at the end
diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index ee116976ea..3e45a64dc9 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -218,6 +218,7 @@ corresponding Unicode character code.
 If it is a string, it is a name of file that contains the above
 information.  The file format is the same as what described for `:map'
 attribute."
+  (declare (indent defun))
   (when (vectorp (car props))
     ;; Old style code:
     ;;   (define-charset CHARSET-ID CHARSET-SYMBOL INFO-VECTOR)
@@ -294,6 +295,8 @@ attribute."
 
     (apply 'define-charset-internal name (mapcar 'cdr attrs))))
 
+(defvar hack-read-symbol-shorthands-function nil
+  "Holds function to compute `read-symbol-shorthands'.")
 
 (defun load-with-code-conversion (fullname file &optional noerror nomessage)
   "Execute a file of Lisp code named FILE whose absolute name is FULLNAME.
@@ -320,7 +323,8 @@ Return t if file exists."
          (let ((load-true-file-name fullname)
                 (load-file-name fullname)
                 (set-auto-coding-for-load t)
-               (inhibit-file-name-operation nil))
+               (inhibit-file-name-operation nil)
+                shorthands)
            (with-current-buffer buffer
               ;; So that we don't get completely screwed if the
               ;; file is encoded in some complicated character set,
@@ -329,6 +333,13 @@ Return t if file exists."
              ;; Don't let deactivate-mark remain set.
              (let (deactivate-mark)
                (insert-file-contents fullname))
+              (setq shorthands
+                    ;; We need this indirection because hacking local
+                    ;; variables in too early seems to have cause
+                    ;; recursive load loops (bug#50946).  Thus it
+                    ;; remains nil until it is save to do so.
+                    (and hack-read-symbol-shorthands-function
+                         (funcall hack-read-symbol-shorthands-function)))
              ;; If the loaded file was inserted with no-conversion or
              ;; raw-text coding system, make the buffer unibyte.
              ;; Otherwise, eval-buffer might try to interpret random
@@ -339,11 +350,13 @@ Return t if file exists."
                  (set-buffer-multibyte nil))
              ;; Make `kill-buffer' quiet.
              (set-buffer-modified-p nil))
-           ;; Have the original buffer current while we eval.
-           (eval-buffer buffer nil
-                        ;; This is compatible with what `load' does.
-                         (if dump-mode file fullname)
-                        nil t))
+           ;; Have the original buffer current while we eval,
+            ;; but consider shorthands of the eval'ed one.
+           (let ((read-symbol-shorthands shorthands))
+              (eval-buffer buffer nil
+                          ;; This is compatible with what `load' does.
+                           (if dump-mode file fullname)
+                          nil t)))
        (let (kill-buffer-hook kill-buffer-query-functions)
          (kill-buffer buffer)))
       (do-after-load-evaluation fullname)
@@ -878,6 +891,7 @@ non-nil.
 VALUE non-nil means Emacs prefers UTF-8 on code detection for
 non-ASCII files.  This attribute is meaningful only when
 `:coding-type' is `undecided'."
+  (declare (indent defun))
   (let* ((common-attrs (mapcar 'list
                               '(:mnemonic
                                 :coding-type
@@ -2308,6 +2322,7 @@ This function sets properties `translation-table' and
 `translation-table-id' of SYMBOL to the created table itself and the
 identification number of the table respectively.  It also registers
 the table in `translation-table-vector'."
+  (declare (indent defun))
   (let ((table (if (and (char-table-p (car args))
                        (eq (char-table-subtype (car args))
                            'translation-table))
@@ -2382,6 +2397,7 @@ Value is what BODY returns."
 Analogous to `define-translation-table', but updates
 `translation-hash-table-vector' and the table is for use in the CCL
 `lookup-integer' and `lookup-character' functions."
+  (declare (indent defun))
   (unless (and (symbolp symbol)
               (hash-table-p table))
     (error "Bad args to define-translation-hash-table"))
diff --git a/lisp/international/quail.el b/lisp/international/quail.el
index 50ff307b73..5cdd6d6242 100644
--- a/lisp/international/quail.el
+++ b/lisp/international/quail.el
@@ -917,7 +917,7 @@ The format of KBD-LAYOUT is the same as 
`quail-keyboard-layout'."
 The variable `quail-keyboard-layout-type' holds the currently selected
 keyboard type."
   (interactive
-   (list (completing-read "Keyboard type (default current choice): "
+   (list (completing-read (format-prompt "Keyboard type" "current choice")
                          quail-keyboard-layout-alist
                          nil t)))
   (or (and keyboard-type (> (length keyboard-type) 0))
@@ -1382,6 +1382,8 @@ a cons cell of the form (no-record . KEY).
 If KEY is a vector of events, the events in the vector are prepended
 to `unread-command-events', after converting each event to a cons cell
 of the form (no-record . EVENT).
+If KEY is an event, it is prepended to `unread-command-events' as a cons
+cell of the form (no-record . EVENT).
 If RESET is non-nil, the events in `unread-command-events' are first
 discarded, i.e. in this case KEY will end up being the only key
 in `unread-command-events'."
@@ -1390,7 +1392,7 @@ in `unread-command-events'."
         (if (characterp key)
             (cons (cons 'no-record key) unread-command-events)
           (append (mapcan (lambda (e) (list (cons 'no-record e)))
-                          (append key nil))
+                          (append (if (vectorp key) key (vector key)) nil))
                   unread-command-events))))
 
 (defun quail-start-translation (key)
diff --git a/lisp/international/titdic-cnv.el b/lisp/international/titdic-cnv.el
index ccb4c8390b..dfd4e5b829 100644
--- a/lisp/international/titdic-cnv.el
+++ b/lisp/international/titdic-cnv.el
@@ -627,8 +627,8 @@ To get complete usage, invoke \"emacs -batch -f 
batch-titdic-convert -h\"."
      py-converter
      "\
 ;; \"pinyin.map\" is included in a free package called CCE.  It is
-;; available at:
-;;     http://ftp.debian.org/debian/dists/potato/main
+;; available at: [link needs updating  -- SK 2021-09-27]
+;;     https://ftp.debian.org/debian/dists/potato/main
 ;;             /source/utils/cce_0.36.orig.tar.gz
 ;; This package contains the following copyright notice.
 ;;
@@ -655,8 +655,8 @@ To get complete usage, invoke \"emacs -batch -f 
batch-titdic-convert -h\"."
      ziranma-converter
      "\
 ;; \"ziranma.cin\" is included in a free package called CCE.  It is
-;; available at:
-;;     http://ftp.debian.org/debian/dists/potato/main
+;; available at: [link needs updating  -- SK 2021-09-27]
+;;     https://ftp.debian.org/debian/dists/potato/main
 ;;             /source/utils/cce_0.36.orig.tar.gz
 ;; This package contains the following copyright notice.
 ;;
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 242f2b0dd0..dea9662477 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -1096,7 +1096,8 @@ as a regexp.  See the command `isearch-forward' for more 
information.
 In incremental searches, a space or spaces normally matches any
 whitespace defined by the variable `search-whitespace-regexp'.
 To search for a literal space and nothing else, enter C-q SPC.
-To toggle whitespace matching, use `isearch-toggle-lax-whitespace'.
+To toggle whitespace matching, use `isearch-toggle-lax-whitespace',
+usually bound to `M-s SPC' during isearch.
 This command does not support character folding."
   (interactive "P\np")
   (isearch-mode t (null not-regexp) nil (not no-recursive-edit)))
@@ -2477,8 +2478,8 @@ The arguments passed to `highlight-regexp' are the regexp 
from
 the last search and the face from `hi-lock-read-face-name'."
   (interactive)
   (isearch--highlight-regexp-or-lines
-   #'(lambda (regexp face lighter)
-       (highlight-regexp regexp face nil lighter))))
+   (lambda (regexp face lighter)
+     (highlight-regexp regexp face nil lighter))))
 
 (defun isearch-highlight-lines-matching-regexp ()
   "Exit Isearch mode and call `highlight-lines-matching-regexp'.
@@ -2486,8 +2487,8 @@ The arguments passed to `highlight-lines-matching-regexp' 
are the
 regexp from the last search and the face from `hi-lock-read-face-name'."
   (interactive)
   (isearch--highlight-regexp-or-lines
-   #'(lambda (regexp face _lighter)
-       (highlight-lines-matching-regexp regexp face))))
+   (lambda (regexp face _lighter)
+     (highlight-lines-matching-regexp regexp face))))
 
 
 (defun isearch-delete-char ()
@@ -3786,8 +3787,10 @@ Isearch, at least partially, as determined by 
`isearch-range-invisible'.
 If `search-invisible' is t, which allows Isearch matches inside
 invisible text, this function will always return non-nil, regardless
 of what `isearch-range-invisible' says."
-  (or (eq search-invisible t)
-      (not (isearch-range-invisible beg end))))
+  (and (or (eq search-invisible t)
+           (not (isearch-range-invisible beg end)))
+       (not (text-property-not-all (min beg end) (max beg end)
+                                   'inhibit-isearch nil))))
 
 
 ;; General utilities
diff --git a/lisp/jka-cmpr-hook.el b/lisp/jka-cmpr-hook.el
index 6933a7c1d0..ed00caedb5 100644
--- a/lisp/jka-cmpr-hook.el
+++ b/lisp/jka-cmpr-hook.el
@@ -203,7 +203,7 @@ options through Custom does this automatically."
   ;; can-append strip-extension-flag file-magic-bytes
   ;; uncompress-function]
   (mapcar 'purecopy
-  '(["\\.Z\\'"
+  `(["\\.Z\\'"
      "compressing"    "compress"     ("-c")
      ;; gzip is more common than uncompress. It can only read, not write.
      "uncompressing"  "gzip"   ("-c" "-q" "-d")
@@ -239,7 +239,8 @@ options through Custom does this automatically."
      "LZMA uncompressing" "lzma"         ("-c" "-q" "-d")
      t t ""]
     ["\\.xz\\'"
-     "XZ compressing"     "xz"           ("-c" "-q")
+     ;; On MacOS, gzip can uncompress xz files.
+     "XZ compressing" ,(if (featurep 'ns) "gzip" "xz") ("-c" "-q")
      "XZ uncompressing"   "xz"           ("-c" "-q" "-d")
      t t "\3757zXZ\0"]
     ["\\.txz\\'"
diff --git a/lisp/kmacro.el b/lisp/kmacro.el
index bb41a962c3..3f492a851e 100644
--- a/lisp/kmacro.el
+++ b/lisp/kmacro.el
@@ -260,8 +260,12 @@ Can be set directly via `kmacro-set-format', which see.")
 Interactively, ARG defaults to 1.  With \\[universal-argument], insert
 the previous value of `kmacro-counter', and do not increment the
 current value.
+
 The previous value of the counter is the one it had before
-the last increment."
+the last increment.
+
+See Info node `(emacs) Keyboard Macro Counter' for more
+information."
   (interactive "P")
   (if kmacro-initial-counter-value
       (setq kmacro-counter kmacro-initial-counter-value
@@ -273,7 +277,24 @@ the last increment."
 
 
 (defun kmacro-set-format (format)
-  "Set the format of `kmacro-counter' to FORMAT."
+  "Set the format of `kmacro-counter' to FORMAT.
+
+The default format is \"%d\", which means to insert the number in
+decimal without any padding.  You can specify any format string
+that the `format' function accepts and that makes sense with a
+single integer extra argument.
+
+If you run this command while no keyboard macro is being defined,
+the new format affects all subsequent macro definitions.
+
+If you run this command while defining a keyboard macro, it
+affects only that macro, from that point on.
+
+Do not put the format string inside double quotes when you insert
+it in the minibuffer.
+
+See Info node `(emacs) Keyboard Macro Counter' for more
+information."
   (interactive "sMacro Counter Format: ")
   (setq kmacro-counter-format
        (if (equal format "") "%d" format))
@@ -283,7 +304,10 @@ the last increment."
 
 
 (defun kmacro-display-counter (&optional value)
-  "Display current counter value."
+  "Display current counter value.
+
+See Info node `(emacs) Keyboard Macro Counter' for more
+information."
   (unless value (setq value kmacro-counter))
   (message "New macro counter value: %s (%d)"
            (format kmacro-counter-format value) value))
@@ -291,7 +315,10 @@ the last increment."
 (defun kmacro-set-counter (arg)
   "Set the value of `kmacro-counter' to ARG, or prompt for value if no 
argument.
 With \\[universal-argument] prefix, reset counter to its value prior to this 
iteration of the
-macro."
+macro.
+
+See Info node `(emacs) Keyboard Macro Counter' for more
+information."
   (interactive "NMacro counter value: ")
   (if (not (or defining-kbd-macro executing-kbd-macro))
       (kmacro-display-counter (setq kmacro-initial-counter-value arg))
@@ -305,7 +332,10 @@ macro."
 
 (defun kmacro-add-counter (arg)
   "Add the value of numeric prefix arg (prompt if missing) to `kmacro-counter'.
-With \\[universal-argument], restore previous counter value."
+With \\[universal-argument], restore previous counter value.
+
+See Info node `(emacs) Keyboard Macro Counter' for more
+information."
   (interactive "NAdd to macro counter: ")
   (if kmacro-initial-counter-value
       (setq kmacro-counter kmacro-initial-counter-value
diff --git a/lisp/language/cyril-util.el b/lisp/language/cyril-util.el
index 04e681d743..e404288ddc 100644
--- a/lisp/language/cyril-util.el
+++ b/lisp/language/cyril-util.el
@@ -60,7 +60,7 @@ If the argument is nil, we return the display table to its 
standard state."
    (list
     (let* ((completion-ignore-case t))
       (completing-read
-       "Cyrillic language (default nil): "
+       (format-prompt "Cyrillic language" "nil")
        cyrillic-language-alist nil t nil nil nil))))
 
   (or standard-display-table
diff --git a/lisp/language/japanese.el b/lisp/language/japanese.el
index bd8ef6ec85..d9bd42093a 100644
--- a/lisp/language/japanese.el
+++ b/lisp/language/japanese.el
@@ -264,29 +264,6 @@ eucJP-ms is defined in 
<http://www.opengroup.or.jp/jvc/cde/appendix.html>."
   (define-translation-table 'unicode-to-jisx0213
     (char-table-extra-slot table 0)))
 
-(defun compose-gstring-for-variation-glyph (gstring _direction)
-  "Compose glyph-string GSTRING for graphic display.
-GSTRING must have two glyphs; the first is a glyph for a han character,
-and the second is a glyph for a variation selector."
-  (let* ((font (lgstring-font gstring))
-        (han (lgstring-char gstring 0))
-        (vs (lgstring-char gstring 1))
-        (glyphs (font-variation-glyphs font han))
-        (g0 (lgstring-glyph gstring 0))
-        (g1 (lgstring-glyph gstring 1)))
-    (catch 'tag
-      (dolist (elt glyphs)
-       (if (= (car elt) vs)
-           (progn
-             (lglyph-set-code g0 (cdr elt))
-             (lglyph-set-from-to g0 (lglyph-from g0) (lglyph-to g1))
-             (lgstring-set-glyph gstring 1 nil)
-             (throw 'tag gstring)))))))
-
-(let ((elt '([".." 1 compose-gstring-for-variation-glyph])))
-  (set-char-table-range composition-function-table '(#xFE00 . #xFE0F) elt)
-  (set-char-table-range composition-function-table '(#xE0100 . #xE01EF) elt))
-
 (provide 'japanese)
 
 ;;; japanese.el ends here
diff --git a/lisp/language/lao.el b/lisp/language/lao.el
index c699d57c15..93849461ea 100644
--- a/lisp/language/lao.el
+++ b/lisp/language/lao.el
@@ -59,11 +59,11 @@
     (let* ((chars (car l))
           (len (length chars))
           ;; Replace `c', `t', `v' to consonant, tone, and vowel.
-          (regexp (mapconcat #'(lambda (c)
-                                 (cond ((= c ?c) consonant)
-                                       ((= c ?t) tone)
-                                       ((= c ?v) vowel-upper-lower)
-                                       (t (string c))))
+           (regexp (mapconcat (lambda (c)
+                                (cond ((= c ?c) consonant)
+                                      ((= c ?t) tone)
+                                      ((= c ?v) vowel-upper-lower)
+                                      (t (string c))))
                              (cdr l) ""))
           ;; Element of composition-function-table.
           (elt (list (vector regexp 1 #'lao-composition-function)
diff --git a/lisp/language/misc-lang.el b/lisp/language/misc-lang.el
index a2ca678b2b..c8a4821abf 100644
--- a/lisp/language/misc-lang.el
+++ b/lisp/language/misc-lang.el
@@ -192,7 +192,25 @@ thin (i.e. 1-dot width) space."
    composition-function-table
    #x13437
    (list (vector "\U00013437[\U00013000-\U0001343F]+"
-                 0 #'egyptian-shape-grouping))))
+                 0 #'egyptian-shape-grouping)))
+  ;; "Normal" hieroglyphs, for fonts that don't support the above
+  ;; controls, but do shape sequences of hieroglyphs without the
+  ;; controls.
+  ;; FIXME: As of late 2021, Egyptian Hieroglyph Format Controls are
+  ;; not yet supported in existing fonts and/or shaping engines, but
+  ;; some fonts do provide ligatures with which texts in Egyptian
+  ;; Hieroglyphs are correctly displayed.  If and when these format
+  ;; controls are supported, as described in section 11.4 "Egyptian
+  ;; Hieroglyphs" of the Unicode Standard, the five lines below (which
+  ;; allow composition of hieroglyphs without formatting controls
+  ;; around) can be removed, and the entry in etc/HELLO can be
+  ;; restored to:
+  ;; Egyptian Hieroglyphs (𓂋𓐰𓏤𓈖𓆎𓅓𓏏𓐰𓊖) 𓅓𓊵𓐰𓐷𓏏𓊪𓐸, 𓇍𓇋𓂻𓍘𓇋
+  (set-char-table-range
+   composition-function-table
+   '(#x13000 . #x1342E)
+   (list (vector "[\U00013000-\U0001342E]+"
+                 0 #'font-shape-gstring))))
 
 (provide 'misc-lang)
 
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index 0ab9552c60..4b9505a135 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -48,7 +48,7 @@ Mutate the result." t nil)
 (autoload '5x5-crack "5x5" "\
 Attempt to find a solution for 5x5.
 
-5x5-crack takes the argument BREEDER which should be a function that takes
+`5x5-crack' takes the argument BREEDER which should be a function that takes
 two parameters, the first will be a grid vector array that is the current
 solution and the second will be the best solution so far.  The function
 should return a grid vector array that is the new solution.
@@ -288,7 +288,7 @@ The syntax of `defadvice' is as follows:
 FUNCTION ::= Name of the function to be advised.
 CLASS ::= `before' | `around' | `after' | `activation' | `deactivation'.
 NAME ::= Non-nil symbol that names this piece of advice.
-POSITION ::= `first' | `last' | NUMBER. Optional, defaults to `first',
+POSITION ::= `first' | `last' | NUMBER.  Optional, defaults to `first',
     see also `ad-add-advice'.
 ARGLIST ::= An optional argument list to be used for the advised function
     instead of the argument list of the original.  The first one found in
@@ -338,11 +338,22 @@ usage: (defadvice FUNCTION (CLASS NAME [POSITION] 
[ARGLIST] FLAG...)
 
 (autoload 'align "align" "\
 Attempt to align a region based on a set of alignment rules.
-BEG and END mark the region.  If BEG and END are specifically set to
-nil (this can only be done programmatically), the beginning and end of
-the current alignment section will be calculated based on the location
-of point, and the value of `align-region-separate' (or possibly each
-rule's `separate' attribute).
+Interactively, BEG and END are the mark/point of the current region.
+
+Many modes define specific alignment rules, and some of these
+rules in some modes react to the current prefix argument.  For
+instance, in `text-mode', `M-x align' will align into columns
+based on space delimiters, while `C-u - M-x align' will align
+into columns based on the \"$\" character.  See the
+`align-rules-list' variable definition for the specific rules.
+
+Also see `align-regexp', which will guide you through various
+parameters for aligning text.
+
+Non-interactively, if BEG and END are nil, the beginning and end
+of the current alignment section will be calculated based on the
+location of point, and the value of `align-region-separate' (or
+possibly each rule's `separate' attribute).
 
 If SEPARATE is non-nil, it overrides the value of
 `align-region-separate' for all rules, except those that have their
@@ -360,6 +371,15 @@ Align the current region using an ad-hoc rule read from 
the minibuffer.
 BEG and END mark the limits of the region.  Interactively, this function
 prompts for the regular expression REGEXP to align with.
 
+Interactively, if you specify a prefix argument, the function
+will guide you through entering the full regular expression, and
+then prompts for which subexpression parenthesis GROUP (default
+1) within REGEXP to modify, the amount of SPACING (default
+`align-default-spacing') to use, and whether or not to REPEAT the
+rule throughout the line.
+
+See `align-rules-list' for more information about these options.
+
 For example, let's say you had a list of phone numbers, and wanted to
 align them so that the opening parentheses would line up:
 
@@ -368,24 +388,19 @@ align them so that the opening parentheses would line up:
     Mary-Anne (123) 456-7890
     Joe (123) 456-7890
 
-There is no predefined rule to handle this, but you could easily do it
-using a REGEXP like \"(\".  Interactively, all you would have to do is
-to mark the region, call `align-regexp' and enter that regular expression.
-
-REGEXP must contain at least one parenthesized subexpression, typically
-whitespace of the form \"\\\\(\\\\s-*\\\\)\".  In normal interactive use,
-this is automatically added to the start of your regular expression after
-you enter it.  You only need to supply the characters to be lined up, and
-any preceding whitespace is replaced.
+There is no predefined rule to handle this, but interactively,
+all you would have to do is to mark the region, call `align-regexp'
+and enter \"(\".
 
-If you specify a prefix argument (or use this function non-interactively),
-you must enter the full regular expression, including the subexpression.
-The function also then prompts for which subexpression parenthesis GROUP
-\(default 1) within REGEXP to modify, the amount of SPACING (default
-`align-default-spacing') to use, and whether or not to REPEAT the rule
-throughout the line.
+REGEXP must contain at least one parenthesized subexpression,
+typically whitespace of the form \"\\\\(\\\\s-*\\\\)\", but in
+interactive use, this is automatically added to the start of your
+regular expression after you enter it.  Interactively, you only
+need to supply the characters to be lined up, and any preceding
+whitespace is replaced.
 
-See `align-rules-list' for more information about these options.
+Non-interactively, you must enter the full regular expression,
+including the subexpression.
 
 The non-interactive form of the previous example would look something like:
   (align-regexp (point-min) (point-max) \"\\\\(\\\\s-*\\\\)(\")
@@ -463,7 +478,7 @@ Control whether and how allout outline mode is automatically
 activated when files are visited with non-nil buffer-specific
 file variable `allout-layout'.
 
-When allout-auto-activation is \"On\" (t), allout mode is
+When `allout-auto-activation' is \"On\" (t), allout mode is
 activated in buffers with non-nil `allout-layout', and the
 specified layout is applied.
 
@@ -1201,8 +1216,9 @@ NOT recognized as integers or real numbers.
   The array MUST reside at the top of the buffer.
 
   TABs are not respected, and may be converted into spaces at any time.
-Setting the variable `array-respect-tabs' to non-nil will prevent TAB 
conversion,
-but will cause many functions to give errors if they encounter one.
+Setting the variable `array-respect-tabs' to non-nil will prevent
+TAB conversion, but will cause many functions to give errors if
+they encounter one.
 
   Upon entering array mode, you will be prompted for the values of
 several variables.  Others will be calculated based on the values you
@@ -1392,7 +1408,7 @@ Drawing with keys
 
  \\[artist-key-set-point]              Does one of the following:
                For lines/rectangles/squares: sets the first/second endpoint
-               For poly-lines: sets a point (use C-u \\[artist-key-set-point] 
to set last point)
+                For poly-lines: sets a point (use \\[universal-argument] 
\\[artist-key-set-point] to set last point)
                When erase characters: toggles erasing
                When cutting/copying: Sets first/last endpoint of rect/square
                When pasting: Pastes
@@ -1517,9 +1533,8 @@ Special commands:
 ;;; Generated autoloads from auth-source.el
 
 (defvar auth-source-cache-expiry 7200 "\
-How many seconds passwords are cached, or nil to disable
-expiring.  Overrides `password-cache-expiry' through a
-let-binding.")
+How many seconds passwords are cached, or nil to disable expiring.
+Overrides `password-cache-expiry' through a let-binding.")
 
 (custom-autoload 'auth-source-cache-expiry "auth-source" t)
 
@@ -1620,7 +1635,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'autoarg-kp-mode)'.
+evaluate `(default-value \\='autoarg-kp-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -1663,6 +1678,8 @@ or if CONDITION had no actions, after all other 
CONDITIONs.
 
 \(fn CONDITION ACTION &optional AFTER)" nil nil)
 
+(function-put 'define-auto-insert 'lisp-indent-function 'defun)
+
 (defvar auto-insert-mode nil "\
 Non-nil if Auto-Insert mode is enabled.
 See the `auto-insert-mode' command
@@ -1685,7 +1702,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'auto-insert-mode)'.
+evaluate `(default-value \\='auto-insert-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -1871,7 +1888,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-auto-revert-mode)'.
+evaluate `(default-value \\='global-auto-revert-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -1967,7 +1984,6 @@ Output stream used is value of `standard-output'." nil 
nil)
 
 (autoload 'bat-mode "bat-mode" "\
 Major mode for editing DOS/Windows batch files.
-
 Start a new script from `bat-template'.  Read help pages for DOS commands
 with `bat-cmd-help'.  Navigate between sections using `imenu'.
 Run script using `bat-run' and `bat-run-args'.
@@ -2011,7 +2027,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'display-battery-mode)'.
+evaluate `(default-value \\='display-battery-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -2385,14 +2401,14 @@ others are still there, should the user decide to 
delete the most
 recent one.
 
 To yank words from the text of the buffer and use them as part of the
-bookmark name, type C-w while setting a bookmark.  Successive C-w's
+bookmark name, type 
\\<bookmark-minibuffer-read-name-map>\\[bookmark-yank-word] while setting a 
bookmark.  Successive \\[bookmark-yank-word]'s
 yank successive words.
 
-Typing C-u inserts (at the bookmark name prompt) the name of the last
+Typing \\[universal-argument] inserts (at the bookmark name prompt) the name 
of the last
 bookmark used in the document where the new bookmark is being set;
 this helps you use a single bookmark name to track progress through a
 large document.  If there is no prior bookmark for this document, then
-C-u inserts an appropriate name based on the buffer or file.
+\\[universal-argument] inserts an appropriate name based on the buffer or file.
 
 Use \\[bookmark-delete] to remove bookmarks (you give it a name and
 it removes only the first instance of a bookmark with that name from
@@ -2415,14 +2431,14 @@ Otherwise, if a bookmark named NAME already exists but 
PUSH-BOOKMARK
 is nil, raise an error.
 
 To yank words from the text of the buffer and use them as part of the
-bookmark name, type C-w while setting a bookmark.  Successive C-w's
+bookmark name, type 
\\<bookmark-minibuffer-read-name-map>\\[bookmark-yank-word] while setting a 
bookmark.  Successive \\[bookmark-yank-word]'s
 yank successive words.
 
-Typing C-u inserts (at the bookmark name prompt) the name of the last
+Typing \\[universal-argument] inserts (at the bookmark name prompt) the name 
of the last
 bookmark used in the document where the new bookmark is being set;
 this helps you use a single bookmark name to track progress through a
 large document.  If there is no prior bookmark for this document, then
-C-u inserts an appropriate name based on the buffer or file.
+\\[universal-argument] inserts an appropriate name based on the buffer or file.
 
 Use \\[bookmark-delete] to remove bookmarks (you give it a name and
 it removes only the first instance of a bookmark with that name from
@@ -2489,7 +2505,7 @@ If called from Lisp, prompt for NEW-NAME if only OLD-NAME 
was passed
 as an argument.  If called with two strings, then no prompting is done.
 You must pass at least OLD-NAME when calling from Lisp.
 
-While you are entering the new name, consecutive C-w's insert
+While you are entering the new name, consecutive 
\\<bookmark-minibuffer-read-name-map>\\[bookmark-yank-word]'s insert
 consecutive words from the text of the buffer into the new bookmark
 name.
 
@@ -2534,7 +2550,7 @@ Write bookmarks to a file (reading the file name with the 
minibuffer)." t nil)
 Save currently defined bookmarks in FILE.
 FILE defaults to `bookmark-default-file'.
 With prefix PARG, query user for a file to save in.
-If MAKE-DEFAULT is non-nil (interactively with prefix C-u C-u)
+If MAKE-DEFAULT is non-nil (interactively with prefix \\[universal-argument] 
\\[universal-argument])
 the file we save in becomes the new default in the current Emacs
 session (without affecting the value of `bookmark-default-file'.).
 
@@ -2958,7 +2974,6 @@ If `current-prefix-arg' is non-nil, use
 
 ;;;### (autoloads nil "bs" "bs.el" (0 0 0 0))
 ;;; Generated autoloads from bs.el
-(push (purecopy '(bs 1 17)) package--builtin-versions)
 
 (autoload 'bs-cycle-next "bs" "\
 Select next buffer defined by buffer cycling.
@@ -3381,7 +3396,7 @@ or a list containing a character position and an error 
message in string form.
 Invoke the Calculator in \"visual keypad\" mode.
 This is most useful in the X window system.
 In this mode, click on the Calc \"buttons\" using the left mouse button.
-Or, position the cursor manually and do M-x calc-keypad-press.
+Or, position the cursor manually and do \\[calc-keypad-press].
 
 \(fn &optional INTERACTIVE)" t nil)
 
@@ -3438,6 +3453,8 @@ See Info node `(calc)Defining Functions'.
 
 (function-put 'defmath 'doc-string-elt '3)
 
+(function-put 'defmath 'lisp-indent-function 'defun)
+
 (register-definition-prefixes "calc" '("calc" "defcalcmodevar" 
"inexact-result" "math-" "var-"))
 
 ;;;***
@@ -3982,7 +3999,7 @@ control).  See \"cc-mode.el\" for more info.
 Major mode for editing C code.
 
 To submit a problem report, enter `\\[c-submit-bug-report]' from a
-c-mode buffer.  This automatically sets up a mail buffer with version
+`c-mode' buffer.  This automatically sets up a mail buffer with version
 information already added.  You just need to add a description of the
 problem, including a reproducible test case, and send the message.
 
@@ -4030,7 +4047,7 @@ Key bindings:
 (autoload 'objc-mode "cc-mode" "\
 Major mode for editing Objective C code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from an
-objc-mode buffer.  This automatically sets up a mail buffer with
+`objc-mode' buffer.  This automatically sets up a mail buffer with
 version information already added.  You just need to add a description
 of the problem, including a reproducible test case, and send the
 message.
@@ -4049,7 +4066,7 @@ Key bindings:
 (autoload 'java-mode "cc-mode" "\
 Major mode for editing Java code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from a
-java-mode buffer.  This automatically sets up a mail buffer with
+`java-mode' buffer.  This automatically sets up a mail buffer with
 version information already added.  You just need to add a description
 of the problem, including a reproducible test case, and send the
 message.
@@ -4068,7 +4085,7 @@ Key bindings:
 (autoload 'idl-mode "cc-mode" "\
 Major mode for editing CORBA's IDL, PSDL and CIDL code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from an
-idl-mode buffer.  This automatically sets up a mail buffer with
+`idl-mode' buffer.  This automatically sets up a mail buffer with
 version information already added.  You just need to add a description
 of the problem, including a reproducible test case, and send the
 message.
@@ -4088,7 +4105,7 @@ Key bindings:
 (autoload 'pike-mode "cc-mode" "\
 Major mode for editing Pike code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from a
-pike-mode buffer.  This automatically sets up a mail buffer with
+`pike-mode' buffer.  This automatically sets up a mail buffer with
 version information already added.  You just need to add a description
 of the problem, including a reproducible test case, and send the
 message.
@@ -4111,7 +4128,7 @@ Key bindings:
 (autoload 'awk-mode "cc-mode" "\
 Major mode for editing AWK code.
 To submit a problem report, enter `\\[c-submit-bug-report]' from an
-awk-mode buffer.  This automatically sets up a mail buffer with version
+`awk-mode' buffer.  This automatically sets up a mail buffer with version
 information already added.  You just need to add a description of the
 problem, including a reproducible test case, and send the message.
 
@@ -4159,7 +4176,7 @@ a null operation.
 \(fn STYLENAME &optional DONT-OVERRIDE)" t nil)
 
 (autoload 'c-add-style "cc-styles" "\
-Adds a style to `c-style-alist', or updates an existing one.
+Add a style to `c-style-alist', or update an existing one.
 STYLE is a string identifying the style to add or update.  DESCRIPTION
 is an association list describing the style and must be of the form:
 
@@ -4467,6 +4484,8 @@ MAP-ID := integer
 
 (function-put 'define-ccl-program 'doc-string-elt '3)
 
+(function-put 'define-ccl-program 'lisp-indent-function 'defun)
+
 (autoload 'check-ccl-program "ccl" "\
 Check validity of CCL-PROGRAM.
 If CCL-PROGRAM is a symbol denoting a CCL program, return
@@ -4656,7 +4675,7 @@ Return t when OBJ is a list of strings.
 (autoload 'checkdoc "checkdoc" "\
 Interactively check the entire buffer for style errors.
 The current status of the check will be displayed in a buffer which
-the users will view as each check is completed." t nil)
+the users will view as each check is completed." '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-interactive "checkdoc" "\
 Interactively check the current buffer for doc string errors.
@@ -4667,7 +4686,7 @@ errors.  Does not check for comment or space warnings.
 Optional argument SHOWSTATUS indicates that we should update the
 checkdoc status window instead of the usual behavior.
 
-\(fn &optional START-HERE SHOWSTATUS)" t nil)
+\(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-message-interactive "checkdoc" "\
 Interactively check the current buffer for message string errors.
@@ -4678,7 +4697,7 @@ errors.  Does not check for comment or space warnings.
 Optional argument SHOWSTATUS indicates that we should update the
 checkdoc status window instead of the usual behavior.
 
-\(fn &optional START-HERE SHOWSTATUS)" t nil)
+\(fn &optional START-HERE SHOWSTATUS)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-eval-current-buffer "checkdoc" "\
 Evaluate and check documentation for the current buffer.
@@ -4692,7 +4711,7 @@ With a prefix argument (in Lisp, the argument TAKE-NOTES),
 store all errors found in a warnings buffer,
 otherwise stop after the first error.
 
-\(fn &optional TAKE-NOTES)" t nil)
+\(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-file "checkdoc" "\
 Check FILE for document, comment, error style, and rogue spaces.
@@ -4706,14 +4725,14 @@ Use `checkdoc-continue' to continue checking if an 
error cannot be fixed.
 Prefix argument TAKE-NOTES means to collect all the warning messages into
 a separate buffer.
 
-\(fn &optional TAKE-NOTES)" t nil)
+\(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-continue "checkdoc" "\
 Find the next doc string in the current buffer which has a style error.
 Prefix argument TAKE-NOTES means to continue through the whole
 buffer and save warnings in a separate buffer.
 
-\(fn &optional TAKE-NOTES)" t nil)
+\(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-comments "checkdoc" "\
 Find missing comment sections in the current Emacs Lisp file.
@@ -4721,7 +4740,7 @@ Prefix argument TAKE-NOTES non-nil means to save warnings 
in a
 separate buffer.  Otherwise print a message.  This returns the error
 if there is one.
 
-\(fn &optional TAKE-NOTES)" t nil)
+\(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-rogue-spaces "checkdoc" "\
 Find extra spaces at the end of lines in the current file.
@@ -4730,13 +4749,13 @@ separate buffer.  Otherwise print a message.  This 
returns the error
 if there is one.
 Optional argument INTERACT permits more interactive fixing.
 
-\(fn &optional TAKE-NOTES INTERACT)" t nil)
+\(fn &optional TAKE-NOTES INTERACT)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-message-text "checkdoc" "\
 Scan the buffer for occurrences of the error function, and verify text.
 Optional argument TAKE-NOTES causes all errors to be logged.
 
-\(fn &optional TAKE-NOTES)" t nil)
+\(fn &optional TAKE-NOTES)" '(emacs-lisp-mode) nil)
 
 (autoload 'checkdoc-eval-defun "checkdoc" "\
 Evaluate the current form with `eval-defun' and check its documentation.
@@ -4930,7 +4949,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'cl-font-lock-built-in-mode)'.
+evaluate `(default-value \\='cl-font-lock-built-in-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -5165,7 +5184,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'cl-old-struct-compat-mode)'.
+evaluate `(default-value \\='cl-old-struct-compat-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -5423,8 +5442,9 @@ clashes.
 \(fn NAME PREFIX &optional FIRST)" nil nil)
 
 (autoload 'comp-clean-up-stale-eln "comp" "\
-Given FILE remove all its *.eln files in `native-comp-eln-load-path'
-sharing the original source filename (including FILE).
+Remove all FILE*.eln* files found in `native-comp-eln-load-path'.
+The files to be removed are those produced from the original source
+filename (including FILE).
 
 \(fn FILE)" nil nil)
 
@@ -5449,10 +5469,17 @@ form, return the compiled function.
 \(fn FUNCTION-OR-FILE &optional OUTPUT)" nil nil)
 
 (autoload 'batch-native-compile "comp" "\
-Perform native compilation on remaining command-line arguments.
-Use this from the command line, with ‘-batch’;
-it won’t work in an interactive Emacs.
-Native compilation equivalent to `batch-byte-compile'." nil nil)
+Perform batch native compilation of remaining command-line arguments.
+
+Native compilation equivalent of `batch-byte-compile'.
+Use this from the command line, with `-batch'; it won't work
+in an interactive Emacs session.
+Optional argument FOR-TARBALL non-nil means the file being compiled
+as part of building the source tarball, in which case the .eln file
+will be placed under the native-lisp/ directory (actually, in the
+last directory in `native-comp-eln-load-path').
+
+\(fn &optional FOR-TARBALL)" nil nil)
 
 (autoload 'batch-byte+native-compile "comp" "\
 Like `batch-native-compile', but used for bootstrap.
@@ -5512,7 +5539,7 @@ If both windows display the same buffer,
 the mark is pushed twice in that buffer:
 first in the other window, then in the selected window.
 
-A prefix arg means reverse the value of variable
+A prefix arg IGNORE-WHITESPACE, means reverse the value of variable
 `compare-ignore-whitespace'.  If `compare-ignore-whitespace' is
 nil, then a prefix arg means ignore changes in whitespace.  If
 `compare-ignore-whitespace' is non-nil, then a prefix arg means
@@ -5768,7 +5795,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'dynamic-completion-mode)'.
+evaluate `(default-value \\='dynamic-completion-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -5974,8 +6001,8 @@ of load, ENDMSG at the end.
 \(fn PHRASE-FILE &optional COUNT STARTMSG ENDMSG)" nil nil)
 
 (autoload 'cookie-snarf "cookie1" "\
-Reads in the PHRASE-FILE, returns it as a vector of strings.
-Emit STARTMSG and ENDMSG before and after.  Caches the result; second
+Read the PHRASE-FILE, return it as a vector of strings.
+Emit STARTMSG and ENDMSG before and after.  Cache the result; second
 and subsequent calls on the same file won't go to disk.
 
 \(fn PHRASE-FILE &optional STARTMSG ENDMSG)" nil nil)
@@ -6102,7 +6129,7 @@ into
 
 \\{cperl-mode-map}
 
-Setting the variable `cperl-font-lock' to t switches on font-lock-mode
+Setting the variable `cperl-font-lock' to t switches on `font-lock-mode'
 \(even with older Emacsen), `cperl-electric-lbrace-space' to t switches
 on electric space between $ and {, `cperl-electric-parens-string' is
 the string that contains parentheses that should be electric in CPerl
@@ -6337,7 +6364,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'cua-mode)'.
+evaluate `(default-value \\='cua-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -7083,7 +7110,7 @@ Variables controlling indentation style and extra 
features:
     These variables control the look of expanded templates.
 
  dcl-imenu-generic-expression
-    Default value for imenu-generic-expression.  The default includes
+    Default value for `imenu-generic-expression'.  The default includes
     SUBROUTINE labels in the main listing and sub-listings for
     other labels, CALL, GOTO and GOSUB statements.
 
@@ -7169,7 +7196,7 @@ Redefining FUNCTION also cancels it.
 
 (autoload 'cancel-debug-on-entry "debug" "\
 Undo effect of \\[debug-on-entry] on FUNCTION.
-If FUNCTION is nil, cancel debug-on-entry for all functions.
+If FUNCTION is nil, cancel `debug-on-entry' for all functions.
 When called interactively, prompt for FUNCTION in the minibuffer.
 To specify a nil argument interactively, exit with an empty minibuffer.
 
@@ -7199,7 +7226,7 @@ another symbol also cancels it.
 
 (autoload 'cancel-debug-on-variable-change "debug" "\
 Undo effect of \\[debug-on-variable-change] on VARIABLE.
-If VARIABLE is nil, cancel debug-on-variable-change for all variables.
+If VARIABLE is nil, cancel `debug-on-variable-change' for all variables.
 When called interactively, prompt for VARIABLE in the minibuffer.
 To specify a nil argument interactively, exit with an empty minibuffer.
 
@@ -7266,7 +7293,7 @@ See the `delimit-columns-str-before',
 `delimit-columns-before', `delimit-columns-after',
 `delimit-columns-separator', `delimit-columns-format' and
 `delimit-columns-extra' variables for customization of the
-look. 
+look.
 
 \(fn START END)" t nil)
 
@@ -7310,7 +7337,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'delete-selection-mode)'.
+evaluate `(default-value \\='delete-selection-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -7346,7 +7373,7 @@ The arguments are as follows:
 CHILD:     the name of the command for the derived mode.
 PARENT:    the name of the command for the parent mode (e.g. `text-mode')
            or nil if there is no parent.
-NAME:      a string which will appear in the status line (e.g. \"Hypertext\")
+NAME:      a string that will appear in the mode line (e.g. \"HTML\")
 DOCSTRING: an optional documentation string--if you do not supply one,
            the function will attempt to invent something useful.
 KEYWORD-ARGS:
@@ -7365,7 +7392,7 @@ KEYWORD-ARGS:
                    A nil value means to simply use the same abbrev-table
                    as the parent.
            :after-hook FORM
-                   A single lisp form which is evaluated after the mode
+                   A single Lisp form which is evaluated after the mode
                    hooks have been run.  It should not be quoted.
            :interactive BOOLEAN
                    Whether the derived mode should be `interactive' or not.
@@ -7392,8 +7419,8 @@ the parent, and then sets the variable `case-fold-search' 
to nil:
 Note that if the documentation string had been left out, it would have
 been generated automatically, with a reference to the keymap.
 
-The new mode runs the hook constructed by the function
-`derived-mode-hook-name'.
+The new mode runs the hook named MODE-hook.  For `foo-mode',
+the hook will be named `foo-mode-hook'.
 
 See Info node `(elisp)Derived Modes' for more details.
 
@@ -7401,6 +7428,8 @@ See Info node `(elisp)Derived Modes' for more details.
 
 (function-put 'define-derived-mode 'doc-string-elt '4)
 
+(function-put 'define-derived-mode 'lisp-indent-function 'defun)
+
 (autoload 'derived-mode-init-mode-variables "derived" "\
 Initialize variables for a new MODE.
 Right now, if they don't already exist, set up a blank keymap, an
@@ -7498,7 +7527,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'desktop-save-mode)'.
+evaluate `(default-value \\='desktop-save-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -7854,16 +7883,24 @@ active it will overwrite that mode for the current 
buffer.
 \(fn &optional ARG)" t nil)
 
 (autoload 'global-dictionary-tooltip-mode "dictionary" "\
-Enable/disable dictionary-tooltip-mode for all buffers.
+Enable/disable `dictionary-tooltip-mode' for all buffers.
 
-Internally it provides a default for the dictionary-tooltip-mode.
-It can be overwritten for each buffer using dictionary-tooltip-mode.
+Internally it provides a default for the `dictionary-tooltip-mode'.
+It can be overwritten for each buffer using `dictionary-tooltip-mode'.
 
 Note: (global-dictionary-tooltip-mode 0) will not disable the mode
 any buffer where (dictionary-tooltip-mode 1) has been called.
 
 \(fn &optional ARG)" t nil)
 
+(autoload 'context-menu-dictionary "dictionary" "\
+Populate MENU with dictionary commands at CLICK.
+When you add this function to `context-menu-functions',
+the context menu will contain an item that searches
+the word at mouse click.
+
+\(fn MENU CLICK)" nil nil)
+
 (register-definition-prefixes "dictionary" '("dictionary-" 
"global-dictionary-tooltip-mode"))
 
 ;;;***
@@ -7901,10 +7938,10 @@ minibuffer.  The default for NEW is the current 
buffer's file
 name, and the default for OLD is a backup file for NEW, if one
 exists.  If NO-ASYNC is non-nil, call diff synchronously.
 
-When called interactively with a prefix argument, prompt
+When called interactively with a prefix argument SWITCHES, prompt
 interactively for diff switches.  Otherwise, the switches
-specified in the variable `diff-switches' are passed to the
-diff command.
+specified in the variable `diff-switches' are passed to the diff
+command.
 
 Non-interactively, OLD and NEW may each be a file or a buffer.
 
@@ -7915,12 +7952,12 @@ Diff this file with its backup file or vice versa.
 Uses the latest backup, if there are several numerical backups.
 If this file is a backup, diff it with its original.
 The backup file is the first file given to `diff'.
-With prefix arg, prompt for diff switches.
+With prefix arg SWITCHES, prompt for diff switches.
 
 \(fn FILE &optional SWITCHES)" t nil)
 
 (autoload 'diff-latest-backup-file "diff" "\
-Return the latest existing backup of FILE, or nil.
+Return the latest existing backup of file FN, or nil.
 
 \(fn FN)" nil nil)
 
@@ -7960,7 +7997,7 @@ Supports unified and context diffs as well as (to a 
lesser extent)
 normal diffs.
 
 When the buffer is read-only, the ESC prefix is not necessary.
-If you edit the buffer manually, diff-mode will try to update the hunk
+If you edit the buffer manually, `diff-mode' will try to update the hunk
 headers for you on-the-fly.
 
 You can also switch between context diff and unified diff with 
\\[diff-context->unified],
@@ -8065,24 +8102,24 @@ If DIRNAME is already in a Dired buffer, that buffer is 
used without refresh.
  (define-key ctl-x-4-map "d" 'dired-other-window)
 
 (autoload 'dired-other-window "dired" "\
-\"Edit\" directory DIRNAME.  Like `dired' but selects in another window.
+\"Edit\" directory DIRNAME.  Like `dired' but select in another window.
 
 \(fn DIRNAME &optional SWITCHES)" t nil)
  (define-key ctl-x-5-map "d" 'dired-other-frame)
 
 (autoload 'dired-other-frame "dired" "\
-\"Edit\" directory DIRNAME.  Like `dired' but makes a new frame.
+\"Edit\" directory DIRNAME.  Like `dired' but make a new frame.
 
 \(fn DIRNAME &optional SWITCHES)" t nil)
  (define-key tab-prefix-map "d" 'dired-other-tab)
 
 (autoload 'dired-other-tab "dired" "\
-\"Edit\" directory DIRNAME.  Like `dired' but makes a new tab.
+\"Edit\" directory DIRNAME.  Like `dired' but make a new tab.
 
 \(fn DIRNAME &optional SWITCHES)" t nil)
 
 (autoload 'dired-noselect "dired" "\
-Like `dired' but returns the Dired buffer as value, does not select it.
+Like `dired' but return the Dired buffer as value, do not select it.
 
 \(fn DIR-OR-LIST &optional SWITCHES)" nil nil)
 
@@ -8349,7 +8386,7 @@ in `.emacs'.
 ;;; Generated autoloads from display-fill-column-indicator.el
 
 (autoload 'display-fill-column-indicator-mode "display-fill-column-indicator" 
"\
-Toggle display of fill-column indicator.
+Toggle display of `fill-column' indicator.
 This uses `display-fill-column-indicator' internally.
 
 This is a minor mode.  If called interactively, toggle the
@@ -8403,8 +8440,8 @@ Display-Fill-Column-Indicator mode is enabled in all 
buffers where
 See `display-fill-column-indicator-mode' for more information on
 Display-Fill-Column-Indicator mode.
 
-`global-display-fill-column-indicator-modes' is used to control
-which modes this minor mode is used in.
+`global-display-fill-column-indicator-modes' is used to control which
+modes this minor mode is used in.
 
 \(fn &optional ARG)" t nil)
 
@@ -8735,7 +8772,7 @@ BODY contains code to execute each time the mode is 
enabled or disabled.
   It is executed after toggling the mode, and before running MODE-hook.
   Before the actual body code, you can write keyword arguments, i.e.
   alternating keywords and values.  If you provide BODY, then you must
-  provide at least one keyword argument (e.g. `:lighter nil').
+  provide at least one keyword argument (e.g. `:lighter nil`).
   The following special keywords are supported (other keywords are passed
   to `defcustom' if the minor mode is global):
 
@@ -8750,8 +8787,8 @@ BODY contains code to execute each time the mode is 
enabled or disabled.
                Not used if you also specify :variable.
 :lighter SPEC  Text displayed in the mode line when the mode is on.
 :keymap MAP    Keymap bound to the mode keymap.  Defaults to `MODE-map'.
-               If non-nil, it should be a variable name (whose value is
-               a keymap), or an expression that returns either a keymap or
+                If non-nil, it should be an unquoted variable name (whose value
+                is a keymap), or an expression that returns either a keymap or
                a list of (KEY . BINDING) pairs where KEY and BINDING are
                suitable for `define-key'.  If you supply a KEYMAP argument
                that is not a symbol, this macro defines the variable MODE-map
@@ -8769,7 +8806,7 @@ BODY contains code to execute each time the mode is 
enabled or disabled.
                 be assigned to PLACE.  If you specify a :variable, this 
function
                 does not define a MODE variable (nor any of the terms used
                in :variable).
-:after-hook     A single lisp form which is evaluated after the mode hooks
+:after-hook     A single Lisp form which is evaluated after the mode hooks
                 have been run.  It should not be quoted.
 
 For example, you could write
@@ -8785,6 +8822,8 @@ INIT-VALUE LIGHTER KEYMAP.
 
 (function-put 'define-minor-mode 'doc-string-elt '2)
 
+(function-put 'define-minor-mode 'lisp-indent-function 'defun)
+
 (defalias 'easy-mmode-define-global-mode #'define-globalized-minor-mode)
 
 (defalias 'define-global-minor-mode #'define-globalized-minor-mode)
@@ -8822,6 +8861,8 @@ on if the hook has explicitly disabled it.
 
 (function-put 'define-globalized-minor-mode 'doc-string-elt '2)
 
+(function-put 'define-globalized-minor-mode 'lisp-indent-function 'defun)
+
 (autoload 'easy-mmode-define-keymap "easy-mmode" "\
 Return a keymap built from bindings BS.
 BS must be a list of (KEY . BINDING) where
@@ -9372,7 +9413,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-ede-mode)'.
+evaluate `(default-value \\='global-ede-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -9670,9 +9711,11 @@ symbol describing the Ediff job type; it defaults to
 (defalias 'ebuffers3 #'ediff-buffers3)
 
 (autoload 'ediff-directories "ediff" "\
-Run Ediff on a pair of directories, DIR1 and DIR2, comparing files that have
-the same name in both.  The third argument, REGEXP, is nil or a regular
-expression; only file names that match the regexp are considered.
+Run Ediff on directories DIR1 and DIR2, comparing files.
+Consider only files that have the same name in both directories.
+
+REGEXP is nil or a regular expression; only file names that match
+the regexp are considered.
 
 \(fn DIR1 DIR2 REGEXP)" t nil)
 
@@ -9688,9 +9731,11 @@ names.  Only the files that are under revision control 
are taken into account.
 (defalias 'edir-revisions #'ediff-directory-revisions)
 
 (autoload 'ediff-directories3 "ediff" "\
-Run Ediff on three directories, DIR1, DIR2, and DIR3, comparing files that
-have the same name in all three.  The last argument, REGEXP, is nil or a
-regular expression; only file names that match the regexp are considered.
+Run Ediff on directories DIR1, DIR2, and DIR3, comparing files.
+Consider only files that have the same name in all three directories.
+
+REGEXP is nil or a regular expression; only file names that match
+the regexp are considered.
 
 \(fn DIR1 DIR2 DIR3 REGEXP)" t nil)
 
@@ -9707,7 +9752,7 @@ MERGE-AUTOSTORE-DIR is the directory in which to store 
merged files.
 (defalias 'edirs-merge #'ediff-merge-directories)
 
 (autoload 'ediff-merge-directories-with-ancestor "ediff" "\
-Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as 
ancestors.
+Merge files in DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
 Ediff merges files that have identical names in DIR1, DIR2.  If a pair of files
 in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
 without ancestor.  The fourth argument, REGEXP, is nil or a regular expression;
@@ -9727,7 +9772,7 @@ MERGE-AUTOSTORE-DIR is the directory in which to store 
merged files.
 (defalias 'edir-merge-revisions #'ediff-merge-directory-revisions)
 
 (autoload 'ediff-merge-directory-revisions-with-ancestor "ediff" "\
-Run Ediff on a directory, DIR1, merging its files with their revisions and 
ancestors.
+Run Ediff on DIR1 and merge its files with their revisions and ancestors.
 The second argument, REGEXP, is a regular expression that filters the file
 names.  Only the files that are under revision control are taken into account.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files.
@@ -9912,7 +9957,7 @@ Call `ediff3-files' with the next three command line 
arguments." nil nil)
 Call `ediff-merge-files' with the next two command line arguments." nil nil)
 
 (autoload 'ediff-merge-with-ancestor-command "ediff" "\
-Call `ediff-merge-files-with-ancestor' with the next three command line 
arguments." nil nil)
+Call `ediff-merge-files-with-ancestor' with next three command line 
arguments." nil nil)
 
 (autoload 'ediff-directories-command "ediff" "\
 Call `ediff-directories' with the next three command line arguments." nil nil)
@@ -9924,7 +9969,8 @@ Call `ediff-directories3' with the next four command line 
arguments." nil nil)
 Call `ediff-merge-directories' with the next three command line arguments." 
nil nil)
 
 (autoload 'ediff-merge-directories-with-ancestor-command "ediff" "\
-Call `ediff-merge-directories-with-ancestor' with the next four command line 
arguments." nil nil)
+Call `ediff-merge-directories-with-ancestor' with the next four command line
+arguments." nil nil)
 
 (register-definition-prefixes "ediff" '("ediff-"))
 
@@ -10229,7 +10275,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'electric-pair-mode)'.
+evaluate `(default-value \\='electric-pair-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -10256,7 +10302,8 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(buffer-local-value 'electric-pair-mode (current-buffer))'.
+evaluate `(buffer-local-value \\='electric-pair-mode
+\(current-buffer))'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -10413,7 +10460,7 @@ Message buffer where you can explain more about the 
patch.
 ;;; Generated autoloads from vc/emerge.el
 
 (autoload 'emerge-files "emerge" "\
-Run Emerge on two files.
+Run Emerge on two files FILE-A and FILE-B.
 
 \(fn ARG FILE-A FILE-B FILE-OUT &optional STARTUP-HOOKS QUIT-HOOKS)" t nil)
 
@@ -10423,7 +10470,7 @@ Run Emerge on two files, giving another file as the 
ancestor.
 \(fn ARG FILE-A FILE-B FILE-ANCESTOR FILE-OUT &optional STARTUP-HOOKS 
QUIT-HOOKS)" t nil)
 
 (autoload 'emerge-buffers "emerge" "\
-Run Emerge on two buffers.
+Run Emerge on two buffers BUFFER-A and BUFFER-B.
 
 \(fn BUFFER-A BUFFER-B &optional STARTUP-HOOKS QUIT-HOOKS)" t nil)
 
@@ -10527,7 +10574,7 @@ List all keys matched with NAME from the private 
keyring.
 
 (autoload 'epa-select-keys "epa" "\
 Display a user's keyring and ask him to select keys.
-CONTEXT is an epg-context.
+CONTEXT is an `epg-context'.
 PROMPT is a string to prompt with.
 NAMES is a list of strings to be matched with keys.  If it is nil, all
 the keys are listed.
@@ -10614,8 +10661,7 @@ For example:
 (function-put 'epa-verify-region 'interactive-only 't)
 
 (autoload 'epa-verify-cleartext-in-region "epa" "\
-Verify OpenPGP cleartext signed messages in the current region
-between START and END.
+Verify OpenPGP cleartext signed messages in current region from START to END.
 
 Don't use this command in Lisp programs!
 See the reason described in the `epa-verify-region' documentation.
@@ -10683,8 +10729,7 @@ Import keys from the region.
 \(fn START END)" t nil)
 
 (autoload 'epa-import-armor-in-region "epa" "\
-Import keys in the OpenPGP armor format in the current region
-between START and END.
+Import keys in the OpenPGP armor format in the current region from START to 
END.
 
 \(fn START END)" t nil)
 
@@ -10843,7 +10888,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'epa-global-mail-mode)'.
+evaluate `(default-value \\='epa-global-mail-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -10909,7 +10954,7 @@ Look at CONFIG and try to expand GROUP.
 
 ;;;### (autoloads nil "erc" "erc/erc.el" (0 0 0 0))
 ;;; Generated autoloads from erc/erc.el
-(push (purecopy '(erc 5 3)) package--builtin-versions)
+(push (purecopy '(erc 5 4 1)) package--builtin-versions)
 
 (autoload 'erc-select-read-args "erc" "\
 Prompt the user for values of nick, server, port, and password." nil nil)
@@ -10967,7 +11012,7 @@ first element is the certificate key file name, and the 
second
 element is the certificate file name itself, or t, which means
 that `auth-source' will be queried for the key and the
 certificate.  Authenticating using a TLS client certificate is
-also refered to as \"CertFP\" (Certificate Fingerprint)
+also referred to as \"CertFP\" (Certificate Fingerprint)
 authentication by various IRC networks.
 
 Example usage:
@@ -11115,6 +11160,22 @@ Kill all test buffers that are still live." t nil)
 
 ;;;***
 
+;;;### (autoloads nil "erts-mode" "progmodes/erts-mode.el" (0 0 0
+;;;;;;  0))
+;;; Generated autoloads from progmodes/erts-mode.el
+
+(autoload 'erts-mode "erts-mode" "\
+Major mode for editing erts (Emacs testing) files.
+This mode mainly provides some font locking.
+
+\\{erts-mode-map}
+
+\(fn)" t nil)
+
+(register-definition-prefixes "erts-mode" '("erts-"))
+
+;;;***
+
 ;;;### (autoloads nil "esh-arg" "eshell/esh-arg.el" (0 0 0 0))
 ;;; Generated autoloads from eshell/esh-arg.el
 
@@ -11207,7 +11268,7 @@ session.  Return the buffer selected (or created).
 
 With a nonnumeric prefix arg, create a new session.
 
-With a numeric prefix arg (as in `C-u 42 M-x eshell RET'), switch
+With a numeric prefix arg (as in `\\[universal-argument] 42 \\[eshell]'), 
switch
 to the session with that number, or create it if it doesn't
 already exist.
 
@@ -11459,7 +11520,7 @@ See documentation of variable `tags-file-name'.
 
 (make-obsolete 'find-tag-regexp 'xref-find-apropos '"25.1")
 
-(defalias 'pop-tag-mark 'xref-pop-marker-stack)
+(defalias 'pop-tag-mark 'xref-go-back)
 
 (defalias 'next-file 'tags-next-file)
 
@@ -11540,7 +11601,21 @@ for \\[find-tag] (which see)." t nil)
 
 (autoload 'etags--xref-backend "etags" nil nil nil)
 
-(register-definition-prefixes "etags" '("default-tags-table-function" "etags-" 
"file-of-tag" "find-tag-" "goto-tag-location-function" 
"initialize-new-tags-table" "last-tag" "list-tags-function" 
"select-tags-table-" "snarf-tag-function" "tag" "verify-tags-table-function" 
"xref-"))
+(register-definition-prefixes "etags" '("default-tags-table-function" "etags-" 
"file-of-tag" "find-tag-" "goto-tag-location-function" 
"initialize-new-tags-table" "last-tag" "list-tags-function" 
"select-tags-table-" "snarf-tag-function" "tag" "verify-tags-table-function"))
+
+;;;***
+
+;;;### (autoloads nil "etc-authors-mode" "textmodes/etc-authors-mode.el"
+;;;;;;  (0 0 0 0))
+;;; Generated autoloads from textmodes/etc-authors-mode.el
+
+(autoload 'etc-authors-mode "etc-authors-mode" "\
+Major mode for viewing \"etc/AUTHORS\" from the Emacs distribution.
+Provides some basic font locking and not much else.
+
+\(fn)" t nil)
+
+(register-definition-prefixes "etc-authors-mode" '("etc-authors-"))
 
 ;;;***
 
@@ -11739,8 +11814,9 @@ see `eudc-inline-expansion-servers'.
 Query the directory server, and return the matching responses.
 The variable `eudc-inline-query-format' controls how to associate the
 individual QUERY-WORDS with directory attribute names.
-After querying the server for the given string, the expansion specified by
-`eudc-inline-expansion-format' is applied to the matches before returning 
them.inserted in the buffer at point.
+After querying the server for the given string, the expansion
+specified by `eudc-inline-expansion-format' is applied to the
+matches before returning them.inserted in the buffer at point.
 Multiple servers can be tried with the same query until one finds a match,
 see `eudc-inline-expansion-servers'.
 
@@ -11946,6 +12022,8 @@ for the search engine used." t nil)
 (autoload 'eww-mode "eww" "\
 Mode for browsing the web.
 
+\\{eww-mode-map}
+
 \(fn)" t nil)
 
 (autoload 'eww-browse-url "eww" "\
@@ -11968,6 +12046,11 @@ instead of `browse-url-new-window-flag'.
 (autoload 'eww-list-bookmarks "eww" "\
 Display the bookmarks." t nil)
 
+(autoload 'eww-bookmark-jump "eww" "\
+Default bookmark handler for EWW buffers.
+
+\(fn BOOKMARK)" nil nil)
+
 (register-definition-prefixes "eww" '("erc--download-directory" "eww-"))
 
 ;;;***
@@ -12224,7 +12307,7 @@ Adjust the height of the default face by INC.
 INC may be passed as a numeric prefix argument.
 
 The actual adjustment made depends on the final component of the
-key-binding used to invoke the command, with all modifiers removed:
+keybinding used to invoke the command, with all modifiers removed:
 
    +, =   Increase the height of the default face by one step
    -      Decrease the height of the default face by one step
@@ -12322,10 +12405,10 @@ If the optional argument LIST is non-nil, it should 
be a list of
 colors to display.  Otherwise, this command computes a list of
 colors that the current display can handle.  Customize
 `list-colors-sort' to change the order in which colors are shown.
-Type `g' or \\[revert-buffer] after customizing `list-colors-sort'
-to redisplay colors in the new order.
+Type \\<help-mode-map>\\[revert-buffer] after customizing `list-colors-sort' 
to redisplay colors in
+the new order.
 
-If the optional argument BUFFER-NAME is nil, it defaults to *Colors*.
+If the optional argument BUFFER-NAME is nil, it defaults to \"*Colors*\".
 
 If the optional argument CALLBACK is non-nil, it should be a
 function to call each time the user types RET or clicks on a
@@ -12454,8 +12537,9 @@ If `ffap-url-regexp' is not nil, the FILENAME may also 
be an URL.
 With a prefix, this command behaves exactly like `ffap-file-finder'.
 If `ffap-require-prefix' is set, the prefix meaning is reversed.
 See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt',
-`ffap-url-unwrap-local', `ffap-url-unwrap-remote', and the functions
-`ffap-file-at-point' and `ffap-url-at-point'.
+`ffap-url-unwrap-local', `ffap-url-unwrap-remote',
+`ffap-file-name-with-spaces', and the functions `ffap-file-at-point'
+and `ffap-url-at-point'.
 
 \(fn &optional FILENAME)" t nil)
 
@@ -12775,7 +12859,7 @@ it finishes, type \\[kill-find].
 \(fn DIR ARGS)" t nil)
 
 (autoload 'find-name-dired "find-dired" "\
-Search DIR recursively for files matching the globbing pattern PATTERN,
+Search DIR recursively for files matching the globbing PATTERN,
 and run Dired on those files.
 PATTERN is a shell wildcard (not an Emacs regexp) and need not be quoted.
 The default command run (after changing into DIR) is
@@ -12906,13 +12990,16 @@ Find the Emacs Lisp source of LIBRARY.
 
 Interactively, prompt for LIBRARY using the one at or near point.
 
+This function searches `find-library-source-path' if non-nil, and
+`load-path' otherwise.
+
 \(fn LIBRARY)" t nil)
 
 (autoload 'read-library-name "find-func" "\
 Read and return a library name, defaulting to the one near point.
 
 A library name is the filename of an Emacs Lisp library located
-in a directory under `load-path' (or `find-function-source-path',
+in a directory under `load-path' (or `find-library-source-path',
 if non-nil)." nil nil)
 
 (autoload 'find-library-other-window "find-func" "\
@@ -12953,10 +13040,6 @@ If FUNCTION is a built-in function, this function 
normally
 attempts to find it in the Emacs C sources; however, if LISP-ONLY
 is non-nil, signal an error instead.
 
-If the file where FUNCTION is defined is not known, then it is
-searched for in `find-function-source-path' if non-nil, otherwise
-in `load-path'.
-
 \(fn FUNCTION &optional LISP-ONLY)" nil nil)
 
 (autoload 'find-function "find-func" "\
@@ -12967,8 +13050,6 @@ near point (selected by `function-called-at-point') in 
a buffer and
 places point before the definition.
 Set mark before moving, if the buffer already existed.
 
-The library where FUNCTION is defined is searched for in
-`find-function-source-path', if non-nil, otherwise in `load-path'.
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
 \(fn FUNCTION)" t nil)
@@ -12994,9 +13075,6 @@ Finds the library containing the definition of VARIABLE 
in a buffer and
 the point of the definition.  The buffer is not selected.
 If the variable's definition can't be found in the buffer, return (BUFFER).
 
-The library where VARIABLE is defined is searched for in FILE or
-`find-function-source-path', if non-nil, otherwise in `load-path'.
-
 \(fn VARIABLE &optional FILE)" nil nil)
 
 (autoload 'find-variable "find-func" "\
@@ -13008,8 +13086,6 @@ places point before the definition.
 
 Set mark before moving, if the buffer already existed.
 
-The library where VARIABLE is defined is searched for in
-`find-function-source-path', if non-nil, otherwise in `load-path'.
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
 \(fn VARIABLE)" t nil)
@@ -13035,9 +13111,6 @@ TYPE says what type of definition: nil for a function, 
`defvar' for a
 variable, `defface' for a face.  This function does not switch to the
 buffer nor display it.
 
-The library where SYMBOL is defined is searched for in FILE or
-`find-function-source-path', if non-nil, otherwise in `load-path'.
-
 \(fn SYMBOL TYPE &optional FILE)" nil nil)
 
 (autoload 'find-face-definition "find-func" "\
@@ -13049,8 +13122,6 @@ places point before the definition.
 
 Set mark before moving, if the buffer already existed.
 
-The library where FACE is defined is searched for in
-`find-function-source-path', if non-nil, otherwise in `load-path'.
 See also `find-function-recenter-line' and `find-function-after-hook'.
 
 \(fn FACE)" t nil)
@@ -13080,7 +13151,7 @@ Find directly the function at point in the other 
window." t nil)
 Find directly the variable at point in the other window." t nil)
 
 (autoload 'find-function-setup-keys "find-func" "\
-Define some key bindings for the find-function family of functions." nil nil)
+Define some key bindings for the `find-function' family of functions." nil nil)
 
 (register-definition-prefixes "find-func" '("find-"))
 
@@ -13173,7 +13244,7 @@ lines.
 
 ;;;### (autoloads nil "flymake" "progmodes/flymake.el" (0 0 0 0))
 ;;; Generated autoloads from progmodes/flymake.el
-(push (purecopy '(flymake 1 1 1)) package--builtin-versions)
+(push (purecopy '(flymake 1 2 1)) package--builtin-versions)
 
 (autoload 'flymake-log "flymake" "\
 Log, at level LEVEL, the message MSG formatted with ARGS.
@@ -13185,23 +13256,32 @@ generated it.
 \(fn LEVEL MSG &rest ARGS)" nil t)
 
 (autoload 'flymake-make-diagnostic "flymake" "\
-Make a Flymake diagnostic for BUFFER's region from BEG to END.
+Make a Flymake diagnostic for LOCUS's region from BEG to END.
+LOCUS is a buffer object or a string designating a file name.
+
 TYPE is a diagnostic symbol and TEXT is string describing the
 problem detected in this region.  DATA is any object that the
 caller wishes to attach to the created diagnostic for later
-retrieval.
+retrieval with `flymake-diagnostic-data'.
+
+If LOCUS is a buffer BEG and END should be buffer positions
+inside it.  If LOCUS designates a file, BEG and END should be a
+cons (LINE . COL) indicating a file position.  In this second
+case, END may be ommited in which case the region is computed
+using `flymake-diag-region' if the diagnostic is appended to an
+actual buffer.
 
 OVERLAY-PROPERTIES is an alist of properties attached to the
 created diagnostic, overriding the default properties and any
-properties of `flymake-overlay-control' of the diagnostic's
-type.
+properties listed in the `flymake-overlay-control' property of
+the diagnostic's type symbol.
 
-\(fn BUFFER BEG END TYPE TEXT &optional DATA OVERLAY-PROPERTIES)" nil nil)
+\(fn LOCUS BEG END TYPE TEXT &optional DATA OVERLAY-PROPERTIES)" nil nil)
 
 (autoload 'flymake-diagnostics "flymake" "\
 Get Flymake diagnostics in region determined by BEG and END.
 
-If neither BEG or END is supplied, use the whole buffer,
+If neither BEG or END is supplied, use whole accessible buffer,
 otherwise if BEG is non-nil and END is nil, consider only
 diagnostics at BEG.
 
@@ -13678,7 +13758,7 @@ Variables controlling indentation style and extra 
features:
 `fortran-comment-line-extra-indent'
   Amount of extra indentation for text in full-line comments (default 0).
 `fortran-comment-indent-style'
-  How to indent the text in full-line comments. Allowed values are:
+  How to indent the text in full-line comments.  Allowed values are:
   nil         don't change the indentation
   `fixed'     indent to `fortran-comment-line-extra-indent' beyond the
               value of either
@@ -13924,7 +14004,8 @@ FORCE-ONSCREEN can be:
           - a list (LEFT TOP WIDTH HEIGHT), describing the workarea.
           It must return non-nil to force the frame onscreen, nil otherwise.
 
-CLEANUP-FRAMES allows \"cleaning up\" the frame list after restoring a 
frameset:
+CLEANUP-FRAMES allows \"cleaning up\" the frame list after
+restoring a frameset:
   t        Delete all frames that were not created or restored upon.
   nil      Keep all frames.
   FUNC     A function called with two arguments:
@@ -14009,7 +14090,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'gdb-enable-debug)'.
+evaluate `(default-value \\='gdb-enable-debug)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -14025,7 +14106,7 @@ becomes the initial working directory and source-file 
directory
 for your debugger.
 If COMMAND-LINE requests that gdb attaches to a process PID, gdb
 will run in *gud-PID*, otherwise it will run in *gud*; in these
-cases the initial working directory is the default-directory of
+cases the initial working directory is the `default-directory' of
 the buffer in which this command was invoked.
 
 COMMAND-LINE should include \"-i=mi\" to use gdb's MI text interface.
@@ -14351,7 +14432,7 @@ Allow Gnus to be an offline newsreader.
 
 The gnus-agentize function is now called internally by gnus when
 gnus-agent is set.  If you wish to avoid calling gnus-agentize,
-customize gnus-agent to nil.
+customize `gnus-agent' to nil.
 
 This will modify the `gnus-setup-news-hook', and
 `message-send-mail-real-function' variables, and install the Gnus agent
@@ -14416,7 +14497,7 @@ CLEAN is obsolete and ignored.
 (autoload 'gnus-article-prepare-display "gnus-art" "\
 Make the current buffer look like a nice article." nil nil)
 
-(register-definition-prefixes "gnus-art" '("article-" "gnus-"))
+(register-definition-prefixes "gnus-art" '(":keymap" "article-" "gnus-"))
 
 ;;;***
 
@@ -14592,7 +14673,7 @@ Checking delayed messages is skipped if optional arg 
NO-CHECK is non-nil.
 ;;; Generated autoloads from gnus/gnus-dired.el
 
 (autoload 'turn-on-gnus-dired-mode "gnus-dired" "\
-Convenience method to turn on gnus-dired-mode." t nil)
+Convenience method to turn on `gnus-dired-mode'." t nil)
 
 (register-definition-prefixes "gnus-dired" '("gnus-dired-"))
 
@@ -14626,7 +14707,8 @@ Reminder user if there are unsent drafts." t nil)
 ;;; Generated autoloads from gnus/gnus-fun.el
 
 (autoload 'gnus--random-face-with-type "gnus-fun" "\
-Return file from DIR with extension EXT, omitting matches of OMIT, processed 
by FUN.
+Return file from DIR with extension EXT.
+Omit matches of OMIT, and process them by FUN.
 
 \(fn DIR EXT OMIT FUN)" nil nil)
 
@@ -14723,7 +14805,7 @@ The arguments have the same meaning as those of
 
 \(fn IDS &optional WINDOW-CONF)" t nil)
 
-(register-definition-prefixes "gnus-group" '("gnus-"))
+(register-definition-prefixes "gnus-group" '(":keymap" "gnus-"))
 
 ;;;***
 
@@ -14855,7 +14937,7 @@ match any of the group-specified splitting rules.  See
 \(fn &optional AUTO-UPDATE CATCH-ALL)" t nil)
 
 (autoload 'gnus-group-split-update "gnus-mlspl" "\
-Computes nnmail-split-fancy from group params and CATCH-ALL.
+Computes `nnmail-split-fancy' from group params and CATCH-ALL.
 It does this by calling (gnus-group-split-fancy nil nil CATCH-ALL).
 
 If CATCH-ALL is nil, `gnus-group-split-default-catch-all-group' is used
@@ -14950,7 +15032,7 @@ Like `message-reply'.
 
 (define-mail-user-agent 'gnus-user-agent 'gnus-msg-mail 'message-send-and-exit 
'message-kill-buffer 'message-send-hook)
 
-(register-definition-prefixes "gnus-msg" '("gnus-"))
+(register-definition-prefixes "gnus-msg" '(":prefix" "gnus-"))
 
 ;;;***
 
@@ -15164,7 +15246,7 @@ BOOKMARK is a bookmark name or a bookmark record.
 
 \(fn BOOKMARK)" nil nil)
 
-(register-definition-prefixes "gnus-sum" '("gnus-"))
+(register-definition-prefixes "gnus-sum" '(":keymap" "gnus-"))
 
 ;;;***
 
@@ -15436,7 +15518,7 @@ This variable's value takes effect when 
`grep-compute-defaults' is called.")
 History list for grep.")
 
 (defvar grep-find-history nil "\
-History list for grep-find.")
+History list for `grep-find'.")
 
 (autoload 'grep-process-setup "grep" "\
 Setup compilation variables and buffer for `grep'.
@@ -15575,7 +15657,7 @@ becomes the initial working directory and source-file 
directory
 for your debugger.
 If COMMAND-LINE requests that gdb attaches to a process PID, gdb
 will run in *gud-PID*, otherwise it will run in *gud*; in these
-cases the initial working directory is the default-directory of
+cases the initial working directory is the `default-directory' of
 the buffer in which this command was invoked.
 
 \(fn COMMAND-LINE)" t nil)
@@ -15679,7 +15761,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'gud-tooltip-mode)'.
+evaluate `(default-value \\='gud-tooltip-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -15804,7 +15886,7 @@ binding mode.
 ;;; Generated autoloads from play/handwrite.el
 
 (autoload 'handwrite "handwrite" "\
-Turns the buffer into a \"handwritten\" document.
+Turn the buffer into a \"handwritten\" document.
 The functions `handwrite-10pt', `handwrite-11pt', `handwrite-12pt'
 and `handwrite-13pt' set up for various sizes of output.
 
@@ -15841,9 +15923,9 @@ second since 1970-01-01 00:00:00 GMT.
 Repent before ring 31 moves." t nil)
 
 (autoload 'hanoi-unix-64 "hanoi" "\
-Like hanoi-unix, but pretend to have a 64-bit clock.
+Like `hanoi-unix', but pretend to have a 64-bit clock.
 This is, necessarily (as of Emacs 20.3), a crock.  When the
-current-time interface is made s2G-compliant, hanoi.el will need
+`current-time' interface is made s2G-compliant, hanoi.el will need
 to be updated." t nil)
 
 (register-definition-prefixes "hanoi" '("hanoi-"))
@@ -16029,13 +16111,16 @@ different regions.  With numeric argument ARG, 
behaves like
 
 (autoload 'describe-function "help-fns" "\
 Display the full documentation of FUNCTION (a symbol).
-When called from lisp, FUNCTION may also be a function object.
+When called from Lisp, FUNCTION may also be a function object.
+
+See the `help-enable-symbol-autoload' variable for special
+handling of autoloaded functions.
 
 \(fn FUNCTION)" t nil)
 
 (autoload 'describe-command "help-fns" "\
 Display the full documentation of COMMAND (a symbol).
-When called from lisp, COMMAND may also be a function object.
+When called from Lisp, COMMAND may also be a function object.
 
 \(fn COMMAND)" t nil)
 
@@ -16188,6 +16273,11 @@ gives the window that lists the options.")
 ;;;### (autoloads nil "help-mode" "help-mode.el" (0 0 0 0))
 ;;; Generated autoloads from help-mode.el
 
+(autoload 'help-mode--add-function-link "help-mode" "\
+
+
+\(fn STR FUN)" nil nil)
+
 (autoload 'help-mode "help-mode" "\
 Major mode for viewing help text and navigating references in it.
 Entry to this mode runs the normal hook `help-mode-hook'.
@@ -16477,9 +16567,9 @@ which can be called interactively, are:
 When hi-lock is started and if the mode is not excluded or patterns
 rejected, the beginning of the buffer is searched for lines of the
 form:
-  Hi-lock: FOO
+  Hi-lock: (FOO ...)
 
-where FOO is a list of patterns.  The patterns must start before
+where (FOO ...) is a list of patterns.  The patterns must start before
 position (number of characters into buffer)
 `hi-lock-file-patterns-range'.  Patterns will be read until
 Hi-lock: end is found.  A mode is excluded if it's in the list
@@ -16912,8 +17002,8 @@ Disable the mode if ARG is a negative number.
 Highlight-Changes mode is enabled in all buffers where
 `highlight-changes-mode-turn-on' would do it.
 
-See `highlight-changes-mode' for more information on
-Highlight-Changes mode.
+See `highlight-changes-mode' for more information on Highlight-Changes
+mode.
 
 \(fn &optional ARG)" t nil)
 
@@ -17008,7 +17098,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-hl-line-mode)'.
+evaluate `(default-value \\='global-hl-line-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -17429,7 +17519,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'fido-mode)'.
+evaluate `(default-value \\='fido-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -17461,7 +17551,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'icomplete-mode)'.
+evaluate `(default-value \\='icomplete-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -17503,7 +17593,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'icomplete-vertical-mode)'.
+evaluate `(default-value \\='icomplete-vertical-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -17540,7 +17630,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'fido-vertical-mode)'.
+evaluate `(default-value \\='fido-vertical-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -17761,7 +17851,7 @@ The main features of this mode are
    Info documentation for this package is available.  Use
    \\[idlwave-info] to display (complain to your sysadmin if that does
    not work).  For Postscript, PDF, and HTML versions of the
-   documentation, check IDLWAVE's homepage at URL
+   documentation, check IDLWAVE's website at URL
    `https://github.com/jdtsmith/idlwave'.
    IDLWAVE has customize support - see the group `idlwave'.
 
@@ -17983,12 +18073,12 @@ The directory is selected interactively by typing a 
substring.
 For details of keybindings, see `ido-find-file'." t nil)
 
 (autoload 'ido-dired-other-window "ido" "\
-\"Edit\" a directory.  Like `ido-dired' but selects in another window.
+\"Edit\" a directory.  Like `ido-dired' but select in another window.
 The directory is selected interactively by typing a substring.
 For details of keybindings, see `ido-find-file'." t nil)
 
 (autoload 'ido-dired-other-frame "ido" "\
-\"Edit\" a directory.  Like `ido-dired' but makes a new frame.
+\"Edit\" a directory.  Like `ido-dired' but make a new frame.
 The directory is selected interactively by typing a substring.
 For details of keybindings, see `ido-find-file'." t nil)
 
@@ -18281,6 +18371,8 @@ Example:
 
 (function-put 'defimage 'doc-string-elt '3)
 
+(function-put 'defimage 'lisp-indent-function 'defun)
+
 (autoload 'imagemagick-register-types "image" "\
 Register file types that can be handled by ImageMagick.
 This function is called at startup, after loading the init file.
@@ -18293,6 +18385,9 @@ recognizes these files as having image type 
`imagemagick'.
 
 If Emacs is compiled without ImageMagick support, this does nothing." nil nil)
 
+(autoload 'image-at-point-p "image" "\
+Return non-nil if there is an image at point." nil nil)
+
 (register-definition-prefixes "image" '("find-image--cache" "image" 
"unknown-image-type"))
 
 ;;;***
@@ -18310,7 +18405,7 @@ If Emacs is compiled without ImageMagick support, this 
does nothing." nil nil)
 (push (purecopy '(image-dired 0 4 11)) package--builtin-versions)
 
 (autoload 'image-dired-dired-toggle-marked-thumbs "image-dired" "\
-Toggle thumbnails in front of file names in the dired buffer.
+Toggle thumbnails in front of file names in the Dired buffer.
 If no marked file could be found, insert or hide thumbnails on the
 current line.  ARG, if non-nil, specifies the files to use instead
 of the marked files.  If ARG is an integer, use the next ARG (or
@@ -18323,12 +18418,12 @@ Open directory DIR and create a default window 
configuration.
 
 Convenience command that:
 
- - Opens dired in folder DIR
+ - Opens Dired in folder DIR
  - Splits windows in most useful (?) way
- - Set `truncate-lines' to t
+ - Sets `truncate-lines' to t
 
 After the command has finished, you would typically mark some
-image files in dired and type
+image files in Dired and type
 \\[image-dired-display-thumbs] (`image-dired-display-thumbs').
 
 If called with prefix argument ARG, skip splitting of windows.
@@ -18346,7 +18441,7 @@ point (this is useful if you have marked some files but 
want to show
 another one).
 
 Recommended usage is to split the current frame horizontally so that
-you have the dired buffer in the left window and the
+you have the Dired buffer in the left window and the
 `image-dired-thumbnail-buffer' buffer in the right window.
 
 With optional argument APPEND, append thumbnail to thumbnail buffer
@@ -18362,19 +18457,21 @@ thumbnail buffer to be selected.
 \(fn &optional ARG APPEND DO-NOT-POP)" t nil)
 
 (autoload 'image-dired-show-all-from-dir "image-dired" "\
-Make a preview buffer for all images in DIR and display it.
-If the number of files in DIR matching `image-file-name-regexp'
-exceeds `image-dired-show-all-from-dir-max-files', a warning will be
-displayed.
+Make a thumbnail buffer for all images in DIR and display it.
+Any file matching `image-file-name-regexp' is considered an image
+file.
+
+If the number of image files in DIR exceeds
+`image-dired-show-all-from-dir-max-files', ask for confirmation
+before creating the thumbnail buffer.  If that variable is nil,
+never ask for confirmation.
 
 \(fn DIR)" t nil)
 
 (defalias 'image-dired 'image-dired-show-all-from-dir)
 
-(define-obsolete-function-alias 'tumme 'image-dired "24.4")
-
 (autoload 'image-dired-tag-files "image-dired" "\
-Tag marked file(s) in dired.  With prefix ARG, tag file at point.
+Tag marked file(s) in Dired.  With prefix ARG, tag file at point.
 
 \(fn ARG)" t nil)
 
@@ -18388,7 +18485,7 @@ With prefix argument ARG, remove tag from file at point.
 Jump to thumbnail buffer." t nil)
 
 (autoload 'image-dired-minor-mode "image-dired" "\
-Setup easy-to-use keybindings for the commands to be used in dired mode.
+Setup easy-to-use keybindings for the commands to be used in Dired mode.
 Note that n, p and <down> and <up> will be hijacked and bound to
 `image-dired-dired-x-line'.
 
@@ -18408,8 +18505,6 @@ disabled.
 
 \(fn &optional ARG)" t nil)
 
-(define-obsolete-function-alias 'image-dired-setup-dired-keybindings 
'image-dired-minor-mode "26.1")
-
 (autoload 'image-dired-display-thumbs-append "image-dired" "\
 Append thumbnails to `image-dired-thumbnail-buffer'." t nil)
 
@@ -18427,7 +18522,7 @@ With prefix argument ARG, display image in its original 
size.
 \(fn &optional ARG)" t nil)
 
 (autoload 'image-dired-dired-comment-files "image-dired" "\
-Add comment to current or marked files in dired." t nil)
+Add comment to current or marked files in Dired." t nil)
 
 (autoload 'image-dired-mark-tagged-files "image-dired" "\
 Use regexp to mark files with matching tag.
@@ -18435,13 +18530,22 @@ A `tag' is a keyword, a piece of meta data, 
associated with an
 image file and stored in image-dired's database file.  This command
 lets you input a regexp and this will be matched against all tags
 on all image files in the database file.  The files that have a
-matching tag will be marked in the dired buffer." t nil)
+matching tag will be marked in the Dired buffer." t nil)
 
 (autoload 'image-dired-dired-edit-comment-and-tags "image-dired" "\
 Edit comment and tags of current or marked image files.
 Edit comment and tags for all marked image files in an
 easy-to-use form." t nil)
 
+(autoload 'image-dired-bookmark-jump "image-dired" "\
+Default bookmark handler for Image-Dired buffers.
+
+\(fn BOOKMARK)" nil nil)
+
+(define-obsolete-function-alias 'tumme #'image-dired "24.4")
+
+(define-obsolete-function-alias 'image-dired-setup-dired-keybindings 
#'image-dired-minor-mode "26.1")
+
 (register-definition-prefixes "image-dired" '("image-dired-"))
 
 ;;;***
@@ -18449,7 +18553,7 @@ easy-to-use form." t nil)
 ;;;### (autoloads nil "image-file" "image-file.el" (0 0 0 0))
 ;;; Generated autoloads from image-file.el
 
-(defvar image-file-name-extensions (purecopy '("png" "jpeg" "jpg" "gif" "tiff" 
"tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg")) "\
+(defvar image-file-name-extensions (purecopy '("png" "jpeg" "jpg" "gif" "tiff" 
"tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg" "webp")) "\
 A list of image-file filename extensions.
 Filenames having one of these extensions are considered image files,
 in addition to those matching `image-file-name-regexps'.
@@ -18506,7 +18610,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'auto-image-file-mode)'.
+evaluate `(default-value \\='auto-image-file-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -18993,7 +19097,7 @@ system." t nil)
 (autoload 'info-lookup-symbol "info-look" "\
 Display the definition of SYMBOL, as found in the relevant manual.
 When this command is called interactively, it reads SYMBOL from the
-minibuffer.  In the minibuffer, use M-n to yank the default argument
+minibuffer.  In the minibuffer, use 
\\<minibuffer-local-completion-map>\\[next-history-element] to yank the default 
argument
 value into the minibuffer so you can edit it.  The default symbol is the
 one found at point.
 
@@ -19005,7 +19109,7 @@ With prefix arg MODE a query for the symbol help mode 
is offered.
 (autoload 'info-lookup-file "info-look" "\
 Display the documentation of a file.
 When this command is called interactively, it reads FILE from the minibuffer.
-In the minibuffer, use M-n to yank the default file name
+In the minibuffer, use 
\\<minibuffer-local-completion-map>\\[next-history-element] to yank the default 
file name
 into the minibuffer so you can edit it.
 The default file name is the one found at point.
 
@@ -19140,7 +19244,7 @@ Check current buffer for validity as an Info file.
 Check that every node pointer points to an existing node." t nil)
 
 (autoload 'batch-info-validate "informat" "\
-Runs `Info-validate' on the files remaining on the command line.
+Run `Info-validate' on the files remaining on the command line.
 Must be used only with -batch, and kills Emacs on completion.
 Each file will be processed even if an error occurred previously.
 For example, invoke \"emacs -batch -f batch-info-validate $info/ ~/*.info\"" 
nil nil)
@@ -19681,7 +19785,7 @@ one of the aforementioned options instead of using this 
mode.
 
 (dolist (name (list "node" "nodejs" "gjs" "rhino")) (add-to-list 
'interpreter-mode-alist (cons (purecopy name) 'js-mode)))
 
-(register-definition-prefixes "js" '("js-" "with-js"))
+(register-definition-prefixes "js" '("js-"))
 
 ;;;***
 
@@ -19752,7 +19856,7 @@ keys are bound.
  `S-cursor' Bind shifted keypad keys to the shifted cursor movement keys.
  `cursor'   Bind keypad keys to the cursor movement keys.
  `numeric'  Plain numeric keypad, i.e. 0 .. 9 and .  (or DECIMAL arg)
- `none'     Removes all bindings for keypad keys in function-key-map;
+ `none'     Removes all bindings for keypad keys in `function-key-map';
             this enables any user-defined bindings for the keypad keys
             in the global and local keymaps.
 
@@ -20071,7 +20175,7 @@ use either \\[customize] or the function 
`latin1-display'.")
 ;;; Generated autoloads from progmodes/ld-script.el
 
 (autoload 'ld-script-mode "ld-script" "\
-A major mode to edit GNU ld script files
+A major mode to edit GNU ld script files.
 
 \(fn)" t nil)
 
@@ -20148,7 +20252,7 @@ essentially expands to
       .site.contents))
 
 If you nest `let-alist' invocations, the inner one can't access
-the variables of the outer one. You can, however, access alists
+the variables of the outer one.  You can, however, access alists
 inside the original alist by using dots inside the symbol, as
 displayed in the example above.
 
@@ -20529,11 +20633,16 @@ use this command, and then save the file.
 
 (autoload 'kbd-macro-query "macros" "\
 Query user during kbd macro execution.
-  With prefix argument, enters recursive edit, reading keyboard
-commands even within a kbd macro.  You can give different commands
-each time the macro executes.
-  Without prefix argument, asks whether to continue running the macro.
+
+With prefix argument FLAG, enter recursive edit, reading
+keyboard commands even within a kbd macro.  You can give
+different commands each time the macro executes.
+
+Without prefix argument, ask whether to continue running the
+macro.
+
 Your options are: \\<query-replace-map>
+
 \\[act]        Finish this iteration normally and continue with the next.
 \\[skip]       Skip the rest of this iteration, and start the next.
 \\[exit]       Stop the macro entirely right now.
@@ -20781,7 +20890,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'mail-abbrevs-mode)'.
+evaluate `(default-value \\='mail-abbrevs-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -21142,7 +21251,7 @@ Default bookmark handler for Man buffers.
 
 ;;;### (autoloads nil "map" "emacs-lisp/map.el" (0 0 0 0))
 ;;; Generated autoloads from emacs-lisp/map.el
-(push (purecopy '(map 3 1)) package--builtin-versions)
+(push (purecopy '(map 3 2 1)) package--builtin-versions)
 
 (register-definition-prefixes "map" '("map-"))
 
@@ -21209,7 +21318,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'minibuffer-depth-indicate-mode)'.
+evaluate `(default-value \\='minibuffer-depth-indicate-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -21610,7 +21719,7 @@ perform the operation on all messages in that region.
 
 \(fn)" t nil)
 
-(register-definition-prefixes "mh-folder" '("mh-"))
+(register-definition-prefixes "mh-folder" '(":keymap" "mh-"))
 
 ;;;***
 
@@ -21646,7 +21755,7 @@ perform the operation on all messages in that region.
 ;;;### (autoloads nil "mh-letter" "mh-e/mh-letter.el" (0 0 0 0))
 ;;; Generated autoloads from mh-e/mh-letter.el
 
-(register-definition-prefixes "mh-letter" '("mh-"))
+(register-definition-prefixes "mh-letter" '(":keymap" "mh-"))
 
 ;;;***
 
@@ -21681,7 +21790,7 @@ perform the operation on all messages in that region.
 ;;;### (autoloads nil "mh-search" "mh-e/mh-search.el" (0 0 0 0))
 ;;; Generated autoloads from mh-e/mh-search.el
 
-(register-definition-prefixes "mh-search" '("mh-"))
+(register-definition-prefixes "mh-search" '(":keymap" "mh-"))
 
 ;;;***
 
@@ -21695,14 +21804,14 @@ perform the operation on all messages in that region.
 ;;;### (autoloads nil "mh-show" "mh-e/mh-show.el" (0 0 0 0))
 ;;; Generated autoloads from mh-e/mh-show.el
 
-(register-definition-prefixes "mh-show" '("mh-"))
+(register-definition-prefixes "mh-show" '(":keymap" "mh-"))
 
 ;;;***
 
 ;;;### (autoloads nil "mh-speed" "mh-e/mh-speed.el" (0 0 0 0))
 ;;; Generated autoloads from mh-e/mh-speed.el
 
-(register-definition-prefixes "mh-speed" '("mh-"))
+(register-definition-prefixes "mh-speed" '(":keymap" "mh-"))
 
 ;;;***
 
@@ -21777,7 +21886,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'midnight-mode)'.
+evaluate `(default-value \\='midnight-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -21833,7 +21942,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'minibuffer-electric-default-mode)'.
+evaluate `(default-value \\='minibuffer-electric-default-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -22417,7 +22526,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'msb-mode)'.
+evaluate `(default-value \\='msb-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -22580,10 +22689,15 @@ Embed OBJ (string or character) at index IDX of 
STRING.
 (autoload 'truncate-string-to-width "mule-util" "\
 Truncate string STR to end at column END-COLUMN.
 The optional 3rd arg START-COLUMN, if non-nil, specifies the starting
-column; that means to return the characters occupying columns
-START-COLUMN ... END-COLUMN of STR.  Both END-COLUMN and START-COLUMN
-are specified in terms of character display width in the current
-buffer; see also `char-width'.
+column (default: zero); that means to return the characters occupying
+columns START-COLUMN ... END-COLUMN of STR.  Both END-COLUMN and
+START-COLUMN are specified in terms of character display width in the
+current buffer; see `char-width'.
+
+Since character composition on display can produce glyphs whose
+width is smaller than the sum of `char-width' values of the
+composed characters, this function can produce inaccurate results
+when used in such cases.
 
 The optional 4th arg PADDING, if non-nil, specifies a padding
 character (which should have a display width of 1) to add at the end
@@ -22740,7 +22854,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'mouse-wheel-mode)'.
+evaluate `(default-value \\='mouse-wheel-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -23389,8 +23503,9 @@ closing requests for requests that are used in matched 
pairs.
 
 (autoload 'nxml-mode "nxml-mode" "\
 Major mode for editing XML.
-
+\\<nxml-mode-map>
 \\[nxml-finish-element] finishes the current element by inserting an end-tag.
+
 C-c C-i closes a start-tag with `>' and then inserts a balancing end-tag
 leaving point between the start-tag and end-tag.
 \\[nxml-balanced-close-start-tag-block] is similar but for block rather than 
inline elements:
@@ -23487,32 +23602,10 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-J" "org/ob-J.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-J.el
-
-(register-definition-prefixes "ob-J" '("obj-" "org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-R" "org/ob-R.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-R.el
 
-(register-definition-prefixes "ob-R" '("ob-R-" "org-babel-"))
-
-;;;***
-
-;;;### (autoloads nil "ob-abc" "org/ob-abc.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-abc.el
-
-(register-definition-prefixes "ob-abc" '("org-babel-"))
-
-;;;***
-
-;;;### (autoloads nil "ob-asymptote" "org/ob-asymptote.el" (0 0 0
-;;;;;;  0))
-;;; Generated autoloads from org/ob-asymptote.el
-
-(register-definition-prefixes "ob-asymptote" '("org-babel-"))
+(register-definition-prefixes "ob-R" '("ob-" "org-babel-"))
 
 ;;;***
 
@@ -23544,13 +23637,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-coq" "org/ob-coq.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-coq.el
-
-(register-definition-prefixes "ob-coq" '("coq-program-name" "org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-css" "org/ob-css.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-css.el
 
@@ -23572,13 +23658,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-ebnf" "org/ob-ebnf.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-ebnf.el
-
-(register-definition-prefixes "ob-ebnf" '("org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-emacs-lisp" "org/ob-emacs-lisp.el" (0 0
 ;;;;;;  0 0))
 ;;; Generated autoloads from org/ob-emacs-lisp.el
@@ -23643,20 +23722,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-hledger" "org/ob-hledger.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-hledger.el
-
-(register-definition-prefixes "ob-hledger" '("org-babel-"))
-
-;;;***
-
-;;;### (autoloads nil "ob-io" "org/ob-io.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-io.el
-
-(register-definition-prefixes "ob-io" '("org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-java" "org/ob-java.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-java.el
 
@@ -23671,24 +23736,24 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-latex" "org/ob-latex.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-latex.el
+;;;### (autoloads nil "ob-julia" "org/ob-julia.el" (0 0 0 0))
+;;; Generated autoloads from org/ob-julia.el
 
-(register-definition-prefixes "ob-latex" '("org-babel-"))
+(register-definition-prefixes "ob-julia" '("org-babel-"))
 
 ;;;***
 
-;;;### (autoloads nil "ob-ledger" "org/ob-ledger.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-ledger.el
+;;;### (autoloads nil "ob-latex" "org/ob-latex.el" (0 0 0 0))
+;;; Generated autoloads from org/ob-latex.el
 
-(register-definition-prefixes "ob-ledger" '("org-babel-"))
+(register-definition-prefixes "ob-latex" '("org-babel-"))
 
 ;;;***
 
 ;;;### (autoloads nil "ob-lilypond" "org/ob-lilypond.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-lilypond.el
 
-(register-definition-prefixes "ob-lilypond" '("lilypond-mode" "org-babel-"))
+(register-definition-prefixes "ob-lilypond" '("lilypond-mode" 
"ob-lilypond-header-args" "org-babel-"))
 
 ;;;***
 
@@ -23720,13 +23785,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-mscgen" "org/ob-mscgen.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-mscgen.el
-
-(register-definition-prefixes "ob-mscgen" '("org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-ocaml" "org/ob-ocaml.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-ocaml.el
 
@@ -23755,13 +23813,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-picolisp" "org/ob-picolisp.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-picolisp.el
-
-(register-definition-prefixes "ob-picolisp" '("org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-plantuml" "org/ob-plantuml.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-plantuml.el
 
@@ -23833,13 +23884,6 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-shen" "org/ob-shen.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-shen.el
-
-(register-definition-prefixes "ob-shen" '("org-babel-"))
-
-;;;***
-
 ;;;### (autoloads nil "ob-sql" "org/ob-sql.el" (0 0 0 0))
 ;;; Generated autoloads from org/ob-sql.el
 
@@ -23854,24 +23898,52 @@ Many aspects this mode can be customized using
 
 ;;;***
 
-;;;### (autoloads nil "ob-stan" "org/ob-stan.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-stan.el
+;;;### (autoloads nil "ob-table" "org/ob-table.el" (0 0 0 0))
+;;; Generated autoloads from org/ob-table.el
 
-(register-definition-prefixes "ob-stan" '("org-babel-"))
+(register-definition-prefixes "ob-table" '("org-"))
 
 ;;;***
 
-;;;### (autoloads nil "ob-table" "org/ob-table.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-table.el
+;;;### (autoloads nil "oc" "org/oc.el" (0 0 0 0))
+;;; Generated autoloads from org/oc.el
 
-(register-definition-prefixes "ob-table" '("org-"))
+(autoload 'org-cite-insert "oc" "\
+Insert a citation at point.
+Insertion is done according to the processor set in 
`org-cite-insert-processor'.
+ARG is the prefix argument received when calling interactively the function.
+
+\(fn ARG)" t nil)
+
+(register-definition-prefixes "oc" '("org-cite-"))
+
+;;;***
+
+;;;### (autoloads nil "oc-basic" "org/oc-basic.el" (0 0 0 0))
+;;; Generated autoloads from org/oc-basic.el
+
+(register-definition-prefixes "oc-basic" '("org-cite-basic-"))
+
+;;;***
+
+;;;### (autoloads nil "oc-biblatex" "org/oc-biblatex.el" (0 0 0 0))
+;;; Generated autoloads from org/oc-biblatex.el
+
+(register-definition-prefixes "oc-biblatex" '("org-cite-biblatex-"))
+
+;;;***
+
+;;;### (autoloads nil "oc-csl" "org/oc-csl.el" (0 0 0 0))
+;;; Generated autoloads from org/oc-csl.el
+
+(register-definition-prefixes "oc-csl" '("org-cite-csl-"))
 
 ;;;***
 
-;;;### (autoloads nil "ob-vala" "org/ob-vala.el" (0 0 0 0))
-;;; Generated autoloads from org/ob-vala.el
+;;;### (autoloads nil "oc-natbib" "org/oc-natbib.el" (0 0 0 0))
+;;; Generated autoloads from org/oc-natbib.el
 
-(register-definition-prefixes "ob-vala" '("org-babel-"))
+(register-definition-prefixes "oc-natbib" '("org-cite-natbib-"))
 
 ;;;***
 
@@ -23939,6 +24011,13 @@ startup file, `~/.emacs-octave'.
 
 ;;;***
 
+;;;### (autoloads nil "ol-doi" "org/ol-doi.el" (0 0 0 0))
+;;; Generated autoloads from org/ol-doi.el
+
+(register-definition-prefixes "ol-doi" '("org-link-doi-"))
+
+;;;***
+
 ;;;### (autoloads nil "ol-eshell" "org/ol-eshell.el" (0 0 0 0))
 ;;; Generated autoloads from org/ol-eshell.el
 
@@ -23967,6 +24046,13 @@ startup file, `~/.emacs-octave'.
 
 ;;;***
 
+;;;### (autoloads nil "ol-man" "org/ol-man.el" (0 0 0 0))
+;;; Generated autoloads from org/ol-man.el
+
+(register-definition-prefixes "ol-man" '("org-man-"))
+
+;;;***
+
 ;;;### (autoloads nil "ol-mhe" "org/ol-mhe.el" (0 0 0 0))
 ;;; Generated autoloads from org/ol-mhe.el
 
@@ -23994,7 +24080,8 @@ startup file, `~/.emacs-octave'.
 (define-obsolete-function-alias 'delphi-mode #'opascal-mode "24.4")
 
 (autoload 'opascal-mode "opascal" "\
-Major mode for editing OPascal code.\\<opascal-mode-map>
+Major mode for editing OPascal code.
+\\<opascal-mode-map>
 \\[opascal-find-unit]  - Search for a OPascal source file.
 \\[opascal-fill-comment]       - Fill the current comment.
 \\[opascal-new-comment-line]   - If in a // comment, do a new comment line.
@@ -24027,7 +24114,7 @@ Coloring:
 
 ;;;### (autoloads nil "org" "org/org.el" (0 0 0 0))
 ;;; Generated autoloads from org/org.el
-(push (purecopy '(org 9 4 4)) package--builtin-versions)
+(push (purecopy '(org 9 5)) package--builtin-versions)
 
 (autoload 'org-babel-do-load-languages "org" "\
 Load the languages defined in `org-babel-load-languages'.
@@ -24267,7 +24354,7 @@ first press `<' once to indicate that the agenda should 
be temporarily
 Pressing `<' twice means to restrict to the current subtree or region
 \(if active).
 
-\(fn &optional ARG ORG-KEYS RESTRICTION)" t nil)
+\(fn &optional ARG KEYS RESTRICTION)" t nil)
 
 (autoload 'org-batch-agenda "org-agenda" "\
 Run an agenda command in batch mode and send the result to STDOUT.
@@ -24453,7 +24540,7 @@ When in a restricted subtree, remove it.
 
 The restriction will span over the entire file if TYPE is `file',
 or if type is '(4), or if the cursor is before the first headline
-in the file. Otherwise, only apply the restriction to the current
+in the file.  Otherwise, only apply the restriction to the current
 subtree.
 
 \(fn &optional TYPE)" t nil)
@@ -24729,6 +24816,109 @@ See the command `outline-mode' for more information 
on this mode.
 
 ;;;***
 
+;;;### (autoloads nil "ox-koma-letter" "org/ox-koma-letter.el" (0
+;;;;;;  0 0 0))
+;;; Generated autoloads from org/ox-koma-letter.el
+
+(autoload 'org-koma-letter-export-as-latex "ox-koma-letter" "\
+Export current buffer as a KOMA Scrlttr2 letter.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org KOMA-LETTER Export*\".  It
+will be displayed if `org-export-show-temporary-export-buffer' is
+non-nil.
+
+\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+
+(autoload 'org-koma-letter-export-to-latex "ox-koma-letter" "\
+Export current buffer as a KOMA Scrlttr2 letter (tex).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+When optional argument PUB-DIR is set, use it as the publishing
+directory.
+
+Return output file's name.
+
+\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+
+(autoload 'org-koma-letter-export-to-pdf "ox-koma-letter" "\
+Export current buffer as a KOMA Scrlttr2 letter (pdf).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return PDF file's name.
+
+\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t nil)
+
+(register-definition-prefixes "ox-koma-letter" '("org-koma-letter-"))
+
+;;;***
+
 ;;;### (autoloads nil "ox-man" "org/ox-man.el" (0 0 0 0))
 ;;; Generated autoloads from org/ox-man.el
 
@@ -24935,46 +25125,6 @@ archive).
 
 ;;;***
 
-;;;### (autoloads nil "paren" "paren.el" (0 0 0 0))
-;;; Generated autoloads from paren.el
-
-(defvar show-paren-mode nil "\
-Non-nil if Show-Paren mode is enabled.
-See the `show-paren-mode' command
-for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `show-paren-mode'.")
-
-(custom-autoload 'show-paren-mode "paren" nil)
-
-(autoload 'show-paren-mode "paren" "\
-Toggle visualization of matching parens (Show Paren mode).
-
-This is a minor mode.  If called interactively, toggle the `Show-Paren
-mode' mode.  If the prefix argument is positive, enable the mode, and
-if it is zero or negative, disable the mode.
-
-If called from Lisp, toggle the mode if ARG is `toggle'.  Enable the
-mode if ARG is nil, omitted, or is a positive number.  Disable the
-mode if ARG is a negative number.
-
-To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'show-paren-mode)'.
-
-The mode's hook is called both when the mode is enabled and when it is
-disabled.
-
-Show Paren mode is a global minor mode.  When enabled, any
-matching parenthesis is highlighted in `show-paren-style' after
-`show-paren-delay' seconds of Emacs idle time.
-
-\(fn &optional ARG)" t nil)
-
-(register-definition-prefixes "paren" '("show-paren-"))
-
-;;;***
-
 ;;;### (autoloads nil "parse-time" "calendar/parse-time.el" (0 0
 ;;;;;;  0 0))
 ;;; Generated autoloads from calendar/parse-time.el
@@ -25125,7 +25275,11 @@ Emacs Lisp manual for more information and examples.
 
 (autoload 'pcase-exhaustive "pcase" "\
 The exhaustive version of `pcase' (which see).
-If EXP fails to match any of the patterns in CASES, an error is signaled.
+If EXP fails to match any of the patterns in CASES, an error is
+signaled.
+
+In contrast, `pcase' will return nil if there is no match, but
+not signal an error.
 
 \(fn EXP &rest CASES)" nil t)
 
@@ -25516,10 +25670,10 @@ Global menu used by PCL-CVS.")
 (put 'perl-label-offset 'safe-local-variable 'integerp)
 
 (autoload 'perl-flymake "perl-mode" "\
-Perl backend for Flymake.  Launches
-`perl-flymake-command' (which see) and passes to its standard
-input the contents of the current buffer.  The output of this
-command is analyzed for error and warning messages.
+Perl backend for Flymake.
+Launch `perl-flymake-command' (which see) and pass to its
+standard input the contents of the current buffer.  The output of
+this command is analyzed for error and warning messages.
 
 \(fn REPORT-FN &rest ARGS)" nil nil)
 
@@ -25596,10 +25750,10 @@ afterwards settable by these commands:
  Move southwest (sw) after insertion:  \\[picture-movement-sw]
  Move southeast (se) after insertion:  \\[picture-movement-se]
 
- Move westnorthwest (wnw) after insertion:  C-u \\[picture-movement-nw]
- Move eastnortheast (ene) after insertion:  C-u \\[picture-movement-ne]
- Move westsouthwest (wsw) after insertion:  C-u \\[picture-movement-sw]
- Move eastsoutheast (ese) after insertion:  C-u \\[picture-movement-se]
+ Move westnorthwest (wnw) after insertion:  \\[universal-argument] 
\\[picture-movement-nw]
+ Move eastnortheast (ene) after insertion:  \\[universal-argument] 
\\[picture-movement-ne]
+ Move westsouthwest (wsw) after insertion:  \\[universal-argument] 
\\[picture-movement-sw]
+ Move eastsoutheast (ese) after insertion:  \\[universal-argument] 
\\[picture-movement-se]
 
 The current direction is displayed in the mode line.  The initial
 direction is right.  Whitespace is inserted and tabs are changed to
@@ -25689,7 +25843,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'pixel-scroll-mode)'.
+evaluate `(default-value \\='pixel-scroll-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -25826,7 +25980,7 @@ For more information, type \\[pr-interface-help].
 Preview directory using ghostview.
 
 Interactively, the command prompts for N-UP printing number, a directory, a
-file name regexp for matching and, when you use a prefix argument (C-u), the
+file name regexp for matching and, when you use a prefix argument 
(\\[universal-argument]), the
 command prompts the user for a file name, and saves the PostScript image in
 that file instead of saving it in a temporary file.
 
@@ -25845,7 +25999,7 @@ See also documentation for `pr-list-directory'.
 Print directory using PostScript through ghostscript.
 
 Interactively, the command prompts for N-UP printing number, a directory, a
-file name regexp for matching and, when you use a prefix argument (C-u), the
+file name regexp for matching and, when you use a prefix argument 
(\\[universal-argument]), the
 command prompts the user for a file name, and saves the PostScript image in
 that file instead of saving it in a temporary file.
 
@@ -25864,7 +26018,7 @@ See also documentation for `pr-list-directory'.
 Print directory using PostScript printer.
 
 Interactively, the command prompts for N-UP printing number, a directory, a
-file name regexp for matching and, when you use a prefix argument (C-u), the
+file name regexp for matching and, when you use a prefix argument 
(\\[universal-argument]), the
 command prompts the user for a file name, and saves the PostScript image in
 that file instead of saving it in a temporary file.
 
@@ -25885,7 +26039,7 @@ Print directory using PostScript printer or through 
ghostscript.
 It depends on `pr-print-using-ghostscript'.
 
 Interactively, the command prompts for N-UP printing number, a directory, a
-file name regexp for matching and, when you use a prefix argument (C-u), the
+file name regexp for matching and, when you use a prefix argument 
(\\[universal-argument]), the
 command prompts the user for a file name, and saves the PostScript image in
 that file instead of saving it in a temporary file.
 
@@ -25904,7 +26058,7 @@ See also documentation for `pr-list-directory'.
 Preview buffer using ghostview.
 
 Interactively, the command prompts for N-UP printing number and, when you use a
-prefix argument (C-u), the command prompts the user for a file name, and saves
+prefix argument (\\[universal-argument]), the command prompts the user for a 
file name, and saves
 the PostScript image in that file instead of saving it in a temporary file.
 
 Noninteractively, if N-UP is nil, prompts for N-UP printing number.  The
@@ -25918,7 +26072,7 @@ with that name.  If FILENAME is t, prompts for a file 
name.
 Print buffer using PostScript through ghostscript.
 
 Interactively, the command prompts for N-UP printing number and, when you use a
-prefix argument (C-u), the command prompts the user for a file name, and saves
+prefix argument (\\[universal-argument]), the command prompts the user for a 
file name, and saves
 the PostScript image in that file instead of sending it to the printer.
 
 Noninteractively, if N-UP is nil, prompts for N-UP printing number.  The
@@ -25932,7 +26086,7 @@ that name.  If FILENAME is t, prompts for a file name.
 Print buffer using PostScript printer.
 
 Interactively, the command prompts for N-UP printing number and, when you use a
-prefix argument (C-u), the command prompts the user for a file name, and saves
+prefix argument (\\[universal-argument]), the command prompts the user for a 
file name, and saves
 the PostScript image in that file instead of sending it to the printer.
 
 Noninteractively, if N-UP is nil, prompts for N-UP printing number.  The
@@ -25948,7 +26102,7 @@ Print buffer using PostScript printer or through 
ghostscript.
 It depends on `pr-print-using-ghostscript'.
 
 Interactively, the command prompts for N-UP printing number and, when you use a
-prefix argument (C-u), the command prompts the user for a file name, and saves
+prefix argument (\\[universal-argument]), the command prompts the user for a 
file name, and saves
 the PostScript image in that file instead of sending it to the printer.
 
 Noninteractively, if N-UP is nil, prompts for N-UP printing number.  The
@@ -26064,7 +26218,7 @@ Print major mode using text printer." t nil)
 (autoload 'pr-despool-preview "printing" "\
 Preview spooled PostScript.
 
-Interactively, when you use a prefix argument (C-u), the command prompts the
+Interactively, when you use a prefix argument (\\[universal-argument]), the 
command prompts the
 user for a file name, and saves the spooled PostScript image in that file
 instead of saving it in a temporary file.
 
@@ -26077,7 +26231,7 @@ PostScript image in a file with that name.
 (autoload 'pr-despool-using-ghostscript "printing" "\
 Print spooled PostScript using ghostscript.
 
-Interactively, when you use a prefix argument (C-u), the command prompts the
+Interactively, when you use a prefix argument (\\[universal-argument]), the 
command prompts the
 user for a file name, and saves the spooled PostScript image in that file
 instead of sending it to the printer.
 
@@ -26090,7 +26244,7 @@ image in a file with that name.
 (autoload 'pr-despool-print "printing" "\
 Send the spooled PostScript to the printer.
 
-Interactively, when you use a prefix argument (C-u), the command prompts the
+Interactively, when you use a prefix argument (\\[universal-argument]), the 
command prompts the
 user for a file name, and saves the spooled PostScript image in that file
 instead of sending it to the printer.
 
@@ -26103,7 +26257,7 @@ image in a file with that name.
 (autoload 'pr-despool-ps-print "printing" "\
 Send the spooled PostScript to the printer or use ghostscript to print it.
 
-Interactively, when you use a prefix argument (C-u), the command prompts the
+Interactively, when you use a prefix argument (\\[universal-argument]), the 
command prompts the
 user for a file name, and saves the spooled PostScript image in that file
 instead of sending it to the printer.
 
@@ -26142,7 +26296,7 @@ Send PostScript file FILENAME to printer or use 
ghostscript to print it.
 Process a PostScript file IFILENAME and send it to printer.
 
 Interactively, the command prompts for N-UP printing number, for an input
-PostScript file IFILENAME and, when you use a prefix argument (C-u), the
+PostScript file IFILENAME and, when you use a prefix argument 
(\\[universal-argument]), the
 command prompts the user for an output PostScript file name OFILENAME, and
 saves the PostScript image in that file instead of sending it to the printer.
 
@@ -26267,22 +26421,22 @@ printed using `pr-ps-mode-ps-print'.
 
 Interactively, you have the following situations:
 
-   M-x pr-ps-fast-fire RET
+   \\[pr-ps-fast-fire]
       The command prompts the user for a N-UP value and printing will
       immediately be done using the current active printer.
 
-   C-u   M-x pr-ps-fast-fire RET
-   C-u 0 M-x pr-ps-fast-fire RET
+   \\[universal-argument]   \\[pr-ps-fast-fire]
+   \\[universal-argument] 0 \\[pr-ps-fast-fire]
       The command prompts the user for a N-UP value and also for a current
       PostScript printer, then printing will immediately be done using the new
       current active printer.
 
-   C-u 1 M-x pr-ps-fast-fire RET
+   \\[universal-argument] 1 \\[pr-ps-fast-fire]
       The command prompts the user for a N-UP value and also for a file name,
       and saves the PostScript image in that file instead of sending it to the
       printer.
 
-   C-u 2 M-x pr-ps-fast-fire RET
+   \\[universal-argument] 2 \\[pr-ps-fast-fire]
       The command prompts the user for a N-UP value, then for a current
       PostScript printer and, finally, for a file name.  Then change the active
       printer to that chosen by user and saves the PostScript image in
@@ -26327,7 +26481,7 @@ Also if the current major-mode is defined in 
`pr-mode-alist', the settings in
 `pr-mode-alist' will be used, that is, the current buffer or region will be
 printed using `pr-txt-mode'.
 
-Interactively, when you use a prefix argument (C-u), the command prompts the
+Interactively, when you use a prefix argument (\\[universal-argument]), the 
command prompts the
 user for a new active text printer.
 
 Noninteractively, the argument SELECT-PRINTER is treated as follows:
@@ -26405,7 +26559,7 @@ Open profile FILENAME.
 
 ;;;### (autoloads nil "project" "progmodes/project.el" (0 0 0 0))
 ;;; Generated autoloads from progmodes/project.el
-(push (purecopy '(project 0 6 1)) package--builtin-versions)
+(push (purecopy '(project 0 8 1)) package--builtin-versions)
 
 (autoload 'project-current "project" "\
 Return the project instance in DIRECTORY, defaulting to `default-directory'.
@@ -26426,7 +26580,7 @@ of the project instance object.
 
 \(fn &optional MAYBE-PROMPT DIRECTORY)" nil nil)
 
-(defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map 
"!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) 
(define-key map "f" 'project-find-file) (define-key map "F" 
'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) 
(define-key map "s" 'project-shell) (define-key map "d" 'project-dired) 
(define-key map "v" 'project-vc-dir) (define-key map "c" 'project-compile) 
(define-key map "e" 'project-eshell) (define-key ma [...]
+(defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map 
"!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) 
(define-key map "f" 'project-find-file) (define-key map "F" 
'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) 
(define-key map "s" 'project-shell) (define-key map "d" 'project-find-dir) 
(define-key map "D" 'project-dired) (define-key map "v" 'project-vc-dir) 
(define-key map "c" 'project-compile) (define-key  [...]
 Keymap for project commands.")
  (define-key ctl-x-map "p" project-prefix-map)
 
@@ -26478,14 +26632,29 @@ pattern to search for.
 (autoload 'project-find-file "project" "\
 Visit a file (with completion) in the current project.
 
-The completion default is the filename at point, determined by
-`thing-at-point' (whether such file exists or not)." t nil)
+The filename at point (determined by `thing-at-point'), if any,
+is available as part of \"future history\".
+
+If INCLUDE-ALL is non-nil, or with prefix argument when called
+interactively, include all files under the project root, except
+for VCS directories listed in `vc-directory-exclusion-list'.
+
+\(fn &optional INCLUDE-ALL)" t nil)
 
 (autoload 'project-or-external-find-file "project" "\
 Visit a file (with completion) in the current project or external roots.
 
-The completion default is the filename at point, determined by
-`thing-at-point' (whether such file exists or not)." t nil)
+The filename at point (determined by `thing-at-point'), if any,
+is available as part of \"future history\".
+
+If INCLUDE-ALL is non-nil, or with prefix argument when called
+interactively, include all files under the project root, except
+for VCS directories listed in `vc-directory-exclusion-list'.
+
+\(fn &optional INCLUDE-ALL)" t nil)
+
+(autoload 'project-find-dir "project" "\
+Start Dired in a directory inside the current project." t nil)
 
 (autoload 'project-dired "project" "\
 Start Dired in the current project's root." t nil)
@@ -26528,8 +26697,8 @@ command \\[fileloop-continue].
 (autoload 'project-query-replace-regexp "project" "\
 Query-replace REGEXP in all the files of the project.
 Stops when a match is found and prompts for whether to replace it.
-If you exit the query-replace, you can later continue the query-replace
-loop using the command \\[fileloop-continue].
+If you exit the `query-replace', you can later continue the
+`query-replace' loop using the command \\[fileloop-continue].
 
 \(fn FROM TO)" t nil)
 
@@ -26586,9 +26755,10 @@ interactively.
 
 (autoload 'project-remember-project "project" "\
 Add project PR to the front of the project list.
-Save the result in `project-list-file' if the list of projects has changed.
+Save the result in `project-list-file' if the list of projects
+has changed, and NO-WRITE is nil.
 
-\(fn PR)" nil nil)
+\(fn PR &optional NO-WRITE)" nil nil)
 
 (autoload 'project-forget-project "project" "\
 Remove directory PROJECT-ROOT from the project list.
@@ -26924,9 +27094,11 @@ If EXTENSION is any other symbol, it is ignored.
 
 (autoload 'pulse-momentary-highlight-one-line "pulse" "\
 Highlight the line around POINT, unhighlighting before next command.
+If POINT is nil or missing, the current point is used instead.
+
 Optional argument FACE specifies the face to do the highlighting.
 
-\(fn POINT &optional FACE)" nil nil)
+\(fn &optional POINT FACE)" nil nil)
 
 (autoload 'pulse-momentary-highlight-region "pulse" "\
 Highlight between START and END, unhighlighting before next command.
@@ -26947,7 +27119,7 @@ Optional argument FACE specifies the face to do the 
highlighting.
 
 ;;;### (autoloads nil "python" "progmodes/python.el" (0 0 0 0))
 ;;; Generated autoloads from progmodes/python.el
-(push (purecopy '(python 0 27 1)) package--builtin-versions)
+(push (purecopy '(python 0 28)) package--builtin-versions)
 
 (add-to-list 'auto-mode-alist (cons (purecopy "\\.py[iw]?\\'") 'python-mode))
 
@@ -27097,7 +27269,7 @@ conversion region is active.  It is an alist of single 
key character
 vs. corresponding command to be called.
 
 If SIMPLE is non-nil, then we do not alter the meanings of
-commands such as C-f, C-b, C-n, C-p and TAB; they are treated as
+commands such as \\[forward-char], \\[backward-char], \\[next-line], 
\\[previous-line] and \\[indent-for-tab-command]; they are treated as
 non-Quail commands.
 
 \(fn NAME LANGUAGE TITLE &optional GUIDANCE DOCSTRING TRANSLATION-KEYS 
FORGET-LAST-SELECTION DETERMINISTIC KBD-TRANSLATE SHOW-LAYOUT CREATE-DECODE-MAP 
MAXIMUM-SHORTEST OVERLAY-PLIST UPDATE-TRANSLATION-FUNCTION CONVERSION-KEYS 
SIMPLE)" nil nil)
@@ -27464,7 +27636,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'rcirc-track-minor-mode)'.
+evaluate `(default-value \\='rcirc-track-minor-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -27524,7 +27696,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'recentf-mode)'.
+evaluate `(default-value \\='recentf-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -27979,7 +28151,7 @@ recently executed command not bound to an input event\".
 \(fn REPEAT-ARG)" t nil)
 
 (defvar repeat-map nil "\
-The value of the repeating map for the next command.
+The value of the repeating transient map for the next command.
 A command called from the map can set it again to the same map when
 the map can't be set on the command symbol property `repeat-map'.")
 
@@ -27997,6 +28169,7 @@ or call the function `repeat-mode'.")
 Toggle Repeat mode.
 When Repeat mode is enabled, and the command symbol has the property named
 `repeat-map', this map is activated temporarily for the next command.
+See `describe-repeat-maps' for a list of all repeatable commands.
 
 This is a minor mode.  If called interactively, toggle the `Repeat
 mode' mode.  If the prefix argument is positive, enable the mode, and
@@ -28007,7 +28180,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'repeat-mode)'.
+evaluate `(default-value \\='repeat-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -28131,7 +28304,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-reveal-mode)'.
+evaluate `(default-value \\='global-reveal-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -29175,7 +29348,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'savehist-mode)'.
+evaluate `(default-value \\='savehist-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -29239,7 +29412,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'save-place-mode)'.
+evaluate `(default-value \\='save-place-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -29358,7 +29531,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'scroll-all-mode)'.
+evaluate `(default-value \\='scroll-all-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -29473,7 +29646,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'semantic-mode)'.
+evaluate `(default-value \\='semantic-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -29970,7 +30143,7 @@ Like `mail' command, but display mail buffer in another 
frame.
 
 ;;;### (autoloads nil "seq" "emacs-lisp/seq.el" (0 0 0 0))
 ;;; Generated autoloads from emacs-lisp/seq.el
-(push (purecopy '(seq 2 22)) package--builtin-versions)
+(push (purecopy '(seq 2 23)) package--builtin-versions)
 
 (autoload 'seq-subseq "seq" "\
 Return the sequence of elements of SEQUENCE from START to END.
@@ -30056,14 +30229,14 @@ TESTFN is used to compare elements, or `equal' if 
TESTFN is nil.
 
 \(fn SEQUENCE &optional TESTFN)" nil nil)
 
-(autoload 'seq-intersection "seq" "\
-Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
+(autoload 'seq-union "seq" "\
+Return a list of all elements that appear in either SEQUENCE1 or SEQUENCE2.
 Equality is defined by TESTFN if non-nil or by `equal' if nil.
 
 \(fn SEQUENCE1 SEQUENCE2 &optional TESTFN)" nil nil)
 
-(autoload 'seq-difference "seq" "\
-Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2.
+(autoload 'seq-intersection "seq" "\
+Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
 Equality is defined by TESTFN if non-nil or by `equal' if nil.
 
 \(fn SEQUENCE1 SEQUENCE2 &optional TESTFN)" nil nil)
@@ -30081,6 +30254,12 @@ SEQUENCE must be a sequence of numbers or markers.
 
 \(fn SEQUENCE)" nil nil)
 
+(autoload 'seq-random-elt "seq" "\
+Return a random element from SEQUENCE.
+Signal an error if SEQUENCE is empty.
+
+\(fn SEQUENCE)" nil nil)
+
 (register-definition-prefixes "seq" '("seq-"))
 
 ;;;***
@@ -30145,7 +30324,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'server-mode)'.
+evaluate `(default-value \\='server-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -30256,10 +30435,11 @@ can also view with a browser to see what happens:
 have <h1>Very Major Headlines</h1> through <h6>Very Minor Headlines</h6>
 <hr> Parts can be separated with horizontal rules.
 
-<p>Paragraphs only need an opening tag.  Line breaks and multiple spaces are
-ignored unless the text is <pre>preformatted.</pre>  Text can be marked as
-<strong>bold</strong>, <em>italic</em> or <u>underlined</u> using the normal 
M-o
-or Edit/Text Properties/Face commands.
+<p>Paragraphs only need an opening tag.  Line breaks and multiple
+spaces are ignored unless the text is <pre>preformatted.</pre>
+Text can be marked as <strong>bold</strong>, <em>italic</em> or
+<u>underlined</u> using the facemenu M-o or Edit/Text
+Properties/Face commands.
 
 Pages can have <a name=\"SOMENAME\">named points</a> and can link other points
 to them with <a href=\"#SOMENAME\">see also somename</a>.  In the same way <a
@@ -30500,7 +30680,7 @@ If FUNCTION is non-nil, place point on the entry for 
FUNCTION (if any).
 
 \(fn GROUP &optional FUNCTION)" t nil)
 
-(register-definition-prefixes "shortdoc" '("alist" "buffer" 
"define-short-documentation-group" "file" "hash-table" "list" "number" 
"overlay" "process" "regexp" "sequence" "shortdoc-" "string" "vector"))
+(register-definition-prefixes "shortdoc" '("alist" "buffer" 
"define-short-documentation-group" "file" "hash-table" "list" "number" 
"overlay" "process" "regexp" "sequence" "shortdoc-" "string" "text-properties" 
"vector"))
 
 ;;;***
 
@@ -30640,6 +30820,8 @@ SKELETON is as defined under `skeleton-insert'.
 
 (function-put 'define-skeleton 'doc-string-elt '2)
 
+(function-put 'define-skeleton 'lisp-indent-function 'defun)
+
 (autoload 'skeleton-proxy-new "skeleton" "\
 Insert SKELETON.
 Prefix ARG allows wrapping around words or regions (see `skeleton-insert').
@@ -30883,7 +31065,7 @@ Tab indents for C code.
 Comments start with -- and end with newline or another --.
 Delete converts tabs to spaces as it moves back.
 \\{snmp-mode-map}
-Turning on snmp-mode runs the hooks in `snmp-common-mode-hook', then
+Turning on `snmp-mode' runs the hooks in `snmp-common-mode-hook', then
 `snmp-mode-hook'." t nil)
 
 (autoload 'snmpv2-mode "snmp-mode" "\
@@ -30893,7 +31075,7 @@ Tab indents for C code.
 Comments start with -- and end with newline or another --.
 Delete converts tabs to spaces as it moves back.
 \\{snmp-mode-map}
-Turning on snmp-mode runs the hooks in `snmp-common-mode-hook',
+Turning on `snmp-mode' runs the hooks in `snmp-common-mode-hook',
 then `snmpv2-mode-hook'." t nil)
 
 (register-definition-prefixes "snmp-mode" '("snmp"))
@@ -30902,13 +31084,13 @@ then `snmpv2-mode-hook'." t nil)
 
 ;;;### (autoloads nil "so-long" "so-long.el" (0 0 0 0))
 ;;; Generated autoloads from so-long.el
-(push (purecopy '(so-long 1 1 1)) package--builtin-versions)
+(push (purecopy '(so-long 1 1 2)) package--builtin-versions)
 
 (autoload 'so-long-commentary "so-long" "\
-View the so-long documentation in `outline-mode'." t nil)
+View the `so-long' library's documentation in `outline-mode'." t nil)
 
 (autoload 'so-long-customize "so-long" "\
-Open the so-long `customize' group." t nil)
+Open the customization group `so-long'." t nil)
 
 (autoload 'so-long-minor-mode "so-long" "\
 This is the minor mode equivalent of `so-long-mode'.
@@ -30959,7 +31141,8 @@ values), despite potential performance issues, type 
\\[so-long-revert].
 
 Use \\[so-long-commentary] for more information.
 
-Use \\[so-long-customize] to configure the behaviour.
+Use \\[so-long-customize] to open the customization group `so-long' to
+configure the behaviour.
 
 \(fn)" t nil)
 
@@ -30981,7 +31164,7 @@ invoking the new action.
 \(fn &optional ACTION)" t nil)
 
 (autoload 'so-long-enable "so-long" "\
-Enable the so-long library's functionality.
+Enable the `so-long' library's functionality.
 
 Equivalent to calling (global-so-long-mode 1)" t nil)
 
@@ -31007,7 +31190,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-so-long-mode)'.
+evaluate `(default-value \\='global-so-long-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -31024,7 +31207,8 @@ When such files are detected by `so-long-predicate', we 
invoke the selected
 
 Use \\[so-long-commentary] for more information.
 
-Use \\[so-long-customize] to configure the behaviour.
+Use \\[so-long-customize] to open the customization group `so-long' to
+configure the behaviour.
 
 \(fn &optional ARG)" t nil)
 
@@ -31168,12 +31352,12 @@ The variable `sort-fold-case' determines whether 
alphabetic case affects
 the sort order.
 
 The next four arguments are functions to be called to move point
-across a sort record.  They will be called many times from within sort-subr.
+across a sort record.  They will be called many times from within `sort-subr'.
 
 NEXTRECFUN is called with point at the end of the previous record.
 It moves point to the start of the next record.
 It should move point to the end of the buffer if there are no more records.
-The first record is assumed to start at the position of point when sort-subr
+The first record is assumed to start at the position of point when `sort-subr'
 is called.
 
 ENDRECFUN is called with point within the record.
@@ -31311,16 +31495,16 @@ Delete all but one copy of any identical lines in the 
region.
 Non-interactively, arguments BEG and END delimit the region.
 Normally it searches forwards, keeping the first instance of
 each identical line.  If REVERSE is non-nil (interactively, with
-a C-u prefix), it searches backwards and keeps the last instance of
+a \\[universal-argument] prefix), it searches backwards and keeps the last 
instance of
 each repeated line.
 
 Identical lines need not be adjacent, unless the argument
-ADJACENT is non-nil (interactively, with a C-u C-u prefix).
+ADJACENT is non-nil (interactively, with a \\[universal-argument] 
\\[universal-argument] prefix).
 This is a more efficient mode of operation, and may be useful
 on large regions that have already been sorted.
 
 If the argument KEEP-BLANKS is non-nil (interactively, with a
-C-u C-u C-u prefix), it retains repeated blank lines.
+\\[universal-argument] \\[universal-argument] \\[universal-argument] prefix), 
it retains repeated blank lines.
 
 Returns the number of deleted lines.  Interactively, or if INTERACTIVE
 is non-nil, it also prints a message describing the number of deletions.
@@ -31350,7 +31534,7 @@ installed through `spam-necessary-extra-headers'.
 
 \(fn &rest SYMBOLS)" t nil)
 
-(register-definition-prefixes "spam" '("spam-"))
+(register-definition-prefixes "spam" '(":keymap" "spam-"))
 
 ;;;***
 
@@ -31437,7 +31621,7 @@ selected.  If the speedbar frame is active, then select 
the attached frame." t n
 ;;; Generated autoloads from play/spook.el
 
 (autoload 'spook "spook" "\
-Adds that special touch of class to your outgoing mail." t nil)
+Add that special touch of class to your outgoing mail." t nil)
 
 (autoload 'snarf-spooks "spook" "\
 Return a vector containing the lines from `spook-phrases-file'." nil nil)
@@ -32128,7 +32312,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'strokes-mode)'.
+evaluate `(default-value \\='strokes-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -32234,7 +32418,33 @@ If OMIT-NULLS, empty lines will be removed from the 
results.
 
 \(fn STRING &optional OMIT-NULLS)" nil nil)
 
-(register-definition-prefixes "subr-x" '("and-let*" "hash-table-" "if-let*" 
"internal--" "named-let" "replace-region-contents" "string-" "thread-" 
"when-let*"))
+(autoload 'ensure-empty-lines "subr-x" "\
+Ensure that there's LINES number of empty lines before point.
+If LINES is nil or missing, a this ensures that there's a single
+empty line before point.
+
+Interactively, this command uses the numerical prefix for LINES.
+
+If there's already more empty lines before point than LINES, the
+number of blank lines will be reduced.
+
+If point is not at the beginning of a line, a newline character
+is inserted before adjusting the number of empty lines.
+
+\(fn &optional LINES)" t nil)
+
+(autoload 'string-pixel-width "subr-x" "\
+Return the width of STRING in pixels.
+
+\(fn STRING)" nil nil)
+
+(autoload 'string-glyph-split "subr-x" "\
+Split STRING into a list of strings representing separate glyphs.
+This takes into account combining characters and grapheme clusters.
+
+\(fn STRING)" nil nil)
+
+(register-definition-prefixes "subr-x" '("and-let*" "hash-table-" "if-let*" 
"internal--" "named-let" "replace-region-contents" "string-" "thread-" 
"when-let*" "with-memoization"))
 
 ;;;***
 
@@ -32431,7 +32641,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'gpm-mouse-mode)'.
+evaluate `(default-value \\='gpm-mouse-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -32454,7 +32664,7 @@ GPM.  This is due to limitations in GPM and the Linux 
kernel.
 ;;; Generated autoloads from tab-line.el
 
 (autoload 'tab-line-mode "tab-line" "\
-Toggle display of window tab line in the buffer.
+Toggle display of tab line in the windows displaying the current buffer.
 
 This is a minor mode.  If called interactively, toggle the `Tab-Line
 mode' mode.  If the prefix argument is positive, enable the mode, and
@@ -32495,8 +32705,8 @@ If called from Lisp, toggle the mode if ARG is `toggle'.
 Enable the mode if ARG is nil, omitted, or is a positive number.
 Disable the mode if ARG is a negative number.
 
-Tab-Line mode is enabled in all buffers where
-`tab-line-mode--turn-on' would do it.
+Tab-Line mode is enabled in all buffers where `tab-line-mode--turn-on'
+would do it.
 
 See `tab-line-mode' for more information on Tab-Line mode.
 
@@ -32773,7 +32983,9 @@ table's rectangle structure.
 Move point forward to the beginning of the next cell.
 With argument ARG, do it ARG times;
 a negative argument ARG = -N means move backward N cells.
-Do not specify NO-RECOGNIZE and UNRECOGNIZE. They are for internal use only.
+
+Do not specify NO-RECOGNIZE and UNRECOGNIZE.  They are for
+internal use only.
 
 Sample Cell Traveling Order (In Irregular Table Cases)
 
@@ -33329,7 +33541,7 @@ Shapes drop from the top of the screen, and the user 
has to move and
 rotate the shape to fit in with those at the bottom of the screen so
 as to form complete rows.
 
-tetris-mode keybindings:
+`tetris-mode' keybindings:
 \\<tetris-mode-map>
 \\[tetris-start-game]  Start a new game of Tetris
 \\[tetris-end-game]    Terminate the current game
@@ -33710,7 +33922,7 @@ and also to be turned into Info files with 
\\[makeinfo-buffer] or
 the `makeinfo' program.  These files must be written in a very restricted and
 modified version of TeX input format.
 
-  Editing commands are like text-mode except that the syntax table is
+  Editing commands are like `text-mode' except that the syntax table is
 set up so expression commands skip Texinfo bracket groups.  To see
 what the Info version of a region of the Texinfo file will look like,
 use \\[makeinfo-region], which runs `makeinfo' on the current region.
@@ -33738,15 +33950,15 @@ updating menus and node pointers.  These functions
 
 Here are the functions:
 
-    texinfo-update-node                \\[texinfo-update-node]
-    texinfo-every-node-update          \\[texinfo-every-node-update]
-    texinfo-sequential-node-update
+    `texinfo-update-node'                \\[texinfo-update-node]
+    `texinfo-every-node-update'          \\[texinfo-every-node-update]
+    `texinfo-sequential-node-update'
 
-    texinfo-make-menu                  \\[texinfo-make-menu]
-    texinfo-all-menus-update           \\[texinfo-all-menus-update]
-    texinfo-master-menu
+    `texinfo-make-menu'                  \\[texinfo-make-menu]
+    `texinfo-all-menus-update'           \\[texinfo-all-menus-update]
+    `texinfo-master-menu'
 
-    texinfo-indent-menu-description (column &optional region-p)
+    `texinfo-indent-menu-description' (column &optional region-p)
 
 The `texinfo-column-for-description' variable specifies the column to
 which menu descriptions are indented.
@@ -33862,6 +34074,20 @@ a symbol as a valid THING.
 
 \(fn THING &optional NO-PROPERTIES)" nil nil)
 
+(autoload 'bounds-of-thing-at-mouse "thingatpt" "\
+Determine start and end locations for THING at mouse click given by EVENT.
+Like `bounds-of-thing-at-point', but tries to use the position in EVENT
+where the mouse button is clicked to find the thing nearby.
+
+\(fn EVENT THING)" nil nil)
+
+(autoload 'thing-at-mouse "thingatpt" "\
+Return the THING at mouse click specified by EVENT.
+Like `thing-at-point', but tries to use the position in EVENT
+where the mouse button is clicked to find the thing nearby.
+
+\(fn EVENT THING &optional NO-PROPERTIES)" nil nil)
+
 (autoload 'sexp-at-point "thingatpt" "\
 Return the sexp at point, or nil if none is found." nil nil)
 
@@ -33973,15 +34199,17 @@ Compose Tibetan text the region BEG and END.
 
 (autoload 'tibetan-decompose-region "tibet-util" "\
 Decompose Tibetan text in the region FROM and TO.
-This is different from decompose-region because precomposed Tibetan characters
-are decomposed into normal Tibetan character sequences.
+This is different from `decompose-region' because precomposed
+Tibetan characters are decomposed into normal Tibetan character
+sequences.
 
 \(fn FROM TO)" t nil)
 
 (autoload 'tibetan-decompose-string "tibet-util" "\
 Decompose Tibetan string STR.
-This is different from decompose-string because precomposed Tibetan characters
-are decomposed into normal Tibetan character sequences.
+This is different from `decompose-string' because precomposed
+Tibetan characters are decomposed into normal Tibetan character
+sequences.
 
 \(fn STR)" nil nil)
 
@@ -33991,7 +34219,7 @@ See also the documentation of the function 
`tibetan-decompose-region'." t nil)
 
 (autoload 'tibetan-compose-buffer "tibet-util" "\
 Composes Tibetan character components in the buffer.
-See also docstring of the function tibetan-compose-region." t nil)
+See also docstring of the function `tibetan-compose-region'." t nil)
 
 (autoload 'tibetan-post-read-conversion "tibet-util" "\
 
@@ -34130,7 +34358,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'display-time-mode)'.
+evaluate `(default-value \\='display-time-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -34161,7 +34389,7 @@ point.
 
 (autoload 'emacs-init-time "time" "\
 Return a string giving the duration of the Emacs initialization.
-FORMAT is a string to format the result, using `format'. If nil,
+FORMAT is a string to format the result, using `format'.  If nil,
 the default format \"%f seconds\" is used.
 
 \(fn &optional FORMAT)" t nil)
@@ -34277,7 +34505,7 @@ Convert the time interval in seconds to a short string.
 (put 'time-stamp-time-zone 'safe-local-variable 'time-stamp-zone-type-p)
 
 (autoload 'time-stamp-zone-type-p "time-stamp" "\
-Return whether or not ZONE is of the correct type for a timezone rule.
+Return non-nil if ZONE is of the correct type for a timezone rule.
 Valid ZONE values are described in the documentation of `format-time-string'.
 
 \(fn ZONE)" nil nil)
@@ -34316,7 +34544,7 @@ this line to a local variables list near the end of the 
file:
 
 If the file has no time-stamp template, this function does nothing.
 
-You can set `time-stamp-pattern' in a files's local variables list
+You can set `time-stamp-pattern' in a file's local variables list
 to customize the information in the time stamp and where it is written.
 
 The time stamp is updated only if `time-stamp-active' is non-nil." t nil)
@@ -34819,7 +35047,7 @@ It must be supported by libarchive(3).")
 Regular expression matching archive file names." '(concat "\\`" "\\(" ".+" 
"\\." (regexp-opt tramp-archive-suffixes) "\\(?:" "\\." (regexp-opt 
tramp-archive-compression-suffixes) "\\)*" "\\)" "\\(" "/" ".*" "\\)" "\\'"))
 
 (defun tramp-archive-autoload-file-name-handler (operation &rest args) "\
-Load Tramp archive file name handler, and perform OPERATION." (when 
tramp-archive-enabled (let ((default-directory temporary-file-directory) 
(tramp-archive-autoload t)) tramp-archive-autoload (apply 
#'tramp-autoload-file-name-handler operation args))))
+Load Tramp archive file name handler, and perform OPERATION." (defvar 
tramp-archive-autoload) (when tramp-archive-enabled (let ((default-directory 
temporary-file-directory) (tramp-archive-autoload t)) (apply 
#'tramp-autoload-file-name-handler operation args))))
 
 (defun tramp-register-archive-file-name-handler nil "\
 Add archive file name handler to `file-name-handler-alist'." (when 
tramp-archive-enabled (add-to-list 'file-name-handler-alist (cons 
(tramp-archive-autoload-file-name-regexp) 
#'tramp-archive-autoload-file-name-handler)) (put 
#'tramp-archive-autoload-file-name-handler 'safe-magic t)))
@@ -34999,7 +35227,7 @@ See info node `(transient)Modifying Existing 
Transients'.
 
 (function-put 'transient-remove-suffix 'lisp-indent-function 'defun)
 
-(register-definition-prefixes "transient" '("transient-"))
+(register-definition-prefixes "transient" '("magit--fit-window-to-buffer" 
"transient-"))
 
 ;;;***
 
@@ -35124,7 +35352,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'type-break-mode)'.
+evaluate `(default-value \\='type-break-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -35445,8 +35673,7 @@ how long to wait for a response before giving up.
 ;;; Generated autoloads from url/url-auth.el
 
 (autoload 'url-get-authentication "url-auth" "\
-Return an authorization string suitable for use in the WWW-Authenticate
-header in an HTTP/1.0 request.
+Return authorization string for the WWW-Authenticate header in HTTP/1.0 
request.
 
 URL    is the url you are requesting authorization to.  This can be either a
        string representing the URL, or the parsed representation returned by
@@ -35660,7 +35887,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'url-handler-mode)'.
+evaluate `(default-value \\='url-handler-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -36056,7 +36283,7 @@ Given a QUERY in the form:
 \(This is the same format as produced by `url-parse-query-string')
 
 This will return a string
-\"key1=val1&key2=val2&key3=val1&key3=val2&key4&key5\". Keys may
+\"key1=val1&key2=val2&key3=val1&key3=val2&key4&key5\".  Keys may
 be strings or symbols; if they are symbols, the symbol name will
 be used.
 
@@ -36504,13 +36731,13 @@ Show the change log for BRANCH root in a window.
 \(fn BRANCH)" t nil)
 
 (autoload 'vc-log-incoming "vc" "\
-Show a log of changes that will be received with a pull operation from 
REMOTE-LOCATION.
+Show log of changes that will be received with pull from REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION.
 
 \(fn &optional REMOTE-LOCATION)" t nil)
 
 (autoload 'vc-log-outgoing "vc" "\
-Show a log of changes that will be sent with a push operation to 
REMOTE-LOCATION.
+Show log of changes that will be sent with a push operation to REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION.
 
 \(fn &optional REMOTE-LOCATION)" t nil)
@@ -36588,6 +36815,8 @@ To get a prompt, use a prefix argument.
 
 \(fn FILE BACKEND)" t nil)
 
+(make-obsolete 'vc-switch-backend 'nil '"28.1")
+
 (autoload 'vc-transfer-file "vc" "\
 Transfer FILE to another version control system NEW-BACKEND.
 If NEW-BACKEND has a higher precedence than FILE's current backend
@@ -36741,7 +36970,7 @@ These are the commands available for use in the file 
status buffer:
 \(fn DIR &optional BACKEND)" t nil)
 
 (autoload 'vc-dir-bookmark-jump "vc-dir" "\
-Provides the bookmark-jump behavior for a `vc-dir' buffer.
+Provide the `bookmark-jump' behavior for a `vc-dir' buffer.
 This implements the `handler' function interface for the record
 type returned by `vc-dir-bookmark-make-record'.
 
@@ -36964,7 +37193,7 @@ Key bindings:
 ;;;### (autoloads nil "verilog-mode" "progmodes/verilog-mode.el"
 ;;;;;;  (0 0 0 0))
 ;;; Generated autoloads from progmodes/verilog-mode.el
-(push (purecopy '(verilog-mode 2021 4 12 188864585)) package--builtin-versions)
+(push (purecopy '(verilog-mode 2021 10 14 127365406)) 
package--builtin-versions)
 
 (autoload 'verilog-mode "verilog-mode" "\
 Major mode for editing Verilog code.
@@ -37077,9 +37306,12 @@ Some other functions are:
     \\[verilog-sk-repeat]  Insert a repeat (..) begin .. end block.
     \\[verilog-sk-specify]  Insert a specify .. endspecify block.
     \\[verilog-sk-task]  Insert a task .. begin .. end endtask block.
-    \\[verilog-sk-while]  Insert a while (...) begin .. end block, prompting 
for details.
-    \\[verilog-sk-casex]  Insert a casex (...) item: begin.. end endcase 
block, prompting for details.
-    \\[verilog-sk-casez]  Insert a casez (...) item: begin.. end endcase 
block, prompting for details.
+    \\[verilog-sk-while]  Insert a while (...) begin .. end block,
+                       prompting for details.
+    \\[verilog-sk-casex]  Insert a casex (...) item: begin.. end endcase block,
+                       prompting for details.
+    \\[verilog-sk-casez]  Insert a casez (...) item: begin.. end endcase block,
+                       prompting for details.
     \\[verilog-sk-if]  Insert an if (..) begin .. end block.
     \\[verilog-sk-else-if]  Insert an else if (..) begin .. end block.
     \\[verilog-sk-comment]  Insert a comment block.
@@ -37470,7 +37702,7 @@ Usage:
     `vhdl-project-alist'.
 
 
-  SPECIAL MENUES:
+  SPECIAL MENUS:
     As an alternative to the speedbar, an index menu can be added (set
     option `vhdl-index-menu' to non-nil) or made accessible as a mouse menu
     (e.g. add \"(global-set-key [S-down-mouse-3] \\='imenu)\" to your start-up
@@ -37978,7 +38210,7 @@ Toggle Viper on/off.
 If Viper is enabled, turn it off.  Otherwise, turn it on." t nil)
 
 (autoload 'viper-mode "viper" "\
-Turn on Viper emulation of Vi in Emacs. See Info node `(viper)Top'." t nil)
+Turn on Viper emulation of Vi in Emacs.  See Info node `(viper)Top'." t nil)
 
 (register-definition-prefixes "viper" '("set-viper-state-in-major-mode" 
"this-major-mode-requires-vi-state" "viper-"))
 
@@ -38229,7 +38461,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'which-function-mode)'.
+evaluate `(default-value \\='which-function-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -38268,6 +38500,9 @@ disabled.
 See also `whitespace-style', `whitespace-newline' and
 `whitespace-display-mappings'.
 
+This mode uses a number of faces to visualize the whitespace; see
+the customization group `whitespace' for details.
+
 \(fn &optional ARG)" t nil)
 
 (autoload 'whitespace-newline-mode "whitespace" "\
@@ -38318,7 +38553,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-whitespace-mode)'.
+evaluate `(default-value \\='global-whitespace-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -38350,7 +38585,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'global-whitespace-newline-mode)'.
+evaluate `(default-value \\='global-whitespace-newline-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -38849,28 +39084,28 @@ Default value of MODIFIERS is `shift-meta'.
 
 (autoload 'windmove-delete-left "windmove" "\
 Delete the window to the left of the current one.
-If prefix ARG is `C-u', delete the selected window and
+If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was to the left of the current one.
 
 \(fn &optional ARG)" t nil)
 
 (autoload 'windmove-delete-up "windmove" "\
 Delete the window above the current one.
-If prefix ARG is `C-u', delete the selected window and
+If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was above the current one.
 
 \(fn &optional ARG)" t nil)
 
 (autoload 'windmove-delete-right "windmove" "\
 Delete the window to the right of the current one.
-If prefix ARG is `C-u', delete the selected window and
+If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was to the right of the current one.
 
 \(fn &optional ARG)" t nil)
 
 (autoload 'windmove-delete-down "windmove" "\
 Delete the window below the current one.
-If prefix ARG is `C-u', delete the selected window and
+If prefix ARG is \\[universal-argument], delete the selected window and
 select the window that was below the current one.
 
 \(fn &optional ARG)" t nil)
@@ -38881,8 +39116,8 @@ Keys are bound to commands that delete windows in the 
specified
 direction.  Keybindings are of the form PREFIX MODIFIERS-{left,right,up,down},
 where PREFIX is a prefix key and MODIFIERS is either a list of modifiers or
 a single modifier.
-If PREFIX is `none', no prefix is used. If MODIFIERS is `none', the keybindings
-are directly bound to the arrow keys.
+If PREFIX is `none', no prefix is used.  If MODIFIERS is `none',
+the keybindings are directly bound to the arrow keys.
 Default value of PREFIX is `C-x' and MODIFIERS is `shift'.
 
 \(fn &optional PREFIX MODIFIERS)" t nil)
@@ -38940,7 +39175,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'winner-mode)'.
+evaluate `(default-value \\='winner-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -39106,15 +39341,24 @@ If LIMIT is non-nil, then do not consider characters 
beyond LIMIT.
 
 ;;;### (autoloads nil "xref" "progmodes/xref.el" (0 0 0 0))
 ;;; Generated autoloads from progmodes/xref.el
-(push (purecopy '(xref 1 1 0)) package--builtin-versions)
+(push (purecopy '(xref 1 3 2)) package--builtin-versions)
 
 (autoload 'xref-find-backend "xref" nil nil nil)
 
-(autoload 'xref-pop-marker-stack "xref" "\
-Pop back to where \\[xref-find-definitions] was last invoked." t nil)
+(defalias 'xref-pop-marker-stack #'xref-go-back)
+
+(autoload 'xref-go-back "xref" "\
+Go back to the previous position in xref history.
+To undo, use \\[xref-go-forward]." t nil)
+
+(autoload 'xref-go-forward "xref" "\
+Got to the point where a previous \\[xref-go-back] was invoked." t nil)
 
 (autoload 'xref-marker-stack-empty-p "xref" "\
-Return t if the marker stack is empty; nil otherwise." nil nil)
+Whether the xref back-history is empty." nil nil)
+
+(autoload 'xref-forward-history-empty-p "xref" "\
+Whether the xref forward-history is empty." nil nil)
 
 (autoload 'xref-find-definitions "xref" "\
 Find the definition of the identifier at point.
@@ -39126,7 +39370,7 @@ definition for IDENTIFIER, display it in the selected 
window.
 Otherwise, display the list of the possible definitions in a
 buffer where the user can select from the list.
 
-Use \\[xref-pop-marker-stack] to return back to where you invoked this command.
+Use \\[xref-go-back] to return back to where you invoked this command.
 
 \(fn IDENTIFIER)" t nil)
 
@@ -39165,10 +39409,13 @@ This command is intended to be bound to a mouse event.
 (autoload 'xref-find-apropos "xref" "\
 Find all meaningful symbols that match PATTERN.
 The argument has the same meaning as in `apropos'.
+See `tags-apropos-additional-actions' for how to augment the
+output of this command when the backend is etags.
 
 \(fn PATTERN)" t nil)
  (define-key esc-map "." #'xref-find-definitions)
- (define-key esc-map "," #'xref-pop-marker-stack)
+ (define-key esc-map "," #'xref-go-back)
+ (define-key esc-map [?\C-,] #'xref-go-forward)
  (define-key esc-map "?" #'xref-find-references)
  (define-key esc-map [?\C-.] #'xref-find-apropos)
  (define-key ctl-x-4-map "." #'xref-find-definitions-other-window)
@@ -39198,6 +39445,9 @@ Find all matches for REGEXP in FILES.
 Return a list of xref values.
 FILES must be a list of absolute file names.
 
+See `xref-search-program' and `xref-search-program-alist' for how
+to control which program to use when looking for matches.
+
 \(fn REGEXP FILES)" nil nil)
 
 (register-definition-prefixes "xref" '("xref-"))
@@ -39243,7 +39493,7 @@ mode if ARG is nil, omitted, or is a positive number.  
Disable the
 mode if ARG is a negative number.
 
 To check whether the minor mode is enabled in the current buffer,
-evaluate `(default-value 'xterm-mouse-mode)'.
+evaluate `(default-value \\='xterm-mouse-mode)'.
 
 The mode's hook is called both when the mode is enabled and when it is
 disabled.
@@ -39352,9 +39602,10 @@ Zone out, completely." t nil)
 ;;;;;;  "emacs-lisp/cl-seq.el" "emacs-lisp/easymenu.el" 
"emacs-lisp/eieio-compat.el"
 ;;;;;;  "emacs-lisp/eieio-custom.el" "emacs-lisp/eieio-opt.el" 
"emacs-lisp/float-sup.el"
 ;;;;;;  "emacs-lisp/lisp-mode.el" "emacs-lisp/lisp.el" "emacs-lisp/macroexp.el"
-;;;;;;  "emacs-lisp/map-ynp.el" "emacs-lisp/nadvice.el" "emacs-lisp/syntax.el"
-;;;;;;  "emacs-lisp/timer.el" "env.el" "epa-hook.el" "erc/erc-autoaway.el"
-;;;;;;  "erc/erc-button.el" "erc/erc-capab.el" "erc/erc-dcc.el" 
"erc/erc-desktop-notifications.el"
+;;;;;;  "emacs-lisp/map-ynp.el" "emacs-lisp/nadvice.el" 
"emacs-lisp/shorthands.el"
+;;;;;;  "emacs-lisp/syntax.el" "emacs-lisp/timer.el" "env.el" "epa-hook.el"
+;;;;;;  "erc/erc-autoaway.el" "erc/erc-button.el" "erc/erc-capab.el"
+;;;;;;  "erc/erc-compat.el" "erc/erc-dcc.el" "erc/erc-desktop-notifications.el"
 ;;;;;;  "erc/erc-ezbounce.el" "erc/erc-fill.el" "erc/erc-identd.el"
 ;;;;;;  "erc/erc-imenu.el" "erc/erc-join.el" "erc/erc-list.el" "erc/erc-log.el"
 ;;;;;;  "erc/erc-match.el" "erc/erc-menu.el" "erc/erc-netsplit.el"
@@ -39371,31 +39622,31 @@ Zone out, completely." t nil)
 ;;;;;;  "eshell/em-xtra.el" "faces.el" "files.el" "font-core.el"
 ;;;;;;  "font-lock.el" "format.el" "frame.el" "help.el" "hfy-cmap.el"
 ;;;;;;  "ibuf-ext.el" "indent.el" "international/characters.el" 
"international/charscript.el"
-;;;;;;  "international/cp51932.el" "international/eucjp-ms.el" 
"international/iso-transl.el"
-;;;;;;  "international/mule-cmds.el" "international/mule-conf.el"
-;;;;;;  "international/mule.el" "isearch.el" "jit-lock.el" "jka-cmpr-hook.el"
-;;;;;;  "language/burmese.el" "language/cham.el" "language/chinese.el"
-;;;;;;  "language/cyrillic.el" "language/czech.el" "language/english.el"
-;;;;;;  "language/ethiopic.el" "language/european.el" "language/georgian.el"
-;;;;;;  "language/greek.el" "language/hebrew.el" "language/indian.el"
-;;;;;;  "language/japanese.el" "language/khmer.el" "language/korean.el"
-;;;;;;  "language/lao.el" "language/misc-lang.el" "language/romanian.el"
-;;;;;;  "language/sinhala.el" "language/slovak.el" "language/tai-viet.el"
-;;;;;;  "language/thai.el" "language/tibetan.el" "language/utf-8-lang.el"
-;;;;;;  "language/vietnamese.el" "ldefs-boot.el" "leim/ja-dic/ja-dic.el"
-;;;;;;  "leim/leim-list.el" "leim/quail/4Corner.el" "leim/quail/ARRAY30.el"
-;;;;;;  "leim/quail/CCDOSPY.el" "leim/quail/CTLau-b5.el" "leim/quail/CTLau.el"
-;;;;;;  "leim/quail/ECDICT.el" "leim/quail/ETZY.el" "leim/quail/PY-b5.el"
-;;;;;;  "leim/quail/PY.el" "leim/quail/Punct-b5.el" "leim/quail/Punct.el"
-;;;;;;  "leim/quail/QJ-b5.el" "leim/quail/QJ.el" "leim/quail/SW.el"
-;;;;;;  "leim/quail/TONEPY.el" "leim/quail/ZIRANMA.el" "leim/quail/ZOZY.el"
-;;;;;;  "leim/quail/arabic.el" "leim/quail/cham.el" "leim/quail/compose.el"
-;;;;;;  "leim/quail/croatian.el" "leim/quail/cyril-jis.el" 
"leim/quail/cyrillic.el"
-;;;;;;  "leim/quail/czech.el" "leim/quail/georgian.el" "leim/quail/greek.el"
-;;;;;;  "leim/quail/hanja-jis.el" "leim/quail/hanja.el" "leim/quail/hanja3.el"
-;;;;;;  "leim/quail/hebrew.el" "leim/quail/ipa-praat.el" 
"leim/quail/latin-alt.el"
-;;;;;;  "leim/quail/latin-ltx.el" "leim/quail/latin-post.el" 
"leim/quail/latin-pre.el"
-;;;;;;  "leim/quail/persian.el" "leim/quail/programmer-dvorak.el"
+;;;;;;  "international/cp51932.el" "international/emoji-zwj.el" 
"international/eucjp-ms.el"
+;;;;;;  "international/iso-transl.el" "international/mule-cmds.el"
+;;;;;;  "international/mule-conf.el" "international/mule.el" "isearch.el"
+;;;;;;  "jit-lock.el" "jka-cmpr-hook.el" "language/burmese.el" 
"language/cham.el"
+;;;;;;  "language/chinese.el" "language/cyrillic.el" "language/czech.el"
+;;;;;;  "language/english.el" "language/ethiopic.el" "language/european.el"
+;;;;;;  "language/georgian.el" "language/greek.el" "language/hebrew.el"
+;;;;;;  "language/indian.el" "language/japanese.el" "language/khmer.el"
+;;;;;;  "language/korean.el" "language/lao.el" "language/misc-lang.el"
+;;;;;;  "language/romanian.el" "language/sinhala.el" "language/slovak.el"
+;;;;;;  "language/tai-viet.el" "language/thai.el" "language/tibetan.el"
+;;;;;;  "language/utf-8-lang.el" "language/vietnamese.el" "ldefs-boot.el"
+;;;;;;  "leim/ja-dic/ja-dic.el" "leim/leim-list.el" "leim/quail/4Corner.el"
+;;;;;;  "leim/quail/ARRAY30.el" "leim/quail/CCDOSPY.el" 
"leim/quail/CTLau-b5.el"
+;;;;;;  "leim/quail/CTLau.el" "leim/quail/ECDICT.el" "leim/quail/ETZY.el"
+;;;;;;  "leim/quail/PY-b5.el" "leim/quail/PY.el" "leim/quail/Punct-b5.el"
+;;;;;;  "leim/quail/Punct.el" "leim/quail/QJ-b5.el" "leim/quail/QJ.el"
+;;;;;;  "leim/quail/SW.el" "leim/quail/TONEPY.el" "leim/quail/ZIRANMA.el"
+;;;;;;  "leim/quail/ZOZY.el" "leim/quail/arabic.el" "leim/quail/cham.el"
+;;;;;;  "leim/quail/compose.el" "leim/quail/croatian.el" 
"leim/quail/cyril-jis.el"
+;;;;;;  "leim/quail/cyrillic.el" "leim/quail/czech.el" "leim/quail/georgian.el"
+;;;;;;  "leim/quail/greek.el" "leim/quail/hanja-jis.el" "leim/quail/hanja.el"
+;;;;;;  "leim/quail/hanja3.el" "leim/quail/hebrew.el" "leim/quail/ipa-praat.el"
+;;;;;;  "leim/quail/latin-alt.el" "leim/quail/latin-ltx.el" 
"leim/quail/latin-post.el"
+;;;;;;  "leim/quail/latin-pre.el" "leim/quail/persian.el" 
"leim/quail/programmer-dvorak.el"
 ;;;;;;  "leim/quail/py-punct.el" "leim/quail/pypunct-b5.el" 
"leim/quail/quick-b5.el"
 ;;;;;;  "leim/quail/quick-cns.el" "leim/quail/rfc1345.el" "leim/quail/sami.el"
 ;;;;;;  "leim/quail/sgml-input.el" "leim/quail/slovak.el" 
"leim/quail/symbol-ksc.el"
@@ -39417,7 +39668,7 @@ Zone out, completely." t nil)
 ;;;;;;  "org/org-table.el" "org/org-timer.el" "org/ox-ascii.el" 
"org/ox-beamer.el"
 ;;;;;;  "org/ox-html.el" "org/ox-icalendar.el" "org/ox-latex.el"
 ;;;;;;  "org/ox-md.el" "org/ox-odt.el" "org/ox-org.el" "org/ox-publish.el"
-;;;;;;  "org/ox-texinfo.el" "org/ox.el" "progmodes/elisp-mode.el"
+;;;;;;  "org/ox-texinfo.el" "org/ox.el" "paren.el" "progmodes/elisp-mode.el"
 ;;;;;;  "progmodes/prog-mode.el" "ps-mule.el" "register.el" "replace.el"
 ;;;;;;  "rfn-eshadow.el" "select.el" "simple.el" "startup.el" "subdirs.el"
 ;;;;;;  "subr.el" "tab-bar.el" "textmodes/fill.el" "textmodes/makeinfo.el"
diff --git a/lisp/leim/quail/ipa.el b/lisp/leim/quail/ipa.el
index c25687574e..ba6ea93842 100644
--- a/lisp/leim/quail/ipa.el
+++ b/lisp/leim/quail/ipa.el
@@ -278,10 +278,10 @@ string."
   (list
    (apply #'vector
          (mapcar
-          #'(lambda (entry)
-               (cl-assert (char-or-string-p entry) t)
-               (format "%s%s" to-prepend
-                       (if (integerp entry) (string entry) entry)))
+           (lambda (entry)
+             (cl-assert (char-or-string-p entry) t)
+             (format "%s%s" to-prepend
+                     (if (integerp entry) (string entry) entry)))
           quail-keymap))))
 
 (defun ipa-x-sampa-underscore-implosive (input-string length)
diff --git a/lisp/leim/quail/latin-post.el b/lisp/leim/quail/latin-post.el
index 8329fff82e..0e1afba1a3 100644
--- a/lisp/leim/quail/latin-post.el
+++ b/lisp/leim/quail/latin-post.el
@@ -215,7 +215,15 @@ Doubling the postfix separates the letter and postfix: 
e.g. a\\='\\=' -> a\\='
   others     |    /    | s/ -> ß
 
 Doubling the postfix separates the letter and postfix: e.g. a\\='\\=' -> a\\='
-" nil t nil nil nil nil nil nil nil nil t)
+"
+ '(("\C-?" . quail-delete-last-char)
+   (">" . quail-next-translation)
+   ("\C-f" . quail-next-translation)
+   ([right] . quail-next-translation)
+   ("<" . quail-prev-translation)
+   ("\C-b" . quail-prev-translation)
+   ([left] . quail-prev-translation))
+ t nil nil nil nil nil nil nil nil t)
 
 (quail-define-rules
  ("A'" ?Á)
@@ -246,9 +254,9 @@ Doubling the postfix separates the letter and postfix: e.g. 
a\\='\\=' -> a\\='
  ("R'" ?Ŕ)
  ("R~" ?Ř)
  ("S'" ?Ś)
- ("S," ?Ş)
+ ("S," "ŞȘ") ; the second variant is for Romanian
  ("S~" ?Š)
- ("T," ?Ţ)
+ ("T," "ŢȚ") ; the second variant is for Romanian
  ("T~" ?Ť)
  ("U'" ?Ú)
  ("U:" ?Ű)
@@ -286,10 +294,10 @@ Doubling the postfix separates the letter and postfix: 
e.g. a\\='\\=' -> a\\='
  ("r'" ?ŕ)
  ("r~" ?ř)
  ("s'" ?ś)
- ("s," ?ş)
+ ("s," "şș") ; the second variant is for Romanian
  ("s/" ?ß)
  ("s~" ?š)
- ("t," ?ţ)
+ ("t," "ţț") ; the second variant is for Romanian
  ("t~" ?ť)
  ("u'" ?ú)
  ("u:" ?ű)
diff --git a/lisp/leim/quail/latin-pre.el b/lisp/leim/quail/latin-pre.el
index 3b9c942a8c..3492de5fba 100644
--- a/lisp/leim/quail/latin-pre.el
+++ b/lisp/leim/quail/latin-pre.el
@@ -497,7 +497,15 @@ Key translation rules are:
    cedilla   |   \\=`    | \\=`c -> ç   \\=`e -> ?ę
     misc     | \\=' \\=` ~  | \\='d -> đ   \\=`l -> ł   \\=`z -> ż   ~o -> ő   
~u -> ű
    symbol    |   ~    | \\=`. -> ˙   ~~ -> ˘   ~. -> ?¸
-" nil t nil nil nil nil nil nil nil nil t)
+"
+ '(("\C-?" . quail-delete-last-char)
+   (">" . quail-next-translation)
+   ("\C-f" . quail-next-translation)
+   ([right] . quail-next-translation)
+   ("<" . quail-prev-translation)
+   ("\C-b" . quail-prev-translation)
+   ([left] . quail-prev-translation))
+ t nil nil nil nil nil nil nil nil t)
 
 (quail-define-rules
  ("'A" ?Á)
@@ -532,15 +540,15 @@ Key translation rules are:
  ("`C" ?Ç)
  ("`E" ?Ę)
  ("`L" ?Ł)
- ("`S" ?Ş)
- ("`T" ?Ţ)
+ ("`S" "ŞȘ")
+ ("`T" "ŢȚ") ; the second variant is for Romanian
  ("`Z" ?Ż)
  ("`a" ?ą)
  ("`l" ?ł)
  ("`c" ?ç)
  ("`e" ?ę)
- ("`s" ?ş)
- ("`t" ?ţ)
+ ("`s" "şș")
+ ("`t" "ţț") ; the second variant is for Romanian
  ("`z" ?ż)
  ("``" ?Ş)
  ("`." ?˙)
diff --git a/lisp/linum.el b/lisp/linum.el
index c78f596d76..1e029e508e 100644
--- a/lisp/linum.el
+++ b/lisp/linum.el
@@ -28,6 +28,9 @@
 ;;
 ;; Toggle display of line numbers with M-x linum-mode.  To enable
 ;; line numbering in all buffers, use M-x global-linum-mode.
+;;
+;; Consider using native line numbers instead:
+;;   M-x display-line-numbers-mode
 
 ;;; Code:
 
diff --git a/lisp/loadup.el b/lisp/loadup.el
index fce17bf113..e8ecb67d56 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -352,6 +352,10 @@
 (load "vc/ediff-hook")
 (load "uniquify")
 (load "electric")
+(load "paren")
+
+(load "emacs-lisp/shorthands")
+
 (load "emacs-lisp/eldoc")
 (load "cus-start") ;Late to reduce customize-rogue (needs loaddefs.el anyway)
 (if (not (eq system-type 'ms-dos))
diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 8e81f79e42..82153ff0ad 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -283,6 +283,7 @@ are also supported; unsupported long options are silently 
ignored."
       (funcall orig-fun
               file switches wildcard full-directory-p)
     ;; We need the directory in order to find the right handler.
+    (setq switches (or switches ""))
     (let ((handler (find-file-name-handler (expand-file-name file)
                                           'insert-directory))
          (orig-file file)
diff --git a/lisp/mail/emacsbug.el b/lisp/mail/emacsbug.el
index 3da1e8b25e..7c3f6ba5e6 100644
--- a/lisp/mail/emacsbug.el
+++ b/lisp/mail/emacsbug.el
@@ -426,7 +426,7 @@ usually do not have translators for other languages.\n\n")))
     (with-output-to-temp-buffer "*Bug Help*"
       (princ (substitute-command-keys
               (format "\
-You invoked the command M-x report-emacs-bug,
+You invoked the command \\[report-emacs-bug],
 but you decided not to mail the bug report to the Emacs maintainers.
 
 If you want to mail it to someone else instead,
diff --git a/lisp/mail/feedmail.el b/lisp/mail/feedmail.el
index 608062fba4..fe686cb6f8 100644
--- a/lisp/mail/feedmail.el
+++ b/lisp/mail/feedmail.el
@@ -2020,7 +2020,7 @@ backup file names and the like)."
                    ;; if can't find EOH, this is no message!
                    (unless (feedmail-find-eoh t)
                      (feedmail-say-chatter "Skipping %s; no 
mail-header-separator" maybe-file)
-                     (error "FQM: you should never see this message"))
+                      (error "FQM: You should never see this message"))
                    (feedmail-say-debug "Prepping %s" maybe-file)
                    ;; the catch is a way out for users to voluntarily skip 
sending a message
                    (catch 'skip-me-q (funcall 
feedmail-queue-runner-message-sender arg))
diff --git a/lisp/mail/rmailkwd.el b/lisp/mail/rmailkwd.el
index 58a8eb7a37..d8fcc1c0a9 100644
--- a/lisp/mail/rmailkwd.el
+++ b/lisp/mail/rmailkwd.el
@@ -74,12 +74,9 @@ according to the choice made, and returns a symbol."
                (rmail-summary-exists)
                (and (setq old (rmail-get-keywords))
                     (mapc #'rmail-make-label (split-string old ", "))))
-           (completing-read (concat prompt
-                                    (if rmail-last-label
-                                        (concat " (default "
-                                                (symbol-name rmail-last-label)
-                                                "): ")
-                                      ": "))
+            (completing-read (format-prompt prompt
+                                            (and rmail-last-label
+                                                 (symbol-name 
rmail-last-label)))
                             rmail-label-obarray
                             nil
                             nil))))
diff --git a/lisp/mail/rmailmm.el b/lisp/mail/rmailmm.el
index 99bff66657..66a1e9a4db 100644
--- a/lisp/mail/rmailmm.el
+++ b/lisp/mail/rmailmm.el
@@ -254,7 +254,7 @@ TRUNCATED is non-nil if the text of this entity was 
truncated."))
        (unless (y-or-n-p "This entity is truncated; save anyway? ")
          (error "Aborted")))
     (setq filename (expand-file-name
-                   (read-file-name (format "Save as (default: %s): " filename)
+                    (read-file-name (format-prompt "Save as" filename)
                                    directory
                                    (expand-file-name filename directory))
                    directory))
diff --git a/lisp/mail/rmailout.el b/lisp/mail/rmailout.el
index 91f86a234d..1f5bb2d9f1 100644
--- a/lisp/mail/rmailout.el
+++ b/lisp/mail/rmailout.el
@@ -107,9 +107,8 @@ error: %S\n"
         (read-file
          (expand-file-name
           (read-file-name
-           (concat "Output message to mail file (default "
-                   (file-name-nondirectory default-file)
-                   "): ")
+            (format-prompt "Output message to mail file"
+                           (file-name-nondirectory default-file))
            (file-name-directory default-file)
            (abbreviate-file-name default-file))
           (file-name-directory default-file))))
diff --git a/lisp/mail/sendmail.el b/lisp/mail/sendmail.el
index 312805f6d8..d0aff093df 100644
--- a/lisp/mail/sendmail.el
+++ b/lisp/mail/sendmail.el
@@ -1950,7 +1950,8 @@ The seventh argument ACTIONS is a list of actions to take
           (setq initialized t)))
     (if (and buffer-auto-save-file-name
             (file-exists-p buffer-auto-save-file-name))
-       (message "Auto save file for draft message exists; consider M-x 
mail-recover"))
+        (message (substitute-command-keys
+                  "Auto save file for draft message exists; consider 
\\[mail-recover]")))
     initialized))
 
 (declare-function dired-view-file "dired" ())
diff --git a/lisp/mail/uce.el b/lisp/mail/uce.el
index b07004de38..4347ff1402 100644
--- a/lisp/mail/uce.el
+++ b/lisp/mail/uce.el
@@ -30,6 +30,9 @@
 ;; uce-reply-to-uce.  Please let me know about your changes so I can
 ;; incorporate them.  I'd appreciate it.
 
+;; NOTE: We don't recommend using this feature; see the message in
+;; 'uce-reply-to-uce' for the reasons.
+
 ;; The command uce-reply-to-uce, if called when the current message
 ;; buffer is a UCE, will setup a reply *mail* buffer as follows.  It
 ;; scans the full headers of the message for: 1) the normal return
@@ -213,6 +216,8 @@ These are mostly meant for headers that prevent delivery 
errors reporting."
 (declare-function rmail-maybe-set-message-counters "rmail" ())
 (declare-function rmail-toggle-header "rmail" (&optional arg))
 
+(defvar uce--usage-warning-displayed nil)
+
 ;;;###autoload
 (defun uce-reply-to-uce (&optional _ignored)
   "Compose a reply to unsolicited commercial email (UCE).
@@ -358,7 +363,32 @@ You might need to set `uce-mail-reader' before using this."
       ;; Run hooks before we leave buffer for editing.  Reasonable usage
       ;; might be to set up special key bindings, replace standard
       ;; functions in mail-mode, etc.
-      (run-hooks 'mail-setup-hook 'uce-setup-hook))))
+      (run-hooks 'mail-setup-hook 'uce-setup-hook)))
+  (unless uce--usage-warning-displayed
+    (setq uce--usage-warning-displayed t)
+    (pop-to-buffer (get-buffer-create "uce-reply-to-uce warning"))
+    (insert "\
+-- !!! NOTE !!! ---------------------------------------------
+
+Replying to spam is at best pointless, but most likely actively
+harmful.
+
+- You will confirm that your email address is valid, thus ensuring
+  you get more spam.
+
+- You will leak information and open yourself up for further
+  attack.  For example, they could use your \"geolocation\" to find
+  your home address and phone number.
+
+- The sender address is likely fake.
+
+- You help them refine their methods of spamming.
+
+Therefore, we strongly recommend that you do not use this package.
+Use a spam filter instead, or just delete the spam.
+
+-------------------------------------------------------------
+")))
 
 (defun uce-insert-ranting (&optional _ignored)
   "Insert text of the usual reply to UCE into current buffer."
diff --git a/lisp/man.el b/lisp/man.el
index 6009a31919..2bde1fc7fb 100644
--- a/lisp/man.el
+++ b/lisp/man.el
@@ -141,11 +141,21 @@ the manpage buffer."
   :group 'man
   :version "24.3")
 
-(defvar Man-ansi-color-map (let ((ansi-color-faces-vector
-                                 [ default Man-overstrike default Man-underline
-                                   Man-underline default default Man-reverse 
]))
-                            (ansi-color-make-color-map))
-  "The value used here for `ansi-color-map'.")
+(defvar Man-ansi-color-basic-faces-vector
+  [nil Man-overstrike nil Man-underline Man-underline nil nil Man-reverse]
+  "The value used here for `ansi-color-basic-faces-vector'.")
+
+(defvar Man-ansi-color-map
+  (with-no-warnings
+    (let ((ansi-color-faces-vector
+           [ default Man-overstrike default Man-underline
+             Man-underline default default Man-reverse ]))
+      (ansi-color-make-color-map)))
+  "The value formerly used here for `ansi-color-map'.
+This variable is obsolete.  To customize the faces used by ansi-color,
+set `Man-ansi-color-basic-faces-vector'.")
+(make-obsolete-variable 'Man-ansi-color-map
+                        'Man-ansi-color-basic-faces-vector "28.1")
 
 (defcustom Man-notify-method 'friendly
   "Selects the behavior when manpage is ready.
@@ -1243,7 +1253,7 @@ Same for the ANSI bold and normal escape sequences."
   (goto-char (point-min))
   ;; Fontify ANSI escapes.
   (let ((ansi-color-apply-face-function #'ansi-color-apply-text-property-face)
-       (ansi-color-map Man-ansi-color-map))
+       (ansi-color-basic-faces-vector Man-ansi-color-basic-faces-vector))
     (ansi-color-apply-on-region (point-min) (point-max)))
   ;; Other highlighting.
   (let ((buffer-undo-list t))
@@ -1776,7 +1786,7 @@ Returns t if section is found, nil otherwise."
                        Man--last-section
                      (car Man--sections)))
           (completion-ignore-case t)
-          (prompt (concat "Go to section (default " default "): "))
+          (prompt (format-prompt "Go to section" default))
           (chosen (completing-read prompt Man--sections
                                    nil nil nil nil default)))
      (list chosen))
@@ -1840,7 +1850,7 @@ Specify which REFERENCE to use; default is based on word 
at point."
             (defaults
               (mapcar 'substring-no-properties
                        (cons default Man--refpages)))
-            (prompt (concat "Refer to (default " default "): "))
+             (prompt (format-prompt "Refer to" default))
             (chosen (completing-read prompt Man--refpages
                                      nil nil nil nil defaults)))
         chosen)))
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index e84eec5002..1a81f1a3d0 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -413,8 +413,14 @@
     (bindings--define-key menu [separator-tag-file]
       '(menu-item "--" nil :visible (menu-bar-goto-uses-etags-p)))
 
+    (bindings--define-key menu [xref-forward]
+      '(menu-item "Forward" xref-go-forward
+                  :visible (and (featurep 'xref)
+                                (not (xref-forward-history-empty-p)))
+                  :help "Forward to the position gone Back from"))
+
     (bindings--define-key menu [xref-pop]
-      '(menu-item "Back" xref-pop-marker-stack
+      '(menu-item "Back" xref-go-back
                   :visible (and (featurep 'xref)
                                 (not (xref-marker-stack-empty-p)))
                   :help "Back to the position of the last search"))
@@ -514,7 +520,11 @@
                                          (cdr yank-menu)
                                        kill-ring))
                                     (not buffer-read-only))))
-                  :help "Paste (yank) text most recently cut/copied"))
+                  :help "Paste (yank) text most recently cut/copied"
+                  :keys ,(lambda ()
+                           (if cua-mode
+                               "\\[cua-paste]"
+                             "\\[yank]"))))
     (bindings--define-key menu [copy]
       ;; ns-win.el said: Substitute a Copy function that works better
       ;; under X (for GNUstep).
@@ -523,14 +533,23 @@
                             'kill-ring-save)
                   :enable mark-active
                   :help "Copy text in region between mark and current position"
-                  :keys ,(if (featurep 'ns)
-                             "\\[ns-copy-including-secondary]"
-                           "\\[kill-ring-save]")))
+                  :keys ,(lambda ()
+                           (cond
+                            ((featurep 'ns)
+                             "\\[ns-copy-including-secondary]")
+                            ((and cua-mode mark-active)
+                             "\\[cua-copy-handler]")
+                            (t
+                             "\\[kill-ring-save]")))))
     (bindings--define-key menu [cut]
-      '(menu-item "Cut" kill-region
+      `(menu-item "Cut" kill-region
                   :enable (and mark-active (not buffer-read-only))
                   :help
-                  "Cut (kill) text in region between mark and current 
position"))
+                  "Cut (kill) text in region between mark and current position"
+                  :keys ,(lambda ()
+                           (if (and cua-mode mark-active)
+                               "\\[cua-cut-handler]"
+                             "\\[kill-region]"))))
     ;; ns-win.el said: Separate undo from cut/paste section.
     (if (featurep 'ns)
         (bindings--define-key menu [separator-undo] menu-bar-separator))
@@ -1918,10 +1937,7 @@ key, a click, or a menu-item"))
   (let* ((default (thing-at-point 'sexp))
          (topic
           (read-from-minibuffer
-           (format "Subject to look up%s: "
-                   (if default
-                       (format " (default \"%s\")" default)
-                     ""))
+           (format-prompt "Subject to look up" default)
            nil nil nil nil default)))
     (list (if (zerop (length topic))
               default
@@ -1960,6 +1976,9 @@ key, a click, or a menu-item"))
                   :help "Find commands whose names match a regexp"))
     (bindings--define-key menu [sep1]
       menu-bar-separator)
+    (bindings--define-key menu [lookup-symbol-in-manual]
+      '(menu-item "Look Up Symbol in Manual..." info-lookup-symbol
+                  :help "Display manual section that describes a symbol"))
     (bindings--define-key menu [lookup-command-in-manual]
       '(menu-item "Look Up Command in User Manual..." 
Info-goto-emacs-command-node
                   :help "Display manual section that describes a command"))
@@ -2156,10 +2175,16 @@ otherwise it could decide to silently do nothing."
     (> count 1)))
 
 (defcustom yank-menu-length 20
-  "Maximum length to display in the `yank-menu'."
+  "Text of items in `yank-menu' longer than this will be truncated."
   :type 'integer
   :group 'menu)
 
+(defcustom yank-menu-max-items 60
+  "Maximum number of entries to display in the `yank-menu'."
+  :type 'integer
+  :group 'menu
+  :version "29.1")
+
 (defun menu-bar-update-yank-menu (string old)
   (let ((front (car (cdr yank-menu)))
        (menu-string (if (<= (length string) yank-menu-length)
@@ -2183,8 +2208,9 @@ otherwise it could decide to silently do nothing."
              (cons
               (cons string (cons menu-string 'menu-bar-select-yank))
               (cdr yank-menu)))))
-  (if (> (length (cdr yank-menu)) kill-ring-max)
-      (setcdr (nthcdr kill-ring-max yank-menu) nil)))
+  (let ((max-items (min yank-menu-max-items kill-ring-max)))
+    (if (> (length (cdr yank-menu)) max-items)
+        (setcdr (nthcdr max-items yank-menu) nil))))
 
 (put 'menu-bar-select-yank 'apropos-inhibit t)
 (defun menu-bar-select-yank ()
@@ -2487,7 +2513,9 @@ created in the future."
   ;; after this function returns, overwriting any message we do here.
   (when (and (called-interactively-p 'interactive) (not menu-bar-mode))
     (run-with-idle-timer 0 nil 'message
-                        "Menu Bar mode disabled.  Use M-x menu-bar-mode to 
make the menu bar appear.")))
+                         (substitute-command-keys
+                          "Menu Bar mode disabled.  \
+Use \\[menu-bar-mode] to make the menu bar appear."))))
 
 ;;;###autoload
 ;; (This does not work right unless it comes after the above definition.)
@@ -2691,10 +2719,13 @@ This command is to be used when you click the mouse in 
the menubar."
                        (cdr menu-bar-item-cons)
                      0))))
 
-(defun menu-bar-keymap ()
+(defun menu-bar-keymap (&optional keymap)
   "Return the current menu-bar keymap.
+The ordering of the return value respects `menu-bar-final-items'.
 
-The ordering of the return value respects `menu-bar-final-items'."
+It's possible to use the KEYMAP argument to override the default keymap
+that is the currently active maps.  For example, the argument KEYMAP
+could provide `global-map' where items are limited to the global map only."
   (let ((menu-bar '())
         (menu-end '()))
     (map-keymap
@@ -2707,7 +2738,7 @@ The ordering of the return value respects 
`menu-bar-final-items'."
              ;; sorting.
              (push (cons pos menu-item) menu-end)
            (push menu-item menu-bar))))
-     (lookup-key (menu-bar-current-active-maps) [menu-bar]))
+     (lookup-key (or keymap (menu-bar-current-active-maps)) [menu-bar]))
     `(keymap ,@(nreverse menu-bar)
              ,@(mapcar #'cdr (sort menu-end
                                    (lambda (a b)
diff --git a/lisp/mh-e/mh-acros.el b/lisp/mh-e/mh-acros.el
index 8fdcf3c62b..0669f5bb22 100644
--- a/lisp/mh-e/mh-acros.el
+++ b/lisp/mh-e/mh-acros.el
@@ -47,13 +47,13 @@
 ;;;###mh-autoload
 (defmacro mh-do-in-gnu-emacs (&rest body)
   "Execute BODY if in GNU Emacs."
-  (declare (debug t) (indent defun))
+  (declare (obsolete progn "29.1") (debug t) (indent defun))
   (unless (featurep 'xemacs) `(progn ,@body)))
 
 ;;;###mh-autoload
 (defmacro mh-do-in-xemacs (&rest body)
   "Execute BODY if in XEmacs."
-  (declare (debug t) (indent defun))
+  (declare (obsolete ignore "29.1") (debug t) (indent defun))
   (when (featurep 'xemacs) `(progn ,@body)))
 
 ;;;###mh-autoload
@@ -72,7 +72,8 @@
   "Create function NAME.
 If FUNCTION exists, then NAME becomes an alias for FUNCTION.
 Otherwise, create function NAME with ARG-LIST and BODY."
-  (declare (indent defun) (doc-string 4)
+  (declare (obsolete defun "29.1")
+           (indent defun) (doc-string 4)
            (debug (&define name symbolp sexp def-body)))
   `(defalias ',name
      (if (fboundp ',function)
@@ -84,7 +85,8 @@ Otherwise, create function NAME with ARG-LIST and BODY."
   "Create macro NAME.
 If MACRO exists, then NAME becomes an alias for MACRO.
 Otherwise, create macro NAME with ARG-LIST and BODY."
-  (declare (indent defun) (doc-string 4)
+  (declare (obsolete defmacro "29.1")
+           (indent defun) (doc-string 4)
            (debug (&define name symbolp sexp def-body)))
   (let ((defined-p (fboundp macro)))
     (if defined-p
@@ -99,22 +101,20 @@ Otherwise, create macro NAME with ARG-LIST and BODY."
   "Make HOOK local if needed.
 XEmacs and versions of GNU Emacs before 21.1 require
 `make-local-hook' to be called."
+  (declare (obsolete nil "29.1"))
   (when (and (fboundp 'make-local-hook)
              (not (get 'make-local-hook 'byte-obsolete-info)))
     `(make-local-hook ,hook)))
 
 ;;;###mh-autoload
 (defmacro mh-mark-active-p (check-transient-mark-mode-flag)
-  "A macro that expands into appropriate code in XEmacs and nil in GNU Emacs.
-In GNU Emacs if CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then
-check if variable `transient-mark-mode' is active."
-  (cond ((featurep 'xemacs)             ;XEmacs
-         '(and (boundp 'zmacs-regions) zmacs-regions (region-active-p)))
-        ((not check-transient-mark-mode-flag) ;GNU Emacs
-         '(and (boundp 'mark-active) mark-active))
-        (t                              ;GNU Emacs
-         '(and (boundp 'transient-mark-mode) transient-mark-mode
-               (boundp 'mark-active) mark-active))))
+  "If CHECK-TRANSIENT-MARK-MODE-FLAG is non-nil then check if
+variable `transient-mark-mode' is active."
+  (declare (obsolete nil "29.1"))
+  (cond ((not check-transient-mark-mode-flag)
+         'mark-active)
+        (t
+         '(and transient-mark-mode mark-active))))
 
 ;;;###mh-autoload
 (defmacro with-mh-folder-updating (save-modification-flag &rest body)
@@ -164,12 +164,8 @@ preserved."
         (original-position (make-symbol "original-position"))
         (modified-flag (make-symbol "modified-flag")))
     `(save-excursion
-       (let* ((,event-window
-               (or (mh-funcall-if-exists posn-window (event-start ,event))
-                   (mh-funcall-if-exists event-window ,event)))
-              (,event-position
-               (or (mh-funcall-if-exists posn-point (event-start ,event))
-                   (mh-funcall-if-exists event-closest-point ,event)))
+       (let* ((,event-window (posn-window (event-start ,event)))
+              (,event-position (posn-point (event-start ,event)))
               (,original-window (selected-window))
               (,original-position (progn
                                    (set-buffer (window-buffer ,event-window))
diff --git a/lisp/mh-e/mh-alias.el b/lisp/mh-e/mh-alias.el
index 37fdb16601..5761df5297 100644
--- a/lisp/mh-e/mh-alias.el
+++ b/lisp/mh-e/mh-alias.el
@@ -112,10 +112,10 @@ COMMA-SEPARATOR is non-nil."
         (setq res (match-string 1 res)))
     ;; Replace "&" with capitalized username
     (if (string-search "&" res)
-        (setq res (mh-replace-regexp-in-string "&" (capitalize username) res)))
+        (setq res (replace-regexp-in-string "&" (capitalize username) res)))
     ;; Remove " character
     (if (string-search "\"" res)
-        (setq res (mh-replace-regexp-in-string "\"" "" res)))
+        (setq res (replace-regexp-in-string "\"" "" res)))
     ;; If empty string, use username instead
     (if (string-equal "" res)
         (setq res username))
@@ -155,7 +155,7 @@ Exclude all aliases already in `mh-alias-alist' from 
\"ali\""
                     (if (string-equal username realname)
                         (concat "<" username ">")
                       (concat realname " <" username ">"))))
-              (when (not (mh-assoc-string alias-name mh-alias-alist t))
+              (when (not (assoc-string alias-name mh-alias-alist t))
                 (setq passwd-alist (cons (list alias-name alias-translation)
                                          passwd-alist)))))))
         (forward-line 1)))
@@ -184,12 +184,12 @@ been loaded."
       (cond
        ((looking-at "^[ \t]"))          ;Continuation line
        ((looking-at "\\(.+\\): .+: .*$") ; A new -blind- MH alias
-        (when (not (mh-assoc-string (match-string 1) mh-alias-blind-alist t))
+        (when (not (assoc-string (match-string 1) mh-alias-blind-alist t))
           (setq mh-alias-blind-alist
                 (cons (list (match-string 1)) mh-alias-blind-alist))
           (setq mh-alias-alist (cons (list (match-string 1)) mh-alias-alist))))
        ((looking-at "\\(.+\\): .*$")    ; A new MH alias
-        (when (not (mh-assoc-string (match-string 1) mh-alias-alist t))
+        (when (not (assoc-string (match-string 1) mh-alias-alist t))
           (setq mh-alias-alist
                 (cons (list (match-string 1)) mh-alias-alist)))))
       (forward-line 1)))
@@ -200,7 +200,7 @@ been loaded."
           user)
       (while local-users
         (setq user (car local-users))
-        (if (not (mh-assoc-string (car user) mh-alias-alist t))
+        (if (not (assoc-string (car user) mh-alias-alist t))
             (setq mh-alias-alist (append mh-alias-alist (list user))))
         (setq local-users (cdr local-users)))))
   (run-hooks 'mh-alias-reloaded-hook)
@@ -239,16 +239,16 @@ done here."
   "Return expansion for ALIAS.
 Blind aliases or users from /etc/passwd are not expanded."
   (cond
-   ((mh-assoc-string alias mh-alias-blind-alist t)
+   ((assoc-string alias mh-alias-blind-alist t)
     alias)                              ; Don't expand a blind alias
-   ((mh-assoc-string alias mh-alias-passwd-alist t)
-    (cadr (mh-assoc-string alias mh-alias-passwd-alist t)))
+   ((assoc-string alias mh-alias-passwd-alist t)
+    (cadr (assoc-string alias mh-alias-passwd-alist t)))
    (t
     (mh-alias-ali alias))))
 
 (eval-and-compile
-  (mh-require 'crm nil t)                 ; completing-read-multiple
-  (mh-require 'multi-prompt nil t))
+  (require 'crm nil t)                 ; completing-read-multiple
+  (require 'multi-prompt nil t))
 
 ;;;###mh-autoload
 (defun mh-read-address (prompt)
@@ -281,7 +281,7 @@ Blind aliases or users from /etc/passwd are not expanded."
       (let* ((case-fold-search t)
              (beg (mh-beginning-of-word))
              (the-name (buffer-substring-no-properties beg (point))))
-        (if (mh-assoc-string the-name mh-alias-alist t)
+        (if (assoc-string the-name mh-alias-alist t)
             (message "%s -> %s" the-name (mh-alias-expand the-name))
           ;; Check if it was a single word likely to be an alias
           (if (and (equal mh-alias-flash-on-comma 1)
@@ -313,7 +313,7 @@ Blind aliases or users from /etc/passwd are not expanded."
                         res)
                   res)))
              ((t) (all-completions string mh-alias-alist pred))
-             ((lambda) (mh-test-completion string mh-alias-alist pred)))))))))
+             ((lambda) (test-completion string mh-alias-alist pred)))))))))
 
 
 ;;; Alias File Updating
diff --git a/lisp/mh-e/mh-comp.el b/lisp/mh-e/mh-comp.el
index 404b6b3ce7..130d3784dd 100644
--- a/lisp/mh-e/mh-comp.el
+++ b/lisp/mh-e/mh-comp.el
@@ -177,9 +177,8 @@ Used by the \\[mh-edit-again] and 
\\[mh-extract-rejected-mail] commands.")
   "Messages annotated, either a sequence name or a list of message numbers.
 This variable can be used by `mh-annotate-msg-hook'.")
 
-(defvar mh-insert-auto-fields-done-local nil
+(defvar-local mh-insert-auto-fields-done-local nil
   "Buffer-local variable set when `mh-insert-auto-fields' called 
successfully.")
-(make-variable-buffer-local 'mh-insert-auto-fields-done-local)
 
 
 
@@ -304,21 +303,7 @@ message and scan line."
   (let ((draft-buffer (current-buffer))
         (file-name buffer-file-name)
         (config mh-previous-window-config)
-        ;; FIXME this is subtly different to select-message-coding-system.
-        (coding-system-for-write
-         (if (fboundp 'select-message-coding-system)
-             (select-message-coding-system) ; Emacs has this since at least 
21.1
-           (if (and (local-variable-p 'buffer-file-coding-system
-                                      (current-buffer)) ;XEmacs needs two args
-                    ;; We're not sure why, but buffer-file-coding-system
-                    ;; tends to get set to undecided-unix.
-                    (not (memq buffer-file-coding-system
-                               '(undecided undecided-unix undecided-dos))))
-               buffer-file-coding-system
-             (or (and (boundp 'sendmail-coding-system) sendmail-coding-system)
-                 (and (default-boundp 'buffer-file-coding-system)
-                      (default-value 'buffer-file-coding-system))
-                 'utf-8)))))
+        (coding-system-for-write (select-message-coding-system)))
     ;; Older versions of spost do not support -msgid and -mime.
     (unless mh-send-uses-spost-flag
       ;; Adding a Message-ID field looks good, makes it easier to search for
@@ -433,7 +418,7 @@ See also `mh-send'."
     (mh-clean-msg-header (point-min) mh-new-draft-cleaned-headers nil)
     (mh-insert-header-separator)
     ;; Merge in components
-    (mh-mapc
+    (mapc
      (lambda (header-field)
        (let ((field (car header-field))
              (value (cdr header-field))
@@ -593,11 +578,12 @@ See also `mh-compose-forward-as-mime-flag',
         (goto-char (point-min))
         ;; Set the local value of mh-mail-header-separator according to what is
         ;; present in the buffer...
-        (set (make-local-variable 'mh-mail-header-separator)
-             (save-excursion
-               (goto-char (mh-mail-header-end))
-               (buffer-substring-no-properties (point) 
(mh-line-end-position))))
-        (set (make-local-variable 'mail-header-separator) 
mh-mail-header-separator) ;override sendmail.el
+        (setq-local mh-mail-header-separator
+                    (save-excursion
+                      (goto-char (mh-mail-header-end))
+                      (buffer-substring-no-properties (point)
+                                                      (line-end-position))))
+        (setq-local mail-header-separator mh-mail-header-separator) ;override 
sendmail.el
         ;; If using MML, translate MH-style directive
         (if (equal mh-compose-insertion 'mml)
             (save-excursion
@@ -697,7 +683,7 @@ message and scan line."
       ;; For "From", the first value wins, with the identity's "From"
       ;; trumping anything in the distcomps file.
       (let ((components-file (mh-bare-components mh-dist-formfile)))
-        (mh-mapc
+        (mapc
          (lambda (header-field)
            (let ((field (car header-field))
                  (value (cdr header-field))
@@ -1077,7 +1063,6 @@ letter."
   ;; Insert identity.
   (mh-insert-identity mh-identity-default t)
   (mh-identity-make-menu)
-  (mh-identity-add-menu)
 
   ;; Cleanup possibly RFC2047 encoded subject header
   (mh-decode-message-subject)
@@ -1096,7 +1081,6 @@ letter."
   (setq mh-previous-window-config config)
   (setq mode-line-buffer-identification (list "    {%b}"))
   (mh-logo-display)
-  (mh-make-local-hook 'kill-buffer-hook)
   (add-hook 'kill-buffer-hook #'mh-tidy-draft-buffer nil t)
   (run-hook-with-args 'mh-compose-letter-function to subject cc))
 
@@ -1107,18 +1091,8 @@ The versions of MH-E, Emacs, and MH are shown."
   ;; Lazily initialize mh-x-mailer-string.
   (when (and mh-insert-x-mailer-flag (null mh-x-mailer-string))
     (setq mh-x-mailer-string
-          (format "MH-E %s; %s; %sEmacs %s"
-                  mh-version mh-variant-in-use
-                  (if (featurep 'xemacs) "X" "GNU ")
-                  (cond ((not (featurep 'xemacs))
-                         (string-match "[0-9]+\\.[0-9]+\\(\\.[0-9]+\\)?"
-                                       emacs-version)
-                         (match-string 0 emacs-version))
-                        ((string-match "[0-9.]*\\( +([ a-z]+[0-9]+)\\)?"
-                                       emacs-version)
-                         (match-string 0 emacs-version))
-                        (t (format "%s.%s" emacs-major-version
-                                   emacs-minor-version))))))
+          (format "MH-E %s; %s; Emacs %s"
+                  mh-version mh-variant-in-use emacs-version)))
   ;; Insert X-Mailer, but only if it doesn't already exist.
   (save-excursion
     (when (and mh-insert-x-mailer-flag
@@ -1245,7 +1219,7 @@ discarded."
   (cond ((and overwrite-flag
               (mh-goto-header-field (concat field ":")))
          (insert " " value)
-         (delete-region (point) (mh-line-end-position)))
+         (delete-region (point) (line-end-position)))
         ((and (not overwrite-flag)
               (mh-regexp-in-field-p (concat "\\b" (regexp-quote value) "\\b") 
field))
          ;; Already there, do nothing.
@@ -1288,11 +1262,8 @@ discarded."
       (set-syntax-table old-syntax-table))))
 
 (defun mh-ascii-buffer-p ()
-  "Check if current buffer is entirely composed of ASCII.
-The function doesn't work for XEmacs since `find-charset-region'
-doesn't exist there."
-  (cl-loop for charset in (mh-funcall-if-exists
-                           find-charset-region (point-min) (point-max))
+  "Check if current buffer is entirely composed of ASCII."
+  (cl-loop for charset in (find-charset-region (point-min) (point-max))
            unless (eq charset 'ascii) return nil
            finally return t))
 
diff --git a/lisp/mh-e/mh-compat.el b/lisp/mh-e/mh-compat.el
index ade80e8b95..19be5afd79 100644
--- a/lisp/mh-e/mh-compat.el
+++ b/lisp/mh-e/mh-compat.el
@@ -34,44 +34,13 @@
 ;; Please use mh-gnus.el when providing compatibility with different
 ;; versions of Gnus.
 
-;; Items are listed alphabetically (except for mh-require which is
-;; needed sooner it would normally appear).
+;; Items are listed alphabetically.
 
 (eval-when-compile (require 'mh-acros))
 
-(mh-do-in-gnu-emacs
-  (defalias 'mh-require #'require))
-
-(mh-do-in-xemacs
-  (defun mh-require (feature &optional filename noerror)
-    "If feature FEATURE is not loaded, load it from FILENAME.
-If FEATURE is not a member of the list `features', then the feature
-is not loaded; so load the file FILENAME.
-If FILENAME is omitted, the printname of FEATURE is used as the file name.
-If the optional third argument NOERROR is non-nil,
-then return nil if the file is not found instead of signaling an error.
-
-Simulate NOERROR argument in XEmacs which lacks it."
-    (if (not (featurep feature))
-        (if filename
-            (load filename noerror t)
-          (load (format "%s" feature) noerror t)))))
-
-(defun-mh mh-assoc-string assoc-string (key list case-fold)
-  "Like `assoc' but specifically for strings.
-Case is ignored if CASE-FOLD is non-nil.
-This function is used by Emacs versions that lack `assoc-string',
-introduced in Emacs 22."
-  ;; Test for fboundp is solely to silence compiler for Emacs >= 22.1.
-  (if (and case-fold (fboundp 'assoc-ignore-case))
-      (assoc-ignore-case key list)
-    (assoc key list)))
-
-;; For XEmacs.
-(defalias 'mh-cancel-timer
-  (if (fboundp 'cancel-timer)
-      'cancel-timer
-    'delete-itimer))
+(define-obsolete-function-alias 'mh-require #'require "29.1")
+(define-obsolete-function-alias 'mh-assoc-string #'assoc-string "29.1")
+(define-obsolete-function-alias 'mh-cancel-timer #'cancel-timer "29.1")
 
 ;; Emacs 24 made flet obsolete and suggested either cl-flet or
 ;; cl-letf. This macro is based upon gmm-flet from Gnus.
@@ -90,17 +59,8 @@ the function cell of FUNCs rather than their value cell.
          ,@body)
     `(flet ,bindings ,@body)))
 
-(defun mh-display-color-cells (&optional display)
-  "Return the number of color cells supported by DISPLAY.
-This function is used by XEmacs to return 2 when `device-color-cells'
-or `display-color-cells' returns nil. This happens when compiling or
-running on a tty and causes errors since `display-color-cells' is
-expected to return an integer."
-  (cond ((fboundp 'display-color-cells) ; GNU Emacs, XEmacs 21.5b28
-         (or (display-color-cells display) 2))
-        ((fboundp 'device-color-cells)  ; XEmacs 21.4
-         (or (device-color-cells display) 2))
-        (t 2)))
+(define-obsolete-function-alias 'mh-display-color-cells
+  #'display-color-cells "29.1")
 
 (defmacro mh-display-completion-list (completions &optional common-substring)
   "Display the list of COMPLETIONS.
@@ -110,209 +70,54 @@ The optional argument COMMON-SUBSTRING, if non-nil, 
should be a string
 specifying a common substring for adding the faces
 `completions-first-difference' and `completions-common-part' to
 the completions."
-  (cond ((< emacs-major-version 22) `(display-completion-list ,completions))
-        ((fboundp 'completion-hilit-commonality) ; Emacs 23.1 and later
-         `(display-completion-list
-           (completion-hilit-commonality ,completions
-                                         ,(length common-substring) nil)))
-        (t                              ; Emacs 22
-         `(display-completion-list ,completions ,common-substring))))
-
-(defmacro mh-face-foreground (face &optional frame inherit)
-  "Return the foreground color name of FACE, or nil if unspecified.
-See documentation for `face-foreground' for a description of the
-arguments FACE, FRAME, and perhaps INHERIT.
-This macro is used by Emacs versions that lack an INHERIT argument,
-introduced in Emacs 22."
-  (if (< emacs-major-version 22)
-      `(face-foreground ,face ,frame)
-    `(face-foreground ,face ,frame ,inherit)))
-
-(defmacro mh-face-background (face &optional frame inherit)
-  "Return the background color name of face, or nil if unspecified.
-See documentation for `face-background' for a description of the
-arguments FACE, FRAME, and INHERIT.
-This macro is used by Emacs versions that lack an INHERIT argument,
-introduced in Emacs 22."
-  (if (< emacs-major-version 22)
-      `(face-background ,face ,frame)
-    `(face-background ,face ,frame ,inherit)))
-
-(defun-mh mh-font-lock-add-keywords font-lock-add-keywords
-  (_mode _keywords &optional _how)
-  "XEmacs does not have `font-lock-add-keywords'.
-This function returns nil on that system.")
-
-(defun-mh mh-image-load-path-for-library
-  image-load-path-for-library (library image &optional path no-error)
-  "Return a suitable search path for images used by LIBRARY.
-
-It searches for IMAGE in `image-load-path' (excluding
-\"`data-directory'/images\") and `load-path', followed by a path
-suitable for LIBRARY, which includes \"../../etc/images\" and
-\"../etc/images\" relative to the library file itself, and then
-in \"`data-directory'/images\".
-
-Then this function returns a list of directories which contains
-first the directory in which IMAGE was found, followed by the
-value of `load-path'. If PATH is given, it is used instead of
-`load-path'.
-
-If NO-ERROR is non-nil and a suitable path can't be found, don't
-signal an error. Instead, return a list of directories as before,
-except that nil appears in place of the image directory.
-
-Here is an example that uses a common idiom to provide
-compatibility with versions of Emacs that lack the variable
-`image-load-path':
-
-    ;; Shush compiler.
-    (defvar image-load-path)
-
-    (let* ((load-path (image-load-path-for-library \"mh-e\" \"mh-logo.xpm\"))
-           (image-load-path (cons (car load-path)
-                                  (when (boundp \\='image-load-path)
-                                    image-load-path))))
-      (mh-tool-bar-folder-buttons-init))"
-  (unless library (error "No library specified"))
-  (unless image   (error "No image specified"))
-  (let (image-directory image-directory-load-path)
-    ;; Check for images in image-load-path or load-path.
-    (let ((img image)
-          (dir (or
-                ;; Images in image-load-path.
-                (mh-image-search-load-path image)
-                ;; Images in load-path.
-                (locate-library image)))
-          parent)
-      ;; Since the image might be in a nested directory (for
-      ;; example, mail/attach.pbm), adjust `image-directory'
-      ;; accordingly.
-      (when dir
-        (setq dir (file-name-directory dir))
-        (while (setq parent (file-name-directory img))
-          (setq img (directory-file-name parent)
-                dir (expand-file-name "../" dir))))
-      (setq image-directory-load-path dir))
-
-    ;; If `image-directory-load-path' isn't Emacs's image directory,
-    ;; it's probably a user preference, so use it. Then use a
-    ;; relative setting if possible; otherwise, use
-    ;; `image-directory-load-path'.
-    (cond
-     ;; User-modified image-load-path?
-     ((and image-directory-load-path
-           (not (equal image-directory-load-path
-                       (file-name-as-directory
-                        (expand-file-name "images" data-directory)))))
-      (setq image-directory image-directory-load-path))
-     ;; Try relative setting.
-     ((let (library-name d1ei d2ei)
-        ;; First, find library in the load-path.
-        (setq library-name (locate-library library))
-        (if (not library-name)
-            (error "Cannot find library %s in load-path" library))
-        ;; And then set image-directory relative to that.
-        (setq
-         ;; Go down 2 levels.
-         d2ei (file-name-as-directory
-               (expand-file-name
-                (concat (file-name-directory library-name) 
"../../etc/images")))
-         ;; Go down 1 level.
-         d1ei (file-name-as-directory
-               (expand-file-name
-                (concat (file-name-directory library-name) "../etc/images"))))
-        (setq image-directory
-              ;; Set it to nil if image is not found.
-              (cond ((file-exists-p (expand-file-name image d2ei)) d2ei)
-                    ((file-exists-p (expand-file-name image d1ei)) d1ei)))))
-     ;; Use Emacs's image directory.
-     (image-directory-load-path
-      (setq image-directory image-directory-load-path))
-     (no-error
-      (message "Could not find image %s for library %s" image library))
-     (t
-      (error "Could not find image %s for library %s" image library)))
-
-    ;; Return an augmented `path' or `load-path'.
-    (nconc (list image-directory)
-           (delete image-directory (copy-sequence (or path load-path))))))
-
-(defun-mh mh-image-search-load-path
-  image-search-load-path (_file &optional _path)
-  "Emacs 21 and XEmacs don't have `image-search-load-path'.
-This function returns nil on those systems."
-  nil)
-
-;; For XEmacs.
-(defalias 'mh-line-beginning-position
-  (if (fboundp 'line-beginning-position)
-      'line-beginning-position
-    'point-at-bol))
-
-;; For XEmacs.
-(defalias 'mh-line-end-position
-  (if (fboundp 'line-end-position)
-      'line-end-position
-    'point-at-eol))
-
-(mh-require 'mailabbrev nil t)
-(defun-mh mh-mail-abbrev-make-syntax-table
-  mail-abbrev-make-syntax-table ()
-  "Emacs 21 and XEmacs don't have `mail-abbrev-make-syntax-table'.
-This function returns nil on those systems."
-  nil)
-
-(defmacro mh-define-obsolete-variable-alias
-  (obsolete-name current-name &optional when docstring)
-  "Make OBSOLETE-NAME a variable alias for CURRENT-NAME and mark it obsolete.
-See documentation for `define-obsolete-variable-alias' for a description
-of the arguments OBSOLETE-NAME, CURRENT-NAME, and perhaps WHEN
-and DOCSTRING. This macro is used by XEmacs that lacks WHEN and
-DOCSTRING arguments."
-  (if (featurep 'xemacs)
-      `(define-obsolete-variable-alias ,obsolete-name ,current-name)
-    `(define-obsolete-variable-alias ,obsolete-name ,current-name ,when 
,docstring)))
-
-(defmacro mh-make-obsolete-variable (obsolete-name current-name &optional when 
access-type)
-  "Make the byte-compiler warn that OBSOLETE-NAME is obsolete.
-See documentation for `make-obsolete-variable' for a description
-of the arguments OBSOLETE-NAME, CURRENT-NAME, and perhaps WHEN
-and ACCESS-TYPE. This macro is used by XEmacs that lacks WHEN and
-ACCESS-TYPE arguments and by Emacs versions that lack ACCESS-TYPE,
-introduced in Emacs 24."
-  (if (featurep 'xemacs)
-      `(make-obsolete-variable ,obsolete-name ,current-name)
-    (if (< emacs-major-version 24)
-        `(make-obsolete-variable ,obsolete-name ,current-name ,when)
-      `(make-obsolete-variable ,obsolete-name ,current-name ,when 
,access-type))))
-
-(defun-mh mh-match-string-no-properties
-  match-string-no-properties (num &optional _string)
-  "Return string of text matched by last search, without text properties.
-This function is used by XEmacs that lacks `match-string-no-properties'.
-The function `buffer-substring-no-properties' is used instead.
-The argument STRING is ignored."
-  (buffer-substring-no-properties
-   (match-beginning num) (match-end num)))
-
-(defun-mh mh-replace-regexp-in-string replace-regexp-in-string
-  (regexp rep string &optional _fixedcase literal _subexp _start)
-  "Replace REGEXP with REP everywhere in STRING and return result.
-This function is used by XEmacs that lacks `replace-regexp-in-string'.
-The function `replace-in-string' is used instead.
-The arguments FIXEDCASE, SUBEXP, and START, used by
-`replace-in-string' are ignored."
-  (if (featurep 'xemacs)                ; silence Emacs compiler
-      (replace-in-string string regexp rep literal)))
-
-(defun-mh mh-test-completion
-  test-completion (_string _collection &optional _predicate)
-  "Return non-nil if STRING is a valid completion.
-XEmacs does not have `test-completion'. This function returns nil
-on that system." nil)
-
-;; Copy of constant from url-util.el in Emacs 22; needed by Emacs 21.
+  `(display-completion-list
+    (completion-hilit-commonality ,completions
+                                  ,(length common-substring) nil)))
+
+(define-obsolete-function-alias 'mh-face-foreground
+  #'face-foreground "29.1")
+
+(define-obsolete-function-alias 'mh-face-background
+  #'face-background "29.1")
+
+(define-obsolete-function-alias 'mh-font-lock-add-keywords
+  #'font-lock-add-keywords "29.1")
+
+;; Not preloaded in without-x builds.
+(declare-function image-load-path-for-library "image")
+(define-obsolete-function-alias 'mh-image-load-path-for-library
+  #'image-load-path-for-library "29.1")
+
+;; Not preloaded in without-x builds.
+(declare-function image-search-load-path "image")
+(define-obsolete-function-alias 'mh-image-search-load-path
+  #'image-search-load-path "29.1")
+
+(define-obsolete-function-alias 'mh-line-beginning-position
+  #'line-beginning-position "29.1")
+
+(define-obsolete-function-alias 'mh-line-end-position
+  #'line-end-position "29.1")
+
+(require 'mailabbrev nil t)
+(define-obsolete-function-alias 'mh-mail-abbrev-make-syntax-table
+  #'mail-abbrev-make-syntax-table "29.1")
+
+(define-obsolete-function-alias 'mh-define-obsolete-variable-alias
+  #'define-obsolete-variable-alias "29.1")
+
+(define-obsolete-function-alias 'mh-make-obsolete-variable
+  #'make-obsolete-variable "29.1")
+
+(define-obsolete-function-alias 'mh-match-string-no-properties
+  #'match-string-no-properties "29.1")
+
+(define-obsolete-function-alias 'mh-replace-regexp-in-string
+  #'replace-regexp-in-string "29.1")
+
+(define-obsolete-function-alias 'mh-test-completion
+  #'test-completion "29.1")
+
 (defconst mh-url-unreserved-chars
   '(
     ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y 
?z
@@ -321,51 +126,21 @@ on that system." nil)
        ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\))
   "A list of characters that are _NOT_ reserved in the URL spec.
 This is taken from RFC 2396.")
+(make-obsolete-variable 'mh-url-unreserved-chars 'url-unreserved-chars "29.1")
+
+(define-obsolete-function-alias 'mh-url-hexify-string
+  #'url-hexify-string "29.1")
+
+(define-obsolete-function-alias 'mh-view-mode-enter
+  #'view-mode-enter "29.1")
 
-(defun-mh mh-url-hexify-string url-hexify-string (str)
-  "Escape characters in a string.
-This is a copy of `url-hexify-string' from url-util.el in Emacs
-22; needed by Emacs 21."
-  (mapconcat
-   (lambda (char)
-     ;; Fixme: use a char table instead.
-     (if (not (memq char mh-url-unreserved-chars))
-         (if (> char 255)
-               (error "Hexifying multibyte character %s" str)
-           (format "%%%02X" char))
-       (char-to-string char)))
-   str ""))
-
-(defun-mh mh-view-mode-enter
-  view-mode-enter (&optional return-to exit-action)
-  "Enter View mode.
-This function is used by XEmacs that lacks `view-mode-enter'.
-The function `view-mode' is used instead.
-The arguments RETURN-TO and EXIT-ACTION are ignored."
-  ;; Shush compiler.
-  (if return-to nil)
-  (if exit-action nil)
-  (view-mode 1))
-
-(defun-mh mh-window-full-height-p
-  window-full-height-p (&optional _window)
-  "Return non-nil if WINDOW is not the result of a vertical split.
-This function is defined in XEmacs as it lacks
-`window-full-height-p'. The values of the functions
-`window-height' and `frame-height' are compared instead. The
-argument WINDOW is ignored."
-  (= (1+ (window-height))
-     (frame-height)))
+(define-obsolete-function-alias 'mh-window-full-height-p
+  #'window-full-height-p "29.1")
 
 (defmacro mh-write-file-functions ()
-  "Return `write-file-functions' if it exists.
-Otherwise return `local-write-file-hooks'.
-This macro exists purely for compatibility. The former symbol is used
-in Emacs 22 onward while the latter is used in previous versions and
-XEmacs."
-  (if (boundp 'write-file-functions)
-      ''write-file-functions            ;Emacs 22 on
-    ''local-write-file-hooks))          ;XEmacs
+  "Return `write-file-functions'. "
+  (declare (obsolete nil "29.1"))
+  ''write-file-functions)
 
 (provide 'mh-compat)
 
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 9cbc8cfb73..4e1ca2897b 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -88,29 +88,6 @@
 (require 'mh-buffers)
 (require 'mh-compat)
 
-(mh-do-in-xemacs
-  (require 'mh-xemacs))
-
-(mh-font-lock-add-keywords
- 'emacs-lisp-mode
- (eval-when-compile
-   `((,(concat "(\\("
-               ;; Function declarations (use font-lock-function-name-face).
-               "\\(def\\(un\\|macro\\)-mh\\)\\|"
-               ;; Variable declarations (use font-lock-variable-name-face).
-               "\\(def\\(custom\\|face\\)-mh\\)\\|"
-               ;; Group declarations (use font-lock-type-face).
-               "\\(defgroup-mh\\)"
-               "\\)\\>"
-               ;; Any whitespace and defined object.
-               "[ \t'(]*"
-               "\\(setf[ \t]+\\sw+)\\|\\sw+\\)?")
-      (1 font-lock-keyword-face)
-      (7 (cond ((match-beginning 2) font-lock-function-name-face)
-               ((match-beginning 4) font-lock-variable-name-face)
-               (t font-lock-type-face))
-         nil t)))))
-
 
 
 ;;; Global Variables
@@ -368,15 +345,13 @@ when searching for a separator.")
   "This regular expression matches the signature separator.
 See `mh-signature-separator'.")
 
-(defvar mh-thread-scan-line-map nil
+(defvar-local mh-thread-scan-line-map nil
   "Map of message index to various parts of the scan line.")
-(make-variable-buffer-local 'mh-thread-scan-line-map)
 
-(defvar mh-thread-scan-line-map-stack nil
+(defvar-local mh-thread-scan-line-map-stack nil
   "Old map of message index to various parts of the scan line.
 This is the original map that is stored when the folder is
 narrowed.")
-(make-variable-buffer-local 'mh-thread-scan-line-map-stack)
 
 (defcustom mh-x-mailer-string nil
   "String containing the contents of the X-Mailer header field.
@@ -486,7 +461,7 @@ all the strings have been used."
                 (count 0))
             (while (and (not (eobp)) (< count mh-index-max-cmdline-args))
               (push (buffer-substring-no-properties (point)
-                                                    (mh-line-end-position))
+                                                    (line-end-position))
                     arg-list)
               (cl-incf count)
               (forward-line))
@@ -619,23 +594,18 @@ Output is expected to be shown to user, not parsed by 
MH-E."
   ;; The bug wasn't seen in emacs21 but still occurred in XEmacs21.4.
   (mh-exchange-point-and-mark-preserving-active-mark))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar mark-active))
-
 (defun mh-exchange-point-and-mark-preserving-active-mark ()
   "Put the mark where point is now, and point where the mark is now.
 This command works even when the mark is not active, and
 preserves whether the mark is active or not."
   (interactive nil)
-  (let ((is-active (and (boundp 'mark-active) mark-active)))
+  (let ((is-active mark-active))
     (let ((omark (mark t)))
       (if (null omark)
           (error "No mark set in this buffer"))
       (set-mark (point))
       (goto-char omark)
-      (if (boundp 'mark-active)
-          (setq mark-active is-active))
+      (setq mark-active is-active)
       nil)))
 
 (defun mh-exec-lib-cmd-output (command &rest args)
@@ -663,56 +633,39 @@ Set mark after inserted text."
 
 ;;; MH-E Customization Support Routines
 
-;; Shush compiler (Emacs 21 and XEmacs).
-(defvar customize-package-emacs-version-alist)
-
 ;; Temporary function and data structure used customization.
 ;; These will be unbound after the options are defined.
 (defmacro mh-strip-package-version (args)
-  "Strip :package-version keyword and its value from ARGS.
-In Emacs versions that support the :package-version keyword,
-ARGS is returned unchanged."
-  `(if (boundp 'customize-package-emacs-version-alist)
-       ,args
-     (let (seen)
-       (cl-loop for keyword in ,args
-                if (cond ((eq keyword ':package-version) (setq seen t) nil)
-                         (seen (setq seen nil) nil)
-                         (t t))
-                collect keyword))))
+  "ARGS is returned unchanged."
+  (declare (obsolete identity "29.1"))
+  args)
 
 (defmacro defgroup-mh (symbol members doc &rest args)
   "Declare SYMBOL as a customization group containing MEMBERS.
 See documentation for `defgroup' for a description of the arguments
-SYMBOL, MEMBERS, DOC and ARGS.
-This macro is used by Emacs versions that lack the :package-version
-keyword, introduced in Emacs 22."
-  (declare (doc-string 3) (indent defun))
-  `(defgroup ,symbol ,members ,doc ,@(mh-strip-package-version args)))
+SYMBOL, MEMBERS, DOC and ARGS."
+  (declare (obsolete defgroup "29.1") (doc-string 3) (indent defun))
+  `(defgroup ,symbol ,members ,doc ,args))
 
 (defmacro defcustom-mh (symbol value doc &rest args)
   "Declare SYMBOL as a customizable variable that defaults to VALUE.
 See documentation for `defcustom' for a description of the arguments
-SYMBOL, VALUE, DOC and ARGS.
-This macro is used by Emacs versions that lack the :package-version
-keyword, introduced in Emacs 22."
-  (declare (doc-string 3) (indent defun))
-  `(defcustom ,symbol ,value ,doc ,@(mh-strip-package-version args)))
+SYMBOL, VALUE, DOC and ARGS."
+  (declare (obsolete defcustom "29.1") (doc-string 3) (indent defun))
+  `(defcustom ,symbol ,value ,doc ,args))
 
 (defmacro defface-mh (face spec doc &rest args)
   "Declare FACE as a customizable face that defaults to SPEC.
 See documentation for `defface' for a description of the arguments
-FACE, SPEC, DOC and ARGS.
-This macro is used by Emacs versions that lack the :package-version
-keyword, introduced in Emacs 22."
-  (declare (doc-string 3) (indent defun))
-  `(defface ,face ,spec ,doc ,@(mh-strip-package-version args)))
+FACE, SPEC, DOC and ARGS."
+  (declare (obsolete defface "29.1") (doc-string 3) (indent defun))
+  `(defface ,face ,spec ,doc ,args))
 
 
 
 ;;; Variant Support
 
-(defcustom-mh mh-path nil
+(defcustom mh-path nil
   "Additional list of directories to search for MH.
 See `mh-variant'."
   :group 'mh-e
@@ -947,7 +900,7 @@ finally GNU mailutils MH."
                (mapconcat (lambda (x) (format "%s" (car x)))
                           (mh-variants) " or "))))))
 
-(defcustom-mh mh-variant 'autodetect
+(defcustom mh-variant 'autodetect
   "Specifies the variant used by MH-E.
 
 The default setting of this option is \"Auto-detect\" which means
@@ -1023,19 +976,18 @@ windows in the frame are removed."
   (when delete-other-windows-flag
     (delete-other-windows)))
 
-(if (boundp 'customize-package-emacs-version-alist)
-    (add-to-list 'customize-package-emacs-version-alist
-                 '(MH-E ("6.0" . "22.1") ("6.1" . "22.1") ("7.0" . "22.1")
-                        ("7.1" . "22.1") ("7.2" . "22.1") ("7.3" . "22.1")
-                        ("7.4" . "22.1") ("8.0" . "22.1") ("8.1" . "23.1")
-                        ("8.2" . "23.1") ("8.3" . "24.1") ("8.4" . "24.4")
-                        ("8.5" . "24.4") ("8.6" . "24.4"))))
+(add-to-list 'customize-package-emacs-version-alist
+             '(MH-E ("6.0" . "22.1") ("6.1" . "22.1") ("7.0" . "22.1")
+                    ("7.1" . "22.1") ("7.2" . "22.1") ("7.3" . "22.1")
+                    ("7.4" . "22.1") ("8.0" . "22.1") ("8.1" . "23.1")
+                    ("8.2" . "23.1") ("8.3" . "24.1") ("8.4" . "24.4")
+                    ("8.5" . "24.4") ("8.6" . "24.4")))
 
 
 
 ;;; MH-E Customization Groups
 
-(defgroup-mh mh-e nil
+(defgroup mh-e nil
   "Emacs interface to the MH mail system.
 MH is the Rand Mail Handler. Other implementations include nmh
 and GNU mailutils."
@@ -1043,126 +995,126 @@ and GNU mailutils."
   :group 'mail
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-alias nil
+(defgroup mh-alias nil
   "Aliases."
   :link '(custom-manual "(mh-e)Aliases")
   :prefix "mh-alias-"
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-folder nil
+(defgroup mh-folder nil
   "Organizing your mail with folders."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Folders")
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-folder-selection nil
+(defgroup mh-folder-selection nil
   "Folder selection."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Folder Selection")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-identity nil
+(defgroup mh-identity nil
   "Identities."
   :link '(custom-manual "(mh-e)Identities")
   :prefix "mh-identity-"
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-inc nil
+(defgroup mh-inc nil
   "Incorporating your mail."
   :prefix "mh-inc-"
   :link '(custom-manual "(mh-e)Incorporating Mail")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-junk nil
+(defgroup mh-junk nil
   "Dealing with junk mail."
   :link '(custom-manual "(mh-e)Junk")
   :prefix "mh-junk-"
   :group 'mh-e
   :package-version '(MH-E . "7.3"))
 
-(defgroup-mh mh-letter nil
+(defgroup mh-letter nil
   "Editing a draft."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Editing Drafts")
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-ranges nil
+(defgroup mh-ranges nil
   "Ranges."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Ranges")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-scan-line-formats nil
+(defgroup mh-scan-line-formats nil
   "Scan line formats."
   :link '(custom-manual "(mh-e)Scan Line Formats")
   :prefix "mh-"
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-search nil
+(defgroup mh-search nil
   "Searching."
   :link '(custom-manual "(mh-e)Searching")
   :prefix "mh-search-"
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-sending-mail nil
+(defgroup mh-sending-mail nil
   "Sending mail."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Sending Mail")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-sequences nil
+(defgroup mh-sequences nil
   "Sequences."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Sequences")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-show nil
+(defgroup mh-show nil
   "Reading your mail."
   :prefix "mh-"
   :link '(custom-manual "(mh-e)Reading Mail")
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-speedbar nil
+(defgroup mh-speedbar nil
   "The speedbar."
   :prefix "mh-speed-"
   :link '(custom-manual "(mh-e)Speedbar")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-thread nil
+(defgroup mh-thread nil
   "Threading."
   :prefix "mh-thread-"
   :link '(custom-manual "(mh-e)Threading")
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-tool-bar nil
+(defgroup mh-tool-bar nil
   "The tool bar"
   :link '(custom-manual "(mh-e)Tool Bar")
   :prefix "mh-"
   :group 'mh-e
   :package-version '(MH-E . "8.0"))
 
-(defgroup-mh mh-hooks nil
+(defgroup mh-hooks nil
   "MH-E hooks."
   :link '(custom-manual "(mh-e)Top")
   :prefix "mh-"
   :group 'mh-e
   :package-version '(MH-E . "7.1"))
 
-(defgroup-mh mh-faces nil
+(defgroup mh-faces nil
   "Faces used in MH-E."
   :link '(custom-manual "(mh-e)Top")
   :prefix "mh-"
@@ -1178,7 +1130,7 @@ and GNU mailutils."
 
 ;;; Aliases (:group 'mh-alias)
 
-(defcustom-mh mh-alias-completion-ignore-case-flag t
+(defcustom mh-alias-completion-ignore-case-flag t
   "Non-nil means don't consider case significant in MH alias completion.
 
 As MH ignores case in the aliases, so too does MH-E. However, you
@@ -1189,7 +1141,7 @@ lowercase for mailing lists and uppercase for people."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-expand-aliases-flag nil
+(defcustom mh-alias-expand-aliases-flag nil
   "Non-nil means to expand aliases entered in the minibuffer.
 
 In other words, aliases entered in the minibuffer will be
@@ -1199,7 +1151,7 @@ this expansion is not performed."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-flash-on-comma t
+(defcustom mh-alias-flash-on-comma t
   "Specify whether to flash address or warn on translation.
 
 This option controls the behavior when a [comma] is pressed while
@@ -1212,7 +1164,7 @@ does not display a warning if the alias is not found."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-insert-file nil
+(defcustom mh-alias-insert-file nil
   "Filename used to store a new MH-E alias.
 
 The default setting of this option is \"Use Aliasfile Profile
@@ -1226,7 +1178,7 @@ name, MH-E will prompt for one of them when MH-E adds an 
alias."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-insertion-location 'sorted
+(defcustom mh-alias-insertion-location 'sorted
   "Specifies where new aliases are entered in alias files.
 
 This option is set to \"Alphabetical\" by default. If you organize
@@ -1238,7 +1190,7 @@ or \"Bottom\" of your alias file might be more 
appropriate."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-local-users t
+(defcustom mh-alias-local-users t
   "Non-nil means local users are added to alias completion.
 
 Aliases are created from \"/etc/passwd\" entries with a user ID
@@ -1259,7 +1211,7 @@ NIS password file."
   :group 'mh-alias
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-alias-local-users-prefix "local."
+(defcustom mh-alias-local-users-prefix "local."
   "String prefixed to the real names of users from the password file.
 This option can also be set to \"Use Login\".
 
@@ -1281,7 +1233,7 @@ turned off."
   :group 'mh-alias
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-alias-passwd-gecos-comma-separator-flag t
+(defcustom mh-alias-passwd-gecos-comma-separator-flag t
   "Non-nil means the gecos field in the password file uses a comma separator.
 
 In the example in `mh-alias-local-users-prefix', commas are used
@@ -1295,7 +1247,7 @@ whose contents may contain commas, you can turn this 
option off."
 
 ;;; Organizing Your Mail with Folders (:group 'mh-folder)
 
-(defcustom-mh mh-new-messages-folders t
+(defcustom mh-new-messages-folders t
   "Folders searched for the \"unseen\" sequence.
 
 Set this option to \"Inbox\" to search the \"+inbox\" folder or
@@ -1310,7 +1262,7 @@ See also `mh-recursive-folders-flag'."
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-ticked-messages-folders t
+(defcustom mh-ticked-messages-folders t
   "Folders searched for `mh-tick-seq'.
 
 Set this option to \"Inbox\" to search the \"+inbox\" folder or
@@ -1325,7 +1277,7 @@ See also `mh-recursive-folders-flag'."
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-large-folder 200
+(defcustom mh-large-folder 200
   "The number of messages that indicates a large folder.
 
 If a folder is deemed to be large, that is the number of messages
@@ -1337,7 +1289,7 @@ folders are treated as if they are small."
   :group 'mh-folder
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-recenter-summary-flag nil
+(defcustom mh-recenter-summary-flag nil
   "Non-nil means to recenter the summary window.
 
 If this option is turned on, recenter the summary window when the
@@ -1346,13 +1298,13 @@ show window is toggled off."
   :group 'mh-folder
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-recursive-folders-flag nil
+(defcustom mh-recursive-folders-flag nil
   "Non-nil means that commands which operate on folders do so recursively."
   :type 'boolean
   :group 'mh-folder
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-sortm-args nil
+(defcustom mh-sortm-args nil
   "Additional arguments for \"sortm\"\\<mh-folder-mode-map>.
 
 This option is consulted when a prefix argument is used with
@@ -1366,7 +1318,7 @@ an alternate view. For example, (\"-nolimit\" 
\"-textfield\"
 
 ;;; Folder Selection (:group 'mh-folder-selection)
 
-(defcustom-mh mh-default-folder-for-message-function nil
+(defcustom mh-default-folder-for-message-function nil
   "Function to select a default folder for refiling or \"Fcc:\".
 
 When this function is called, the current buffer contains the message
@@ -1378,7 +1330,7 @@ the default, or an empty string to suppress the default 
entirely."
   :group 'mh-folder-selection
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-default-folder-list nil
+(defcustom mh-default-folder-list nil
   "List of addresses and folders.
 
 The folder name associated with the first address found in this
@@ -1396,7 +1348,7 @@ for more information."
   :group 'mh-folder-selection
   :package-version '(MH-E . "7.2"))
 
-(defcustom-mh mh-default-folder-must-exist-flag t
+(defcustom mh-default-folder-must-exist-flag t
   "Non-nil means guessed folder name must exist to be used.
 
 If the derived folder does not exist, and this option is on, then
@@ -1410,7 +1362,7 @@ for more information."
   :group 'mh-folder-selection
   :package-version '(MH-E . "7.2"))
 
-(defcustom-mh mh-default-folder-prefix ""
+(defcustom mh-default-folder-prefix ""
   "Prefix used for folder names generated from aliases.
 The prefix is used to prevent clutter in your mail directory.
 
@@ -1429,7 +1381,7 @@ for more information."
 Real definition will take effect when mh-identity is loaded."
       nil)))
 
-(defcustom-mh mh-identity-list nil
+(defcustom mh-identity-list nil
   "List of identities.
 
 To customize this option, click on the \"INS\" button and enter a label
@@ -1498,7 +1450,7 @@ fashion."
   :group 'mh-identity
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-auto-fields-list nil
+(defcustom mh-auto-fields-list nil
   "List of recipients for which header lines are automatically inserted.
 
 This option can be used to set the identity depending on the
@@ -1559,14 +1511,14 @@ as the result is undefined."
   :group 'mh-identity
   :package-version '(MH-E . "7.3"))
 
-(defcustom-mh mh-auto-fields-prompt-flag t
+(defcustom mh-auto-fields-prompt-flag t
   "Non-nil means to prompt before sending if fields inserted.
 See `mh-auto-fields-list'."
   :type 'boolean
   :group 'mh-identity
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-identity-default nil
+(defcustom mh-identity-default nil
   "Default identity to use when `mh-letter-mode' is called.
 See `mh-identity-list'."
   :type (append
@@ -1577,7 +1529,7 @@ See `mh-identity-list'."
   :group 'mh-identity
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-identity-handlers
+(defcustom mh-identity-handlers
   '(("From" . mh-identity-handler-top)
     (":default" . mh-identity-handler-bottom)
     (":attribution-verb" . mh-identity-handler-attribution-verb)
@@ -1613,7 +1565,7 @@ containing the VALUE for the field is given."
 
 ;;; Incorporating Your Mail (:group 'mh-inc)
 
-(defcustom-mh mh-inc-prog "inc"
+(defcustom mh-inc-prog "inc"
   "Program to incorporate new mail into a folder.
 
 This program generates a one-line summary for each of the new
@@ -1632,7 +1584,7 @@ several scan line format variables appropriately."
 Real definition will take effect when mh-inc is loaded."
       nil)))
 
-(defcustom-mh mh-inc-spool-list nil
+(defcustom mh-inc-spool-list nil
   "Alternate spool files.
 
 You can use the `mh-inc-spool-list' variable to direct MH-E to
@@ -1662,10 +1614,7 @@ using the Emacs 22 command \"emacsclient\" as follows:
         origMode
         polltime 10
         headertime 0
-        command emacsclient --eval \\='(mh-inc-spool-mh-e)\\='
-
-In XEmacs, the command \"gnuclient\" is used in a similar
-fashion."
+        command emacsclient --eval \\='(mh-inc-spool-mh-e)\\='"
   :type '(repeat (list (file :tag "Spool File")
                        (string :tag "Folder")
                        (character :tag "Key Binding")))
@@ -1705,7 +1654,7 @@ The function is always called with SYMBOL bound to
                      until (executable-find (symbol-name (car element)))
                      finally return (car element)))))
 
-(defcustom-mh mh-junk-background nil
+(defcustom mh-junk-background nil
   "If on, spam programs are run in background.
 
 By default, the programs are run in the foreground, but this can
@@ -1723,14 +1672,14 @@ may be useful for debugging."
   :group 'mh-junk
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-junk-disposition nil
+(defcustom mh-junk-disposition nil
   "Disposition of junk mail."
   :type '(choice (const :tag "Delete Spam" nil)
                  (string :tag "Spam Folder"))
   :group 'mh-junk
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-junk-program nil
+(defcustom mh-junk-program nil
   "Spam program that MH-E should use.
 
 The default setting of this option is \"Auto-detect\" which means
@@ -1748,7 +1697,7 @@ bogofilter, then you can set this option to 
\"Bogofilter\"."
 
 ;;; Editing a Draft (:group 'mh-letter)
 
-(defcustom-mh mh-compose-insertion (if (locate-library "mml") 'mml 'mh)
+(defcustom mh-compose-insertion (if (locate-library "mml") 'mml 'mh)
   "Type of tags used when composing MIME messages.
 
 In addition to MH-style directives, MH-E also supports MML (MIME
@@ -1762,7 +1711,7 @@ MH-style directives are preferred."
   :group 'mh-letter
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-compose-skipped-header-fields
+(defcustom mh-compose-skipped-header-fields
   '("From" "Organization" "References" "In-Reply-To"
     "X-Face" "Face" "X-Image-URL" "X-Mailer")
   "List of header fields to skip over when navigating in draft."
@@ -1770,13 +1719,13 @@ MH-style directives are preferred."
   :group 'mh-letter
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-compose-space-does-completion-flag nil
+(defcustom mh-compose-space-does-completion-flag nil
   "Non-nil means \\<mh-letter-mode-map>\\[mh-letter-complete-or-space] does 
completion in message header."
   :type 'boolean
   :group 'mh-letter
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-delete-yanked-msg-window-flag nil
+(defcustom mh-delete-yanked-msg-window-flag nil
   "Non-nil means delete any window displaying the message.
 
 This deletes the window containing the original message after
@@ -1786,7 +1735,7 @@ more room on your screen for your reply."
   :group 'mh-letter
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-extract-from-attribution-verb "wrote:"
+(defcustom mh-extract-from-attribution-verb "wrote:"
   "Verb to use for attribution when a message is yanked by 
\\<mh-letter-mode-map>\\[mh-yank-cur-msg].
 
 The attribution consists of the sender's name and email address
@@ -1800,7 +1749,7 @@ followed by the content of this option. This option can 
be set to
   :group 'mh-letter
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-ins-buf-prefix "> "
+(defcustom mh-ins-buf-prefix "> "
   "String to put before each line of a yanked or inserted message.
 
 The prefix \"> \" is the default setting of this option. I
@@ -1816,17 +1765,17 @@ flavors of `mh-yank-behavior' or you have added a
   :group 'mh-letter
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-letter-complete-function 'ispell-complete-word
+(defcustom mh-letter-complete-function 'ispell-complete-word
   "Function to call when completing outside of address or folder fields.
 
 In the body of the message,
-\\<mh-letter-mode-map>\\[mh-letter-complete] runs this function,
+\\<mh-letter-mode-map>\\[completion-at-point] runs this function,
 which is set to \"ispell-complete-word\" by default."
   :type '(choice function (const nil))
   :group 'mh-letter
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-letter-fill-column 72
+(defcustom mh-letter-fill-column 72
   "Fill column to use in MH Letter mode.
 
 By default, this option is 72 to allow others to quote your
@@ -1835,7 +1784,7 @@ message without line wrapping."
   :group 'mh-letter
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-mml-method-default (if mh-pgp-support-flag "pgpmime" "none")
+(defcustom mh-mml-method-default (if mh-pgp-support-flag "pgpmime" "none")
   "Default method to use in security tags.
 
 This option is used to select between a variety of mail security
@@ -1858,7 +1807,7 @@ you write!"
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-signature-file-name "~/.signature"
+(defcustom mh-signature-file-name "~/.signature"
   "Source of user's signature.
 
 By default, the text of your signature is taken from the file
@@ -1881,7 +1830,7 @@ The signature is inserted into your message with the 
command
   :group 'mh-letter
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-signature-separator-flag t
+(defcustom mh-signature-separator-flag t
   "Non-nil means a signature separator should be inserted.
 
 It is not recommended that you change this option since various
@@ -1892,7 +1841,7 @@ replying or yanking a letter into a draft."
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-x-face-file "~/.face"
+(defcustom mh-x-face-file "~/.face"
   "File containing face header field to insert in outgoing mail.
 
 If the file starts with either of the strings \"X-Face:\", \"Face:\"
@@ -1921,7 +1870,7 @@ this option doesn't exist."
   :group 'mh-letter
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-yank-behavior 'attribution
+(defcustom mh-yank-behavior 'attribution
   "Controls which part of a message is yanked by 
\\<mh-letter-mode-map>\\[mh-yank-cur-msg].
 
 To include the entire message, including the entire header, use
@@ -1968,7 +1917,7 @@ inserted."
 
 ;;; Ranges (:group 'mh-ranges)
 
-(defcustom-mh mh-interpret-number-as-range-flag t
+(defcustom mh-interpret-number-as-range-flag t
   "Non-nil means interpret a number as a range.
 
 Since one of the most frequent ranges used is \"last:N\", MH-E
@@ -1988,7 +1937,7 @@ message 200, then use the range \"200:200\"."
 Real definition, below, uses variables that aren't defined yet."
       (set-default symbol value))))
 
-(defcustom-mh mh-adaptive-cmd-note-flag t
+(defcustom mh-adaptive-cmd-note-flag t
   "Non-nil means that the message number width is determined dynamically.
 
 If you've created your own format to handle long message numbers,
@@ -2017,7 +1966,7 @@ set SYMBOL to VALUE."
              "unless you use \"Use MH-E scan Format\"")
     (set-default symbol value)))
 
-(defcustom-mh mh-scan-format-file t
+(defcustom mh-scan-format-file t
   "Specifies the format file to pass to the scan program.
 
 The default setting for this option is \"Use MH-E scan Format\". This
@@ -2056,7 +2005,7 @@ Otherwise, set SYMBOL to VALUE."
              "is set to \"Use MH-E scan Format\"")
     (set-default symbol value)))
 
-(defcustom-mh mh-scan-prog "scan"
+(defcustom mh-scan-prog "scan"
   "Program used to scan messages.
 
 The name of the program that generates a listing of one line per
@@ -2071,7 +2020,7 @@ directory. You may link another program to `scan' (see
 
 ;;; Searching (:group 'mh-search)
 
-(defcustom-mh mh-search-program nil
+(defcustom mh-search-program nil
   "Search program that MH-E shall use.
 
 The default setting of this option is \"Auto-detect\" which means
@@ -2094,7 +2043,7 @@ MH-E can be found in the documentation of `mh-search'."
 
 ;;; Sending Mail (:group 'mh-sending-mail)
 
-(defcustom-mh mh-compose-forward-as-mime-flag t
+(defcustom mh-compose-forward-as-mime-flag t
   "Non-nil means that messages are forwarded as attachments.
 
 By default, this option is on which means that the forwarded
@@ -2110,7 +2059,7 @@ regardless of the settings of this option."
   :group 'mh-sending-mail
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-compose-letter-function nil
+(defcustom mh-compose-letter-function nil
   "Invoked when starting a new draft.
 
 However, it is the last function called before you edit your
@@ -2122,13 +2071,13 @@ fields."
   :group 'mh-sending-mail
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-compose-prompt-flag nil
+(defcustom mh-compose-prompt-flag nil
   "Non-nil means prompt for header fields when composing a new draft."
   :type 'boolean
   :group 'mh-sending-mail
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-forward-subject-format "%s: %s"
+(defcustom mh-forward-subject-format "%s: %s"
   "Format string for forwarded message subject.
 
 This option is a string which includes two escapes (\"%s\"). The
@@ -2138,7 +2087,7 @@ and the second one is replaced with the original 
\"Subject:\"."
   :group 'mh-sending-mail
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-insert-x-mailer-flag t
+(defcustom mh-insert-x-mailer-flag t
   "Non-nil means append an \"X-Mailer:\" header field to the header.
 
 This header field includes the version of MH-E and Emacs that you
@@ -2148,7 +2097,7 @@ can turn this option off."
   :group 'mh-sending-mail
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-redist-full-contents-flag nil
+(defcustom mh-redist-full-contents-flag nil
   "Non-nil means the \"dist\" command needs entire letter for redistribution.
 
 This option must be turned on if \"dist\" requires the whole
@@ -2160,7 +2109,7 @@ has been redistributed before, turn off this option."
   :group 'mh-sending-mail
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-reply-default-reply-to nil
+(defcustom mh-reply-default-reply-to nil
   "Sets the person or persons to whom a reply will be sent.
 
 This option is set to \"Prompt\" by default so that you are
@@ -2176,7 +2125,7 @@ this option to \"cc\". Other choices include \"from\", 
\"to\", or
   :group 'mh-sending-mail
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-reply-show-message-flag t
+(defcustom mh-reply-show-message-flag t
   "Non-nil means the MH-Show buffer is displayed when replying.
 
 If you include the message automatically, you can hide the
@@ -2193,7 +2142,7 @@ See also `mh-reply'."
 ;; the docstring: "Additional sequences that should not to be preserved can be
 ;; specified by setting `mh-unpropagated-sequences' appropriately." XXX
 
-(defcustom-mh mh-refile-preserves-sequences-flag t
+(defcustom mh-refile-preserves-sequences-flag t
   "Non-nil means that sequences are preserved when messages are refiled.
 
 If a message is in any sequence (except \"Previous-Sequence:\"
@@ -2204,7 +2153,7 @@ desired, then turn off this option."
   :group 'mh-sequences
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-tick-seq 'tick
+(defcustom mh-tick-seq 'tick
   "The name of the MH sequence for ticked messages.
 
 You can customize this option if you already use the \"tick\"
@@ -2216,7 +2165,7 @@ there isn't much advantage to that."
   :group 'mh-sequences
   :package-version '(MH-E . "7.3"))
 
-(defcustom-mh mh-update-sequences-after-mh-show-flag t
+(defcustom mh-update-sequences-after-mh-show-flag t
   "Non-nil means flush MH sequences to disk after message is 
shown\\<mh-folder-mode-map>.
 
 Three sequences are maintained internally by MH-E and pushed out
@@ -2231,7 +2180,7 @@ commands."
   :group 'mh-sequences
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-allowlist-preserves-sequences-flag t
+(defcustom mh-allowlist-preserves-sequences-flag t
   "Non-nil means that sequences are preserved when messages are allowlisted.
 
 If a message is in any sequence (except \"Previous-Sequence:\"
@@ -2244,7 +2193,7 @@ not desired, then turn off this option."
 
 ;;; Reading Your Mail (:group 'mh-show)
 
-(defcustom-mh mh-bury-show-buffer-flag t
+(defcustom mh-bury-show-buffer-flag t
   "Non-nil means show buffer is buried.
 
 One advantage of not burying the show buffer is that one can
@@ -2255,7 +2204,7 @@ running \\[electric-buffer-list] to see what I mean."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-clean-message-header-flag t
+(defcustom mh-clean-message-header-flag t
   "Non-nil means remove extraneous header fields.
 
 See also `mh-invisible-header-fields-default' and
@@ -2264,7 +2213,7 @@ See also `mh-invisible-header-fields-default' and
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-decode-mime-flag (not (not (locate-library "mm-decode")))
+(defcustom mh-decode-mime-flag (not (not (locate-library "mm-decode")))
   "Non-nil means attachments are handled\\<mh-folder-mode-map>.
 
 MH-E can handle attachments as well if the Gnus `mm-decode'
@@ -2282,7 +2231,7 @@ messages and other graphical widgets. See the options
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-display-buttons-for-alternatives-flag nil
+(defcustom mh-display-buttons-for-alternatives-flag nil
   "Non-nil means display buttons for all alternative attachments.
 
 Sometimes, a mail program will produce multiple alternatives of
@@ -2294,7 +2243,7 @@ inline and buttons are shown for each of the other 
alternatives."
   :group 'mh-show
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-display-buttons-for-inline-parts-flag nil
+(defcustom mh-display-buttons-for-inline-parts-flag nil
   "Non-nil means display buttons for all inline 
attachments\\<mh-folder-mode-map>.
 
 The sender can request that attachments should be viewed inline so
@@ -2317,7 +2266,7 @@ text (including HTML) and images."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-do-not-confirm-flag nil
+(defcustom mh-do-not-confirm-flag nil
   "Non-nil means non-reversible commands do not prompt for confirmation.
 
 Commands such as `mh-pack-folder' prompt to confirm whether to
@@ -2329,7 +2278,7 @@ retracted--without question."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-fetch-x-image-url nil
+(defcustom mh-fetch-x-image-url nil
   "Control fetching of \"X-Image-URL:\" header field image.
 
 This option controls the fetching of the \"X-Image-URL:\" header
@@ -2365,7 +2314,7 @@ turned on."
   :group 'mh-show
   :package-version '(MH-E . "7.3"))
 
-(defcustom-mh mh-graphical-smileys-flag t
+(defcustom mh-graphical-smileys-flag t
   "Non-nil means graphical smileys are displayed.
 
 It is a long standing custom to inject body language using a
@@ -2380,7 +2329,7 @@ turned off."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-graphical-emphasis-flag t
+(defcustom mh-graphical-emphasis-flag t
   "Non-nil means graphical emphasis is displayed.
 
 A few typesetting features are indicated in ASCII text with
@@ -2397,7 +2346,7 @@ turned off."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-highlight-citation-style 'gnus
+(defcustom mh-highlight-citation-style 'gnus
   "Style for highlighting citations.
 
 If the sender of the message has cited other messages in his
@@ -2819,7 +2768,7 @@ Because the function `mh-invisible-headers' uses both
 `mh-invisible-header-fields' and `mh-invisible-header-fields', it
 cannot be run until both variables have been initialized.")
 
-(defcustom-mh mh-invisible-header-fields nil
+(defcustom mh-invisible-header-fields nil
   "Additional header fields to hide.
 
 Header fields that you would like to hide that aren't listed in
@@ -2842,7 +2791,7 @@ See also `mh-clean-message-header-flag'."
   :group 'mh-show
   :package-version '(MH-E . "7.1"))
 
-(defcustom-mh mh-invisible-header-fields-default nil
+(defcustom mh-invisible-header-fields-default nil
   "List of hidden header fields.
 
 The header fields listed in this option are hidden, although you
@@ -2899,7 +2848,7 @@ removed and entries from `mh-invisible-header-fields' are 
added."
 ;; Compile invisible header fields.
 (mh-invisible-headers)
 
-(defcustom-mh mh-lpr-command-format "lpr -J '%s'"
+(defcustom mh-lpr-command-format "lpr -J '%s'"
   "Command used to print\\<mh-folder-mode-map>.
 
 This option contains the Unix command line which performs the
@@ -2916,7 +2865,7 @@ This option is not used by the commands 
\\[mh-ps-print-msg] or
   :group 'mh-show
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-max-inline-image-height nil
+(defcustom mh-max-inline-image-height nil
   "Maximum inline image height if \"Content-Disposition:\" is not present.
 
 Some older mail programs do not insert this needed plumbing to
@@ -2932,7 +2881,7 @@ these numbers."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-max-inline-image-width nil
+(defcustom mh-max-inline-image-width nil
   "Maximum inline image width if \"Content-Disposition:\" is not present.
 
 Some older mail programs do not insert this needed plumbing to
@@ -2948,7 +2897,7 @@ these numbers."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-mhl-format-file nil
+(defcustom mh-mhl-format-file nil
   "Specifies the format file to pass to the \"mhl\" program.
 
 Normally MH-E takes care of displaying messages itself (rather than
@@ -2972,7 +2921,7 @@ file."
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-mime-save-parts-default-directory t
+(defcustom mh-mime-save-parts-default-directory t
   "Default directory to use for \\<mh-folder-mode-map>\\[mh-mime-save-parts].
 
 The default value for this option is \"Prompt Always\" so that
@@ -2988,7 +2937,7 @@ directory's name."
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-print-background-flag nil
+(defcustom mh-print-background-flag nil
   "Non-nil means messages should be printed in the 
background\\<mh-folder-mode-map>.
 
 Normally messages are printed in the foreground. If this is slow on
@@ -3004,7 +2953,7 @@ This option is not used by the commands 
\\[mh-ps-print-msg] or
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-show-maximum-size 0
+(defcustom mh-show-maximum-size 0
   "Maximum size of message (in bytes) to display automatically.
 
 This option provides an opportunity to skip over large messages
@@ -3014,7 +2963,7 @@ message are shown regardless of size."
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-show-use-xface-flag (>= emacs-major-version 21)
+(defcustom mh-show-use-xface-flag (>= emacs-major-version 21)
   "Non-nil means display face images in MH-show buffers.
 
 MH-E can display the content of \"Face:\", \"X-Face:\", and
@@ -3029,15 +2978,12 @@ and off. This feature will be turned on by default if 
your system
 supports it.
 
 The first header field used, if present, is the Gnus-specific
-\"Face:\" field. The \"Face:\" field appeared in GNU Emacs 21 and
-XEmacs. For more information, see URL
+\"Face:\" field. The \"Face:\" field appeared in Emacs 21.
+For more information, see URL
 `https://quimby.gnus.org/circus/face/'. Next is the traditional
 \"X-Face:\" header field. The display of this field requires the
 \"uncompface\" program (see URL
-`ftp://ftp.cs.indiana.edu/pub/faces/compface/compface.tar.z'). Recent
-versions of XEmacs have internal support for \"X-Face:\" images. If
-your version of XEmacs does not, then you'll need both \"uncompface\"
-and the x-face package (see URL `https://www.jpl.org/ftp/pub/elisp/').
+`ftp://ftp.cs.indiana.edu/pub/faces/compface/compface.tar.z').
 
 Finally, MH-E will display images referenced by the \"X-Image-URL:\"
 header field if neither the \"Face:\" nor the \"X-Face:\" fields are
@@ -3054,7 +3000,7 @@ The option `mh-fetch-x-image-url' controls the fetching 
of the
   :group 'mh-show
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-store-default-directory nil
+(defcustom mh-store-default-directory nil
   "Default directory for \\<mh-folder-mode-map>\\[mh-store-msg].
 
 If you would like to change the initial default directory,
@@ -3066,7 +3012,7 @@ the content of these messages."
   :group 'mh-show
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-summary-height nil
+(defcustom mh-summary-height nil
   "Number of lines in MH-Folder buffer (including the mode line).
 
 The default value of this option is \"Automatic\" which means
@@ -3081,7 +3027,7 @@ lines you'd like to see."
 
 ;;; The Speedbar (:group 'mh-speedbar)
 
-(defcustom-mh mh-speed-update-interval 60
+(defcustom mh-speed-update-interval 60
   "Time between speedbar updates in seconds.
 Set to 0 to disable automatic update."
   :type 'integer
@@ -3090,7 +3036,7 @@ Set to 0 to disable automatic update."
 
 ;;; Threading (:group 'mh-thread)
 
-(defcustom-mh mh-show-threads-flag nil
+(defcustom mh-show-threads-flag nil
   "Non-nil means new folders start in threaded mode.
 
 Threading large number of messages can be time consuming so this
@@ -3106,7 +3052,7 @@ threaded is less than `mh-large-folder'."
 ;; mh-tool-bar-folder-buttons and mh-tool-bar-letter-buttons defined
 ;; dynamically in mh-tool-bar.el.
 
-(defcustom-mh mh-tool-bar-search-function 'mh-search
+(defcustom mh-tool-bar-search-function 'mh-search
   "Function called by the tool bar search button.
 
 By default, this is set to `mh-search'. You can also choose
@@ -3117,47 +3063,11 @@ of your own choosing."
   :group 'mh-tool-bar
   :package-version '(MH-E . "7.0"))
 
-;; XEmacs has a couple of extra customizations...
-(mh-do-in-xemacs
-  (defcustom-mh mh-xemacs-use-tool-bar-flag mh-xemacs-has-tool-bar-flag
-    "If non-nil, use tool bar.
-
-This option controls whether to show the MH-E icons at all. By
-default, this option is turned on if the window system supports
-tool bars. If your system doesn't support tool bars, then you
-won't be able to turn on this option."
-    :type 'boolean
-    :group 'mh-tool-bar
-    :set (lambda (symbol value)
-           (if (and (eq value t)
-                    (not mh-xemacs-has-tool-bar-flag))
-               (error "Tool bar not supported"))
-           (set-default symbol value))
-    :package-version '(MH-E . "7.3"))
-
-  (defcustom-mh mh-xemacs-tool-bar-position nil
-    "Tool bar location.
-
-This option controls the placement of the tool bar along the four
-edges of the frame. You can choose from one of \"Same As Default
-Tool Bar\", \"Top\", \"Bottom\", \"Left\", or \"Right\". If this
-variable is set to anything other than \"Same As Default Tool
-Bar\" and the default tool bar is in a different location, then
-two tool bars will be displayed: the MH-E tool bar and the
-default tool bar."
-    :type '(radio (const :tag "Same As Default Tool Bar" :value nil)
-                  (const :tag "Top" :value top)
-                  (const :tag "Bottom" :value bottom)
-                  (const :tag "Left" :value left)
-                  (const :tag "Right" :value right))
-    :group 'mh-tool-bar
-    :package-version '(MH-E . "7.3")))
-
 
 
 ;;; Hooks (:group 'mh-hooks + group where hook described)
 
-(defcustom-mh mh-after-commands-processed-hook nil
+(defcustom mh-after-commands-processed-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-execute-commands] after performing 
outstanding refile and delete requests.
 
 Variables that are useful in this hook include
@@ -3169,14 +3079,14 @@ folder, which is also available in `mh-current-folder'."
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-alias-reloaded-hook nil
+(defcustom mh-alias-reloaded-hook nil
   "Hook run by `mh-alias-reload' after loading aliases."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-alias
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-annotate-msg-hook nil
+(defcustom mh-annotate-msg-hook nil
   "Hook run when a message is sent and after annotating the scan lines and 
message.
 Hook functions can access the current folder name with
 `mh-current-folder' and obtain the message numbers of the
@@ -3186,7 +3096,7 @@ annotated messages with `mh-annotate-list'."
   :group 'mh-sending-mail
   :package-version '(MH-E . "8.1"))
 
-(defcustom-mh mh-before-commands-processed-hook nil
+(defcustom mh-before-commands-processed-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-execute-commands] before performing 
outstanding refile and delete requests.
 
 Variables that are useful in this hook include `mh-delete-list',
@@ -3198,7 +3108,7 @@ used to see which changes will be made to the current 
folder,
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-before-quit-hook nil
+(defcustom mh-before-quit-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-quit] before quitting MH-E.
 
 This hook is called before the quit occurs, so you might use it
@@ -3211,7 +3121,7 @@ See also `mh-quit-hook'."
   :group 'mh-folder
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-before-send-letter-hook nil
+(defcustom mh-before-send-letter-hook nil
   "Hook run at the beginning of the \\<mh-letter-mode-map>\\[mh-send-letter] 
command.
 
 For example, if you want to check your spelling in your message
@@ -3222,14 +3132,14 @@ before sending, add the `ispell-message' function."
   :group 'mh-letter
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-blocklist-msg-hook nil
+(defcustom mh-blocklist-msg-hook nil
   "Hook run by \\<mh-letter-mode-map>\\[mh-junk-blocklist] after marking each 
message for blocklisting."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-show
   :package-version '(MH-E . "8.4"))
 
-(defcustom-mh mh-delete-msg-hook nil
+(defcustom mh-delete-msg-hook nil
   "Hook run by \\<mh-letter-mode-map>\\[mh-delete-msg] after marking each 
message for deletion.
 
 For example, a past maintainer of MH-E used this once when he
@@ -3239,7 +3149,7 @@ kept statistics on his mail usage."
   :group 'mh-show
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-find-path-hook nil
+(defcustom mh-find-path-hook nil
   "Hook run by `mh-find-path' after reading the user's MH profile.
 
 This hook can be used the change the value of the variables that
@@ -3250,28 +3160,28 @@ between MH and MH-E."
   :group 'mh-e
   :package-version '(MH-E . "7.0"))
 
-(defcustom-mh mh-folder-mode-hook nil
+(defcustom mh-folder-mode-hook nil
   "Hook run by `mh-folder-mode' when visiting a new folder."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-folder
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-forward-hook nil
+(defcustom mh-forward-hook nil
   "Hook run by `mh-forward' on a forwarded letter."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-sending-mail
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-inc-folder-hook nil
+(defcustom mh-inc-folder-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-inc-folder] after incorporating 
mail into a folder."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-inc
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-insert-signature-hook nil
+(defcustom mh-insert-signature-hook nil
   "Hook run by \\<mh-letter-mode-map>\\[mh-insert-signature] after signature 
has been inserted.
 
 Hook functions may access the actual name of the file or the
@@ -3282,9 +3192,9 @@ function used to insert the signature with
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(mh-define-obsolete-variable-alias 'mh-kill-folder-suppress-prompt-hooks
+(define-obsolete-variable-alias 'mh-kill-folder-suppress-prompt-hooks
   'mh-kill-folder-suppress-prompt-functions "24.3")
-(defcustom-mh mh-kill-folder-suppress-prompt-functions '(mh-search-p)
+(defcustom mh-kill-folder-suppress-prompt-functions '(mh-search-p)
   "Abnormal hook run at the beginning of 
\\<mh-folder-mode-map>\\[mh-kill-folder].
 
 The hook functions are called with no arguments and should return
@@ -3302,7 +3212,7 @@ accident in the \"+inbox\" folder, you will not be happy."
   :group 'mh-folder
   :package-version '(MH-E . "7.4"))
 
-(defcustom-mh mh-letter-mode-hook nil
+(defcustom mh-letter-mode-hook nil
   "Hook run by `mh-letter-mode' on a new letter.
 
 This hook allows you to do some processing before editing a
@@ -3315,14 +3225,14 @@ go."
   :group 'mh-sending-mail
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-mh-to-mime-hook nil
+(defcustom mh-mh-to-mime-hook nil
   "Hook run on the formatted letter by 
\\<mh-letter-mode-map>\\[mh-mh-to-mime]."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-search-mode-hook nil
+(defcustom mh-search-mode-hook nil
   "Hook run upon entry to `mh-search-mode'\\<mh-folder-mode-map>.
 
 If you find that you do the same thing over and over when editing
@@ -3334,7 +3244,7 @@ This can be done with this hook which is called when
   :group 'mh-search
   :package-version '(MH-E . "8.0"))
 
-(defcustom-mh mh-pack-folder-hook nil
+(defcustom mh-pack-folder-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-pack-folder] after renumbering the 
messages.
 Hook functions can access the current folder name with `mh-current-folder'."
   :type 'hook
@@ -3342,7 +3252,7 @@ Hook functions can access the current folder name with 
`mh-current-folder'."
   :group 'mh-folder
   :package-version '(MH-E . "8.2"))
 
-(defcustom-mh mh-quit-hook nil
+(defcustom mh-quit-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-quit] after quitting MH-E.
 
 This hook is not run in an MH-E context, so you might use it to
@@ -3354,14 +3264,14 @@ See also `mh-before-quit-hook'."
   :group 'mh-folder
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-refile-msg-hook nil
+(defcustom mh-refile-msg-hook nil
   "Hook run by \\<mh-folder-mode-map>\\[mh-refile-msg] after marking each 
message for refiling."
   :type 'hook
   :group 'mh-hooks
   :group 'mh-folder
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-show-hook nil
+(defcustom mh-show-hook nil
   "Hook run after \\<mh-folder-mode-map>\\[mh-show] shows a message.
 
 It is the last thing called after messages are displayed. It's
@@ -3372,7 +3282,7 @@ used to affect the behavior of MH-E in general or when
   :group 'mh-show
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-show-mode-hook nil
+(defcustom mh-show-mode-hook nil
   "Hook run upon entry to `mh-show-mode'.
 
 This hook is called early on in the process of the message display,
@@ -3384,7 +3294,7 @@ buffer itself. See also `mh-show-hook'."
   :group 'mh-show
   :package-version '(MH-E . "8.7"))
 
-(defcustom-mh mh-unseen-updated-hook nil
+(defcustom mh-unseen-updated-hook nil
   "Hook run after the unseen sequence has been updated.
 
 The variable `mh-seen-list' can be used by this hook to obtain
@@ -3395,7 +3305,7 @@ sequence."
   :group 'mh-sequences
   :package-version '(MH-E . "6.0"))
 
-(defcustom-mh mh-allowlist-msg-hook nil
+(defcustom mh-allowlist-msg-hook nil
   "Hook run by \\<mh-letter-mode-map>\\[mh-junk-allowlist] after marking each 
message for allowlisting."
   :type 'hook
   :group 'mh-hooks
@@ -3406,15 +3316,10 @@ sequence."
 
 ;;; Faces (:group 'mh-faces + group where faces described)
 
-(if (boundp 'facemenu-unlisted-faces)
-    ;; This variable was removed in Emacs 22.1.
-    (add-to-list 'facemenu-unlisted-faces "^mh-"))
-
 ;; To add a new face:
 ;; 1. Add entry to variable mh-face-data.
-;; 2. Create face using defface-mh (which removes min-color spec and
-;;    :package-version keyword where these are not supported),
-;;    accessing face data with function mh-face-data.
+;; 2. Create face using defface, accessing face data with function
+;;    mh-face-data.
 ;; 3. Add inherit argument to function mh-face-data if applicable.
 (defvar mh-face-data
   '((mh-folder-followup
@@ -3561,18 +3466,17 @@ sequence."
        (:underline t)))))
   "MH-E face data.
 Used by function `mh-face-data' which returns spec that is
-consumed by `defface-mh'.")
+consumed by `defface'.")
 
 (require 'cus-face)
 
-(defvar mh-inherit-face-flag (assq :inherit custom-face-attributes)
-  "Non-nil means that the `defface' :inherit keyword is available.
-The :inherit keyword is available on all supported versions of
-GNU Emacs and XEmacs from at least 21.5.23 on.")
+(defvar mh-inherit-face-flag t
+  "Non-nil means that the `defface' :inherit keyword is available.")
+(make-obsolete-variable 'mh-inherit-face-flag nil "29.1")
 
-(defvar mh-min-colors-defined-flag (and (not (featurep 'xemacs))
-                                        (>= emacs-major-version 22))
+(defvar mh-min-colors-defined-flag t
   "Non-nil means `defface' supports min-colors display requirement.")
+(make-obsolete-variable 'mh-min-colors-defined-flag nil "29.1")
 
 (defun mh-face-data (face &optional inherit)
   "Return spec for FACE.
@@ -3583,53 +3487,26 @@ keyword, return INHERIT literally; otherwise, return 
spec for
 FACE from the variable `mh-face-data'. This isn't a perfect
 implementation. In the case that the :inherit keyword is not
 supported, any additional attributes in the inherit parameter are
-not added to the returned spec.
-
-Furthermore, when `mh-min-colors-defined-flag' is nil, this
-function finds display entries with \"min-colors\" requirements
-and either removes the \"min-colors\" requirement or strips the
-display entirely if the display does not support the number of
-specified colors."
-  (let ((spec
-         (if (and inherit mh-inherit-face-flag)
-             inherit
-           (or (cadr (assq face mh-face-data))
-               (error "Could not find %s in mh-face-data" face)))))
-
-    (if mh-min-colors-defined-flag
-        spec
-      (let ((cells (mh-display-color-cells))
-            new-spec)
-        ;; Remove entries with min-colors, or delete them if we have
-        ;; fewer colors than they specify.
-        (cl-loop
-         for entry in (reverse spec) do
-         (let ((requirement (if (eq (car entry) t)
-                                nil
-                              (assq 'min-colors (car entry)))))
-           (if requirement
-               (when (>= cells (nth 1 requirement))
-                 (setq new-spec (cons (cons (delq requirement (car entry))
-                                            (cdr entry))
-                                      new-spec)))
-             (setq new-spec (cons entry new-spec)))))
-        new-spec))))
-
-(defface-mh mh-folder-address
+not added to the returned spec."
+  (or inherit
+      (cadr (assq face mh-face-data))
+      (error "Could not find %s in mh-face-data" face)))
+
+(defface mh-folder-address
   (mh-face-data 'mh-folder-subject '((t (:inherit mh-folder-subject))))
   "Recipient face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-blocklisted
+(defface mh-folder-blocklisted
   (mh-face-data 'mh-folder-msg-number '((t (:inherit mh-folder-msg-number))))
   "Blocklisted message face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.4"))
 
-(defface-mh mh-folder-body
+(defface mh-folder-body
   (mh-face-data 'mh-folder-msg-number
                 '((((class color))
                    (:inherit mh-folder-msg-number))
@@ -3640,7 +3517,7 @@ specified colors."
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-cur-msg-number
+(defface mh-folder-cur-msg-number
   (mh-face-data 'mh-folder-msg-number
                 '((t (:inherit mh-folder-msg-number :bold t))))
   "Current message number face."
@@ -3648,39 +3525,39 @@ specified colors."
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-date
+(defface mh-folder-date
   (mh-face-data 'mh-folder-msg-number '((t (:inherit mh-folder-msg-number))))
   "Date face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-deleted
+(defface mh-folder-deleted
   (mh-face-data 'mh-folder-msg-number '((t (:inherit mh-folder-msg-number))))
   "Deleted message face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-followup (mh-face-data 'mh-folder-followup)
+(defface mh-folder-followup (mh-face-data 'mh-folder-followup)
   "\"Re:\" face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-msg-number (mh-face-data 'mh-folder-msg-number)
+(defface mh-folder-msg-number (mh-face-data 'mh-folder-msg-number)
   "Message number face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-refiled (mh-face-data 'mh-folder-refiled)
+(defface mh-folder-refiled (mh-face-data 'mh-folder-refiled)
   "Refiled message face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-sent-to-me-hint
+(defface mh-folder-sent-to-me-hint
   (mh-face-data 'mh-folder-msg-number '((t (:inherit mh-folder-date))))
   "Fontification hint face in messages sent directly to us.
 The detection of messages sent to us is governed by the scan
@@ -3690,7 +3567,7 @@ format `mh-scan-format-nmh' and the regular expression
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-sent-to-me-sender
+(defface mh-folder-sent-to-me-sender
   (mh-face-data 'mh-folder-followup '((t (:inherit mh-folder-followup))))
   "Sender face in messages sent directly to us.
 The detection of messages sent to us is governed by the scan
@@ -3700,105 +3577,105 @@ format `mh-scan-format-nmh' and the regular expression
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-subject (mh-face-data 'mh-folder-subject)
+(defface mh-folder-subject (mh-face-data 'mh-folder-subject)
   "Subject face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-tick (mh-face-data 'mh-folder-tick)
+(defface mh-folder-tick (mh-face-data 'mh-folder-tick)
   "Ticked message face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-to (mh-face-data 'mh-folder-to)
+(defface mh-folder-to (mh-face-data 'mh-folder-to)
   "\"To:\" face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-folder-allowlisted
+(defface mh-folder-allowlisted
   (mh-face-data 'mh-folder-refiled '((t (:inherit mh-folder-refiled))))
   "Allowlisted message face."
   :group 'mh-faces
   :group 'mh-folder
   :package-version '(MH-E . "8.4"))
 
-(defface-mh mh-letter-header-field (mh-face-data 'mh-letter-header-field)
+(defface mh-letter-header-field (mh-face-data 'mh-letter-header-field)
   "Editable header field value face in draft buffers."
   :group 'mh-faces
   :group 'mh-letter
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-search-folder (mh-face-data 'mh-search-folder)
+(defface mh-search-folder (mh-face-data 'mh-search-folder)
   "Folder heading face in MH-Folder buffers created by searches."
   :group 'mh-faces
   :group 'mh-search
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-cc (mh-face-data 'mh-show-cc)
+(defface mh-show-cc (mh-face-data 'mh-show-cc)
   "Face used to highlight \"cc:\" header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-date (mh-face-data 'mh-show-date)
+(defface mh-show-date (mh-face-data 'mh-show-date)
   "Face used to highlight \"Date:\" header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-from (mh-face-data 'mh-show-from)
+(defface mh-show-from (mh-face-data 'mh-show-from)
   "Face used to highlight \"From:\" header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-header (mh-face-data 'mh-show-header)
+(defface mh-show-header (mh-face-data 'mh-show-header)
   "Face used to deemphasize less interesting header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-pgg-bad (mh-face-data 'mh-show-pgg-bad)
+(defface mh-show-pgg-bad (mh-face-data 'mh-show-pgg-bad)
   "Bad PGG signature face."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-pgg-good (mh-face-data 'mh-show-pgg-good)
+(defface mh-show-pgg-good (mh-face-data 'mh-show-pgg-good)
   "Good PGG signature face."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-pgg-unknown (mh-face-data 'mh-show-pgg-unknown)
+(defface mh-show-pgg-unknown (mh-face-data 'mh-show-pgg-unknown)
   "Unknown or untrusted PGG signature face."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-signature (mh-face-data 'mh-show-signature)
+(defface mh-show-signature (mh-face-data 'mh-show-signature)
   "Signature face."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-subject
+(defface mh-show-subject
   (mh-face-data 'mh-folder-subject '((t (:inherit mh-folder-subject))))
   "Face used to highlight \"Subject:\" header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-to (mh-face-data 'mh-show-to)
+(defface mh-show-to (mh-face-data 'mh-show-to)
   "Face used to highlight \"To:\" header fields."
   :group 'mh-faces
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-show-xface
+(defface mh-show-xface
   (mh-face-data 'mh-show-from '((t (:inherit (mh-show-from highlight)))))
 "X-Face image face.
 The background and foreground are used in the image."
@@ -3806,13 +3683,13 @@ The background and foreground are used in the image."
   :group 'mh-show
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-speedbar-folder (mh-face-data 'mh-speedbar-folder)
+(defface mh-speedbar-folder (mh-face-data 'mh-speedbar-folder)
   "Basic folder face."
   :group 'mh-faces
   :group 'mh-speedbar
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-speedbar-folder-with-unseen-messages
+(defface mh-speedbar-folder-with-unseen-messages
   (mh-face-data 'mh-speedbar-folder
                 '((t (:inherit mh-speedbar-folder :bold t))))
   "Folder face when folder contains unread messages."
@@ -3820,14 +3697,14 @@ The background and foreground are used in the image."
   :group 'mh-speedbar
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-speedbar-selected-folder
+(defface mh-speedbar-selected-folder
   (mh-face-data 'mh-speedbar-selected-folder)
   "Selected folder face."
   :group 'mh-faces
   :group 'mh-speedbar
   :package-version '(MH-E . "8.0"))
 
-(defface-mh mh-speedbar-selected-folder-with-unseen-messages
+(defface mh-speedbar-selected-folder-with-unseen-messages
   (mh-face-data 'mh-speedbar-selected-folder
                 '((t (:inherit mh-speedbar-selected-folder :bold t))))
   "Selected folder face when folder contains unread messages."
diff --git a/lisp/mh-e/mh-folder.el b/lisp/mh-e/mh-folder.el
index 35277ae46a..c700b3348d 100644
--- a/lisp/mh-e/mh-folder.el
+++ b/lisp/mh-e/mh-folder.el
@@ -72,10 +72,8 @@ the MH mail system."
 
 ;;; Desktop Integration
 
-;; desktop-buffer-mode-handlers appeared in Emacs 22.
-(if (boundp 'desktop-buffer-mode-handlers)
-    (add-to-list 'desktop-buffer-mode-handlers
-                 '(mh-folder-mode . mh-restore-desktop-buffer)))
+(add-to-list 'desktop-buffer-mode-handlers
+             '(mh-folder-mode . mh-restore-desktop-buffer))
 
 (defun mh-restore-desktop-buffer (_file-name name _misc)
   "Restore an MH folder buffer specified in a desktop file.
@@ -213,141 +211,137 @@ annotation.")
 (defalias 'mh-alt-visit-folder #'mh-visit-folder)
 
 ;; Save the "b" binding for a future `back'. Maybe?
-(gnus-define-keys  mh-folder-mode-map
-  " "           mh-page-msg
-  "!"           mh-refile-or-write-again
-  "'"           mh-toggle-tick
-  ","           mh-header-display
-  "."           mh-alt-show
-  ":"           mh-show-preferred-alternative
-  ";"           mh-toggle-mh-decode-mime-flag
-  ">"           mh-write-msg-to-file
-  "?"           mh-help
-  "E"           mh-extract-rejected-mail
-  "M"           mh-modify
-  "\177"        mh-previous-page
-  "\C-d"        mh-delete-msg-no-motion
-  "\t"          mh-index-next-folder
-  [backtab]     mh-index-previous-folder
-  "\M-\t"       mh-index-previous-folder
-  "\e<"         mh-first-msg
-  "\e>"         mh-last-msg
-  "\ed"         mh-redistribute
-  "\r"          mh-show
-  "^"           mh-alt-refile-msg
-  "c"           mh-copy-msg
-  "d"           mh-delete-msg
-  "e"           mh-edit-again
-  "f"           mh-forward
-  "g"           mh-goto-msg
-  "i"           mh-inc-folder
-  "k"           mh-delete-subject-or-thread
-  "m"           mh-alt-send
-  "n"           mh-next-undeleted-msg
-  "\M-n"        mh-next-unread-msg
-  "o"           mh-refile-msg
-  "p"           mh-previous-undeleted-msg
-  "\M-p"        mh-previous-unread-msg
-  "q"           mh-quit
-  "r"           mh-reply
-  "s"           mh-send
-  "t"           mh-toggle-showing
-  "u"           mh-undo
-  "v"           mh-index-visit-folder
-  "x"           mh-execute-commands
-  "|"           mh-pipe-msg)
-
-(gnus-define-keys (mh-folder-map "F" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "'"           mh-index-ticked-messages
-  "S"           mh-sort-folder
-  "c"           mh-catchup
-  "f"           mh-alt-visit-folder
-  "k"           mh-kill-folder
-  "l"           mh-list-folders
-  "n"           mh-index-new-messages
-  "o"           mh-alt-visit-folder
-  "p"           mh-pack-folder
-  "q"           mh-index-sequenced-messages
-  "r"           mh-rescan-folder
-  "s"           mh-search
-  "u"           mh-undo-folder
-  "v"           mh-visit-folder)
-
-(define-key mh-folder-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-junk-map "J" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-junk-allowlist
-  "b"           mh-junk-blocklist
-  "w"           mh-junk-whitelist)
-
-(gnus-define-keys (mh-ps-print-map "P" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "C"           mh-ps-print-toggle-color
-  "F"           mh-ps-print-toggle-faces
-  "f"           mh-ps-print-msg-file
-  "l"           mh-print-msg
-  "p"           mh-ps-print-msg)
-
-(gnus-define-keys (mh-sequence-map "S" mh-folder-mode-map)
-  "'"           mh-narrow-to-tick
-  "?"           mh-prefix-help
-  "d"           mh-delete-msg-from-seq
-  "k"           mh-delete-seq
-  "l"           mh-list-sequences
-  "n"           mh-narrow-to-seq
-  "p"           mh-put-msg-in-seq
-  "s"           mh-msg-is-in-seq
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-thread-map "T" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "u"           mh-thread-ancestor
-  "p"           mh-thread-previous-sibling
-  "n"           mh-thread-next-sibling
-  "t"           mh-toggle-threads
-  "d"           mh-thread-delete
-  "o"           mh-thread-refile)
-
-(gnus-define-keys (mh-limit-map "/" mh-folder-mode-map)
-  "'"           mh-narrow-to-tick
-  "?"           mh-prefix-help
-  "c"           mh-narrow-to-cc
-  "g"           mh-narrow-to-range
-  "m"           mh-narrow-to-from
-  "s"           mh-narrow-to-subject
-  "t"           mh-narrow-to-to
-  "w"           mh-widen)
-
-(gnus-define-keys (mh-extract-map "X" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "s"           mh-store-msg            ;shar
-  "u"           mh-store-msg)           ;uuencode
-
-(gnus-define-keys (mh-digest-map "D" mh-folder-mode-map)
-  " "           mh-page-digest
-  "?"           mh-prefix-help
-  "\177"        mh-page-digest-backwards
-  "b"           mh-burst-digest)
-
-(gnus-define-keys (mh-mime-map "K" mh-folder-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-mime-save-parts
-  "e"           mh-display-with-external-viewer
-  "i"           mh-folder-inline-mime-part
-  "o"           mh-folder-save-mime-part
-  "t"           mh-toggle-mime-buttons
-  "v"           mh-folder-toggle-mime-part
-  "\t"          mh-next-button
-  [backtab]     mh-prev-button
-  "\M-\t"       mh-prev-button)
-
-(cond
- ((featurep 'xemacs)
-  (define-key mh-folder-mode-map [button2] 'mh-show-mouse))
- (t
-  (define-key mh-folder-mode-map [mouse-2] 'mh-show-mouse)))
+(define-keymap :keymap mh-folder-mode-map
+  " "           #'mh-page-msg
+  "!"           #'mh-refile-or-write-again
+  "'"           #'mh-toggle-tick
+  ","           #'mh-header-display
+  "."           #'mh-alt-show
+  ":"           #'mh-show-preferred-alternative
+  ";"           #'mh-toggle-mh-decode-mime-flag
+  ">"           #'mh-write-msg-to-file
+  "?"           #'mh-help
+  "E"           #'mh-extract-rejected-mail
+  "M"           #'mh-modify
+  "\177"        #'mh-previous-page
+  "\C-d"        #'mh-delete-msg-no-motion
+  "\t"          #'mh-index-next-folder
+  [backtab]     #'mh-index-previous-folder
+  "\M-\t"       #'mh-index-previous-folder
+  "\e<"         #'mh-first-msg
+  "\e>"         #'mh-last-msg
+  "\ed"         #'mh-redistribute
+  "\r"          #'mh-show
+  "^"           #'mh-alt-refile-msg
+  "c"           #'mh-copy-msg
+  "d"           #'mh-delete-msg
+  "e"           #'mh-edit-again
+  "f"           #'mh-forward
+  "g"           #'mh-goto-msg
+  "i"           #'mh-inc-folder
+  "k"           #'mh-delete-subject-or-thread
+  "m"           #'mh-alt-send
+  "n"           #'mh-next-undeleted-msg
+  "\M-n"        #'mh-next-unread-msg
+  "o"           #'mh-refile-msg
+  "p"           #'mh-previous-undeleted-msg
+  "\M-p"        #'mh-previous-unread-msg
+  "q"           #'mh-quit
+  "r"           #'mh-reply
+  "s"           #'mh-send
+  "t"           #'mh-toggle-showing
+  "u"           #'mh-undo
+  "v"           #'mh-index-visit-folder
+  "x"           #'mh-execute-commands
+  "|"           #'mh-pipe-msg
+
+  "F" (define-keymap :prefix 'mh-folder-map
+        "?"           #'mh-prefix-help
+        "'"           #'mh-index-ticked-messages
+        "S"           #'mh-sort-folder
+        "c"           #'mh-catchup
+        "f"           #'mh-alt-visit-folder
+        "k"           #'mh-kill-folder
+        "l"           #'mh-list-folders
+        "n"           #'mh-index-new-messages
+        "o"           #'mh-alt-visit-folder
+        "p"           #'mh-pack-folder
+        "q"           #'mh-index-sequenced-messages
+        "r"           #'mh-rescan-folder
+        "s"           #'mh-search
+        "u"           #'mh-undo-folder
+        "v"           #'mh-visit-folder)
+
+  "I" mh-inc-spool-map
+
+  "J" (define-keymap :prefix 'mh-junk-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-junk-allowlist
+        "b"           #'mh-junk-blocklist
+        "w"           #'mh-junk-whitelist)
+
+  "P" (define-keymap :prefix 'mh-ps-print-map
+        "?"           #'mh-prefix-help
+        "C"           #'mh-ps-print-toggle-color
+        "F"           #'mh-ps-print-toggle-faces
+        "f"           #'mh-ps-print-msg-file
+        "l"           #'mh-print-msg
+        "p"           #'mh-ps-print-msg)
+
+  "S" (define-keymap :prefix 'mh-sequence-map
+        "'"           #'mh-narrow-to-tick
+        "?"           #'mh-prefix-help
+        "d"           #'mh-delete-msg-from-seq
+        "k"           #'mh-delete-seq
+        "l"           #'mh-list-sequences
+        "n"           #'mh-narrow-to-seq
+        "p"           #'mh-put-msg-in-seq
+        "s"           #'mh-msg-is-in-seq
+        "w"           #'mh-widen)
+
+  "T" (define-keymap :prefix 'mh-thread-map
+        "?"           #'mh-prefix-help
+        "u"           #'mh-thread-ancestor
+        "p"           #'mh-thread-previous-sibling
+        "n"           #'mh-thread-next-sibling
+        "t"           #'mh-toggle-threads
+        "d"           #'mh-thread-delete
+        "o"           #'mh-thread-refile)
+
+  "/" (define-keymap :prefix 'mh-limit-map
+        "'"           #'mh-narrow-to-tick
+        "?"           #'mh-prefix-help
+        "c"           #'mh-narrow-to-cc
+        "g"           #'mh-narrow-to-range
+        "m"           #'mh-narrow-to-from
+        "s"           #'mh-narrow-to-subject
+        "t"           #'mh-narrow-to-to
+        "w"           #'mh-widen)
+
+  "X" (define-keymap :prefix 'mh-extract-map
+        "?"           #'mh-prefix-help
+        "s"           #'mh-store-msg    ;shar
+        "u"           #'mh-store-msg)   ;uuencode
+
+  "D" (define-keymap :prefix 'mh-digest-map
+        " "           #'mh-page-digest
+        "?"           #'mh-prefix-help
+        "\177"        #'mh-page-digest-backwards
+        "b"           #'mh-burst-digest)
+
+  "K" (define-keymap :prefix 'mh-mime-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-mime-save-parts
+        "e"           #'mh-display-with-external-viewer
+        "i"           #'mh-folder-inline-mime-part
+        "o"           #'mh-folder-save-mime-part
+        "t"           #'mh-toggle-mime-buttons
+        "v"           #'mh-folder-toggle-mime-part
+        "\t"          #'mh-next-button
+        [backtab]     #'mh-prev-button
+        "\M-\t"       #'mh-prev-button)
+
+  [mouse-2] #'mh-show-mouse)
 
 ;; "C-c /" prefix is used in mh-folder-mode by pgp.el and mailcrypt
 
@@ -512,24 +506,14 @@ font-lock is done highlighting.")
 ;;; MH-Folder Mode
 
 (defmacro mh-remove-xemacs-horizontal-scrollbar ()
-  "Get rid of the horizontal scrollbar that XEmacs insists on putting in."
-  (when (featurep 'xemacs)
-    '(if (and (featurep 'scrollbar)
-              (fboundp 'set-specifier))
-         (set-specifier horizontal-scrollbar-visible-p nil
-                        (cons (current-buffer) nil)))))
+  (declare (obsolete nil "29.1"))
+  nil)
 
 ;; Register mh-folder-mode as supporting which-function-mode...
-(eval-and-compile (mh-require 'which-func nil t))
+(eval-and-compile (require 'which-func nil t))
 (when (and (boundp 'which-func-modes) (listp which-func-modes))
   (add-to-list 'which-func-modes 'mh-folder-mode))
 
-;; Shush compiler.
-(defvar desktop-save-buffer)
-(defvar font-lock-auto-fontify)
-(mh-do-in-xemacs
-  (defvar font-lock-defaults))
-
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-folder-mode 'mode-class 'special)
 
@@ -590,80 +574,68 @@ region in the MH-Folder buffer, then the MH-E command will
 perform the operation on all messages in that region.
 
 \\{mh-folder-mode-map}"
-  (mh-do-in-gnu-emacs
-    (unless mh-folder-tool-bar-map
-        (mh-tool-bar-folder-buttons-init))
-    (if (boundp 'tool-bar-map)
-        (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :folder))
+  (unless mh-folder-tool-bar-map
+    (mh-tool-bar-folder-buttons-init))
+  (if (boundp 'tool-bar-map)
+      (setq-local tool-bar-map mh-folder-tool-bar-map))
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(mh-folder-font-lock-keywords t))
   (make-local-variable 'desktop-save-buffer)
   (setq desktop-save-buffer t)
-  (mh-make-local-vars
-   'mh-colors-available-flag (mh-colors-available-p)
+  (setq-local
+   mh-colors-available-flag (mh-colors-available-p)
                                         ; Do we have colors available
-   'mh-current-folder (buffer-name)     ; Name of folder, a string
-   'mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
-   'mh-folder-filename                  ; e.g. "/usr/foobar/Mail/inbox/"
+   mh-current-folder (buffer-name)      ; Name of folder, a string
+   mh-show-buffer (format "show-%s" (buffer-name)) ; Buffer that displays msgs
+   mh-folder-filename                   ; e.g. "/usr/foobar/Mail/inbox/"
    (file-name-as-directory (mh-expand-file-name (buffer-name)))
-   'mh-display-buttons-for-inline-parts-flag
+   mh-display-buttons-for-inline-parts-flag
    mh-display-buttons-for-inline-parts-flag ; Allow for display of buttons to
                                         ; be  toggled.
-   'mh-arrow-marker (make-marker)       ; Marker where arrow is displayed
-   'overlay-arrow-position nil          ; Allow for simultaneous display in
-   'overlay-arrow-string ">"            ;  different MH-E buffers.
-   'mh-showing-mode nil                 ; Show message also?
-   'mh-refile-list nil                  ; List of folder names in mh-seq-list
-   'mh-delete-list nil                  ; List of msgs nums to delete
-   'mh-blocklist nil                    ; List of messages to process as spam
-   'mh-allowlist nil                    ; List of messages to process as ham
-   'mh-seq-list nil                     ; Alist of (seq . msgs) nums
-   'mh-seen-list nil                    ; List of displayed messages
-   'mh-next-direction 'forward          ; Direction to move to next message
-   'mh-view-ops ()                      ; Stack that keeps track of the order
+   mh-arrow-marker (make-marker)        ; Marker where arrow is displayed
+   overlay-arrow-position nil           ; Allow for simultaneous display in
+   overlay-arrow-string ">"             ;  different MH-E buffers.
+   mh-showing-mode nil                  ; Show message also?
+   mh-refile-list nil                   ; List of folder names in mh-seq-list
+   mh-delete-list nil                   ; List of msgs nums to delete
+   mh-blocklist nil                     ; List of messages to process as spam
+   mh-allowlist nil                     ; List of messages to process as ham
+   mh-seq-list nil                      ; Alist of (seq . msgs) nums
+   mh-seen-list nil                     ; List of displayed messages
+   mh-next-direction 'forward           ; Direction to move to next message
+   mh-view-ops ()                       ; Stack that keeps track of the order
                                         ; in which narrowing/threading has been
                                         ; carried out.
-   'mh-folder-view-stack ()             ; Stack of previous views of the
+   mh-folder-view-stack ()              ; Stack of previous views of the
                                         ; folder.
-   'mh-index-data nil                   ; If the folder was created by a call
+   mh-index-data nil                    ; If the folder was created by a call
                                         ; to mh-search, this contains info
                                         ; about the search results.
-   'mh-index-previous-search nil        ; folder, indexer, search-regexp
-   'mh-index-msg-checksum-map nil       ; msg -> checksum map
-   'mh-index-checksum-origin-map nil    ; checksum -> ( orig-folder, orig-msg )
-   'mh-index-sequence-search-flag nil   ; folder resulted from sequence search
-   'mh-first-msg-num nil                ; Number of first msg in buffer
-   'mh-last-msg-num nil                 ; Number of last msg in buffer
-   'mh-msg-count nil                    ; Number of msgs in buffer
-   'mh-mode-line-annotation nil         ; Indicates message range
-   'mh-sequence-notation-history (make-hash-table)
+   mh-index-previous-search nil         ; folder, indexer, search-regexp
+   mh-index-msg-checksum-map nil        ; msg -> checksum map
+   mh-index-checksum-origin-map nil     ; checksum -> ( orig-folder, orig-msg )
+   mh-index-sequence-search-flag nil    ; folder resulted from sequence search
+   mh-first-msg-num nil                 ; Number of first msg in buffer
+   mh-last-msg-num nil                  ; Number of last msg in buffer
+   mh-msg-count nil                     ; Number of msgs in buffer
+   mh-mode-line-annotation nil          ; Indicates message range
+   mh-sequence-notation-history (make-hash-table)
                                         ; Remember what is overwritten by
                                         ; mh-note-seq.
-   'imenu-create-index-function 'mh-index-create-imenu-index
+   imenu-create-index-function 'mh-index-create-imenu-index
                                         ; Setup imenu support
-   'mh-previous-window-config nil)      ; Previous window configuration
-  (mh-remove-xemacs-horizontal-scrollbar)
+   mh-previous-window-config nil)       ; Previous window configuration
   (setq truncate-lines t)
   (auto-save-mode -1)
   (setq buffer-offer-save t)
-  (mh-make-local-hook (mh-write-file-functions))
-  (add-hook (mh-write-file-functions) #'mh-execute-commands nil t)
+  (add-hook 'write-file-functions #'mh-execute-commands nil t)
   (make-local-variable 'revert-buffer-function)
   (make-local-variable 'hl-line-mode)   ; avoid pollution
   (mh-funcall-if-exists hl-line-mode 1)
   (setq revert-buffer-function #'mh-undo-folder)
   (add-to-list 'minor-mode-alist '(mh-showing-mode " Show"))
-  (mh-do-in-xemacs
-    (easy-menu-add mh-folder-sequence-menu)
-    (easy-menu-add mh-folder-message-menu)
-    (easy-menu-add mh-folder-folder-menu))
   (mh-inc-spool-make)
-  (mh-set-help mh-folder-mode-help-messages)
-  (if (and (featurep 'xemacs)
-           font-lock-auto-fontify)
-      (turn-on-font-lock)))             ; Force font-lock in XEmacs.
+  (mh-set-help mh-folder-mode-help-messages))
 
 
 
@@ -1571,35 +1543,35 @@ after the commands are processed."
               (append folders-changed (mh-index-execute-commands))))
 
       ;; Then refile messages
-      (mh-mapc #'(lambda (folder-msg-list)
-                   (let* ((dest-folder (symbol-name (car folder-msg-list)))
-                          (last (car (mh-translate-range dest-folder "last")))
-                          (msgs (cdr folder-msg-list)))
-                     (push dest-folder folders-changed)
-                     (setq redraw-needed-flag t)
-                     (apply #'mh-exec-cmd
-                            "refile" "-src" folder dest-folder
-                            (mh-coalesce-msg-list msgs))
-                     (mh-delete-scan-msgs msgs)
-                     ;; Preserve sequences in destination folder...
-                     (when mh-refile-preserves-sequences-flag
-                       (clrhash dest-map)
-                       (cl-loop
-                        for i from (1+ (or last 0))
-                        for msg in (sort (copy-sequence msgs) #'<)
-                        do (cl-loop for seq-name in (gethash msg seq-map)
-                                    do (push i (gethash seq-name dest-map))))
-                       (maphash
-                        #'(lambda (seq msgs)
-                            ;; Can't be run in the background, since the
-                            ;; current folder is changed by mark this could
-                            ;; lead to a race condition with the next refile.
-                            (apply #'mh-exec-cmd "mark"
-                                   "-sequence" (symbol-name seq) dest-folder
-                                   "-add" (mapcar #'(lambda (x) (format "%s" 
x))
-                                                  (mh-coalesce-msg-list 
msgs))))
-                        dest-map))))
-               mh-refile-list)
+      (mapc (lambda (folder-msg-list)
+              (let* ((dest-folder (symbol-name (car folder-msg-list)))
+                     (last (car (mh-translate-range dest-folder "last")))
+                     (msgs (cdr folder-msg-list)))
+                (push dest-folder folders-changed)
+                (setq redraw-needed-flag t)
+                (apply #'mh-exec-cmd
+                       "refile" "-src" folder dest-folder
+                       (mh-coalesce-msg-list msgs))
+                (mh-delete-scan-msgs msgs)
+                ;; Preserve sequences in destination folder...
+                (when mh-refile-preserves-sequences-flag
+                  (clrhash dest-map)
+                  (cl-loop
+                   for i from (1+ (or last 0))
+                   for msg in (sort (copy-sequence msgs) #'<)
+                   do (cl-loop for seq-name in (gethash msg seq-map)
+                               do (push i (gethash seq-name dest-map))))
+                  (maphash
+                   #'(lambda (seq msgs)
+                       ;; Can't be run in the background, since the
+                       ;; current folder is changed by mark this could
+                       ;; lead to a race condition with the next refile.
+                       (apply #'mh-exec-cmd "mark"
+                              "-sequence" (symbol-name seq) dest-folder
+                              "-add" (mapcar #'(lambda (x) (format "%s" x))
+                                             (mh-coalesce-msg-list msgs))))
+                   dest-map))))
+            mh-refile-list)
       (setq mh-refile-list ())
 
       ;; Now delete messages
@@ -1642,14 +1614,14 @@ after the commands are processed."
                      do (cl-loop for seq-name in (gethash msg seq-map)
                                  do (push i (gethash seq-name allow-map))))
             (maphash
-             #'(lambda (seq msgs)
-                 ;; Can't be run in background, since the current
-                 ;; folder is changed by mark this could lead to a
-                 ;; race condition with the next refile/allowlist.
-                 (apply #'mh-exec-cmd "mark"
-                        "-sequence" (symbol-name seq) mh-inbox
-                        "-add" (mapcar #'(lambda(x) (format "%s" x))
-                                       (mh-coalesce-msg-list msgs))))
+             (lambda (seq msgs)
+               ;; Can't be run in background, since the current
+               ;; folder is changed by mark this could lead to a
+               ;; race condition with the next refile/allowlist.
+               (apply #'mh-exec-cmd "mark"
+                      "-sequence" (symbol-name seq) mh-inbox
+                      "-add" (mapcar #'(lambda(x) (format "%s" x))
+                                     (mh-coalesce-msg-list msgs))))
              allow-map))
           (setq mh-allowlist nil)))
 
diff --git a/lisp/mh-e/mh-funcs.el b/lisp/mh-e/mh-funcs.el
index 4a5e670c1e..0c73aae0d7 100644
--- a/lisp/mh-e/mh-funcs.el
+++ b/lisp/mh-e/mh-funcs.el
@@ -147,7 +147,7 @@ Display the results only if something went wrong."
                                             "-recurse"
                                           "-norecurse"))
         (goto-char (point-min))
-        (mh-view-mode-enter)
+        (view-mode-enter)
         (setq view-exit-action 'kill-buffer)
         (message "Listing folders...done")))))
 
diff --git a/lisp/mh-e/mh-gnus.el b/lisp/mh-e/mh-gnus.el
index cc60f7b664..0e1bde71f2 100644
--- a/lisp/mh-e/mh-gnus.el
+++ b/lisp/mh-e/mh-gnus.el
@@ -29,110 +29,49 @@
 (require 'mh-e)
 
 (eval-and-compile
-  (mh-require 'gnus-util nil t)
-  (mh-require 'mm-bodies nil t)
-  (mh-require 'mm-decode nil t)
-  (mh-require 'mm-view nil t)
-  (mh-require 'mml nil t))
-
-;; Copy of function from gnus-util.el.
-;; TODO This is not in Gnus 5.11.
-(defun-mh mh-gnus-local-map-property gnus-local-map-property (map)
+  (require 'gnus-util nil t)
+  (require 'mm-bodies nil t)
+  (require 'mm-decode nil t)
+  (require 'mm-view nil t)
+  (require 'mml nil t))
+
+(defun mh-gnus-local-map-property (map)
   "Return a list suitable for a text property list specifying keymap MAP."
-  (cond ((featurep 'xemacs) (list 'keymap map))
-        ((>= emacs-major-version 21) (list 'keymap map))
-        (t (list 'local-map map))))
-
-;; Copy of function from mm-decode.el.
-(defun-mh mh-mm-merge-handles mm-merge-handles (handles1 handles2)
-  (append
-   (if (listp (car handles1))
-       handles1
-     (list handles1))
-   (if (listp (car handles2))
-       handles2
-     (list handles2))))
-
-;; Copy of function from mm-decode.el.
-(defun-mh mh-mm-set-handle-multipart-parameter
-  mm-set-handle-multipart-parameter (handle parameter value)
-  ;; HANDLE could be a CTL.
-  (when handle
-    (put-text-property 0 (length (car handle)) parameter value
-                      (car handle))))
-
-;; Copy of function from mm-view.el.
-(defun-mh mh-mm-inline-text-vcard mm-inline-text-vcard (handle)
-  (let ((inhibit-read-only t))
-    (mm-insert-inline
-     handle
-     (concat "\n-- \n"
-            (ignore-errors
-              (if (fboundp 'vcard-pretty-print)
-                  (vcard-pretty-print (mm-get-part handle))
-                (vcard-format-string
-                 (vcard-parse-string (mm-get-part handle)
-                                     'vcard-standard-filter))))))))
-
-;; Function from mm-decode.el used in PGP messages. Just define it with older
-;; Gnus to avoid compiler warning.
-(defun-mh mh-mm-possibly-verify-or-decrypt
-  mm-possibly-verify-or-decrypt (_parts _ctl)
-  nil)
-
-;; Copy of macro in mm-decode.el.
-(defmacro-mh mh-mm-handle-multipart-ctl-parameter
-  mm-handle-multipart-ctl-parameter (handle parameter)
-  `(get-text-property 0 ,parameter (car ,handle)))
-
-;; Copy of function in mm-decode.el.
-(defun-mh mh-mm-readable-p mm-readable-p (handle)
-  "Say whether the content of HANDLE is readable."
-  (and (< (with-current-buffer (mm-handle-buffer handle)
-            (buffer-size)) 10000)
-       (mm-with-unibyte-buffer
-         (mm-insert-part handle)
-         (and (eq (mm-body-7-or-8) '7bit)
-              (not (mh-mm-long-lines-p 76))))))
-
-;; Copy of function in mm-bodies.el.
-(defun-mh mh-mm-long-lines-p mm-long-lines-p (length)
-  "Say whether any of the lines in the buffer is longer than LENGTH."
-  (save-excursion
-    (goto-char (point-min))
-    (end-of-line)
-    (while (and (not (eobp))
-                (not (> (current-column) length)))
-      (forward-line 1)
-      (end-of-line))
-    (and (> (current-column) length)
-         (current-column))))
-
-(defun-mh mh-mm-keep-viewer-alive-p mm-keep-viewer-alive-p (_handle)
-  ;; Released Gnus doesn't keep handles associated with externally displayed
-  ;; MIME parts. So this will always return nil.
-  nil)
-
-(defun-mh mh-mm-destroy-parts mm-destroy-parts (_list)
-  "Older versions of Emacs don't have this function."
-  nil)
-
-(defun-mh mh-mm-uu-dissect-text-parts mm-uu-dissect-text-parts (_handles)
-  "Emacs 21 and XEmacs don't have this function."
-  nil)
-
-;; Copy of function in mml.el.
-(defun-mh mh-mml-minibuffer-read-disposition
-  mml-minibuffer-read-disposition (type &optional default filename)
-  (unless default
-    (setq default (mml-content-disposition type filename)))
-  (let ((disposition (completing-read
-                     (format-prompt "Disposition" default)
-                     '(("attachment") ("inline") (""))
-                     nil t nil nil default)))
-    (if (not (equal disposition ""))
-       disposition
-      default)))
+  (declare (obsolete nil "29.1"))
+  (list 'keymap map))
+
+(define-obsolete-function-alias 'mh-mm-merge-handles
+  #'mm-merge-handles "29.1")
+
+(define-obsolete-function-alias 'mh-mm-set-handle-multipart-parameter
+  #'mm-set-handle-multipart-parameter "29.1")
+
+(define-obsolete-function-alias 'mh-mm-inline-text-vcard
+  #'mm-inline-text-vcard "29.1")
+
+(define-obsolete-function-alias 'mh-mm-possibly-verify-or-decrypt
+  #'mm-possibly-verify-or-decrypt "29.1")
+
+(define-obsolete-function-alias 'mh-mm-handle-multipart-ctl-parameter
+  #'mm-handle-multipart-ctl-parameter "29.1")
+
+(define-obsolete-function-alias 'mh-mm-readable-p
+  #'mm-readable-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-long-lines-p
+  #'mm-long-lines-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-keep-viewer-alive-p
+  #'mm-keep-viewer-alive-p "29.1")
+
+(define-obsolete-function-alias 'mh-mm-destroy-parts
+  #'mm-destroy-parts "29.1")
+
+(define-obsolete-function-alias 'mh-mm-uu-dissect-text-parts
+  #'mm-uu-dissect-text-parts "29.1")
+
+(define-obsolete-function-alias 'mh-mml-minibuffer-read-disposition
+  #'mml-minibuffer-read-disposition "29.1")
 
 ;; This is mm-save-part from Gnus 5.11 since that function in Emacs
 ;; 21.2 is buggy (the args to read-file-name are incorrect) and the
@@ -163,8 +102,8 @@ PROMPT overrides the default one used to ask user for a 
file name."
 
 (defun mh-mm-text-html-renderer ()
   "Find the renderer Gnus is using to display text/html MIME parts."
-  (or (and (boundp 'mm-inline-text-html-renderer) mm-inline-text-html-renderer)
-      (and (boundp 'mm-text-html-renderer) mm-text-html-renderer)))
+  (declare (obsolete mm-text-html-renderer "29.1"))
+  mm-text-html-renderer)
 
 (provide 'mh-gnus)
 
diff --git a/lisp/mh-e/mh-identity.el b/lisp/mh-e/mh-identity.el
index ceede0d07c..994ab71391 100644
--- a/lisp/mh-e/mh-identity.el
+++ b/lisp/mh-e/mh-identity.el
@@ -39,11 +39,10 @@
 
 (autoload 'mml-insert-tag "mml")
 
-(defvar mh-identity-pgg-default-user-id nil
+(defvar-local mh-identity-pgg-default-user-id nil
   "Holds the GPG key ID to be used by pgg.el.
 This is normally set as part of an Identity in
 `mh-identity-list'.")
-(make-variable-buffer-local 'mh-identity-pgg-default-user-id)
 
 (defvar mh-identity-menu nil
   "The Identity menu.")
@@ -54,8 +53,7 @@ This is normally set as part of an Identity in
 (defun mh-identity-make-menu ()
   "Build the Identity menu.
 This should be called any time `mh-identity-list' or
-`mh-auto-fields-list' change.
-See `mh-identity-add-menu'."
+`mh-auto-fields-list' change."
   (easy-menu-define mh-identity-menu mh-letter-mode-map
     "MH-E identity menu"
     (append
@@ -88,12 +86,11 @@ See `mh-identity-add-menu'."
 (defun mh-identity-add-menu ()
   "Add the current Identity menu.
 See `mh-identity-make-menu'."
-  (if mh-identity-menu
-      (mh-do-in-xemacs (easy-menu-add mh-identity-menu))))
+  (declare (obsolete nil "29.1"))
+  nil)
 
-(defvar mh-identity-local nil
+(defvar-local mh-identity-local nil
   "Buffer-local variable that holds the identity currently in use.")
-(make-variable-buffer-local 'mh-identity-local)
 
 (defun mh-header-field-delete (field value-only)
   "Delete header FIELD, or only its value if VALUE-ONLY is t.
@@ -122,7 +119,7 @@ The field name is downcased. If the FIELD begins with the
 character \":\", then it must have a special handler defined in
 `mh-identity-handlers', else return an error since it is not a
 valid header field."
-  (or (cdr (mh-assoc-string field mh-identity-handlers t))
+  (or (cdr (assoc-string field mh-identity-handlers t))
       (and (eq (aref field 0) ?:)
            (error "Field %s not found in `mh-identity-handlers'" field))
       (cdr (assoc ":default" mh-identity-handlers))
@@ -235,11 +232,9 @@ added."
         (if (null value)
             (mh-insert-signature)
           (mh-insert-signature value))
-        (set (make-local-variable 'mh-identity-signature-start)
-             (point-min-marker))
+        (setq-local mh-identity-signature-start (point-min-marker))
         (set-marker-insertion-type mh-identity-signature-start t)
-        (set (make-local-variable 'mh-identity-signature-end)
-             (point-max-marker)))))))
+        (setq-local mh-identity-signature-end (point-max-marker)))))))
 
 (defvar mh-identity-attribution-verb-start nil
   "Marker for the beginning of the attribution verb.")
@@ -271,11 +266,9 @@ If VALUE is nil, use `mh-extract-from-attribution-verb'."
     (if (null value)
         (insert mh-extract-from-attribution-verb)
       (insert value))
-    (set (make-local-variable 'mh-identity-attribution-verb-start)
-         (point-min-marker))
+    (setq-local mh-identity-attribution-verb-start (point-min-marker))
     (set-marker-insertion-type mh-identity-attribution-verb-start t)
-    (set (make-local-variable 'mh-identity-attribution-verb-end)
-         (point-max-marker))))
+    (setq-local mh-identity-attribution-verb-end (point-max-marker))))
 
 (defun mh-identity-handler-default (field action top &optional value)
   "Process header FIELD.
diff --git a/lisp/mh-e/mh-junk.el b/lisp/mh-e/mh-junk.el
index 467667f5af..2097bcbe1e 100644
--- a/lisp/mh-e/mh-junk.el
+++ b/lisp/mh-e/mh-junk.el
@@ -110,8 +110,15 @@ message(s) as specified by the option 
`mh-junk-disposition'."
 ;;;###mh-autoload
 (defun mh-junk-whitelist (range)
   "Old name for `mh-junk-allowlist'; use \\[mh-junk-allowlist] instead."
-  (declare (obsolete mh-junk-allowlist "28.1"))
   (interactive (list (mh-interactive-range "Allowlist")))
+  ;; We do our own message here instead of using "declare obsolete"
+  ;; in order to talk about keys instead of function names.  Also, it
+  ;; lets us bind "J w" to this without the Emacs 29 compiler complaining.
+  (when (not (get 'mh-junk-whitelist 'command-execute-obsolete-warned))
+    (message "%s is an obsolete key (as of 28.1); use %s instead"
+             (substitute-command-keys "\\[mh-junk-whitelist]")
+             (substitute-command-keys "\\[mh-junk-allowlist]"))
+    (put 'mh-junk-whitelist 'command-execute-obsolete-warned t))
   (mh-junk-allowlist range))
 
 ;;;###mh-autoload
diff --git a/lisp/mh-e/mh-letter.el b/lisp/mh-e/mh-letter.el
index ae5b80d580..1f7902640a 100644
--- a/lisp/mh-e/mh-letter.el
+++ b/lisp/mh-e/mh-letter.el
@@ -114,68 +114,68 @@
 ;;; MH-Letter Keys
 
 ;; If this changes, modify mh-letter-mode-help-messages accordingly, above.
-(gnus-define-keys  mh-letter-mode-map
-  " "                   mh-letter-complete-or-space
-  ","                   mh-letter-confirm-address
-  "\C-c?"               mh-help
-  "\C-c\C-\\"           mh-fully-kill-draft ;if no C-q
-  "\C-c\C-^"            mh-insert-signature ;if no C-s
-  "\C-c\C-c"            mh-send-letter
-  "\C-c\C-d"            mh-insert-identity
-  "\C-c\C-e"            mh-mh-to-mime
-  "\C-c\C-f\C-a"        mh-to-field
-  "\C-c\C-f\C-b"        mh-to-field
-  "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-d"        mh-to-field
-  "\C-c\C-f\C-f"        mh-to-fcc
-  "\C-c\C-f\C-l"        mh-to-field
-  "\C-c\C-f\C-m"        mh-to-field
-  "\C-c\C-f\C-r"        mh-to-field
-  "\C-c\C-f\C-s"        mh-to-field
-  "\C-c\C-f\C-t"        mh-to-field
-  "\C-c\C-fa"           mh-to-field
-  "\C-c\C-fb"           mh-to-field
-  "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fd"           mh-to-field
-  "\C-c\C-ff"           mh-to-fcc
-  "\C-c\C-fl"           mh-to-field
-  "\C-c\C-fm"           mh-to-field
-  "\C-c\C-fr"           mh-to-field
-  "\C-c\C-fs"           mh-to-field
-  "\C-c\C-ft"           mh-to-field
-  "\C-c\C-i"            mh-insert-letter
-  "\C-c\C-m\C-e"        mh-mml-secure-message-encrypt
-  "\C-c\C-m\C-f"        mh-compose-forward
-  "\C-c\C-m\C-g"        mh-mh-compose-anon-ftp
-  "\C-c\C-m\C-i"        mh-compose-insertion
-  "\C-c\C-m\C-m"        mh-mml-to-mime
-  "\C-c\C-m\C-n"        mh-mml-unsecure-message
-  "\C-c\C-m\C-s"        mh-mml-secure-message-sign
-  "\C-c\C-m\C-t"        mh-mh-compose-external-compressed-tar
-  "\C-c\C-m\C-u"        mh-mh-to-mime-undo
-  "\C-c\C-m\C-x"        mh-mh-compose-external-type
-  "\C-c\C-mee"          mh-mml-secure-message-encrypt
-  "\C-c\C-mes"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mf"           mh-compose-forward
-  "\C-c\C-mg"           mh-mh-compose-anon-ftp
-  "\C-c\C-mi"           mh-compose-insertion
-  "\C-c\C-mm"           mh-mml-to-mime
-  "\C-c\C-mn"           mh-mml-unsecure-message
-  "\C-c\C-mse"          mh-mml-secure-message-signencrypt
-  "\C-c\C-mss"          mh-mml-secure-message-sign
-  "\C-c\C-mt"           mh-mh-compose-external-compressed-tar
-  "\C-c\C-mu"           mh-mh-to-mime-undo
-  "\C-c\C-mx"           mh-mh-compose-external-type
-  "\C-c\C-o"            mh-open-line
-  "\C-c\C-q"            mh-fully-kill-draft
-  "\C-c\C-s"            mh-insert-signature
-  "\C-c\C-t"            mh-letter-toggle-header-field-display
-  "\C-c\C-w"            mh-check-whom
-  "\C-c\C-y"            mh-yank-cur-msg
-  "\C-c\M-d"            mh-insert-auto-fields
-  "\M-\t"               mh-letter-complete
-  "\t"                  mh-letter-next-header-field-or-indent
-  [backtab]             mh-letter-previous-header-field)
+(define-keymap :keymap mh-letter-mode-map
+  " "                   #'mh-letter-complete-or-space
+  ","                   #'mh-letter-confirm-address
+  "\C-c?"               #'mh-help
+  "\C-c\C-\\"           #'mh-fully-kill-draft ;if no C-q
+  "\C-c\C-^"            #'mh-insert-signature ;if no C-s
+  "\C-c\C-c"            #'mh-send-letter
+  "\C-c\C-d"            #'mh-insert-identity
+  "\C-c\C-e"            #'mh-mh-to-mime
+  "\C-c\C-f\C-a"        #'mh-to-field
+  "\C-c\C-f\C-b"        #'mh-to-field
+  "\C-c\C-f\C-c"        #'mh-to-field
+  "\C-c\C-f\C-d"        #'mh-to-field
+  "\C-c\C-f\C-f"        #'mh-to-fcc
+  "\C-c\C-f\C-l"        #'mh-to-field
+  "\C-c\C-f\C-m"        #'mh-to-field
+  "\C-c\C-f\C-r"        #'mh-to-field
+  "\C-c\C-f\C-s"        #'mh-to-field
+  "\C-c\C-f\C-t"        #'mh-to-field
+  "\C-c\C-fa"           #'mh-to-field
+  "\C-c\C-fb"           #'mh-to-field
+  "\C-c\C-fc"           #'mh-to-field
+  "\C-c\C-fd"           #'mh-to-field
+  "\C-c\C-ff"           #'mh-to-fcc
+  "\C-c\C-fl"           #'mh-to-field
+  "\C-c\C-fm"           #'mh-to-field
+  "\C-c\C-fr"           #'mh-to-field
+  "\C-c\C-fs"           #'mh-to-field
+  "\C-c\C-ft"           #'mh-to-field
+  "\C-c\C-i"            #'mh-insert-letter
+  "\C-c\C-m\C-e"        #'mh-mml-secure-message-encrypt
+  "\C-c\C-m\C-f"        #'mh-compose-forward
+  "\C-c\C-m\C-g"        #'mh-mh-compose-anon-ftp
+  "\C-c\C-m\C-i"        #'mh-compose-insertion
+  "\C-c\C-m\C-m"        #'mh-mml-to-mime
+  "\C-c\C-m\C-n"        #'mh-mml-unsecure-message
+  "\C-c\C-m\C-s"        #'mh-mml-secure-message-sign
+  "\C-c\C-m\C-t"        #'mh-mh-compose-external-compressed-tar
+  "\C-c\C-m\C-u"        #'mh-mh-to-mime-undo
+  "\C-c\C-m\C-x"        #'mh-mh-compose-external-type
+  "\C-c\C-mee"          #'mh-mml-secure-message-encrypt
+  "\C-c\C-mes"          #'mh-mml-secure-message-signencrypt
+  "\C-c\C-mf"           #'mh-compose-forward
+  "\C-c\C-mg"           #'mh-mh-compose-anon-ftp
+  "\C-c\C-mi"           #'mh-compose-insertion
+  "\C-c\C-mm"           #'mh-mml-to-mime
+  "\C-c\C-mn"           #'mh-mml-unsecure-message
+  "\C-c\C-mse"          #'mh-mml-secure-message-signencrypt
+  "\C-c\C-mss"          #'mh-mml-secure-message-sign
+  "\C-c\C-mt"           #'mh-mh-compose-external-compressed-tar
+  "\C-c\C-mu"           #'mh-mh-to-mime-undo
+  "\C-c\C-mx"           #'mh-mh-compose-external-type
+  "\C-c\C-o"            #'mh-open-line
+  "\C-c\C-q"            #'mh-fully-kill-draft
+  "\C-c\C-s"            #'mh-insert-signature
+  "\C-c\C-t"            #'mh-letter-toggle-header-field-display
+  "\C-c\C-w"            #'mh-check-whom
+  "\C-c\C-y"            #'mh-yank-cur-msg
+  "\C-c\M-d"            #'mh-insert-auto-fields
+  "\M-\t"               #'completion-at-point
+  "\t"                  #'mh-letter-next-header-field-or-indent
+  [backtab]             #'mh-letter-previous-header-field)
 
 ;; "C-c /" prefix is used in mh-letter-mode by pgp.el and mailcrypt.el.
 
@@ -253,17 +253,13 @@ searching for `mh-mail-header-separator' in the buffer."
     (goto-char (point-min))
     (cond ((equal mh-mail-header-separator "") (point-min))
           ((search-forward (format "\n%s\n" mh-mail-header-separator) nil t)
-           (mh-line-beginning-position 0))
+           (line-beginning-position 0))
           (t (point-min)))))
 
 
 
 ;;; MH-Letter Mode
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar font-lock-defaults))
-
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-letter-mode 'mode-class 'special)
 
@@ -295,24 +291,21 @@ order).
   (make-local-variable 'mh-previous-window-config)
   (make-local-variable 'mh-sent-from-folder)
   (make-local-variable 'mh-sent-from-msg)
-  (mh-do-in-gnu-emacs
-    (unless mh-letter-tool-bar-map
-      (mh-tool-bar-letter-buttons-init))
-    (if (boundp 'tool-bar-map)
-        (set (make-local-variable 'tool-bar-map) mh-letter-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :letter))
+  (unless mh-letter-tool-bar-map
+    (mh-tool-bar-letter-buttons-init))
+  (if (boundp 'tool-bar-map)
+      (setq-local tool-bar-map mh-letter-tool-bar-map))
   ;; Set the local value of mh-mail-header-separator according to what is
   ;; present in the buffer...
-  (set (make-local-variable 'mh-mail-header-separator)
-       (save-excursion
-         (goto-char (mh-mail-header-end))
-         (buffer-substring-no-properties (point) (mh-line-end-position))))
+  (setq-local mh-mail-header-separator
+              (save-excursion
+                (goto-char (mh-mail-header-end))
+                (buffer-substring-no-properties (point) (line-end-position))))
   (make-local-variable 'mail-header-separator)
   (setq mail-header-separator mh-mail-header-separator) ;override sendmail.el
   (mh-set-help mh-letter-mode-help-messages)
   (setq buffer-invisibility-spec '((vanish . t) t))
-  (set (make-local-variable 'line-move-ignore-invisible) t)
+  (setq-local line-move-ignore-invisible t)
 
   ;; Enable undo since a show-mode buffer might have been reused.
   (buffer-enable-undo)
@@ -328,12 +321,10 @@ order).
    (t
     ;; ...or the header only
     (setq font-lock-defaults '((mh-show-font-lock-keywords) t))))
-  (mh-do-in-xemacs (easy-menu-add mh-letter-menu))
   ;; Maybe we want to use the existing Mail menu from mail-mode in
   ;; 9.0; in the mean time, let's remove it since the redundancy will
   ;; only produce confusion.
   (define-key mh-letter-mode-map [menu-bar mail] #'undefined)
-  (mh-do-in-xemacs (easy-menu-remove mail-menubar-menu))
   (setq fill-column mh-letter-fill-column)
   (add-hook 'completion-at-point-functions
             #'mh-letter-completion-at-point nil 'local)
@@ -488,29 +479,8 @@ This provides alias and folder completion in header fields 
according to
         (or (funcall func) #'ignore)
       mh-letter-complete-function)))
 
-;; TODO Now that completion-at-point performs the task of
-;; mh-letter-complete, perhaps mh-letter-complete along with
-;; mh-complete-word should be rewritten as a more general function for
-;; XEmacs, renamed to mh-completion-at-point, and moved to
-;; mh-compat.el.
-(defun-mh mh-letter-complete completion-at-point ()
-  "Perform completion on header field or word preceding point.
-
-If the field contains addresses (for example, \"To:\" or \"Cc:\")
-or folders (for example, \"Fcc:\") then this command will provide
-alias completion. In the body of the message, this command runs
-`mh-letter-complete-function' instead, which is set to
-`ispell-complete-word' by default."
-      (interactive)
-      (let ((data (mh-letter-completion-at-point)))
-        (cond
-         ((functionp data) (funcall data))
-         ((consp data)
-          (let ((start (nth 0 data))
-                (end (nth 1 data))
-                (table (nth 2 data)))
-            (mh-complete-word (buffer-substring-no-properties start end)
-                              table start end))))))
+(define-obsolete-function-alias 'mh-letter-complete
+  #'completion-at-point "29.1")
 
 (defun mh-letter-complete-or-space (arg)
   "Perform completion or insert space.
@@ -530,7 +500,7 @@ one space."
           ((> (point) end-of-prev) (self-insert-command arg))
           ((let ((mh-letter-complete-function nil))
              (mh-letter-completion-at-point))
-           (mh-letter-complete))
+           (completion-at-point))
           (t (self-insert-command arg)))))
 
 (defun mh-letter-confirm-address ()
@@ -722,7 +692,7 @@ and `mh-ins-buf-prefix' is not inserted."
           ;; Find displayed message
           (with-current-buffer show-buffer
             (let* ((from-attr (mh-extract-from-attribution))
-                   (yank-region (mh-mark-active-p nil))
+                   (yank-region mark-active)
                    (mh-ins-str
                     (cond ((and yank-region
                                 (or (eq 'supercite mh-yank-behavior)
@@ -834,7 +804,7 @@ body."
           ((< (point) (progn
                         (beginning-of-line)
                         (re-search-forward mh-letter-header-field-regexp
-                                           (mh-line-end-position) t)
+                                           (line-end-position) t)
                         (point)))
            (beginning-of-line))
           (t (end-of-line)))
diff --git a/lisp/mh-e/mh-limit.el b/lisp/mh-e/mh-limit.el
index 39cf7c5d27..a00252284a 100644
--- a/lisp/mh-e/mh-limit.el
+++ b/lisp/mh-e/mh-limit.el
@@ -124,7 +124,7 @@ Use \\<mh-folder-mode-map>\\[mh-widen] to undo this 
command."
   (setq pick-expr
         (let ((case-fold-search t))
           (cl-loop for s in pick-expr
-                   collect (mh-replace-regexp-in-string "re: *" "" s))))
+                   collect (replace-regexp-in-string "re: *" "" s))))
   (mh-narrow-to-header-field 'subject pick-expr))
 
 ;;;###mh-autoload
@@ -214,7 +214,7 @@ Return number of messages put in the sequence:
             (string-equal "" (match-string 3)))
         (progn (message "No subject line")
                nil)
-      (let ((subject (mh-match-string-no-properties 3))
+      (let ((subject (match-string-no-properties 3))
             (list))
         (if (> (length subject) mh-limit-max-subject-size)
             (setq subject (substring subject 0 mh-limit-max-subject-size)))
@@ -222,7 +222,7 @@ Return number of messages put in the sequence:
           (if all
               (goto-char (point-min)))
           (while (re-search-forward mh-scan-subject-regexp nil t)
-            (let ((this-subject (mh-match-string-no-properties 3)))
+            (let ((this-subject (match-string-no-properties 3)))
               (if (> (length this-subject) mh-limit-max-subject-size)
                   (setq this-subject (substring this-subject
                                                 0 mh-limit-max-subject-size)))
@@ -313,7 +313,7 @@ The MH command pick is used to do the match."
       (while (not (eobp))
         (let ((num (ignore-errors
                      (string-to-number
-                      (buffer-substring (point) (mh-line-end-position))))))
+                      (buffer-substring (point) (line-end-position))))))
           (when num (push num msg-list))
           (forward-line))))
     (if (null msg-list)
diff --git a/lisp/mh-e/mh-mime.el b/lisp/mh-e/mh-mime.el
index ad594aef90..0b58d7ba1f 100644
--- a/lisp/mh-e/mh-mime.el
+++ b/lisp/mh-e/mh-mime.el
@@ -135,13 +135,11 @@
     ("application/emacs-lisp" mm-display-elisp-inline identity)
     ("application/x-emacs-lisp" mm-display-elisp-inline identity)
     ("text/html"
-     ,(if (fboundp 'mm-inline-text-html) 'mm-inline-text-html 'mm-inline-text)
+     mm-inline-text-html
      (lambda (handle)
-       (or (and (boundp 'mm-inline-text-html-renderer)
-                mm-inline-text-html-renderer)
-           (and (boundp 'mm-text-html-renderer) mm-text-html-renderer))))
+       mm-text-html-renderer))
     ("text/x-vcard"
-     mh-mm-inline-text-vcard
+     mm-inline-text-vcard
      (lambda (handle)
        (or (featurep 'vcard)
            (locate-library "vcard"))))
@@ -171,7 +169,7 @@
     ("audio/.*" ignore ignore)
     ("image/.*" ignore ignore)
     ;; Default to displaying as text
-    (".*" mm-inline-text mh-mm-readable-p))
+    (".*" mm-inline-text mm-readable-p))
   "Alist of media types/tests saying whether types can be displayed inline.")
 
 (defvar mh-mime-save-parts-directory nil
@@ -184,13 +182,7 @@ Set from last use.")
   '((mh-press-button "\r" "Toggle Display")))
 (defvar mh-mime-button-map
   (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      ;; XEmacs doesn't care.
-      (set-keymap-parent map mh-show-mode-map))
-    (mh-do-in-gnu-emacs
-     (define-key map [mouse-2] #'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) #'mh-push-button))
+    (define-key map [mouse-2] #'mh-push-button)
     (dolist (c mh-mime-button-commands)
       (define-key map (cadr c) (car c)))
     map))
@@ -210,13 +202,8 @@ Set from last use.")
     (?D pressed-details ?s)))
 (defvar mh-mime-security-button-map
   (let ((map (make-sparse-keymap)))
-    (unless (>= (string-to-number emacs-version) 21)
-      (set-keymap-parent map mh-show-mode-map))
     (define-key map "\r" #'mh-press-button)
-    (mh-do-in-gnu-emacs
-     (define-key map [mouse-2] #'mh-push-button))
-    (mh-do-in-xemacs
-     (define-key map '(button2) #'mh-push-button))
+    (define-key map [mouse-2] #'mh-push-button)
     map))
 
 
@@ -251,24 +238,24 @@ usually reads the file \"/etc/mailcap\"."
   (when (consp part-index) (setq part-index (car part-index)))
   (mh-folder-mime-action
    part-index
-   #'(lambda ()
-       (let* ((part (get-text-property (point) 'mh-data))
-              (type (mm-handle-media-type part))
-              (methods (mapcar (lambda (x) (list (cdr (assoc 'viewer x))))
-                               (mailcap-mime-info type 'all)))
-              (def (caar methods))
-              (prompt (format-prompt "Viewer" def))
-              (method (completing-read prompt methods nil nil nil nil def))
-              (folder mh-show-folder-buffer)
-              (buffer-read-only nil))
-         (when (string-match "^[^% \t]+$" method)
-           (setq method (concat method " %s")))
-         (mh-flet
-          ((mm-handle-set-external-undisplayer
-            (handle function)
-            (mh-handle-set-external-undisplayer folder handle function)))
-          (unwind-protect (mm-display-external part method)
-            (set-buffer-modified-p nil)))))
+   (lambda ()
+     (let* ((part (get-text-property (point) 'mh-data))
+            (type (mm-handle-media-type part))
+            (methods (mapcar (lambda (x) (list (cdr (assoc 'viewer x))))
+                             (mailcap-mime-info type 'all)))
+            (def (caar methods))
+            (prompt (format-prompt "Viewer" def))
+            (method (completing-read prompt methods nil nil nil nil def))
+            (folder mh-show-folder-buffer)
+            (buffer-read-only nil))
+       (when (string-match "^[^% \t]+$" method)
+         (setq method (concat method " %s")))
+       (mh-flet
+        ((mm-handle-set-external-undisplayer
+          (handle function)
+          (mh-handle-set-external-undisplayer folder handle function)))
+        (unwind-protect (mm-display-external part method)
+          (set-buffer-modified-p nil)))))
    nil))
 
 ;;;###mh-autoload
@@ -299,14 +286,14 @@ the attachment labeled with that number."
          start end)
     (cond ((and data (not inserted-flag) (not displayed-flag))
            (let ((contents (mm-get-part data)))
-             (add-text-properties (mh-line-beginning-position)
-                                  (mh-line-end-position) '(mh-mime-inserted t))
+             (add-text-properties (line-beginning-position)
+                                  (line-end-position) '(mh-mime-inserted t))
              (setq start (point-marker))
              (forward-line 1)
              (mm-insert-inline data contents)
              (setq end (point-marker))
              (add-text-properties
-              start (progn (goto-char start) (mh-line-end-position))
+              start (progn (goto-char start) (line-end-position))
               `(mh-region (,start . ,end)))))
           ((and data (or inserted-flag displayed-flag))
            (mh-press-button)
@@ -458,10 +445,10 @@ decoding the same message multiple times."
              (setf (gethash handle (mh-mime-handles-cache (mh-buffer-data)))
                    (let ((handles (mm-dissect-buffer nil)))
                      (if handles
-                         (mh-mm-uu-dissect-text-parts handles)
+                         (mm-uu-dissect-text-parts handles)
                        (setq handles (mm-uu-dissect)))
                      (setf (mh-mime-handles (mh-buffer-data))
-                           (mh-mm-merge-handles
+                           (mm-merge-handles
                             handles (mh-mime-handles (mh-buffer-data))))
                      handles))))
 
@@ -532,10 +519,10 @@ parsed and then displayed."
            (if pre-dissected-handles
                (setq handles pre-dissected-handles)
              (if (setq handles (mm-dissect-buffer nil))
-                 (mh-mm-uu-dissect-text-parts handles)
+                 (mm-uu-dissect-text-parts handles)
                (setq handles (mm-uu-dissect)))
              (setf (mh-mime-handles (mh-buffer-data))
-                   (mh-mm-merge-handles handles
+                   (mm-merge-handles handles
                                         (mh-mime-handles (mh-buffer-data))))
              (unless handles
                (mh-decode-message-body)))
@@ -641,7 +628,7 @@ buttons for alternative parts that are usually suppressed."
     (let ((mh-mime-security-button-line-format
            mh-mime-security-button-end-line-format))
       (mh-insert-mime-security-button handle))
-    (mh-mm-set-handle-multipart-parameter
+    (mm-set-handle-multipart-parameter
      handle 'mh-region (cons (point-min-marker) (point-max-marker)))))
 
 (defun mh-mime-display-single (handle)
@@ -752,8 +739,8 @@ buttons for alternative parts that are usually suppressed."
         (mh-insert-mime-button handle id (mm-handle-displayed-p handle))
         (goto-char point)
         (when region
-          (add-text-properties (mh-line-beginning-position)
-                               (mh-line-end-position)
+          (add-text-properties (line-beginning-position)
+                               (line-end-position)
                                `(mh-region ,region)))))))
 
 (defun mh-mime-part-index (handle)
@@ -777,20 +764,12 @@ This is only useful if a Content-Disposition header is 
not present."
                                         ; this only tells us if the image is
                                         ; something that emacs can display
          (let ((image (mm-get-image handle)))
-           (or (mh-do-in-xemacs
-                 (and (mh-funcall-if-exists glyphp image)
-                      (< (glyph-width image)
-                         (or mh-max-inline-image-width (window-pixel-width)))
-                      (< (glyph-height image)
-                         (or mh-max-inline-image-height
-                             (window-pixel-height)))))
-               (mh-do-in-gnu-emacs
-                 (let ((size (and (fboundp 'image-size) (image-size image))))
-                   (and size
-                        (< (cdr size) (or mh-max-inline-image-height
-                                          (1- (window-height))))
-                        (< (car size) (or mh-max-inline-image-width
-                                          (window-width)))))))))))
+           (let ((size (and (fboundp 'image-size) (image-size image))))
+             (and size
+                  (< (cdr size) (or mh-max-inline-image-height
+                                    (1- (window-height))))
+                  (< (car size) (or mh-max-inline-image-width
+                                    (window-width)))))))))
 
 (defun mh-inline-vcard-p (handle)
   "Decide if HANDLE is a vcard that must be displayed inline."
@@ -813,27 +792,19 @@ being used to highlight the signature in a MIME part."
                ((not (and (equal (mm-handle-media-supertype handle) "text")
                           (equal (mm-handle-media-subtype handle) "html")))
                 "^-- $")
-               ((eq (mh-mm-text-html-renderer) 'lynx) "^   --$")
+               ((eq mm-text-html-renderer 'lynx) "^   --$")
                (t "^--$"))))
     (save-excursion
       (goto-char (point-max))
       (when (re-search-backward regexp nil t)
-        (mh-do-in-gnu-emacs
-          (let ((ov (make-overlay (point) (point-max))))
-            (overlay-put ov 'face 'mh-show-signature)
-            (overlay-put ov 'evaporate t)))
-        (mh-do-in-xemacs
-          (set-extent-property (make-extent (point) (point-max))
-                               'face 'mh-show-signature))))))
+        (let ((ov (make-overlay (point) (point-max))))
+          (overlay-put ov 'face 'mh-show-signature)
+          (overlay-put ov 'evaporate t))))))
 
 
 
 ;;; Button Display
 
-;; Shush compiler.
-(mh-do-in-xemacs
- (defvar ov))
-
 (defun mh-insert-mime-button (handle index displayed)
   "Insert MIME button for HANDLE.
 INDEX is the part number that will be DISPLAYED. It is also used
@@ -865,10 +836,10 @@ by commands like \"K v\" which operate on individual MIME 
parts."
       (setq begin (point))
       (gnus-eval-format
        mh-mime-button-line-format mh-mime-button-line-format-alist
-       `(,@(mh-gnus-local-map-property mh-mime-button-map)
-         mh-callback mh-mm-display-part
-         mh-part ,index
-         mh-data ,handle)))
+       `(keymap ,mh-mime-button-map
+                mh-callback mh-mm-display-part
+                mh-part ,index
+                mh-data ,handle)))
     (setq end (point))
     (widget-convert-button
      'link begin end
@@ -877,16 +848,12 @@ by commands like \"K v\" which operate on individual MIME 
parts."
      :button-keymap mh-mime-button-map
      :help-echo
      "Mouse-2 click or press RET (in show buffer) to toggle display")
-    (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-      (mh-funcall-if-exists overlay-put ov 'evaporate t))))
-
-;; Shush compiler.
-(defvar mm-verify-function-alist)       ; < Emacs 22
-(defvar mm-decrypt-function-alist)      ; < Emacs 22
+    (dolist (ov (overlays-in begin end))
+      (overlay-put ov 'evaporate t))))
 
 (defun mh-insert-mime-security-button (handle)
   "Display buttons for PGP message, HANDLE."
-  (let* ((protocol (mh-mm-handle-multipart-ctl-parameter handle 'protocol))
+  (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
          (crypto-type (or (nth 2 (assoc protocol mm-verify-function-alist))
                           (nth 2 (assoc protocol mm-decrypt-function-alist))
                           "Unknown"))
@@ -897,10 +864,10 @@ by commands like \"K v\" which operate on individual MIME 
parts."
                              (if (equal (car handle) "multipart/signed")
                                  " Signed" " Encrypted")
                              " Part"))
-               (info (or (mh-mm-handle-multipart-ctl-parameter
+               (info (or (mm-handle-multipart-ctl-parameter
                           handle 'gnus-info)
                          "Undecided"))
-               (details (mh-mm-handle-multipart-ctl-parameter
+               (details (mm-handle-multipart-ctl-parameter
                          handle 'gnus-details))
                pressed-details)
       (setq details (if details (concat "\n" details) ""))
@@ -911,11 +878,11 @@ by commands like \"K v\" which operate on individual MIME 
parts."
       (gnus-eval-format
        mh-mime-security-button-line-format
        mh-mime-security-button-line-format-alist
-       `(,@(mh-gnus-local-map-property mh-mime-security-button-map)
-         mh-button-pressed ,mh-mime-security-button-pressed
-         mh-callback mh-mime-security-press-button
-         mh-line-format ,mh-mime-security-button-line-format
-         mh-data ,handle))
+       `(keymap ,mh-mime-security-button-map
+                mh-button-pressed ,mh-mime-security-button-pressed
+                mh-callback mh-mime-security-press-button
+                mh-line-format ,mh-mime-security-button-line-format
+                mh-data ,handle))
       (setq end (point))
       (widget-convert-button 'link begin end
                              :mime-handle handle
@@ -923,8 +890,8 @@ by commands like \"K v\" which operate on individual MIME 
parts."
                              :button-keymap mh-mime-security-button-map
                              :button-face face
                              :help-echo "Mouse-2 click or press RET (in show 
buffer) to see security details.")
-      (dolist (ov (mh-funcall-if-exists overlays-in begin end))
-        (mh-funcall-if-exists overlay-put ov 'evaporate t))
+      (dolist (ov (overlays-in begin end))
+        (overlay-put ov 'evaporate t))
       (when (equal info "Failed")
         (let* ((type (if (equal (car handle) "multipart/signed")
                          "verification" "decryption"))
@@ -1081,7 +1048,7 @@ This is only called in recent versions of Gnus. The MIME 
handles
 are stored in data structures corresponding to MH-E folder buffer
 FOLDER instead of in Gnus (as in the original). The MIME part,
 HANDLE is associated with the undisplayer FUNCTION."
-  (if (mh-mm-keep-viewer-alive-p handle)
+  (if (mm-keep-viewer-alive-p handle)
       (let ((new-handle (copy-sequence handle)))
         (mm-handle-set-undisplayer new-handle function)
         (mm-handle-set-undisplayer handle nil)
@@ -1091,19 +1058,19 @@ HANDLE is associated with the undisplayer FUNCTION."
 
 (defun mh-mime-security-press-button (handle)
   "Callback from security button for part HANDLE."
-  (if (mh-mm-handle-multipart-ctl-parameter handle 'gnus-info)
+  (if (mm-handle-multipart-ctl-parameter handle 'gnus-info)
       (mh-mime-security-show-details handle)
-    (let ((region (mh-mm-handle-multipart-ctl-parameter handle 'mh-region))
+    (let ((region (mm-handle-multipart-ctl-parameter handle 'mh-region))
           point)
       (setq point (point))
       (goto-char (car region))
       (delete-region (car region) (cdr region))
-      (with-current-buffer (mh-mm-handle-multipart-ctl-parameter handle 
'buffer)
+      (with-current-buffer (mm-handle-multipart-ctl-parameter handle 'buffer)
         (let* ((mm-verify-option 'known)
                (mm-decrypt-option 'known)
-               (new (mh-mm-possibly-verify-or-decrypt (cdr handle) handle)))
+               (new (mm-possibly-verify-or-decrypt (cdr handle) handle)))
           (unless (eq new (cdr handle))
-            (mh-mm-destroy-parts (cdr handle))
+            (mm-destroy-parts (cdr handle))
             (setcdr handle new))))
       (mh-mime-display-security handle)
       (goto-char point))))
@@ -1113,7 +1080,7 @@ HANDLE is associated with the undisplayer FUNCTION."
 ;; to be no way of getting rid of the inserted text.
 (defun mh-mime-security-show-details (handle)
   "Toggle display of detailed security info for HANDLE."
-  (let ((details (mh-mm-handle-multipart-ctl-parameter handle 'gnus-details)))
+  (let ((details (mm-handle-multipart-ctl-parameter handle 'gnus-details)))
     (when details
       (let ((mh-mime-security-button-pressed
              (not (get-text-property (point) 'mh-button-pressed)))
@@ -1158,7 +1125,7 @@ this ;-)"
 (defun mh-display-smileys ()
   "Display smileys."
   (when (and mh-graphical-smileys-flag (mh-small-show-buffer-p))
-    (mh-funcall-if-exists smiley-region (point-min) (point-max))))
+    (smiley-region (point-min) (point-max))))
 
 ;;;###mh-autoload
 (defun mh-display-emphasis ()
@@ -1175,6 +1142,7 @@ this ;-)"
 This is used to decide if smileys and graphical emphasis should be
 displayed."
   (let ((max nil))
+    ;; FIXME: font-lock-maximum-size is obsolete.
     (when (and (boundp 'font-lock-maximum-size) font-lock-maximum-size)
       (cond ((numberp font-lock-maximum-size)
              (setq max font-lock-maximum-size))
@@ -1303,7 +1271,7 @@ automatically."
          (type (mh-minibuffer-read-type file))
          (description (mml-minibuffer-read-description))
          (dispos (or disposition
-                     (mh-mml-minibuffer-read-disposition type))))
+                     (mml-minibuffer-read-disposition type))))
     (mml-insert-empty-tag 'part 'type type 'filename file
                           'disposition dispos 'description description)))
 
@@ -1507,9 +1475,9 @@ This function will quote all such characters."
     (goto-char (point-min))
     (while (re-search-forward "^#" nil t)
       (beginning-of-line)
-      (unless (mh-mh-directive-present-p (point) (mh-line-end-position))
+      (unless (mh-mh-directive-present-p (point) (line-end-position))
         (insert "#"))
-      (goto-char (mh-line-end-position)))))
+      (goto-char (line-end-position)))))
 
 ;;;###mh-autoload
 (defun mh-mh-to-mime-undo (noconfirm)
@@ -1695,7 +1663,7 @@ buffer, while END defaults to the end of the buffer."
       (goto-char begin)
       (while (re-search-forward "^#" end t)
         (let ((s (buffer-substring-no-properties
-                  (point) (mh-line-end-position))))
+                  (point) (line-end-position))))
           (cond ((equal s ""))
                 ((string-match "^forw[ \t\n]+" s)
                  (cl-return-from search-for-mh-directive t))
@@ -1799,8 +1767,7 @@ initialized. Always use the command 
`mh-have-file-command'.")
 'file -i' is used to get MIME type of composition insertion."
   (when (eq mh-have-file-command 'undefined)
     (setq mh-have-file-command
-          (and (fboundp 'executable-find)
-               (executable-find "file") ; file command exists
+          (and (executable-find "file") ; file command exists
                                         ;   and accepts -i and -b args.
                (zerop (call-process "file" nil nil nil "-i" "-b"
                                     (expand-file-name "inc" mh-progs))))))
@@ -1814,10 +1781,9 @@ initialized. Always use the command 
`mh-have-file-command'.")
 (defun mh-mime-cleanup ()
   "Free the decoded MIME parts."
   (let ((mime-data (gethash (current-buffer) mh-globals-hash)))
-    ;; This is for Emacs, what about XEmacs?
-    (mh-funcall-if-exists remove-images (point-min) (point-max))
+    (remove-images (point-min) (point-max))
     (when mime-data
-      (mh-mm-destroy-parts (mh-mime-handles mime-data))
+      (mm-destroy-parts (mh-mime-handles mime-data))
       (remhash (current-buffer) mh-globals-hash))))
 
 ;;;###mh-autoload
@@ -1825,7 +1791,7 @@ initialized. Always use the command 
`mh-have-file-command'.")
   "Free MIME data for externally displayed MIME parts."
   (let ((mime-data (mh-buffer-data)))
     (when mime-data
-      (mh-mm-destroy-parts (mh-mime-handles mime-data)))
+      (mm-destroy-parts (mh-mime-handles mime-data)))
     (remhash (current-buffer) mh-globals-hash)))
 
 (provide 'mh-mime)
diff --git a/lisp/mh-e/mh-scan.el b/lisp/mh-e/mh-scan.el
index 10235209dc..5a1a671aee 100644
--- a/lisp/mh-e/mh-scan.el
+++ b/lisp/mh-e/mh-scan.el
@@ -103,15 +103,21 @@ non-empty Newsgroups: field is present."
 
 ;; Alphabetical.
 
-(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
-  "This regular expression matches the message body fragment.
+(defvar mh-scan-allowlisted-msg-regexp "^\\( *[0-9]+\\)A"
+  "This regular expression matches allowlisted (non-spam) messages.
 
-Note that the default setting of `mh-folder-font-lock-keywords'
-expects this expression to contain at least one parenthesized
-expression which matches the body text as in the default of
-\"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\".  If this regular expression is
-not correct, the body fragment will not be highlighted with the
-face `mh-folder-body'.")
+It must match from the beginning of the line. Note that the
+default setting of `mh-folder-font-lock-keywords' expects this
+expression to contain at least one parenthesized expression which
+matches the message number as in the default of
+
+  \"^\\\\( *[0-9]+\\\\)A\".
+
+This expression includes the leading space within parenthesis
+since it looks better to highlight it as well. The highlighting
+is done with the face `mh-folder-allowlisted'. This regular
+expression should be correct as it is needed by non-fontification
+functions. See also `mh-note-allowlisted'.")
 
 (defvar mh-scan-blocklisted-msg-regexp "^\\( *[0-9]+\\)B"
   "This regular expression matches blocklisted (spam) messages.
@@ -129,6 +135,16 @@ is done with the face `mh-folder-blocklisted'. This regular
 expression should be correct as it is needed by non-fontification
 functions. See also `mh-note-blocklisted'.")
 
+(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
+  "This regular expression matches the message body fragment.
+
+Note that the default setting of `mh-folder-font-lock-keywords'
+expects this expression to contain at least one parenthesized
+expression which matches the body text as in the default of
+\"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\".  If this regular expression is
+not correct, the body fragment will not be highlighted with the
+face `mh-folder-body'.")
+
 (defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
   "This regular expression matches the current message.
 
@@ -173,7 +189,7 @@ is done with the face `mh-folder-deleted'.  This regular
 expression should be correct as it is needed by non-fontification
 functions.  See also `mh-note-deleted'.")
 
-(defvar mh-scan-good-msg-regexp  "^\\( *[0-9]+\\)[^^DBW0-9]"
+(defvar mh-scan-good-msg-regexp  "^\\( *[0-9]+\\)[^^DBA0-9]"
   "This regular expression matches \"good\" messages.
 
 It must match from the beginning of the line.  Note that the
@@ -181,7 +197,7 @@ default setting of `mh-folder-font-lock-keywords' expects 
this
 expression to contain at least one parenthesized expression which
 matches the message number as in the default of
 
-  \"^\\\\( *[0-9]+\\\\)[^^DBW0-9]\".
+  \"^\\\\( *[0-9]+\\\\)[^^DBA0-9]\".
 
 This expression includes the leading space within the parenthesis
 since it looks better to highlight it as well.  The highlighting
@@ -295,27 +311,11 @@ non-fontification functions.")
 This is used to eliminate error messages that are occasionally
 produced by \"inc\".")
 
-(defvar mh-scan-allowlisted-msg-regexp "^\\( *[0-9]+\\)A"
-  "This regular expression matches allowlisted (non-spam) messages.
-
-It must match from the beginning of the line. Note that the
-default setting of `mh-folder-font-lock-keywords' expects this
-expression to contain at least one parenthesized expression which
-matches the message number as in the default of
-
-  \"^\\\\( *[0-9]+\\\\)A\".
-
-This expression includes the leading space within parenthesis
-since it looks better to highlight it as well. The highlighting
-is done with the face `mh-folder-allowlisted'. This regular
-expression should be correct as it is needed by non-fontification
-functions. See also `mh-note-allowlisted'.")
-
 
 
 ;;; Widths, Offsets and Columns
 
-(defvar mh-cmd-note 4
+(defvar-local mh-cmd-note 4
   "Column for notations.
 
 This variable should be set with the function `mh-set-cmd-note'.
@@ -323,12 +323,11 @@ This variable may be updated dynamically if
 `mh-adaptive-cmd-note-flag' is on.
 
 Note that columns in Emacs start with 0.")
-(make-variable-buffer-local 'mh-cmd-note)
 
 (defvar mh-scan-cmd-note-width 1
   "Number of columns consumed by the cmd-note field in `mh-scan-format'.
 
-This column will have one of the values: \" \", \"^\", \"D\", \"B\", \"W\", 
\"+\", where
+This column will have one of the values: \" \", \"^\", \"D\", \"B\", \"A\", 
\"+\", where
 
   \" \" is the default value,
   \"^\" is the `mh-note-refiled' character,
@@ -399,17 +398,21 @@ This column will only ever have spaces in it.")
 
 ;; Alphabetical.
 
+(defvar mh-note-allowlisted ?A
+  "Messages that have been allowlisted are marked by this character.
+See also `mh-scan-allowlisted-msg-regexp'.")
+
 (defvar mh-note-blocklisted ?B
   "Messages that have been blocklisted are marked by this character.
 See also `mh-scan-blocklisted-msg-regexp'.")
 
+(defvar mh-note-copied ?C
+  "Messages that have been copied are marked by this character.")
+
 (defvar mh-note-cur ?+
   "The current message (in MH, not in MH-E) is marked by this character.
 See also `mh-scan-cur-msg-number-regexp'.")
 
-(defvar mh-note-copied ?C
-  "Messages that have been copied are marked by this character.")
-
 (defvar mh-note-deleted ?D
   "Messages that have been deleted are marked by this character.
 See also `mh-scan-deleted-msg-regexp'.")
@@ -436,10 +439,6 @@ See also `mh-scan-refiled-msg-regexp'.")
 Messages in the \"search\" sequence are marked by this character as
 well.")
 
-(defvar mh-note-allowlisted ?A
-  "Messages that have been allowlisted are marked by this character.
-See also `mh-scan-allowlisted-msg-regexp'.")
-
 
 
 ;;; Utilities
diff --git a/lisp/mh-e/mh-search.el b/lisp/mh-e/mh-search.el
index e03c9dc83f..ef84c5eb28 100644
--- a/lisp/mh-e/mh-search.el
+++ b/lisp/mh-e/mh-search.el
@@ -42,6 +42,7 @@
 ;;; Code:
 
 (require 'mh-e)
+(require 'mh-letter)
 
 (require 'gnus-util)
 (require 'imenu)
@@ -318,10 +319,6 @@ folder containing the index search results."
                  (cl-loop for msg-hash being the hash-values of mh-index-data
                           count (> (hash-table-count msg-hash) 0)))))))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar pick-folder))                    ;FIXME: Why?
-
 (defun mh-search-folder (folder window-config)
   "Search FOLDER for messages matching a pattern.
 
@@ -336,8 +333,8 @@ configuration and is used when the search folder is 
dismissed."
             (not (y-or-n-p "Reuse pattern? ")))
         (mh-make-pick-template)
       (message ""))
-    (mh-make-local-vars 'mh-current-folder folder
-                        'mh-previous-window-config window-config)
+    (setq-local mh-current-folder folder
+                mh-previous-window-config window-config)
     (message "%s" (substitute-command-keys
                    (concat "Type \\[mh-index-do-search] to search messages, "
                            "\\[mh-pick-do-search] to use pick, "
@@ -356,13 +353,13 @@ configuration and is used when the search folder is 
dismissed."
   (goto-char (point-min))
   (dotimes (_ 5)
     (add-text-properties (point) (1+ (point)) '(front-sticky t))
-    (add-text-properties (- (mh-line-end-position) 2)
-                         (1- (mh-line-end-position))
+    (add-text-properties (- (line-end-position) 2)
+                         (1- (line-end-position))
                          '(rear-nonsticky t))
-    (add-text-properties (point) (1- (mh-line-end-position)) '(read-only t))
+    (add-text-properties (point) (1- (line-end-position)) '(read-only t))
     (forward-line))
   (add-text-properties (point) (1+ (point)) '(front-sticky t))
-  (add-text-properties (point) (1- (mh-line-end-position)) '(read-only t))
+  (add-text-properties (point) (1- (line-end-position)) '(read-only t))
   (goto-char (point-max)))
 
 ;; Sequence Searches
@@ -522,10 +519,10 @@ group of results."
       (cond ((and (bolp) (eolp))
              (ignore-errors (forward-line -1))
              (setq msg (mh-get-msg-num t)))
-            ((equal (char-after (mh-line-beginning-position)) ?+)
+            ((equal (char-after (line-beginning-position)) ?+)
              (setq folder (buffer-substring-no-properties
-                           (mh-line-beginning-position)
-                           (mh-line-end-position))))
+                           (line-beginning-position)
+                           (line-end-position))))
             (t (setq msg (mh-get-msg-num t)))))
     (when (not folder)
       (setq folder (car (gethash (gethash msg mh-index-msg-checksum-map)
@@ -552,20 +549,20 @@ group of results."
 ;;; MH-Search Keys
 
 ;; If this changes, modify mh-search-mode-help-messages accordingly, below.
-(gnus-define-keys  mh-search-mode-map
-  "\C-c?"               mh-help
-  "\C-c\C-c"            mh-index-do-search
-  "\C-c\C-p"            mh-pick-do-search
-  "\C-c\C-f\C-b"        mh-to-field
-  "\C-c\C-f\C-c"        mh-to-field
-  "\C-c\C-f\C-m"        mh-to-field
-  "\C-c\C-f\C-s"        mh-to-field
-  "\C-c\C-f\C-t"        mh-to-field
-  "\C-c\C-fb"           mh-to-field
-  "\C-c\C-fc"           mh-to-field
-  "\C-c\C-fm"           mh-to-field
-  "\C-c\C-fs"           mh-to-field
-  "\C-c\C-ft"           mh-to-field)
+(define-keymap :keymap mh-search-mode-map
+  "\C-c?"               #'mh-help
+  "\C-c\C-c"            #'mh-index-do-search
+  "\C-c\C-p"            #'mh-pick-do-search
+  "\C-c\C-f\C-b"        #'mh-to-field
+  "\C-c\C-f\C-c"        #'mh-to-field
+  "\C-c\C-f\C-m"        #'mh-to-field
+  "\C-c\C-f\C-s"        #'mh-to-field
+  "\C-c\C-f\C-t"        #'mh-to-field
+  "\C-c\C-fb"           #'mh-to-field
+  "\C-c\C-fc"           #'mh-to-field
+  "\C-c\C-fm"           #'mh-to-field
+  "\C-c\C-fs"           #'mh-to-field
+  "\C-c\C-ft"           #'mh-to-field)
 
 
 
@@ -616,7 +613,6 @@ The hook `mh-search-mode-hook' is called upon entry to this 
mode.
 
 \\{mh-search-mode-map}"
 
-  (mh-do-in-xemacs (easy-menu-add mh-pick-menu))
   (mh-set-help mh-search-mode-help-messages))
 
 
@@ -653,13 +649,13 @@ The cdr of the element is the pattern to search."
           start begin)
       (goto-char (point-min))
       (while (not (eobp))
-        (if (search-forward "--------" (mh-line-end-position) t)
+        (if (search-forward "--------" (line-end-position) t)
             (setq in-body-flag t)
           (beginning-of-line)
           (setq begin (point))
           (setq start (if in-body-flag
                           (point)
-                        (search-forward ":" (mh-line-end-position) t)
+                        (search-forward ":" (line-end-position) t)
                         (point)))
           (push (cons (and (not in-body-flag)
                            (intern (downcase
@@ -667,7 +663,7 @@ The cdr of the element is the pattern to search."
                                      begin (1- start)))))
                       (mh-index-parse-search-regexp
                        (buffer-substring-no-properties
-                        start (mh-line-end-position))))
+                        start (line-end-position))))
                 pattern-list))
         (forward-line))
       pattern-list)))
@@ -977,8 +973,8 @@ is used to search."
           (cl-return nil))
         (when (equal (char-after (point)) ?#)
           (cl-return 'error))
-        (let* ((start (search-forward " " (mh-line-end-position) t))
-               (end (search-forward " " (mh-line-end-position) t)))
+        (let* ((start (search-forward " " (line-end-position) t))
+               (end (search-forward " " (line-end-position) t)))
           (unless (and start end)
             (cl-return 'error))
           (setq end (1- end))
@@ -1056,7 +1052,7 @@ SEARCH-REGEXP-LIST is used to search."
           (cl-return 'error))
         (let ((start (point))
               end msg-start)
-          (setq end (mh-line-end-position))
+          (setq end (line-end-position))
           (unless (search-forward mh-mairix-folder end t)
             (cl-return 'error))
           (goto-char (match-beginning 0))
@@ -1197,7 +1193,7 @@ is used to search."
       (cl-block nil
         (when (eobp) (cl-return nil))
         (let ((file-name (buffer-substring-no-properties
-                          (point) (mh-line-end-position))))
+                          (point) (line-end-position))))
           (unless (equal (string-match mh-namazu-folder file-name) 0)
             (cl-return 'error))
           (unless (file-exists-p file-name)
@@ -1245,17 +1241,17 @@ is used to search."
   (prog1
       (cl-block nil
         (when (eobp) (cl-return nil))
-        (when (search-forward-regexp "^\\+" (mh-line-end-position) t)
+        (when (search-forward-regexp "^\\+" (line-end-position) t)
           (setq mh-index-pick-folder
-                (buffer-substring-no-properties (mh-line-beginning-position)
-                                                (mh-line-end-position)))
+                (buffer-substring-no-properties (line-beginning-position)
+                                                (line-end-position)))
           (cl-return 'error))
-        (unless (search-forward-regexp "^[1-9][0-9]*$" (mh-line-end-position) 
t)
+        (unless (search-forward-regexp "^[1-9][0-9]*$" (line-end-position) t)
           (cl-return 'error))
         (list mh-index-pick-folder
               (string-to-number
-               (buffer-substring-no-properties (mh-line-beginning-position)
-                                               (mh-line-end-position)))
+               (buffer-substring-no-properties (line-beginning-position)
+                                               (line-end-position)))
               nil))
     (forward-line)))
 
@@ -1332,8 +1328,8 @@ record is invalid return `error'."
       (cl-block nil
         (when (eobp)
           (cl-return nil))
-        (let ((eol-pos (mh-line-end-position))
-              (bol-pos (mh-line-beginning-position))
+        (let ((eol-pos (line-end-position))
+              (bol-pos (line-beginning-position))
               folder-start msg-end)
           (goto-char bol-pos)
           (unless (search-forward mh-user-path eol-pos t)
@@ -1415,10 +1411,7 @@ being the list of messages originally from that folder."
     (when cur-msg (mh-goto-msg cur-msg t t))
     (set-buffer-modified-p old-buffer-modified-flag)))
 
-(eval-and-compile (mh-require 'which-func nil t))
-
-;; Shush compiler.
-(defvar which-func-mode)                ; < Emacs 22, XEmacs
+(eval-and-compile (require 'which-func nil t))
 
 ;;;###mh-autoload
 (defun mh-index-create-imenu-index ()
@@ -1432,7 +1425,7 @@ being the list of messages originally from that folder."
         (save-excursion
           (beginning-of-line)
           (push (cons (buffer-substring-no-properties
-                       (point) (mh-line-end-position))
+                       (point) (line-end-position))
                       (point-marker))
                 alist)))
       (setq imenu--index-alist (nreverse alist)))))
@@ -1717,7 +1710,7 @@ folder, is removed from `mh-index-data'."
                         "-format" "%{x-mhe-checksum}\n" folder msg)
     (goto-char (point-min))
     (string-equal (buffer-substring-no-properties
-                   (point) (mh-line-end-position))
+                   (point) (line-end-position))
                   checksum)))
 
 
@@ -1826,8 +1819,8 @@ PROC is used to convert the value to actual data."
 
 (defun mh-md5sum-parser ()
   "Parse md5sum output."
-  (let ((begin (mh-line-beginning-position))
-        (end (mh-line-end-position))
+  (let ((begin (line-beginning-position))
+        (end (line-end-position))
         first-space last-slash)
     (setq first-space (search-forward " " end t))
     (goto-char end)
@@ -1840,8 +1833,8 @@ PROC is used to convert the value to actual data."
 
 (defun mh-openssl-parser ()
   "Parse openssl output."
-  (let ((begin (mh-line-beginning-position))
-        (end (mh-line-end-position))
+  (let ((begin (line-beginning-position))
+        (end (line-end-position))
         last-space last-slash)
     (goto-char end)
     (setq last-space (search-backward " " begin t))
@@ -1874,7 +1867,7 @@ origin-index) map is updated too."
       (let (msg checksum)
         (while (not (eobp))
           (setq msg (buffer-substring-no-properties
-                     (point) (mh-line-end-position)))
+                     (point) (line-end-position)))
           (forward-line)
           (save-excursion
             (cond ((not (string-match "^[0-9]*$" msg)))
@@ -1885,7 +1878,7 @@ origin-index) map is updated too."
                   (t
                    ;; update maps
                    (setq checksum (buffer-substring-no-properties
-                                   (point) (mh-line-end-position)))
+                                   (point) (line-end-position)))
                    (let ((msg (string-to-number msg)))
                      (set-buffer folder)
                      (mh-index-update-single-msg msg checksum origin-map)))))
diff --git a/lisp/mh-e/mh-seq.el b/lisp/mh-e/mh-seq.el
index a50319a455..077e289c01 100644
--- a/lisp/mh-e/mh-seq.el
+++ b/lisp/mh-e/mh-seq.el
@@ -38,9 +38,8 @@
 (defvar mh-last-seq-used nil
   "Name of seq to which a msg was last added.")
 
-(defvar mh-non-seq-mode-line-annotation nil
+(defvar-local mh-non-seq-mode-line-annotation nil
   "Saved value of `mh-mode-line-annotation' when narrowed to a seq.")
-(make-variable-buffer-local 'mh-non-seq-mode-line-annotation)
 
 (defvar mh-internal-seqs '(answered cur deleted forwarded printed))
 
@@ -167,7 +166,7 @@ The list appears in a buffer named \"*MH-E Sequences*\"."
             (insert "\n"))
           (setq seq-list (cdr seq-list)))
         (goto-char (point-min))
-        (mh-view-mode-enter)
+        (view-mode-enter)
         (setq view-exit-action 'kill-buffer)
         (message "Listing sequences...done")))))
 
@@ -193,11 +192,6 @@ MESSAGE appears."
                         (mh-list-to-string (mh-seq-containing-msg message t))
                         " "))))
 
-;; Shush compiler.
-(mh-do-in-xemacs
-  (defvar tool-bar-mode))
-(defvar tool-bar-map)
-
 ;;;###mh-autoload
 (defun mh-narrow-to-seq (sequence)
   "Restrict display to messages in SEQUENCE.
@@ -229,12 +223,12 @@ When you want to widen the view to all your messages 
again, use
              (mh-make-folder-mode-line)
              (mh-recenter nil)
              (when (and (boundp 'tool-bar-mode) tool-bar-mode)
-               (set (make-local-variable 'tool-bar-map)
-                    mh-folder-seq-tool-bar-map)
+               (setq-local tool-bar-map
+                           mh-folder-seq-tool-bar-map)
                (when (buffer-live-p (get-buffer mh-show-buffer))
                  (with-current-buffer mh-show-buffer
-                   (set (make-local-variable 'tool-bar-map)
-                        mh-show-seq-tool-bar-map))))
+                   (setq-local tool-bar-map
+                               mh-show-seq-tool-bar-map))))
              (push 'widen mh-view-ops)))
           (t
            (error "No messages in sequence %s" (symbol-name sequence))))))
@@ -362,10 +356,10 @@ remove all limits and sequence restrictions."
       (mh-notate-cur)
       (mh-recenter nil)))
   (when (and (null mh-folder-view-stack) (boundp 'tool-bar-mode) tool-bar-mode)
-    (set (make-local-variable 'tool-bar-map) mh-folder-tool-bar-map)
+    (setq-local tool-bar-map mh-folder-tool-bar-map)
     (when (buffer-live-p (get-buffer mh-show-buffer))
       (with-current-buffer mh-show-buffer
-        (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))))
+        (setq-local tool-bar-map mh-show-tool-bar-map)))))
 
 
 
@@ -582,7 +576,7 @@ Otherwise, the message number at point is returned.
 
 This function is usually used with `mh-iterate-on-range' in order to
 provide a uniform interface to MH-E functions."
-  (cond ((mh-mark-active-p t) (cons (region-beginning) (region-end)))
+  (cond ((and transient-mark-mode mark-active) (cons (region-beginning) 
(region-end)))
         (current-prefix-arg (mh-read-range range-prompt nil nil t t))
         (default default)
         (t (mh-get-msg-num t))))
@@ -736,7 +730,7 @@ completion is over."
     (cl-multiple-value-bind (folder unseen total)
         (cl-values-list
          (mh-parse-flist-output-line
-          (buffer-substring (point) (mh-line-end-position))))
+          (buffer-substring (point) (line-end-position))))
       (list total unseen folder))))
 
 (defun mh-folder-size-folder (folder)
@@ -764,7 +758,7 @@ folders whose names end with a `+' character."
       (when (search-backward " out of " (point-min) t)
         (setq total (string-to-number
                      (buffer-substring-no-properties
-                      (match-end 0) (mh-line-end-position))))
+                      (match-end 0) (line-end-position))))
         (when (search-backward " in sequence " (point-min) t)
           (setq p (point))
           (when (search-backward " has " (point-min) t)
@@ -786,10 +780,10 @@ If SAVE-REFILES is non-nil, then keep the sequences
 that note messages to be refiled."
   (let ((seqs ()))
     (cond (save-refiles
-           (mh-mapc (lambda (seq) ; Save the refiling sequences
-                      (if (mh-folder-name-p (mh-seq-name seq))
-                          (setq seqs (cons seq seqs))))
-                    mh-seq-list)))
+           (mapc (lambda (seq) ; Save the refiling sequences
+                   (if (mh-folder-name-p (mh-seq-name seq))
+                       (setq seqs (cons seq seqs))))
+                 mh-seq-list)))
     (save-excursion
       (if (eq 0 (mh-exec-cmd-quiet nil "mark" folder "-list"))
           (progn
@@ -942,7 +936,7 @@ font-lock is turned on."
             ;; the case of user sequences.
             (mh-notate nil nil mh-cmd-note)
             (when font-lock-mode
-              (font-lock-fontify-region (point) (mh-line-end-position))))
+              (font-lock-fontify-region (point) (line-end-position))))
         (forward-char (+ mh-cmd-note mh-scan-field-destination-offset))
         (let ((stack (gethash msg mh-sequence-notation-history)))
           (setf (gethash msg mh-sequence-notation-history)
diff --git a/lisp/mh-e/mh-show.el b/lisp/mh-e/mh-show.el
index 803f07e02b..524179648d 100644
--- a/lisp/mh-e/mh-show.el
+++ b/lisp/mh-e/mh-show.el
@@ -144,7 +144,7 @@ displayed."
             (if (not clean-message-header)
                 (mh-start-of-uncleaned-message)))
         (mh-display-msg msg folder)))
-    (unless (mh-window-full-height-p) ; not vertically split
+    (unless (window-full-height-p) ; not vertically split
       (shrink-window (- (window-height) (or mh-summary-height
                                             (mh-summary-height)))))
     (mh-recenter nil)
@@ -328,17 +328,15 @@ ignored if VISIBLE-HEADERS is non-nil."
 (defun mh-summary-height ()
   "Return ideal value for the variable `mh-summary-height'.
 The current frame height is taken into consideration."
-  (or (and (fboundp 'frame-height)
-           (> (frame-height) 24)
+  (or (and (> (frame-height) 24)
            (min 10 (/ (frame-height) 6)))
       4))
 
 
 
-;; Infrastructure to generate show-buffer functions from folder functions
-;; XEmacs does not have deactivate-mark? What is the equivalent of
-;; transient-mark-mode for XEmacs? Should we be restoring the mark in the
-;; folder buffer after the operation has been carried out.
+;; Infrastructure to generate show-buffer functions from folder functions.
+;; Should we be restoring the mark in the folder buffer after the
+;; operation has been carried out?
 (defmacro mh-defun-show-buffer (function original-function
                                          &optional dont-return)
   "Define FUNCTION to run ORIGINAL-FUNCTION in folder buffer.
@@ -363,11 +361,11 @@ still visible.\n")
                         folder-buffer)
            (delete-other-windows))
          (mh-goto-cur-msg t)
-         (mh-funcall-if-exists deactivate-mark)
+         (deactivate-mark)
          (unwind-protect
              (prog1 (call-interactively (function ,original-function))
                (setq normal-exit t))
-           (mh-funcall-if-exists deactivate-mark)
+           (deactivate-mark)
            (when (eq major-mode 'mh-folder-mode)
              (mh-funcall-if-exists hl-line-highlight))
            (cond ((not normal-exit)
@@ -464,8 +462,7 @@ still visible.\n")
 (mh-defun-show-buffer mh-show-toggle-tick mh-toggle-tick)
 (mh-defun-show-buffer mh-show-narrow-to-tick mh-narrow-to-tick)
 (mh-defun-show-buffer mh-show-junk-allowlist mh-junk-allowlist)
-(mh-defun-show-buffer mh-show-junk-whitelist mh-junk-allowlist)
-(make-obsolete 'mh-show-junk-whitelist 'mh-show-junk-allowlist "28.1")
+(mh-defun-show-buffer mh-show-junk-whitelist mh-junk-whitelist)
 (mh-defun-show-buffer mh-show-junk-blocklist mh-junk-blocklist)
 (mh-defun-show-buffer mh-show-index-new-messages mh-index-new-messages)
 (mh-defun-show-buffer mh-show-index-ticked-messages mh-index-ticked-messages)
@@ -562,132 +559,132 @@ still visible.\n")
 
 ;;; MH-Show Keys
 
-(gnus-define-keys mh-show-mode-map
-  " "    mh-show-page-msg
-  "!"    mh-show-refile-or-write-again
-  "'"    mh-show-toggle-tick
-  ","    mh-show-header-display
-  "."    mh-show-show
-  ":"    mh-show-show-preferred-alternative
-  ">"    mh-show-write-message-to-file
-  "?"    mh-help
-  "E"    mh-show-extract-rejected-mail
-  "M"    mh-show-modify
-  "\177" mh-show-previous-page
-  "\C-d" mh-show-delete-msg-no-motion
-  "\t"   mh-show-next-button
-  [backtab] mh-show-prev-button
-  "\M-\t" mh-show-prev-button
-  "\ed"  mh-show-redistribute
-  "^"    mh-show-refile-msg
-  "c"    mh-show-copy-msg
-  "d"    mh-show-delete-msg
-  "e"    mh-show-edit-again
-  "f"    mh-show-forward
-  "g"    mh-show-goto-msg
-  "i"    mh-show-inc-folder
-  "k"    mh-show-delete-subject-or-thread
-  "m"    mh-show-send
-  "n"    mh-show-next-undeleted-msg
-  "\M-n" mh-show-next-unread-msg
-  "o"    mh-show-refile-msg
-  "p"    mh-show-previous-undeleted-msg
-  "\M-p" mh-show-previous-unread-msg
-  "q"    mh-show-quit
-  "r"    mh-show-reply
-  "s"    mh-show-send
-  "t"    mh-show-toggle-showing
-  "u"    mh-show-undo
-  "x"    mh-show-execute-commands
-  "v"    mh-show-index-visit-folder
-  "|"    mh-show-pipe-msg)
-
-(gnus-define-keys (mh-show-folder-map "F" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "'"    mh-index-ticked-messages
-  "S"    mh-show-sort-folder
-  "c"    mh-show-catchup
-  "f"    mh-show-visit-folder
-  "k"    mh-show-kill-folder
-  "l"    mh-show-list-folders
-  "n"    mh-index-new-messages
-  "o"    mh-show-visit-folder
-  "p"    mh-show-pack-folder
-  "q"    mh-show-index-sequenced-messages
-  "r"    mh-show-rescan-folder
-  "s"    mh-search
-  "t"    mh-show-toggle-threads
-  "u"    mh-show-undo-folder
-  "v"    mh-show-visit-folder)
-
-(gnus-define-keys (mh-show-sequence-map "S" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "d"    mh-show-delete-msg-from-seq
-  "k"    mh-show-delete-seq
-  "l"    mh-show-list-sequences
-  "n"    mh-show-narrow-to-seq
-  "p"    mh-show-put-msg-in-seq
-  "s"    mh-show-msg-is-in-seq
-  "w"    mh-show-widen)
-
-(define-key mh-show-mode-map "I" mh-inc-spool-map)
-
-(gnus-define-keys (mh-show-junk-map "J" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "a"    mh-show-junk-allowlist
-  "b"    mh-show-junk-blocklist
-  "w"    mh-show-junk-whitelist)
-
-(gnus-define-keys (mh-show-ps-print-map "P" mh-show-mode-map)
-  "?"   mh-prefix-help
-  "C"   mh-show-ps-print-toggle-color
-  "F"   mh-show-ps-print-toggle-faces
-  "f"   mh-show-ps-print-msg-file
-  "l"   mh-show-print-msg
-  "p"   mh-show-ps-print-msg)
-
-(gnus-define-keys (mh-show-thread-map "T" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "u"    mh-show-thread-ancestor
-  "p"    mh-show-thread-previous-sibling
-  "n"    mh-show-thread-next-sibling
-  "t"    mh-show-toggle-threads
-  "d"    mh-show-thread-delete
-  "o"    mh-show-thread-refile)
-
-(gnus-define-keys (mh-show-limit-map "/" mh-show-mode-map)
-  "'"    mh-show-narrow-to-tick
-  "?"    mh-prefix-help
-  "c"    mh-show-narrow-to-cc
-  "g"    mh-show-narrow-to-range
-  "m"    mh-show-narrow-to-from
-  "s"    mh-show-narrow-to-subject
-  "t"    mh-show-narrow-to-to
-  "w"    mh-show-widen)
-
-(gnus-define-keys (mh-show-extract-map "X" mh-show-mode-map)
-  "?"    mh-prefix-help
-  "s"    mh-show-store-msg
-  "u"    mh-show-store-msg)
-
-(gnus-define-keys (mh-show-digest-map "D" mh-show-mode-map)
-  "?"    mh-prefix-help
-  " "    mh-show-page-digest
-  "\177" mh-show-page-digest-backwards
-  "b"    mh-show-burst-digest)
-
-(gnus-define-keys (mh-show-mime-map "K" mh-show-mode-map)
-  "?"           mh-prefix-help
-  "a"           mh-mime-save-parts
-  "e"           mh-show-display-with-external-viewer
-  "v"           mh-show-toggle-mime-part
-  "o"           mh-show-save-mime-part
-  "i"           mh-show-inline-mime-part
-  "t"           mh-show-toggle-mime-buttons
-  "\t"          mh-show-next-button
-  [backtab]     mh-show-prev-button
-  "\M-\t"       mh-show-prev-button)
+(define-keymap :keymap mh-show-mode-map
+  " "    #'mh-show-page-msg
+  "!"    #'mh-show-refile-or-write-again
+  "'"    #'mh-show-toggle-tick
+  ","    #'mh-show-header-display
+  "."    #'mh-show-show
+  ":"    #'mh-show-show-preferred-alternative
+  ">"    #'mh-show-write-message-to-file
+  "?"    #'mh-help
+  "E"    #'mh-show-extract-rejected-mail
+  "M"    #'mh-show-modify
+  "\177" #'mh-show-previous-page
+  "\C-d" #'mh-show-delete-msg-no-motion
+  "\t"   #'mh-show-next-button
+  [backtab] #'mh-show-prev-button
+  "\M-\t" #'mh-show-prev-button
+  "\ed"  #'mh-show-redistribute
+  "^"    #'mh-show-refile-msg
+  "c"    #'mh-show-copy-msg
+  "d"    #'mh-show-delete-msg
+  "e"    #'mh-show-edit-again
+  "f"    #'mh-show-forward
+  "g"    #'mh-show-goto-msg
+  "i"    #'mh-show-inc-folder
+  "k"    #'mh-show-delete-subject-or-thread
+  "m"    #'mh-show-send
+  "n"    #'mh-show-next-undeleted-msg
+  "\M-n" #'mh-show-next-unread-msg
+  "o"    #'mh-show-refile-msg
+  "p"    #'mh-show-previous-undeleted-msg
+  "\M-p" #'mh-show-previous-unread-msg
+  "q"    #'mh-show-quit
+  "r"    #'mh-show-reply
+  "s"    #'mh-show-send
+  "t"    #'mh-show-toggle-showing
+  "u"    #'mh-show-undo
+  "x"    #'mh-show-execute-commands
+  "v"    #'mh-show-index-visit-folder
+  "|"    #'mh-show-pipe-msg
+
+  "F" (define-keymap :prefix 'mh-show-folder-map
+        "?"    #'mh-prefix-help
+        "'"    #'mh-index-ticked-messages
+        "S"    #'mh-show-sort-folder
+        "c"    #'mh-show-catchup
+        "f"    #'mh-show-visit-folder
+        "k"    #'mh-show-kill-folder
+        "l"    #'mh-show-list-folders
+        "n"    #'mh-index-new-messages
+        "o"    #'mh-show-visit-folder
+        "p"    #'mh-show-pack-folder
+        "q"    #'mh-show-index-sequenced-messages
+        "r"    #'mh-show-rescan-folder
+        "s"    #'mh-search
+        "t"    #'mh-show-toggle-threads
+        "u"    #'mh-show-undo-folder
+        "v"    #'mh-show-visit-folder)
+
+  "S" (define-keymap :prefix 'mh-show-sequence-map
+        "'"    #'mh-show-narrow-to-tick
+        "?"    #'mh-prefix-help
+        "d"    #'mh-show-delete-msg-from-seq
+        "k"    #'mh-show-delete-seq
+        "l"    #'mh-show-list-sequences
+        "n"    #'mh-show-narrow-to-seq
+        "p"    #'mh-show-put-msg-in-seq
+        "s"    #'mh-show-msg-is-in-seq
+        "w"    #'mh-show-widen)
+
+  "I" mh-inc-spool-map
+
+  "J" (define-keymap :prefix 'mh-show-junk-map
+        "?"    #'mh-prefix-help
+        "a"    #'mh-show-junk-allowlist
+        "b"    #'mh-show-junk-blocklist
+        "w"    #'mh-show-junk-whitelist)
+
+  "P" (define-keymap :prefix 'mh-show-ps-print-map
+        "?"   #'mh-prefix-help
+        "C"   #'mh-show-ps-print-toggle-color
+        "F"   #'mh-show-ps-print-toggle-faces
+        "f"   #'mh-show-ps-print-msg-file
+        "l"   #'mh-show-print-msg
+        "p"   #'mh-show-ps-print-msg)
+
+  "T" (define-keymap :prefix 'mh-show-thread-map
+        "?"    #'mh-prefix-help
+        "u"    #'mh-show-thread-ancestor
+        "p"    #'mh-show-thread-previous-sibling
+        "n"    #'mh-show-thread-next-sibling
+        "t"    #'mh-show-toggle-threads
+        "d"    #'mh-show-thread-delete
+        "o"    #'mh-show-thread-refile)
+
+  "/" (define-keymap :prefix 'mh-show-limit-map
+        "'"    #'mh-show-narrow-to-tick
+        "?"    #'mh-prefix-help
+        "c"    #'mh-show-narrow-to-cc
+        "g"    #'mh-show-narrow-to-range
+        "m"    #'mh-show-narrow-to-from
+        "s"    #'mh-show-narrow-to-subject
+        "t"    #'mh-show-narrow-to-to
+        "w"    #'mh-show-widen)
+
+  "X" (define-keymap :prefix 'mh-show-extract-map
+        "?"    #'mh-prefix-help
+        "s"    #'mh-show-store-msg
+        "u"    #'mh-show-store-msg)
+
+  "D" (define-keymap :prefix 'mh-show-digest-map
+        "?"    #'mh-prefix-help
+        " "    #'mh-show-page-digest
+        "\177" #'mh-show-page-digest-backwards
+        "b"    #'mh-show-burst-digest)
+
+  "K" (define-keymap :prefix 'mh-show-mime-map
+        "?"           #'mh-prefix-help
+        "a"           #'mh-mime-save-parts
+        "e"           #'mh-show-display-with-external-viewer
+        "v"           #'mh-show-toggle-mime-part
+        "o"           #'mh-show-save-mime-part
+        "i"           #'mh-show-inline-mime-part
+        "t"           #'mh-show-toggle-mime-buttons
+        "\t"          #'mh-show-next-button
+        [backtab]     #'mh-show-prev-button
+        "\M-\t"       #'mh-show-prev-button))
 
 
 
@@ -817,9 +814,6 @@ operation."
 ;; Ensure new buffers won't get this mode if default major-mode is nil.
 (put 'mh-show-mode 'mode-class 'special)
 
-;; Shush compiler.
-(defvar font-lock-auto-fontify)
-
 ;;;###mh-autoload
 (define-derived-mode mh-show-mode text-mode "MH-Show"
   "Major mode for showing messages in MH-E.\\<mh-show-mode-map>
@@ -836,17 +830,14 @@ The hook `mh-show-mode-hook' is called upon entry to this 
mode.
 See also `mh-folder-mode'.
 
 \\{mh-show-mode-map}"
-  (mh-do-in-gnu-emacs
-   (if (boundp 'tool-bar-map)
-       (set (make-local-variable 'tool-bar-map) mh-show-tool-bar-map)))
-  (mh-do-in-xemacs
-    (mh-tool-bar-init :show))
-  (set (make-local-variable 'mail-header-separator) mh-mail-header-separator)
+  (if (boundp 'tool-bar-map)
+      (setq-local tool-bar-map mh-show-tool-bar-map))
+  (setq-local mail-header-separator mh-mail-header-separator)
   (setq paragraph-start (default-value 'paragraph-start))
   (setq buffer-invisibility-spec '((vanish . t) t))
-  (set (make-local-variable 'line-move-ignore-invisible) t)
+  (setq-local line-move-ignore-invisible t)
   (make-local-variable 'font-lock-defaults)
-  ;;(set (make-local-variable 'font-lock-support-mode) nil)
+  ;;(setq-local font-lock-support-mode nil)
   (cond
    ((equal mh-highlight-citation-style 'font-lock)
     (setq font-lock-defaults '(mh-show-font-lock-keywords-with-cite t)))
@@ -858,16 +849,8 @@ See also `mh-folder-mode'.
     (mh-gnus-article-highlight-citation))
    (t
     (setq font-lock-defaults '(mh-show-font-lock-keywords t))))
-  (if (and (featurep 'xemacs)
-           font-lock-auto-fontify)
-      (turn-on-font-lock))
   (when mh-decode-mime-flag
-    (mh-make-local-hook 'kill-buffer-hook)
     (add-hook 'kill-buffer-hook #'mh-mime-cleanup nil t))
-  (mh-do-in-xemacs
-    (easy-menu-add mh-show-sequence-menu)
-    (easy-menu-add mh-show-message-menu)
-    (easy-menu-add mh-show-folder-menu))
   (make-local-variable 'mh-show-folder-buffer)
   (buffer-disable-undo)
   (use-local-map mh-show-mode-map))
diff --git a/lisp/mh-e/mh-speed.el b/lisp/mh-e/mh-speed.el
index 76ef990d82..82b108c8c8 100644
--- a/lisp/mh-e/mh-speed.el
+++ b/lisp/mh-e/mh-speed.el
@@ -63,13 +63,13 @@
   '("--"
     ["Visit Folder" mh-speed-view
      (with-current-buffer speedbar-buffer
-       (get-text-property (mh-line-beginning-position) 'mh-folder))]
+       (get-text-property (line-beginning-position) 'mh-folder))]
     ["Expand Nested Folders" mh-speed-expand-folder
-     (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
-          (not (get-text-property (mh-line-beginning-position) 'mh-expanded)))]
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (not (get-text-property (line-beginning-position) 'mh-expanded)))]
     ["Contract Nested Folders" mh-speed-contract-folder
-     (and (get-text-property (mh-line-beginning-position) 'mh-children-p)
-          (get-text-property (mh-line-beginning-position) 'mh-expanded))]
+     (and (get-text-property (line-beginning-position) 'mh-children-p)
+          (get-text-property (line-beginning-position) 'mh-expanded))]
     ["Refresh Speedbar" mh-speed-refresh t])
   "Extra menu items for speedbar.")
 
@@ -83,11 +83,11 @@
 (defvar mh-folder-speedbar-key-map (speedbar-make-specialized-keymap)
   "Specialized speedbar keymap for MH-E buffers.")
 
-(gnus-define-keys mh-folder-speedbar-key-map
-  "+"           mh-speed-expand-folder
-  "-"           mh-speed-contract-folder
-  "\r"          mh-speed-view
-  "r"           mh-speed-refresh)
+(define-keymap :keymap mh-folder-speedbar-key-map
+  "+"           #'mh-speed-expand-folder
+  "-"           #'mh-speed-contract-folder
+  "\r"          #'mh-speed-view
+  "r"           #'mh-speed-refresh)
 
 (defvar mh-show-speedbar-key-map mh-folder-speedbar-key-map)
 (defvar mh-letter-speedbar-key-map mh-folder-speedbar-key-map)
@@ -150,7 +150,7 @@ The optional arguments from speedbar are IGNORED."
              (forward-line -1)
              (speedbar-change-expand-button-char ?+)
              (add-text-properties
-              (mh-line-beginning-position) (1+ (line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               '(mh-expanded nil)))
             (t
              (forward-line)
@@ -158,14 +158,14 @@ The optional arguments from speedbar are IGNORED."
              (goto-char point)
              (speedbar-change-expand-button-char ?-)
              (add-text-properties
-              (mh-line-beginning-position) (1+ (line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               '(mh-expanded t)))))))
 
 (defun mh-speed-view (&rest _ignored)
   "Visits the selected folder just as if you had used 
\\<mh-folder-mode-map>\\[mh-visit-folder].
 The optional arguments from speedbar are IGNORED."
   (interactive)
-  (let* ((folder (get-text-property (mh-line-beginning-position) 'mh-folder))
+  (let* ((folder (get-text-property (line-beginning-position) 'mh-folder))
          (range (and (stringp folder)
                      (mh-read-range "Scan" folder t nil nil
                                     mh-interpret-number-as-range-flag))))
@@ -191,9 +191,9 @@ created."
     (forward-line -1)
     (setf (gethash nil mh-speed-folder-map)
           (set-marker (or (gethash nil mh-speed-folder-map) (make-marker))
-                      (1+ (mh-line-beginning-position))))
+                      (1+ (line-beginning-position))))
     (add-text-properties
-     (mh-line-beginning-position) (1+ (line-beginning-position))
+     (line-beginning-position) (1+ (line-beginning-position))
      '(mh-folder nil mh-expanded nil mh-children-p t mh-level 0))
     (mh-speed-stealth-update t)
     (when (> mh-speed-update-interval 0)
@@ -260,12 +260,12 @@ The update is always carried out if FORCE is non-nil."
     (speedbar-with-writable
       (goto-char (gethash folder mh-speed-folder-map (point)))
       (beginning-of-line)
-      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (mh-line-end-position) t)
+      (if (re-search-forward "([1-9][0-9]*/[0-9]+)" (line-end-position) t)
           (setq face (mh-speed-bold-face face))
         (setq face (mh-speed-normal-face face)))
       (beginning-of-line)
-      (when (re-search-forward "\\[.\\] " (mh-line-end-position) t)
-        (put-text-property (point) (mh-line-end-position) 'face face)))))
+      (when (re-search-forward "\\[.\\] " (line-end-position) t)
+        (put-text-property (point) (line-end-position) 'face face)))))
 
 (defun mh-speed-normal-face (face)
   "Return normal face for given FACE."
@@ -305,7 +305,7 @@ The function will expand out parent folders of FOLDER if 
needed."
     (while suffix-list
       ;; We always need at least one toggle. We need two if the directory list
       ;; is stale since a folder was added.
-      (when (equal prefix (get-text-property (mh-line-beginning-position)
+      (when (equal prefix (get-text-property (line-beginning-position)
                                              'mh-folder))
         (mh-speed-toggle)
         (unless (get-text-property (point) 'mh-expanded)
@@ -359,9 +359,9 @@ uses."
              (setf (gethash folder-name mh-speed-folder-map)
                    (set-marker (or (gethash folder-name mh-speed-folder-map)
                                    (make-marker))
-                               (1+ (mh-line-beginning-position))))
+                               (1+ (line-beginning-position))))
              (add-text-properties
-              (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+              (line-beginning-position) (1+ (line-beginning-position))
               `(mh-folder ,folder-name
                           mh-expanded nil
                           mh-children-p ,(not (not (cdr f)))
@@ -374,12 +374,9 @@ uses."
 (defvar mh-speed-flists-folder nil)
 
 (defmacro mh-process-kill-without-query (process)
-  "PROCESS can be killed without query on Emacs exit.
-Avoid using `process-kill-without-query' if possible since it is
-now obsolete."
-  (if (fboundp 'set-process-query-on-exit-flag)
-      `(set-process-query-on-exit-flag ,process nil)
-    `(process-kill-without-query ,process)))
+  "PROCESS can be killed without query on Emacs exit."
+  (declare (obsolete set-process-query-on-exit-flag "29.1"))
+  `(set-process-query-on-exit-flag ,process nil))
 
 ;;;###mh-autoload
 (defun mh-speed-flists (force &rest folders)
@@ -391,7 +388,7 @@ flists is run only for that one folder."
   (interactive (list t))
   (when force
     (when mh-speed-flists-timer
-      (mh-cancel-timer mh-speed-flists-timer)
+      (cancel-timer mh-speed-flists-timer)
       (setq mh-speed-flists-timer nil))
     (when (and (processp mh-speed-flists-process)
                (not (eq (process-status mh-speed-flists-process) 'exit)))
@@ -427,7 +424,7 @@ flists is run only for that one folder."
                             (or mh-speed-flists-folder '("-recurse"))))
                ;; Run flists on all folders the next time around...
                (setq mh-speed-flists-folder nil)
-               (mh-process-kill-without-query mh-speed-flists-process)
+               (set-process-query-on-exit-flag mh-speed-flists-process nil)
                (set-process-filter mh-speed-flists-process
                                    #'mh-speed-parse-flists-output)))))))
 
@@ -462,25 +459,25 @@ be handled next."
                           face)
                       (when pos
                         (goto-char pos)
-                        (goto-char (mh-line-beginning-position))
+                        (goto-char (line-beginning-position))
                         (cond
                          ((null (get-text-property (point) 'mh-count))
-                          (goto-char (mh-line-end-position))
+                          (goto-char (line-end-position))
                           (setq face (get-text-property (1- (point)) 'face))
                           (insert (format " (%s/%s)" unseen total))
                           (mh-speed-highlight 'unknown face)
-                          (goto-char (mh-line-beginning-position))
+                          (goto-char (line-beginning-position))
                           (add-text-properties (point) (1+ (point))
                                                `(mh-count (,unseen . ,total))))
                          ((not (equal (get-text-property (point) 'mh-count)
                                       (cons unseen total)))
-                          (goto-char (mh-line-end-position))
+                          (goto-char (line-end-position))
                           (setq face (get-text-property (1- (point)) 'face))
-                          (re-search-backward " " (mh-line-beginning-position) 
t)
-                          (delete-region (point) (mh-line-end-position))
+                          (re-search-backward " " (line-beginning-position) t)
+                          (delete-region (point) (line-end-position))
                           (insert (format " (%s/%s)" unseen total))
                           (mh-speed-highlight 'unknown face)
-                          (goto-char (mh-line-beginning-position))
+                          (goto-char (line-beginning-position))
                           (add-text-properties
                            (point) (1+ (point))
                            `(mh-count (,unseen . ,total))))))))))))
@@ -509,15 +506,15 @@ be handled next."
                              (caar parent-kids)))
                  (setq parent-change ? ))))
         (goto-char parent-position)
-        (when (equal (get-text-property (mh-line-beginning-position) 
'mh-folder)
+        (when (equal (get-text-property (line-beginning-position) 'mh-folder)
                      parent)
-          (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
+          (when (get-text-property (line-beginning-position) 'mh-expanded)
             (mh-speed-toggle))
           (when parent-change
             (speedbar-with-writable
               (mh-speedbar-change-expand-button-char parent-change)
               (add-text-properties
-               (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+               (line-beginning-position) (1+ (line-beginning-position))
                `(mh-children-p ,(equal parent-change ?+)))))
           (mh-speed-highlight mh-speed-last-selected-folder 
'mh-speedbar-folder)
           (setq mh-speed-last-selected-folder nil)
@@ -531,7 +528,7 @@ be handled next."
   "Change the expansion button character to CHAR for the current line."
   (save-excursion
     (beginning-of-line)
-    (if (re-search-forward "\\[.\\]" (mh-line-end-position) t)
+    (if (re-search-forward "\\[.\\]" (line-end-position) t)
         (speedbar-with-writable
           (backward-char 2)
           (delete-char 1)
@@ -562,9 +559,9 @@ The function invalidates the latest ancestor that is 
present."
       (speedbar-with-writable
         (mh-speedbar-change-expand-button-char ?+)
         (add-text-properties
-         (mh-line-beginning-position) (1+ (mh-line-beginning-position))
+         (line-beginning-position) (1+ (line-beginning-position))
          '(mh-children-p t)))
-      (when (get-text-property (mh-line-beginning-position) 'mh-expanded)
+      (when (get-text-property (line-beginning-position) 'mh-expanded)
         (mh-speed-toggle))
       (setq mh-speed-refresh-flag t))))
 
diff --git a/lisp/mh-e/mh-thread.el b/lisp/mh-e/mh-thread.el
index 89b0dbd979..21954da6ac 100644
--- a/lisp/mh-e/mh-thread.el
+++ b/lisp/mh-e/mh-thread.el
@@ -86,41 +86,33 @@
   message parent children
   (real-child-p t))
 
-(defvar mh-thread-id-hash nil
+(defvar-local mh-thread-id-hash nil
   "Hash table used to canonicalize message identifiers.")
-(make-variable-buffer-local 'mh-thread-id-hash)
 
-(defvar mh-thread-subject-hash nil
+(defvar-local mh-thread-subject-hash nil
   "Hash table used to canonicalize subject strings.")
-(make-variable-buffer-local 'mh-thread-subject-hash)
 
-(defvar mh-thread-id-table nil
+(defvar-local mh-thread-id-table nil
   "Thread ID table maps from message identifiers to message containers.")
-(make-variable-buffer-local 'mh-thread-id-table)
 
-(defvar mh-thread-index-id-map nil
+(defvar-local mh-thread-index-id-map nil
   "Table to look up message identifier from message index.")
-(make-variable-buffer-local 'mh-thread-index-id-map)
 
-(defvar mh-thread-id-index-map nil
+(defvar-local mh-thread-id-index-map nil
   "Table to look up message index number from message identifier.")
-(make-variable-buffer-local 'mh-thread-id-index-map)
 
-(defvar mh-thread-subject-container-hash nil
+(defvar-local mh-thread-subject-container-hash nil
   "Hash table used to group messages by subject.")
-(make-variable-buffer-local 'mh-thread-subject-container-hash)
 
-(defvar mh-thread-duplicates nil
+(defvar-local mh-thread-duplicates nil
   "Hash table used to associate messages with the same message identifier.")
-(make-variable-buffer-local 'mh-thread-duplicates)
 
-(defvar mh-thread-history ()
+(defvar-local mh-thread-history ()
   "Variable to remember the transformations to the thread tree.
 When new messages are added, these transformations are rewound,
 then the links are added from the newly seen messages. Finally
 the transformations are redone to get the new thread tree. This
 makes incremental threading easier.")
-(make-variable-buffer-local 'mh-thread-history)
 
 (defvar mh-thread-body-width nil
   "Width of scan substring that contains subject and body of message.")
@@ -294,7 +286,7 @@ at the end."
         (while (not (eobp))
           (forward-char address-start-offset)
           (unless (equal (string-match spaces (buffer-substring-no-properties
-                                               (point) (mh-line-end-position)))
+                                               (point) (line-end-position)))
                          0)
             (beginning-of-line)
             (backward-char)
@@ -455,8 +447,8 @@ If optional argument STRING is given then that is assumed 
to be
 the scan line. Otherwise uses the line at point as the scan line
 to parse."
   (let* ((string (or string (buffer-substring-no-properties
-                             (mh-line-beginning-position)
-                             (mh-line-end-position))))
+                             (line-beginning-position)
+                             (line-end-position))))
          (address-start (+ mh-cmd-note mh-scan-field-from-start-offset))
          (body-start (+ mh-cmd-note mh-scan-field-from-end-offset))
          (first-string (substring string 0 address-start)))
@@ -597,20 +589,20 @@ Only information about messages in MSG-LIST are added to 
the tree."
         (while (not (eobp))
           (cl-block process-message
             (let* ((index-line
-                    (prog1 (buffer-substring (point) (mh-line-end-position))
+                    (prog1 (buffer-substring (point) (line-end-position))
                       (forward-line)))
                    (index (string-to-number index-line))
-                   (id (prog1 (buffer-substring (point) (mh-line-end-position))
+                   (id (prog1 (buffer-substring (point) (line-end-position))
                          (forward-line)))
                    (refs (prog1
-                             (buffer-substring (point) (mh-line-end-position))
+                             (buffer-substring (point) (line-end-position))
                            (forward-line)))
                    (in-reply-to (prog1 (buffer-substring (point)
-                                                         
(mh-line-end-position))
+                                                         (line-end-position))
                                   (forward-line)))
                    (subject (prog1
                                 (buffer-substring
-                                 (point) (mh-line-end-position))
+                                 (point) (line-end-position))
                               (forward-line)))
                    (subject-re-p nil))
               (unless (gethash index mh-thread-scan-line-map)
diff --git a/lisp/mh-e/mh-tool-bar.el b/lisp/mh-e/mh-tool-bar.el
index 94aa8dd4a9..0200d232c3 100644
--- a/lisp/mh-e/mh-tool-bar.el
+++ b/lisp/mh-e/mh-tool-bar.el
@@ -27,10 +27,8 @@
 ;;; Code:
 
 (require 'mh-e)
-(mh-do-in-gnu-emacs
-  (require 'tool-bar))
-(mh-do-in-xemacs
-  (require 'toolbar))
+(require 'mh-acros)
+(require 'tool-bar)
 
 ;;; Tool Bar Commands
 
@@ -79,9 +77,6 @@ When INCLUDE-FLAG is non-nil, include message body being 
replied to."
 
 ;;; Tool Bar Creation
 
-;; Shush compiler.
-(defvar image-load-path)
-
 (defmacro mh-tool-bar-define (defaults &rest buttons)
   "Define a tool bar for MH-E.
 DEFAULTS is the list of buttons that are present by default. It
@@ -145,8 +140,6 @@ where,
       (let* ((name (nth 0 button))
              (name-str (symbol-name name))
              (icon (nth 2 button))
-             (xemacs-icon (mh-do-in-xemacs
-                            `(cdr (assoc (quote ,(intern icon)) 
mh-xemacs-icon-map))))
              (full-doc (nth 3 button))
              (doc (if (string-match "\\(.*\\)\n" full-doc)
                       (match-string 1 full-doc)
@@ -186,7 +179,7 @@ where,
                                  (t 'folder-buttons)))
                  (docs (cond ((eq mbuttons 'letter-buttons) 'letter-docs)
                              ((eq mbuttons 'folder-buttons) 'folder-docs))))
-            (add-to-list vector-list `(vector ,xemacs-icon ',function t 
,full-doc))
+            (add-to-list vector-list `(vector nil ',function t ,full-doc))
             (add-to-list
              setter `(when (member ',name ,list)
                        (mh-funcall-if-exists
@@ -209,145 +202,69 @@ where,
       (unless (memq x letter-buttons)
         (error "Letter defaults contains unknown button %s" x)))
     `(eval-and-compile
-       ;; GNU Emacs tool bar specific code
-       (mh-do-in-gnu-emacs
-         (defun mh-buffer-exists-p (mode)
-           "Test whether a buffer with major mode MODE is present."
-           (cl-loop for buf in (buffer-list)
-                    when (with-current-buffer buf
-                           (eq major-mode mode))
-                    return t))
-         ;; Tool bar initialization functions
-         (defun mh-tool-bar-folder-buttons-init ()
-           (when (mh-buffer-exists-p 'mh-folder-mode)
-             (let* ((load-path (mh-image-load-path-for-library "mh-e"
-                                                               "mh-logo.xpm"))
-                    (image-load-path (cons (car load-path)
-                                           (when (boundp 'image-load-path)
-                                             image-load-path))))
-               (setq mh-folder-tool-bar-map
-                     (let ((tool-bar-map (make-sparse-keymap)))
-                       ,@(nreverse folder-button-setter)
-                       tool-bar-map))
-               (setq mh-folder-seq-tool-bar-map
-                     (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
-                       ,@(nreverse sequence-button-setter)
-                       tool-bar-map))
-               (setq mh-show-tool-bar-map
-                     (let ((tool-bar-map (make-sparse-keymap)))
-                       ,@(nreverse show-button-setter)
-                       tool-bar-map))
-               (setq mh-show-seq-tool-bar-map
-                     (let ((tool-bar-map (copy-keymap mh-show-tool-bar-map)))
-                       ,@(nreverse show-seq-button-setter)
-                       tool-bar-map)))))
-         (defun mh-tool-bar-letter-buttons-init ()
-           (when (mh-buffer-exists-p 'mh-letter-mode)
-             (let* ((load-path (mh-image-load-path-for-library "mh-e"
-                                                               "mh-logo.xpm"))
-                    (image-load-path (cons (car load-path)
-                                           (when (boundp 'image-load-path)
-                                             image-load-path))))
-               (setq mh-letter-tool-bar-map
-                     (let ((tool-bar-map (make-sparse-keymap)))
-                       ,@(nreverse letter-button-setter)
-                       tool-bar-map)))))
-         ;; Custom setter functions
-         (defun mh-tool-bar-update (mode default-map sequence-map)
-           "Update `tool-bar-map' in all buffers of MODE.
+       (defun mh-buffer-exists-p (mode)
+         "Test whether a buffer with major mode MODE is present."
+         (cl-loop for buf in (buffer-list)
+                  when (with-current-buffer buf
+                         (eq major-mode mode))
+                  return t))
+       ;; Tool bar initialization functions
+       (defun mh-tool-bar-folder-buttons-init ()
+         (when (mh-buffer-exists-p 'mh-folder-mode)
+           (mh--with-image-load-path
+             (setq mh-folder-tool-bar-map
+                   (let ((tool-bar-map (make-sparse-keymap)))
+                     ,@(nreverse folder-button-setter)
+                     tool-bar-map))
+             (setq mh-folder-seq-tool-bar-map
+                   (let ((tool-bar-map (copy-keymap mh-folder-tool-bar-map)))
+                     ,@(nreverse sequence-button-setter)
+                     tool-bar-map))
+             (setq mh-show-tool-bar-map
+                   (let ((tool-bar-map (make-sparse-keymap)))
+                     ,@(nreverse show-button-setter)
+                     tool-bar-map))
+             (setq mh-show-seq-tool-bar-map
+                   (let ((tool-bar-map (copy-keymap mh-show-tool-bar-map)))
+                     ,@(nreverse show-seq-button-setter)
+                     tool-bar-map)))))
+       (defun mh-tool-bar-letter-buttons-init ()
+         (when (mh-buffer-exists-p 'mh-letter-mode)
+           (mh--with-image-load-path
+             (setq mh-letter-tool-bar-map
+                   (let ((tool-bar-map (make-sparse-keymap)))
+                     ,@(nreverse letter-button-setter)
+                     tool-bar-map)))))
+       ;; Custom setter functions
+       (defun mh-tool-bar-update (mode default-map sequence-map)
+         "Update `tool-bar-map' in all buffers of MODE.
 Use SEQUENCE-MAP if display is limited; DEFAULT-MAP otherwise."
-           (cl-loop for buf in (buffer-list)
-                    do (with-current-buffer buf
-                         (when (eq mode major-mode) ;FIXME: derived-mode-p?
-                           (let ((map (if mh-folder-view-stack
-                                          sequence-map
-                                        default-map)))
-                             ;; Yes, make-local-variable is necessary since we
-                             ;; get here during initialization when loading
-                             ;; mh-e.el, after the +inbox buffer has been
-                             ;; created, but before mh-folder-mode has run and
-                             ;; created the local map.
-                             (set (make-local-variable 'tool-bar-map) map))))))
-         (defun mh-tool-bar-folder-buttons-set (symbol value)
-           "Construct tool bar for `mh-folder-mode' and `mh-show-mode'."
-           (set-default symbol value)
-           (mh-tool-bar-folder-buttons-init)
-           (mh-tool-bar-update 'mh-folder-mode mh-folder-tool-bar-map
-                               mh-folder-seq-tool-bar-map)
-           (mh-tool-bar-update 'mh-show-mode mh-show-tool-bar-map
-                               mh-show-seq-tool-bar-map))
-         (defun mh-tool-bar-letter-buttons-set (symbol value)
-           "Construct tool bar for `mh-letter-mode'."
-           (set-default symbol value)
-           (mh-tool-bar-letter-buttons-init)
-           (mh-tool-bar-update 'mh-letter-mode mh-letter-tool-bar-map
-                               mh-letter-tool-bar-map)))
-       ;; XEmacs specific code
-       (mh-do-in-xemacs
-         (defvar mh-tool-bar-folder-vector-map
-           (list ,@(cl-loop for button in folder-buttons
-                            for vector in folder-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-show-vector-map
-           (list ,@(cl-loop for button in show-buttons
-                            for vector in show-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-letter-vector-map
-           (list ,@(cl-loop for button in letter-buttons
-                            for vector in letter-vectors
-                            collect `(cons ',button ,vector))))
-         (defvar mh-tool-bar-folder-buttons)
-         (defvar mh-tool-bar-show-buttons)
-         (defvar mh-tool-bar-letter-buttons)
-         ;; Custom setter functions
-         (defun mh-tool-bar-letter-buttons-set (symbol value)
-           (set-default symbol value)
-           (when mh-xemacs-has-tool-bar-flag
-             (setq mh-tool-bar-letter-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-letter-vector-map))))))
-         (defun mh-tool-bar-folder-buttons-set (symbol value)
-           (set-default symbol value)
-           (when mh-xemacs-has-tool-bar-flag
-             (setq mh-tool-bar-folder-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-folder-vector-map))))
-             (setq mh-tool-bar-show-buttons
-                   (cl-loop
-                    for b in value
-                    collect (cdr (assoc b mh-tool-bar-show-vector-map))))))
-         (defun mh-tool-bar-init (mode)
-           "Install tool bar in MODE."
-           (when mh-xemacs-use-tool-bar-flag
-             (let ((tool-bar (cond ((eq mode :folder)
-                                    mh-tool-bar-folder-buttons)
-                                   ((eq mode :letter)
-                                    mh-tool-bar-letter-buttons)
-                                   ((eq mode :show)
-                                    mh-tool-bar-show-buttons)))
-                   (height 37)
-                   (width 40)
-                   (buffer (current-buffer)))
-               (cond
-                ((eq mh-xemacs-tool-bar-position 'top)
-                 (set-specifier top-toolbar tool-bar buffer)
-                 (set-specifier top-toolbar-visible-p t)
-                 (set-specifier top-toolbar-height height))
-                ((eq mh-xemacs-tool-bar-position 'bottom)
-                 (set-specifier bottom-toolbar tool-bar buffer)
-                 (set-specifier bottom-toolbar-visible-p t)
-                 (set-specifier bottom-toolbar-height height))
-                ((eq mh-xemacs-tool-bar-position 'left)
-                 (set-specifier left-toolbar tool-bar buffer)
-                 (set-specifier left-toolbar-visible-p t)
-                 (set-specifier left-toolbar-width width))
-                ((eq mh-xemacs-tool-bar-position 'right)
-                 (set-specifier right-toolbar tool-bar buffer)
-                 (set-specifier right-toolbar-visible-p t)
-                 (set-specifier right-toolbar-width width))
-                (t (set-specifier default-toolbar tool-bar buffer)))))))
+         (cl-loop for buf in (buffer-list)
+                  do (with-current-buffer buf
+                       (when (eq mode major-mode) ;FIXME: derived-mode-p?
+                         (let ((map (if mh-folder-view-stack
+                                        sequence-map
+                                      default-map)))
+                           ;; Yes, make-local-variable is necessary since we
+                           ;; get here during initialization when loading
+                           ;; mh-e.el, after the +inbox buffer has been
+                           ;; created, but before mh-folder-mode has run and
+                           ;; created the local map.
+                           (setq-local tool-bar-map map))))))
+       (defun mh-tool-bar-folder-buttons-set (symbol value)
+         "Construct tool bar for `mh-folder-mode' and `mh-show-mode'."
+         (set-default symbol value)
+         (mh-tool-bar-folder-buttons-init)
+         (mh-tool-bar-update 'mh-folder-mode mh-folder-tool-bar-map
+                             mh-folder-seq-tool-bar-map)
+         (mh-tool-bar-update 'mh-show-mode mh-show-tool-bar-map
+                             mh-show-seq-tool-bar-map))
+       (defun mh-tool-bar-letter-buttons-set (symbol value)
+         "Construct tool bar for `mh-letter-mode'."
+         (set-default symbol value)
+         (mh-tool-bar-letter-buttons-init)
+         (mh-tool-bar-update 'mh-letter-mode mh-letter-tool-bar-map
+                             mh-letter-tool-bar-map))
        ;; Declare customizable tool bars
        (custom-declare-variable
         'mh-tool-bar-folder-buttons
@@ -372,7 +289,6 @@ Use SEQUENCE-MAP if display is limited; DEFAULT-MAP 
otherwise."
         ;;:package-version '(MH-E "7.1")
         ))))
 
-;; The icon names are duplicated in the Makefile and mh-xemacs.el.
 (mh-tool-bar-define
  ((:folder mh-inc-folder mh-mime-save-parts
            mh-previous-undeleted-msg mh-page-msg
diff --git a/lisp/mh-e/mh-utils.el b/lisp/mh-e/mh-utils.el
index bbce17013b..feebf6416f 100644
--- a/lisp/mh-e/mh-utils.el
+++ b/lisp/mh-e/mh-utils.el
@@ -52,7 +52,7 @@ used in lieu of `search' in the CL package."
   (let ((syntax-table (syntax-table)))
     (unwind-protect
         (save-excursion
-          (mh-mail-abbrev-make-syntax-table)
+          (mail-abbrev-make-syntax-table)
           (set-syntax-table mail-abbrev-syntax-table)
           (backward-word n)
           (point))
@@ -61,9 +61,9 @@ used in lieu of `search' in the CL package."
 ;;;###mh-autoload
 (defun mh-colors-available-p ()
   "Check if colors are available in the Emacs being used."
-  (or (featurep 'xemacs)
-      (let ((color-cells (mh-display-color-cells)))
-        (and (numberp color-cells) (>= color-cells 8)))))
+  ;; FIXME: Can this be replaced with `display-color-p'?
+  (let ((color-cells (display-color-cells)))
+    (and (numberp color-cells) (>= color-cells 8))))
 
 ;;;###mh-autoload
 (defun mh-colors-in-use-p ()
@@ -78,16 +78,13 @@ used in lieu of `search' in the CL package."
 ;;;###mh-autoload
 (defun mh-make-local-vars (&rest pairs)
   "Initialize local variables according to the variable-value PAIRS."
+  (declare (obsolete setq-local "29.1"))
   (while pairs
     (set (make-local-variable (car pairs)) (car (cdr pairs)))
     (setq pairs (cdr (cdr pairs)))))
 
 ;;;###mh-autoload
-(defun mh-mapc (function list)
-  "Apply FUNCTION to each element of LIST for side effects only."
-  (while list
-    (funcall function (car list))
-    (setq list (cdr list))))
+(define-obsolete-function-alias 'mh-mapc #'mapc "29.1")
 
 (defvar mh-pick-regexp-chars ".*$["
   "List of special characters in pick regular expressions.")
@@ -102,7 +99,7 @@ PICK-EXPR is a list of strings. Return nil if PICK-EXPR is 
nil."
                  (not (string-equal string "")))
         (cl-loop for i from 0 to (1- (length mh-pick-regexp-chars)) do
                  (let ((s (string ?\\ (aref mh-pick-regexp-chars i))))
-                   (setq string (mh-replace-regexp-in-string s s string t t))))
+                   (setq string (replace-regexp-in-string s s string t t))))
         (setq quoted-pick-expr (append quoted-pick-expr (list string)))))
     quoted-pick-expr))
 
@@ -119,34 +116,33 @@ Ignores case when searching for OLD."
 
 ;;; Logo Display
 
-(defvar mh-logo-cache nil)
+;;;###mh-autoload
+(defmacro mh--with-image-load-path (&rest body)
+  "Load `image' and eval BODY with `image-load-path' set appropriately."
+  (declare (debug t) (indent 0))
+  `(progn
+     ;; Not preloaded in without-x builds.
+     (require 'image)
+     (defvar image-load-path)
+     (declare-function image-load-path-for-library "image")
+     (let* ((load-path (image-load-path-for-library "mh-e" "mh-logo.xpm"))
+            (image-load-path (cons (car load-path) image-load-path)))
+       ,@body)))
 
-;; Shush compiler.
-(defvar image-load-path)
+(defvar mh-logo-cache nil)
 
 ;;;###mh-autoload
 (defun mh-logo-display ()
   "Modify mode line to display MH-E logo."
-  (mh-do-in-gnu-emacs
-    (let* ((load-path (mh-image-load-path-for-library "mh-e" "mh-logo.xpm"))
-           (image-load-path (cons (car load-path)
-                                  (when (boundp 'image-load-path)
-                                    image-load-path))))
-      (add-text-properties
-       0 2
-       `(display ,(or mh-logo-cache
-                      (setq mh-logo-cache
-                            (mh-funcall-if-exists
-                             find-image '((:type xpm :ascent center
-                                                 :file "mh-logo.xpm"))))))
-       (car mode-line-buffer-identification))))
-  (mh-do-in-xemacs
-    (setq modeline-buffer-identification
-          (list
-           (if mh-modeline-glyph
-               (cons modeline-buffer-id-left-extent mh-modeline-glyph)
-             (cons modeline-buffer-id-left-extent "XEmacs%N:"))
-           (cons modeline-buffer-id-right-extent " %17b")))))
+  (mh--with-image-load-path
+    (add-text-properties
+     0 2
+     `(display ,(or mh-logo-cache
+                    (setq mh-logo-cache
+                          (mh-funcall-if-exists
+                           find-image '(( :type xpm :ascent center
+                                          :file "mh-logo.xpm" ))))))
+     (car mode-line-buffer-identification))))
 
 
 
@@ -509,8 +505,8 @@ they will not be returned."
     ;; folder is specified, ensure it is nil to avoid adding the
     ;; folder to the folder-list and adding a slash to it.
     (when folder
-      (setq folder (mh-replace-regexp-in-string "^\\+" "" folder))
-      (setq folder (mh-replace-regexp-in-string "/+$" "" folder))
+      (setq folder (replace-regexp-in-string "^\\+" "" folder))
+      (setq folder (replace-regexp-in-string "/+$" "" folder))
       (if (equal folder "")
           (setq folder nil)))
     ;; Add provided folder to list, unless all folders are asked for.
@@ -573,10 +569,10 @@ Expects FOLDER to have already been normalized with
       (apply #'call-process arg-list)
       (goto-char (point-min))
       (while (not (and (eolp) (bolp)))
-        (goto-char (mh-line-end-position))
-        (let ((start-pos (mh-line-beginning-position))
+        (goto-char (line-end-position))
+        (let ((start-pos (line-beginning-position))
               (has-pos (search-backward " has "
-                                        (mh-line-beginning-position) t)))
+                                        (line-beginning-position) t)))
           (when (integerp has-pos)
             (while (equal (char-after has-pos) ? )
               (cl-decf has-pos))
@@ -591,7 +587,7 @@ Expects FOLDER to have already been normalized with
                   (setq name (substring name 0 (1- (length name)))))
                 (push
                  (cons name
-                       (search-forward "(others)" (mh-line-end-position) t))
+                       (search-forward "(others)" (line-end-position) t))
                  results))))
           (forward-line 1))))
     (setq results (nreverse results))
@@ -727,16 +723,12 @@ See Info node `(elisp) Programmed Completion' for 
details."
                    ((equal path mh-user-path) nil)
                    (t (file-directory-p path))))))))
 
-;; Shush compiler.
-(defvar completion-root-regexp) ;; Apparently used in XEmacs
-
 (defun mh-folder-completing-read (prompt default allow-root-folder-flag)
   "Read folder name with PROMPT and default result DEFAULT.
 If ALLOW-ROOT-FOLDER-FLAG is non-nil then \"+\" is allowed to be
 a folder name corresponding to `mh-user-path'."
   (mh-normalize-folder-name
-   (let ((completion-root-regexp "^[+/]") ;FIXME: Who/what uses that?
-         (minibuffer-local-completion-map mh-folder-completion-map)
+   (let ((minibuffer-local-completion-map mh-folder-completion-map)
          (mh-allow-root-folder-flag allow-root-folder-flag))
      (completing-read prompt 'mh-folder-completion-function nil nil nil
                       'mh-folder-hist default))
@@ -920,11 +912,7 @@ Handle RFC 822 (or later) continuation lines."
 
 (defvar mh-hidden-header-keymap
   (let ((map (make-sparse-keymap)))
-    (mh-do-in-gnu-emacs
-      (define-key map [mouse-2] 
#'mh-letter-toggle-header-field-display-button))
-    (mh-do-in-xemacs
-      (define-key map '(button2)
-        #'mh-letter-toggle-header-field-display-button))
+    (define-key map [mouse-2] #'mh-letter-toggle-header-field-display-button)
     map))
 
 ;;;###mh-autoload
@@ -958,9 +946,9 @@ is hidden, if positive then the field is displayed."
                      (and (numberp arg)
                           (>= arg 0))
                      (and (eq arg 'long)
-                          (> (mh-line-beginning-position 5) end)))
+                          (> (line-beginning-position 5) end)))
                  (remove-text-properties begin end '(invisible nil))
-                 (search-forward ":" (mh-line-end-position) t)
+                 (search-forward ":" (line-end-position) t)
                  (mh-letter-skip-leading-whitespace-in-header-field))
                 ;; XXX Redesign to make usable by user. Perhaps use a positive
                 ;; numeric prefix to make that many lines visible.
diff --git a/lisp/mh-e/mh-xface.el b/lisp/mh-e/mh-xface.el
index 58177c1794..0c1bcdfefd 100644
--- a/lisp/mh-e/mh-xface.el
+++ b/lisp/mh-e/mh-xface.el
@@ -30,17 +30,11 @@
 (autoload 'mail-header-parse-address "mail-parse")
 (autoload 'message-fetch-field "message")
 
-(defvar mh-show-xface-function
-  (cond ((and (featurep 'xemacs) (locate-library "x-face") (not (featurep 
'xface)))
-         (load "x-face" t t)
-         #'mh-face-display-function)
-        ((>= emacs-major-version 21)
-         #'mh-face-display-function)
-        (t #'ignore))
+(defvar mh-show-xface-function #'mh-face-display-function
   "Determine at run time what function should be called to display X-Face.")
+(make-obsolete-variable 'mh-show-xface-function nil "29.1")
 
-(defvar mh-uncompface-executable
-  (and (fboundp 'executable-find) (executable-find "uncompface")))
+(defvar mh-uncompface-executable (executable-find "uncompface"))
 
 
 
@@ -52,7 +46,7 @@
   (when (and window-system mh-show-use-xface-flag
              (or mh-decode-mime-flag mh-mhl-format-file
                  mh-clean-message-header-flag))
-    (funcall mh-show-xface-function)))
+    (mh-face-display-function)))
 
 (defun mh-face-display-function ()
   "Display a Face, X-Face, or X-Image-URL header field.
@@ -77,53 +71,21 @@ in this order is used."
       (when type
         (goto-char (point-min))
         (when (re-search-forward "^from:" (point-max) t)
-          ;; GNU Emacs
-          (mh-do-in-gnu-emacs
-            (if (eq type 'url)
-                (mh-x-image-url-display url)
-              (mh-funcall-if-exists
-               insert-image (create-image
-                             raw type t
-                             :foreground
-                             (mh-face-foreground 'mh-show-xface nil t)
-                             :background
-                             (mh-face-background 'mh-show-xface nil t))
-               " ")))
-          ;; XEmacs
-          (mh-do-in-xemacs
-            (cond
-             ((eq type 'url)
-              (mh-x-image-url-display url))
-             ((eq type 'png)
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector 'png ':data (mh-face-to-png face))))))
-             ;; Try internal xface support if available...
-             ((and (eq type 'pbm) (featurep 'xface))
-              (set-glyph-face
-               (set-extent-begin-glyph
-                (make-extent (point) (point))
-                (make-glyph (vector 'xface ':data (concat "X-Face: " x-face))))
-               'mh-show-xface))
-             ;; Otherwise try external support with x-face...
-             ((and (eq type 'pbm)
-                   (fboundp 'x-face-xmas-wl-display-x-face)
-                   (fboundp 'executable-find) (executable-find "uncompface"))
-              (mh-funcall-if-exists x-face-xmas-wl-display-x-face))
-             ;; Picon display
-             ((and raw (member type '(xpm xbm gif)))
-              (when (featurep type)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph (vector type ':data raw))))))
-            (when raw (insert " "))))))))
+          (if (eq type 'url)
+              (mh-x-image-url-display url)
+            (mh-funcall-if-exists
+             insert-image (create-image
+                           raw type t
+                           :foreground
+                           (face-foreground 'mh-show-xface nil t)
+                           :background
+                           (face-background 'mh-show-xface nil t))
+             " ")))))))
 
 (defun mh-face-to-png (data)
   "Convert base64 encoded DATA to png image."
   (with-temp-buffer
-    (if (fboundp 'set-buffer-multibyte)
-        (set-buffer-multibyte nil))
+    (set-buffer-multibyte nil)
     (insert data)
     (ignore-errors (base64-decode-region (point-min) (point-max)))
     (buffer-string)))
@@ -131,8 +93,7 @@ in this order is used."
 (defun mh-uncompface (data)
   "Run DATA through `uncompface' to generate bitmap."
   (with-temp-buffer
-    (if (fboundp 'set-buffer-multibyte)
-        (set-buffer-multibyte nil))
+    (set-buffer-multibyte nil)
     (insert data)
     (when (and mh-uncompface-executable
                (equal (call-process-region (point-min) (point-max)
@@ -176,10 +137,8 @@ The directories are searched for in the order they appear 
in the list.")
 
 (defvar mh-picon-image-types
   (cl-loop for type in '(xpm xbm gif)
-           when (or (mh-do-in-gnu-emacs
-                     (ignore-errors
-                       (mh-funcall-if-exists image-type-available-p type)))
-                    (mh-do-in-xemacs (featurep type)))
+           when (ignore-errors
+                  (image-type-available-p type))
            collect type))
 
 (autoload 'message-tokenize-header "sendmail")
@@ -270,8 +229,7 @@ file contents as a string is returned. If FILE is nil, then 
both
 elements of the list are nil."
   (if (stringp file)
       (with-temp-buffer
-        (if (fboundp 'set-buffer-multibyte)
-            (set-buffer-multibyte nil))
+        (set-buffer-multibyte nil)
         (let ((type (and (string-match ".*\\.\\(...\\)$" file)
                          (intern (match-string 1 file)))))
           (insert-file-contents-literally file)
@@ -321,7 +279,7 @@ If the URL isn't present in the cache then it is fetched 
with wget."
   (let* ((cache-filename (mh-x-image-url-cache-canonicalize url))
          (state (mh-x-image-get-download-state cache-filename))
          (marker (point-marker)))
-    (set (make-local-variable 'mh-x-image-marker) marker)
+    (setq-local mh-x-image-marker marker)
     (cond ((not (mh-x-image-url-sane-p url)))
           ((eq state 'ok)
            (mh-x-image-display cache-filename marker))
@@ -357,14 +315,14 @@ This is only done if `mh-x-image-cache-directory' is nil."
 (defun mh-x-image-url-cache-canonicalize (url)
   "Canonicalize URL.
 Replace the ?/ character with a ?! character and append .png.
-Also replaces special characters with `mh-url-hexify-string'
+Also replaces special characters with `url-hexify-string'
 since not all characters, such as :, are valid within Windows
 filenames.  In addition, replaces * with %2a. See URL
 
`https://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/iitemnamelimits/GetValidCharacters.asp'."
   (format "%s/%s.png" mh-x-image-cache-directory
-          (mh-replace-regexp-in-string
+          (replace-regexp-in-string
            "\\*" "%2a"
-           (mh-url-hexify-string
+           (url-hexify-string
             (with-temp-buffer
               (insert url)
               (mh-replace-string "/" "!")
@@ -404,16 +362,7 @@ filenames.  In addition, replaces * with %2a. See URL
           (when (and (file-readable-p image) (not (file-symlink-p image))
                      (eq marker mh-x-image-marker))
             (goto-char marker)
-            (mh-do-in-gnu-emacs
-              (mh-funcall-if-exists insert-image (create-image image 'png)))
-            (mh-do-in-xemacs
-              (when (featurep 'png)
-                (set-extent-begin-glyph
-                 (make-extent (point) (point))
-                 (make-glyph
-                  (vector 'png ':data (with-temp-buffer
-                                        (insert-file-contents-literally image)
-                                        (buffer-string))))))))
+            (insert-image (create-image image 'png)))
         (set-buffer-modified-p buffer-modified-flag)))))
 
 (defun mh-x-image-url-fetch-image (url cache-file marker sentinel)
@@ -423,12 +372,11 @@ be displayed in a buffer and position specified by 
MARKER. The
 actual display is carried out by the SENTINEL function."
   (if mh-wget-executable
       (let ((buffer (generate-new-buffer mh-temp-fetch-buffer))
-            (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
-                          (expand-file-name (make-temp-name "~/mhe-fetch")))))
+            (filename (make-temp-file "mhe-fetch")))
         (with-current-buffer buffer
-          (set (make-local-variable 'mh-x-image-url-cache-file) cache-file)
-          (set (make-local-variable 'mh-x-image-marker) marker)
-          (set (make-local-variable 'mh-x-image-temp-file) filename))
+          (setq-local mh-x-image-url-cache-file cache-file)
+          (setq-local mh-x-image-marker marker)
+          (setq-local mh-x-image-temp-file filename))
         (set-process-sentinel
          (start-process "*mh-x-image-url-fetch*" buffer
                         mh-wget-executable mh-wget-option filename url)
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 1e1a6f852e..0fea057d1c 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1,4 +1,4 @@
-;;; minibuffer.el --- Minibuffer completion functions -*- lexical-binding: t 
-*-
+;;; minibuffer.el --- Minibuffer and completion functions -*- lexical-binding: 
t -*-
 
 ;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
@@ -943,7 +943,12 @@ When completing \"foo\" the glob \"*f*o*o*\" is used, so 
that
      completion-initials-try-completion completion-initials-all-completions
      "Completion of acronyms and initialisms.
 E.g. can complete M-x lch to list-command-history
-and C-x C-f ~/sew to ~/src/emacs/work."))
+and C-x C-f ~/sew to ~/src/emacs/work.")
+    (shorthand
+     completion-shorthand-try-completion completion-shorthand-all-completions
+     "Completion of symbol shorthands setup in `read-symbol-shorthands'.
+E.g. can complete \"x-foo\" to \"xavier-foo\" if the shorthand
+((\"x-\" . \"xavier-\")) is set up in the buffer of origin."))
   "List of available completion styles.
 Each element has the form (NAME TRY-COMPLETION ALL-COMPLETIONS DOC):
 where NAME is the name that should be used in `completion-styles',
@@ -990,7 +995,8 @@ styles for specific categories, such as files, buffers, 
etc."
     ;; e.g. one that does not anchor to bos.
     (project-file (styles . (substring)))
     (xref-location (styles . (substring)))
-    (info-menu (styles . (basic substring))))
+    (info-menu (styles . (basic substring)))
+    (symbol-help (styles . (basic shorthand substring))))
   "Default settings for specific completion categories.
 Each entry has the shape (CATEGORY . ALIST) where ALIST is
 an association list that can specify properties such as:
@@ -1618,6 +1624,9 @@ DONT-CYCLE tells the function not to setup cycling."
 (defvar minibuffer--require-match nil
   "Value of REQUIRE-MATCH passed to `completing-read'.")
 
+(defvar minibuffer--original-buffer nil
+  "Buffer that was current when `completing-read' was called.")
+
 (defun minibuffer-complete-and-exit ()
   "Exit if the minibuffer contains a valid completion.
 Otherwise, try to complete the minibuffer contents.  If
@@ -3205,7 +3214,6 @@ See `read-file-name' for the meaning of the arguments."
         (unless val (error "No file name specified"))
 
         (if (and default-filename
-                (not (file-remote-p dir))
                  (string-equal val (if (consp insdef) (car insdef) insdef)))
             (setq val default-filename))
         (setq val (substitute-in-file-name val))
@@ -3571,12 +3579,13 @@ between 0 and 1, and with faces 
`completions-common-part',
                 ;; "hole" in the middle of the string is indicated by
                 ;; "-".  Note that there are no "holes" near the edges
                 ;; of the string.  The completion score is a number
-                ;; bound by ]0..1]: the higher the better and only a
-                ;; perfect match (pattern equals string) will have
-                ;; score 1.  The formula takes the form of a quotient.
-                ;; For the numerator, we use the number of +, i.e. the
-                ;; length of the pattern.  For the denominator, it
-                ;; first computes
+                ;; bound by (0..1] (i.e., larger than (but not equal
+                ;; to) zero, and smaller or equal to one): the higher
+                ;; the better and only a perfect match (pattern equals
+                ;; string) will have score 1.  The formula takes the
+                ;; form of a quotient.  For the numerator, we use the
+                ;; number of +, i.e. the length of the pattern.  For
+                ;; the denominator, it first computes
                 ;;
                 ;;     hole_i_contrib = 1 + (Li-1)^(1/tightness)
                 ;;
@@ -4080,6 +4089,40 @@ which is at the core of flex logic.  The extra
   (let ((newstr (completion-initials-expand string table pred)))
     (when newstr
       (completion-pcm-try-completion newstr table pred (length newstr)))))
+
+;; Shorthand completion
+;;
+;; Iff there is a (("x-" . "string-library-")) shorthand setup and
+;; string-library-foo is in candidates, complete x-foo to it.
+
+(defun completion-shorthand-try-completion (string table pred point)
+  "Try completion with `read-symbol-shorthands' of original buffer."
+  (cl-loop with expanded
+           for (short . long) in
+           (with-current-buffer minibuffer--original-buffer
+             read-symbol-shorthands)
+           for probe =
+           (and (> point (length short))
+                (string-prefix-p short string)
+                (try-completion (setq expanded
+                                      (concat long
+                                              (substring
+                                               string
+                                               (length short))))
+                                table pred))
+           when probe
+           do (message "Shorthand expansion")
+           and return (cons expanded (max (length long)
+                                          (+ (- point (length short))
+                                             (length long))))))
+
+(defun completion-shorthand-all-completions (_string _table _pred _point)
+  ;; no-op: For now, we don't want shorthands to list all the possible
+  ;; locally active longhands.  For the completion categories where
+  ;; this style is active, it could hide other more interesting
+  ;; matches from subsequent styles.
+  nil)
+
 
 (defvar completing-read-function #'completing-read-default
   "The function called by `completing-read' to do its work.
@@ -4111,6 +4154,7 @@ See `completing-read' for the meaning of the arguments."
                     ;; in minibuffer-local-filename-completion-map can
                     ;; override bindings in base-keymap.
                     base-keymap)))
+         (buffer (current-buffer))
          (result
           (minibuffer-with-setup-hook
               (lambda ()
@@ -4119,7 +4163,8 @@ See `completing-read' for the meaning of the arguments."
                 ;; FIXME: Remove/rename this var, see the next one.
                 (setq-local minibuffer-completion-confirm
                             (unless (eq require-match t) require-match))
-                (setq-local minibuffer--require-match require-match))
+                (setq-local minibuffer--require-match require-match)
+                (setq-local minibuffer--original-buffer buffer))
             (read-from-minibuffer prompt initial-input keymap
                                   nil hist def inherit-input-method))))
     (when (and (equal result "") def)
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 8ad3f7664a..4f9c49ce46 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -290,6 +290,7 @@ and should return the same menu with changes such as added 
new menu items."
   :type '(repeat
           (choice (function-item context-menu-undo)
                   (function-item context-menu-region)
+                  (function-item context-menu-middle-separator)
                   (function-item context-menu-toolbar)
                   (function-item context-menu-global)
                   (function-item context-menu-local)
@@ -328,7 +329,7 @@ the function `context-menu-filter-function'."
 
     ;; Remove duplicate separators
     (let ((l menu))
-      (while l
+      (while (consp l)
         (when (and (equal (cdr-safe (car l)) menu-bar-separator)
                    (equal (cdr-safe (cadr l)) menu-bar-separator))
           (setcdr l (cddr l)))
@@ -363,7 +364,7 @@ Some context functions add menu items below the separator."
                 (when (consp binding)
                   (define-key-after menu (vector key)
                     (copy-sequence binding))))
-              (lookup-key global-map [menu-bar]))
+              (menu-bar-keymap global-map))
   menu)
 
 (defun context-menu-local (menu _click)
@@ -478,24 +479,18 @@ Some context functions add menu items below the 
separator."
       `(menu-item "All"
                   ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'buffer))
                   :help "Mark the whole buffer for a subsequent cut/copy"))
-    (define-key-after submenu [mark-defun]
-      `(menu-item "Defun"
-                  ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'defun))
-                  :help "Mark the defun at click for a subsequent cut/copy"))
-    (define-key-after submenu [mark-list-or-string]
-      `(menu-item ,(if (nth 8 (save-excursion
-                                (syntax-ppss (posn-point (event-end click)))))
-                       "String" "List")
-                  ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'list-or-string))
-                  :help "Mark list or string at click for a subsequent 
cut/copy"))
+    (when (let* ((pos (posn-point (event-end click)))
+                 (char (when pos (char-after pos))))
+            (or (and char (eq (char-syntax char) ?\"))
+                (nth 3 (save-excursion (syntax-ppss pos)))))
+      (define-key-after submenu [mark-string]
+        `(menu-item "String"
+                    ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'string))
+                    :help "Mark the string at click for a subsequent 
cut/copy")))
     (define-key-after submenu [mark-line]
       `(menu-item "Line"
                   ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 'line))
                   :help "Mark the line at click for a subsequent cut/copy"))
-    (define-key-after submenu [mark-symbol]
-      `(menu-item "Symbol"
-                  ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'symbol))
-                  :help "Mark the symbol at click for a subsequent cut/copy"))
     (when (region-active-p)
       (define-key-after submenu [mark-none]
         `(menu-item "None"
@@ -576,7 +571,8 @@ This is the keyboard interface to \\[context-menu-map]."
 
 (defun mouse-minibuffer-check (event)
   (let ((w (posn-window (event-start event))))
-    (and (window-minibuffer-p w)
+    (and (windowp w)
+         (window-minibuffer-p w)
         (not (minibuffer-window-active-p w))
         (user-error "Minibuffer window is not active")))
   ;; Give temporary modes such as isearch a chance to turn off.
@@ -1573,8 +1569,7 @@ The region will be defined with mark and point."
   (mouse-minibuffer-check start-event)
   (setq mouse-selection-click-count-buffer (current-buffer))
   (deactivate-mark)
-  (let* ((scroll-margin 0) ; Avoid margin scrolling (Bug#9541).
-        (start-posn (event-start start-event))
+  (let* ((start-posn (event-start start-event))
         (start-point (posn-point start-posn))
         (start-window (posn-window start-posn))
         (_ (with-current-buffer (window-buffer start-window)
@@ -1596,72 +1591,84 @@ The region will be defined with mark and point."
                   ;; Don't count the mode line.
                   (1- (nth 3 bounds))))
         (click-count (1- (event-click-count start-event)))
-        ;; Suppress automatic hscrolling, because that is a nuisance
-        ;; when setting point near the right fringe (but see below).
+         ;; Save original automatic scrolling behavior (see below).
         (auto-hscroll-mode-saved auto-hscroll-mode)
-         (old-track-mouse track-mouse))
+        (scroll-margin-saved scroll-margin)
+         (old-track-mouse track-mouse)
+         (cleanup (lambda ()
+                    (setq track-mouse old-track-mouse)
+                    (setq auto-hscroll-mode auto-hscroll-mode-saved)
+                    (setq scroll-margin scroll-margin-saved))))
+    (condition-case err
+        (progn
+          (setq mouse-selection-click-count click-count)
+
+          ;; Suppress automatic scrolling near the edges while tracking
+          ;; movement, as it interferes with the natural dragging behavior
+          ;; (point will unexpectedly be moved beneath the pointer, making
+          ;; selections in auto-scrolling margins impossible).
+          (setq auto-hscroll-mode nil)
+          (setq scroll-margin 0)
+
+          ;; In case the down click is in the middle of some intangible text,
+          ;; use the end of that text, and put it in START-POINT.
+          (if (< (point) start-point)
+             (goto-char start-point))
+          (setq start-point (point))
+
+          ;; Activate the region, using `mouse-start-end' to determine where
+          ;; to put point and mark (e.g., double-click will select a word).
+          (setq-local transient-mark-mode
+                      (if (eq transient-mark-mode 'lambda)
+                          '(only)
+                        (cons 'only transient-mark-mode)))
+          (let ((range (mouse-start-end start-point start-point click-count)))
+            (push-mark (nth 0 range) t t)
+            (goto-char (nth 1 range)))
 
-    (setq mouse-selection-click-count click-count)
-    ;; In case the down click is in the middle of some intangible text,
-    ;; use the end of that text, and put it in START-POINT.
-    (if (< (point) start-point)
-       (goto-char start-point))
-    (setq start-point (point))
+          (setf (terminal-parameter nil 'mouse-drag-start) start-event)
+          (setq track-mouse t)
 
-    ;; Activate the region, using `mouse-start-end' to determine where
-    ;; to put point and mark (e.g., double-click will select a word).
-    (setq-local transient-mark-mode
-                (if (eq transient-mark-mode 'lambda)
-                    '(only)
-                  (cons 'only transient-mark-mode)))
-    (let ((range (mouse-start-end start-point start-point click-count)))
-      (push-mark (nth 0 range) t t)
-      (goto-char (nth 1 range)))
-
-    (setf (terminal-parameter nil 'mouse-drag-start) start-event)
-    (setq track-mouse t)
-    (setq auto-hscroll-mode nil)
-
-    (set-transient-map
-     (let ((map (make-sparse-keymap)))
-       (define-key map [switch-frame] #'ignore)
-       (define-key map [select-window] #'ignore)
-       (define-key map [mouse-movement]
-         (lambda (event) (interactive "e")
-           (let* ((end (event-end event))
-                  (end-point (posn-point end)))
-             (unless (eq end-point start-point)
-               ;; As soon as the user moves, we can re-enable auto-hscroll.
-               (setq auto-hscroll-mode auto-hscroll-mode-saved)
-               ;; And remember that we have moved, so mouse-set-region can know
-               ;; its event is really a drag event.
-               (setcar start-event 'mouse-movement))
-             (if (and (eq (posn-window end) start-window)
-                      (integer-or-marker-p end-point))
-                 (mouse--drag-set-mark-and-point start-point
-                                                 end-point click-count)
-               (let ((mouse-row (cdr (cdr (mouse-position)))))
-                 (cond
-                  ((null mouse-row))
-                  ((< mouse-row top)
-                   (mouse-scroll-subr start-window (- mouse-row top)
-                                      nil start-point))
-                  ((>= mouse-row bottom)
-                   (mouse-scroll-subr start-window (1+ (- mouse-row bottom))
-                                      nil start-point))))))))
-       map)
-     t (lambda ()
-         (setq track-mouse old-track-mouse)
-         (setq auto-hscroll-mode auto-hscroll-mode-saved)
-         ;; Don't deactivate the mark when the context menu was invoked
-         ;; by down-mouse-3 immediately after down-mouse-1 and without
-         ;; releasing the mouse button with mouse-1. This allows to use
-         ;; region-related context menu to operate on the selected region.
-         (unless (and context-menu-mode
-                      (eq (car-safe (aref (this-command-keys-vector) 0))
-                          'down-mouse-3))
-           (deactivate-mark)
-           (pop-mark))))))
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [mouse-movement]
+               (lambda (event) (interactive "e")
+                 (let* ((end (event-end event))
+                        (end-point (posn-point end)))
+                   (unless (eq end-point start-point)
+                     ;; And remember that we have moved, so mouse-set-region 
can know
+                     ;; its event is really a drag event.
+                     (setcar start-event 'mouse-movement))
+                   (if (and (eq (posn-window end) start-window)
+                            (integer-or-marker-p end-point))
+                       (mouse--drag-set-mark-and-point start-point
+                                                       end-point click-count)
+                     (let ((mouse-row (cdr (cdr (mouse-position)))))
+                       (cond
+                        ((null mouse-row))
+                        ((< mouse-row top)
+                         (mouse-scroll-subr start-window (- mouse-row top)
+                                            nil start-point))
+                        ((>= mouse-row bottom)
+                         (mouse-scroll-subr start-window (1+ (- mouse-row 
bottom))
+                                            nil start-point))))))))
+             map)
+           t (lambda ()
+               (funcall cleanup)
+               ;; Don't deactivate the mark when the context menu was invoked
+               ;; by down-mouse-3 immediately after down-mouse-1 and without
+               ;; releasing the mouse button with mouse-1. This allows to use
+               ;; region-related context menu to operate on the selected 
region.
+               (unless (and context-menu-mode
+                            (eq (car-safe (aref (this-command-keys-vector) 0))
+                                'down-mouse-3))
+                 (deactivate-mark)
+                 (pop-mark)))))
+      ;; Cleanup on errors
+      (error (funcall cleanup)
+             (signal (car err) (cdr err))))))
 
 (defun mouse--drag-set-mark-and-point (start click click-count)
   (let* ((range (mouse-start-end start click click-count))
@@ -2470,7 +2477,7 @@ a large number if you prefer a mixed multitude.  The 
default is 4."
     ("Text" . "Text")
     ("Outline" . "Text")
     ("\\(HT\\|SG\\|X\\|XHT\\)ML" . "SGML")
-    ("log\\|diff\\|vc\\|cvs\\|Git\\|Annotate" . "Version Control")
+    ("\\blog\\b\\|diff\\|\\bvc\\b\\|cvs\\|Git\\|Annotate" . "Version Control")
     
("Threads\\|Memory\\|Disassembly\\|Breakpoints\\|Frames\\|Locals\\|Registers\\|Inferior
 I/O\\|Debugger"
      . "GDB")
     ("Lisp" . "Lisp")))
diff --git a/lisp/mpc.el b/lisp/mpc.el
index 1f4cb4fe9c..c47d4336e5 100644
--- a/lisp/mpc.el
+++ b/lisp/mpc.el
@@ -962,6 +962,11 @@ If PLAYLIST is t or nil or missing, use the main playlist."
 
 ;;; Formatter ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+(defcustom mpc-cover-image-re nil ; (rx (or ".jpg" ".jpeg" ".png") string-end)
+  "If non-nil, it is a regexp that should match a valid cover image."
+  :type '(choice (const nil) regexp)
+  :version "28.1")
+
 (defun mpc-secs-to-time (secs)
   ;; We could use `format-seconds', but it doesn't seem worth the trouble
   ;; because we'd still need to check (>= secs (* 60 100)) since the special
@@ -1034,15 +1039,18 @@ If PLAYLIST is t or nil or missing, use the main 
playlist."
                                  (and (funcall oldpred info)
                                       (equal dir (file-name-directory
                                                   (cdr (assq 'file info))))))))
-                       (if-let* ((covers '(".folder.png" "cover.jpg" 
"folder.jpg"))
+                       (if-let* ((covers '(".folder.png" "folder.png" 
"cover.jpg" "folder.jpg"))
                                  (cover (cl-loop for file in (directory-files 
(mpc-file-local-copy dir))
-                                                 if (member (downcase file) 
covers)
+                                                 if (or (member (downcase 
file) covers)
+                                                        (and mpc-cover-image-re
+                                                             (string-match 
mpc-cover-image-re file)))
                                                  return (concat dir file)))
                                  (file (with-demoted-errors "MPC: %s"
                                          (mpc-file-local-copy cover))))
                            (let (image)
                              (if (null size) (setq image (create-image file))
                                (let ((tempfile (make-temp-file "mpc" nil 
".jpg")))
+                                 ;; FIXME: Use native image scaling instead.
                                  (call-process "convert" nil nil nil
                                                "-scale" size file tempfile)
                                  (setq image (create-image tempfile))
@@ -1111,6 +1119,9 @@ If PLAYLIST is t or nil or missing, use the main 
playlist."
           (if (null size) (setq col (+ col textwidth postwidth))
             (insert space)
             (setq col (+ col size))))))
+    ;; Print the rest of format-spec, in case there is text after the
+    ;; last actual format specifier.
+    (insert (substring format-spec pos))
     (put-text-property start (point) 'mpc--uptodate-p pred)))
 
 ;;; The actual UI code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1139,6 +1150,7 @@ If PLAYLIST is t or nil or missing, use the main 
playlist."
     (define-key map ">" #'mpc-next)
     (define-key map "<" #'mpc-prev)
     (define-key map "g" #'mpc-seek-current)
+    (define-key map "o" #'mpc-goto-playing-song)
     map))
 
 (easy-menu-define mpc-mode-menu mpc-mode-map
@@ -1870,7 +1882,8 @@ A value of t means the main playlist.")
     (when (buffer-live-p status-buf)
       (with-current-buffer status-buf (force-mode-line-update)))))
 
-(defvar mpc-volume-step 5)
+(defvar mpc-volume-step 5
+  "Change volume in increments of this integer.")
 
 (defun mpc-volume-mouse-set (&optional event)
   "Change volume setting."
@@ -1884,7 +1897,7 @@ A value of t means the main playlist.")
                     '(?◁ ?<))
               (- mpc-volume-step) mpc-volume-step))
          (curvol (string-to-number (cdr (assq 'volume mpc-status))))
-         (newvol (max 0 (min 100 (+ curvol diff)))))
+         (newvol (max 0 (min 100 (+ (- curvol (mod curvol diff)) diff)))))
     (if (= newvol curvol)
         (progn
           (message "MPD volume already at %s%%" newvol)
@@ -2658,6 +2671,18 @@ If stopped, start playback."
   (mpc-select event)
   (mpc-play))
 
+(defun mpc-goto-playing-song ()
+  "Move point to the currently playing song in the \"*Songs*\" buffer."
+  (interactive)
+  (let* ((buf (mpc-proc-buffer (mpc-proc) 'songs))
+         (win (get-buffer-window buf)))
+    (when (and (buffer-live-p buf) win)
+      (select-window win)
+      (with-current-buffer buf
+        (when (and overlay-arrow-position
+                   (eq (marker-buffer overlay-arrow-position) buf))
+          (goto-char (marker-position overlay-arrow-position)))))))
+
 ;; (defun mpc-play-tagval ()
 ;;   "Play all the songs of the tag at point."
 ;;   (interactive)
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index def7758774..51410e3ef4 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -103,7 +103,7 @@ less than a full screen.
 If AMOUNT is the symbol 'hscroll', this means that with MODIFIER,
 the mouse wheel will scroll horizontally instead of vertically.
 
-If AMOUNT is the symbol text-scale, this means that with
+If AMOUNT is the symbol 'text-scale', this means that with
 MODIFIER, the mouse wheel will change the face height instead of
 scrolling."
   :group 'mouse
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 56a1d76d71..a6c256eeba 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -1230,8 +1230,9 @@ only return the directory part of FILE."
                            ;; found another machine with the same user.
                            ;; Try that account.
                            (read-passwd
-                            (format "passwd for %s@%s (default same as %s@%s): 
"
-                                    user host user other)
+                             (format-prompt "passwd for %s@%s"
+                                            (format "same as %s@%s" user other)
+                                            user host)
                             nil
                             (ange-ftp-lookup-passwd other user))
 
@@ -4723,7 +4724,7 @@ NEWNAME should be the name to give the new compressed or 
uncompressed file.")
 ;; by using the ftp chmod command.
 (defun ange-ftp-call-chmod (args)
   (if (< (length args) 2)
-      (error "ange-ftp-call-chmod: missing mode and/or filename: %s" args))
+      (error "ange-ftp-call-chmod: Missing mode and/or filename: %s" args))
   (let ((mode (car args))
        (rest (cdr args)))
     (if (equal "--" (car rest))
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index b21c66ef14..3af37e412d 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -1600,7 +1600,7 @@ used instead of `browse-url-new-window-flag'."
 
 ;; --- mailto ---
 
-(autoload 'rfc6068-parse-mailto-url "rfc2368")
+(autoload 'rfc6068-parse-mailto-url "rfc6068")
 
 ;;;###autoload
 (defun browse-url-mail (url &optional new-window)
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el
index 4116d293e1..3fff5398c0 100644
--- a/lisp/net/dbus.el
+++ b/lisp/net/dbus.el
@@ -2073,7 +2073,8 @@ either a method name, a signal name, or an error name."
     (goto-char point)))
 
 (defun dbus-monitor-handler (&rest _args)
-  "Default handler for the \"org.freedesktop.DBus.Monitoring.BecomeMonitor\" 
interface.
+  "Default handler for the \"Monitoring.BecomeMonitor\" interface.
+Its full name is \"org.freedesktop.DBus.Monitoring.BecomeMonitor\".
 It will be applied for all objects created by `dbus-register-monitor'
 which don't declare an own handler.  The printed timestamps do
 not reflect the time the D-Bus message has passed the D-Bus
@@ -2251,15 +2252,19 @@ keywords `:system-private' or `:session-private', 
respectively."
      bus nil dbus-path-local dbus-interface-local
      "Disconnected" #'dbus-handle-bus-disconnect)))
 
- 
-;; Initialize `:system' and `:session' buses.  This adds their file
-;; descriptors to input_wait_mask, in order to detect incoming
-;; messages immediately.
-(when (featurep 'dbusbind)
-  (dbus-ignore-errors
-    (dbus-init-bus :system))
-  (dbus-ignore-errors
-    (dbus-init-bus :session)))
+
+(defun dbus--init ()
+  ;; Initialize `:system' and `:session' buses.  This adds their file
+  ;; descriptors to input_wait_mask, in order to detect incoming
+  ;; messages immediately.
+  (when (featurep 'dbusbind)
+    (dbus-ignore-errors
+      (dbus-init-bus :system))
+    (dbus-ignore-errors
+      (dbus-init-bus :session))))
+
+(add-hook 'after-pdump-load-hook #'dbus--init)
+(dbus--init)
 
 (provide 'dbus)
 
diff --git a/lisp/net/dictionary.el b/lisp/net/dictionary.el
index 85467cd782..1d07989ef5 100644
--- a/lisp/net/dictionary.el
+++ b/lisp/net/dictionary.el
@@ -1049,7 +1049,7 @@ If PATTERN is omitted, it defaults to \"[ 
\\f\\t\\n\\r\\v]+\"."
                                'dictionary-display-match-result)))
 
 (defun dictionary-do-matching (word dictionary strategy function)
-  "Find matches for WORD with STRATEGY in DICTIONARY and display them with 
FUNCTION."
+  "Search for WORD with STRATEGY in DICTIONARY and display them with FUNCTION."
   (message "Lookup matching words for %s in %s using %s"
           word dictionary strategy)
   (dictionary-send-command
@@ -1375,16 +1375,20 @@ any buffer where (dictionary-tooltip-mode 1) has been 
called."
                  (current-word)))))
     (dictionary-search word)))
 
+;;;###autoload
 (defun context-menu-dictionary (menu click)
-  "Populate MENU with dictionary commands at CLICK."
+  "Populate MENU with dictionary commands at CLICK.
+When you add this function to `context-menu-functions',
+the context menu will contain an item that searches
+the word at mouse click."
   (when (thing-at-mouse click 'word)
-    (define-key menu [dictionary-separator] menu-bar-separator)
-    (define-key menu [dictionary-search-word-at-mouse]
+    (define-key-after menu [dictionary-separator] menu-bar-separator
+      'middle-separator)
+    (define-key-after menu [dictionary-search-word-at-mouse]
       '(menu-item "Dictionary Search" dictionary-search-word-at-mouse
-                  :help "Search the word at mouse click in dictionary")))
+                  :help "Search the word at mouse click in dictionary")
+      'dictionary-separator))
   menu)
 
-(add-hook 'context-menu-functions 'context-menu-dictionary 15)
-
 (provide 'dictionary)
 ;;; dictionary.el ends here
diff --git a/lisp/net/eudc.el b/lisp/net/eudc.el
index 5c451c6556..14e5c28b2d 100644
--- a/lisp/net/eudc.el
+++ b/lisp/net/eudc.el
@@ -798,8 +798,9 @@ see `eudc-inline-expansion-servers'."
   "Query the directory server, and return the matching responses.
 The variable `eudc-inline-query-format' controls how to associate the
 individual QUERY-WORDS with directory attribute names.
-After querying the server for the given string, the expansion specified by
-`eudc-inline-expansion-format' is applied to the matches before returning 
them.inserted in the buffer at point.
+After querying the server for the given string, the expansion
+specified by `eudc-inline-expansion-format' is applied to the
+matches before returning them.inserted in the buffer at point.
 Multiple servers can be tried with the same query until one finds a match,
 see `eudc-inline-expansion-servers'."
   (cond
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 701dc4fade..70ebc1d2ec 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -145,12 +145,12 @@ The string will be passed through 
`substitute-command-keys'."
   "Command to retrieve an URL via an external program.
 If nil, `url-retrieve' is used to download the data.
 If `sync', `url-retrieve-synchronously' is used.
-For other non-nil values, this should be a list where the first item
-is the program, and the rest are the arguments."
+For other non-nil values, this should be a list of strings where
+the first item is the program, and the rest are the arguments."
   :version "28.1"
   :type '(choice (const :tag "Use `url-retrieve'" nil)
                  (const :tag "Use `url-retrieve-synchronously'" sync)
-                 (repeat string)))
+                 (repeat :tag "Command/args" string )))
 
 (defcustom eww-use-external-browser-for-content-type
   "\\`\\(video/\\|audio/\\|application/ogg\\)"
@@ -178,6 +178,40 @@ the tab bar is enabled."
   :group 'eww
   :type 'hook)
 
+(defcustom eww-auto-rename-buffer nil
+  "Automatically rename EWW buffers once the page is rendered.
+
+When nil, do not rename the buffer.  With a non-nil value
+determine the renaming scheme, as follows:
+
+- `title': Use the web page's title.
+- `url': Use the web page's URL.
+- a function's symbol: Run a user-defined function that returns a
+  string with which to rename the buffer.  Sample of a
+  user-defined function:
+
+  (defun my-eww-rename-buffer ()
+    (when (eq major-mode 'eww-mode)
+      (when-let ((string (or (plist-get eww-data :title)
+                             (plist-get eww-data :url))))
+        (format \"*%s*\" string))))
+
+The string of `title' and `url' is always truncated to the value
+of `eww-buffer-name-length'."
+  :version "29.1"
+  :type '(choice
+          (const :tag "Do not rename buffers (default)" nil)
+          (const :tag "Rename buffer to web page title" title)
+          (const :tag "Rename buffer to web page URL" url)
+          (function :tag "A user-defined function to rename the buffer"))
+  :group 'eww)
+
+(defcustom eww-buffer-name-length 40
+  "Length of renamed buffer name, per `eww-auto-rename-buffer'."
+  :type 'natnum
+  :version "29.1"
+  :group 'eww)
+
 (defcustom eww-form-checkbox-selected-symbol "[X]"
   "Symbol used to represent a selected checkbox.
 See also `eww-form-checkbox-symbol'."
@@ -197,6 +231,13 @@ See also `eww-form-checkbox-selected-symbol'."
                  (const "☐")            ; Unicode BALLOT BOX
                  string))
 
+(defcustom eww-url-transformers '(eww-remove-tracking)
+  "This is a list of transforming functions applied to an URL before usage.
+The functions will be called with the URL as the single
+parameter, and should return the (possibly) transformed URL."
+  :type '(repeat function)
+  :version "29.1")
+
 (defface eww-form-submit
   '((((type x w32 ns) (class color))   ; Like default mode line
      :box (:line-width 2 :style released-button)
@@ -271,15 +312,13 @@ See also `eww-form-checkbox-selected-symbol'."
   "text/html, text/plain, text/sgml, text/css, application/xhtml+xml, 
*/*;q=0.01"
   "Value used for the HTTP 'Accept' header.")
 
-(defvar eww-link-keymap
-  (let ((map (copy-keymap shr-map)))
-    (define-key map "\r" 'eww-follow-link)
-    map))
+(defvar-keymap eww-link-keymap
+  :parent shr-map
+  "\r" #'eww-follow-link)
 
-(defvar eww-image-link-keymap
-  (let ((map (copy-keymap shr-image-map)))
-    (define-key map "\r" 'eww-follow-link)
-    map))
+(defvar-keymap eww-image-link-keymap
+  :parent shr-map
+  "\r" #'eww-follow-link)
 
 (defun eww-suggested-uris nil
   "Return the list of URIs to suggest at the `eww' prompt.
@@ -313,13 +352,13 @@ will start Emacs and browse the GNU web site."
 
 
 ;;;###autoload
-(defun eww (url &optional arg buffer)
+(defun eww (url &optional new-buffer buffer)
   "Fetch URL and render the page.
 If the input doesn't look like an URL or a domain name, the
 word(s) will be searched for via `eww-search-prefix'.
 
-If called with a prefix ARG, use a new buffer instead of reusing
-the default EWW buffer.
+If NEW-BUFFER is non-nil (interactively, the prefix arg), use a
+new buffer instead of reusing the default EWW buffer.
 
 If BUFFER, the data to be rendered is in that buffer.  In that
 case, this function doesn't actually fetch URL.  BUFFER will be
@@ -329,11 +368,11 @@ killed after rendering."
      (list (read-string (format-prompt "Enter URL or keywords"
                                        (and uris (car uris)))
                         nil 'eww-prompt-history uris)
-           (prefix-numeric-value current-prefix-arg))))
+           current-prefix-arg)))
   (setq url (eww--dwim-expand-url url))
   (pop-to-buffer-same-window
    (cond
-    ((eq arg 4)
+    (new-buffer
      (generate-new-buffer "*eww*"))
     ((eq major-mode 'eww-mode)
      (current-buffer))
@@ -353,9 +392,10 @@ killed after rendering."
       (while (string-match "\\`/[.][.]/" (url-filename parsed))
         (setf (url-filename parsed) (substring (url-filename parsed) 3))))
     (setq url (url-recreate-url parsed)))
+  (setq url (eww--transform-url url))
   (plist-put eww-data :url url)
   (plist-put eww-data :title "")
-  (eww-update-header-line-format)
+  (eww--after-page-change)
   (let ((inhibit-read-only t))
     (insert (format "Loading %s..." url))
     (goto-char (point-min)))
@@ -504,6 +544,30 @@ Currently this means either text/html or 
application/xhtml+xml."
   (member content-type '("text/html"
                         "application/xhtml+xml")))
 
+(defun eww--rename-buffer ()
+  "Rename the current EWW buffer.
+The renaming scheme is performed in accordance with
+`eww-auto-rename-buffer'."
+  (let ((rename-string)
+        (formatter
+         (lambda (string)
+           (format "*%s # eww*" (truncate-string-to-width
+                                 string eww-buffer-name-length))))
+        (site-title (plist-get eww-data :title))
+        (site-url (plist-get eww-data :url)))
+    (cond ((null eww-auto-rename-buffer))
+          ((eq eww-auto-rename-buffer 'url)
+           (setq rename-string (funcall formatter site-url)))
+          ((functionp eww-auto-rename-buffer)
+           (setq rename-string (funcall eww-auto-rename-buffer)))
+          (t (setq rename-string
+                   (funcall formatter (if (or (equal site-title "")
+                                              (null site-title))
+                                          "Untitled"
+                                        site-title)))))
+    (when rename-string
+      (rename-buffer rename-string t))))
+
 (defun eww-render (status url &optional point buffer encode)
   (let* ((headers (eww-parse-headers))
         (content-type
@@ -554,7 +618,7 @@ Currently this means either text/html or 
application/xhtml+xml."
            (eww-display-raw buffer (or encode charset 'utf-8))))
          (with-current-buffer buffer
            (plist-put eww-data :url url)
-           (eww-update-header-line-format)
+           (eww--after-page-change)
            (setq eww-history-position 0)
            (and last-coding-system-used
                 (set-buffer-file-coding-system last-coding-system-used))
@@ -638,7 +702,8 @@ Currently this means either text/html or 
application/xhtml+xml."
                 (meta . eww-tag-meta)
                 (a . eww-tag-a)))))
        (erase-buffer)
-       (shr-insert-document document)
+        (with-delayed-message (2 "Rendering HTML...")
+         (shr-insert-document document))
        (cond
         (point
          (goto-char point))
@@ -798,12 +863,16 @@ Currently this means either text/html or 
application/xhtml+xml."
                 `((?u . ,(or url ""))
                   (?t . ,title))))))))
 
+(defun eww--after-page-change ()
+  (eww-update-header-line-format)
+  (eww--rename-buffer))
+
 (defun eww-tag-title (dom)
   (plist-put eww-data :title
             (replace-regexp-in-string
              "^ \\| $" ""
              (replace-regexp-in-string "[ \t\r\n]+" " " (dom-text dom))))
-  (eww-update-header-line-format))
+  (eww--after-page-change))
 
 (defun eww-display-raw (buffer &optional encode)
   (let ((data (buffer-substring (point) (point-max))))
@@ -931,7 +1000,7 @@ the like."
                      nil (current-buffer))
     (dolist (elem '(:source :url :title :next :previous :up))
       (plist-put eww-data elem (plist-get old-data elem)))
-    (eww-update-header-line-format)))
+    (eww--after-page-change)))
 
 (defun eww-score-readability (node)
   (let ((score -1))
@@ -973,67 +1042,67 @@ the like."
          (setq result highest))))
     result))
 
-(defvar eww-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "g" 'eww-reload) ;FIXME: revert-buffer-function instead!
-    (define-key map "G" 'eww)
-    (define-key map [?\M-\r] 'eww-open-in-new-buffer)
-    (define-key map [?\t] 'shr-next-link)
-    (define-key map [?\M-\t] 'shr-previous-link)
-    (define-key map [backtab] 'shr-previous-link)
-    (define-key map [delete] 'scroll-down-command)
-    (define-key map "l" 'eww-back-url)
-    (define-key map "r" 'eww-forward-url)
-    (define-key map "n" 'eww-next-url)
-    (define-key map "p" 'eww-previous-url)
-    (define-key map "u" 'eww-up-url)
-    (define-key map "t" 'eww-top-url)
-    (define-key map "&" 'eww-browse-with-external-browser)
-    (define-key map "d" 'eww-download)
-    (define-key map "w" 'eww-copy-page-url)
-    (define-key map "C" 'url-cookie-list)
-    (define-key map "v" 'eww-view-source)
-    (define-key map "R" 'eww-readable)
-    (define-key map "H" 'eww-list-histories)
-    (define-key map "E" 'eww-set-character-encoding)
-    (define-key map "s" 'eww-switch-to-buffer)
-    (define-key map "S" 'eww-list-buffers)
-    (define-key map "F" 'eww-toggle-fonts)
-    (define-key map "D" 'eww-toggle-paragraph-direction)
-    (define-key map [(meta C)] 'eww-toggle-colors)
-    (define-key map [(meta I)] 'eww-toggle-images)
-
-    (define-key map "b" 'eww-add-bookmark)
-    (define-key map "B" 'eww-list-bookmarks)
-    (define-key map [(meta n)] 'eww-next-bookmark)
-    (define-key map [(meta p)] 'eww-previous-bookmark)
-
-    (easy-menu-define nil map ""
-      '("Eww"
-       ["Exit" quit-window t]
-       ["Close browser" quit-window t]
-       ["Reload" eww-reload t]
-       ["Follow URL in new buffer" eww-open-in-new-buffer]
-       ["Back to previous page" eww-back-url
-        :active (not (zerop (length eww-history)))]
-       ["Forward to next page" eww-forward-url
-        :active (not (zerop eww-history-position))]
-       ["Browse with external browser" eww-browse-with-external-browser t]
-       ["Download" eww-download t]
-       ["View page source" eww-view-source]
-       ["Copy page URL" eww-copy-page-url t]
-       ["List histories" eww-list-histories t]
-       ["Switch to buffer" eww-switch-to-buffer t]
-       ["List buffers" eww-list-buffers t]
-       ["Add bookmark" eww-add-bookmark t]
-       ["List bookmarks" eww-list-bookmarks t]
-       ["List cookies" url-cookie-list t]
-       ["Toggle fonts" eww-toggle-fonts t]
-       ["Toggle colors" eww-toggle-colors t]
-       ["Toggle images" eww-toggle-images t]
-        ["Character Encoding" eww-set-character-encoding]
-        ["Toggle Paragraph Direction" eww-toggle-paragraph-direction]))
-    map))
+(defvar-keymap eww-mode-map
+  "g" #'eww-reload             ;FIXME: revert-buffer-function instead!
+  "G" #'eww
+  [?\M-\r] #'eww-open-in-new-buffer
+  [?\t] #'shr-next-link
+  [?\M-\t] #'shr-previous-link
+  [backtab] #'shr-previous-link
+  [delete] #'scroll-down-command
+  "l" #'eww-back-url
+  "r" #'eww-forward-url
+  "n" #'eww-next-url
+  "p" #'eww-previous-url
+  "u" #'eww-up-url
+  "t" #'eww-top-url
+  "&" #'eww-browse-with-external-browser
+  "d" #'eww-download
+  "w" #'eww-copy-page-url
+  "C" #'url-cookie-list
+  "v" #'eww-view-source
+  "R" #'eww-readable
+  "H" #'eww-list-histories
+  "E" #'eww-set-character-encoding
+  "s" #'eww-switch-to-buffer
+  "S" #'eww-list-buffers
+  "F" #'eww-toggle-fonts
+  "D" #'eww-toggle-paragraph-direction
+  [(meta C)] #'eww-toggle-colors
+  [(meta I)] #'eww-toggle-images
+
+  "b" #'eww-add-bookmark
+  "B" #'eww-list-bookmarks
+  [(meta n)] #'eww-next-bookmark
+  [(meta p)] #'eww-previous-bookmark
+
+  [(mouse-8)] #'eww-back-url
+  [(mouse-9)] #'eww-forward-url
+
+  :menu '("Eww"
+          ["Exit" quit-window t]
+          ["Close browser" quit-window t]
+          ["Reload" eww-reload t]
+          ["Follow URL in new buffer" eww-open-in-new-buffer]
+          ["Back to previous page" eww-back-url
+           :active (not (zerop (length eww-history)))]
+          ["Forward to next page" eww-forward-url
+           :active (not (zerop eww-history-position))]
+          ["Browse with external browser" eww-browse-with-external-browser t]
+          ["Download" eww-download t]
+          ["View page source" eww-view-source]
+          ["Copy page URL" eww-copy-page-url t]
+          ["List histories" eww-list-histories t]
+          ["Switch to buffer" eww-switch-to-buffer t]
+          ["List buffers" eww-list-buffers t]
+          ["Add bookmark" eww-add-bookmark t]
+          ["List bookmarks" eww-list-bookmarks t]
+          ["List cookies" url-cookie-list t]
+          ["Toggle fonts" eww-toggle-fonts t]
+          ["Toggle colors" eww-toggle-colors t]
+          ["Toggle images" eww-toggle-images t]
+          ["Character Encoding" eww-set-character-encoding]
+          ["Toggle Paragraph Direction" eww-toggle-paragraph-direction]))
 
 (defun eww-context-menu (menu click)
   "Populate MENU with eww commands at CLICK."
@@ -1083,7 +1152,9 @@ the like."
 ;; Autoload cookie needed by desktop.el.
 ;;;###autoload
 (define-derived-mode eww-mode special-mode "eww"
-  "Mode for browsing the web."
+  "Mode for browsing the web.
+
+\\{eww-mode-map}"
   :interactive nil
   (setq-local eww-data (list :title ""))
   (setq-local browse-url-browser-function #'eww-browse-url)
@@ -1099,6 +1170,7 @@ the like."
   (setq-local thing-at-point-provider-alist
               (append thing-at-point-provider-alist
                       '((url . eww--url-at-point))))
+  (setq-local bookmark-make-record-function #'eww-bookmark-make-record)
   (buffer-disable-undo)
   (setq buffer-read-only t))
 
@@ -1163,7 +1235,7 @@ instead of `browse-url-new-window-flag'."
       (goto-char (plist-get elem :point))
       ;; Make buffer listings more informative.
       (setq list-buffers-directory (plist-get elem :url))
-      (eww-update-header-line-format))))
+      (eww--after-page-change))))
 
 (defun eww-next-url ()
   "Go to the page marked `next'.
@@ -1227,54 +1299,43 @@ just re-display the HTML already fetched."
 
 (defvar eww-form nil)
 
-(defvar eww-submit-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\r" 'eww-submit)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    map))
-
-(defvar eww-submit-file
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\r" 'eww-select-file)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    map))
-
-(defvar eww-checkbox-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map " " 'eww-toggle-checkbox)
-    (define-key map "\r" 'eww-toggle-checkbox)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    map))
-
-(defvar eww-text-map
-  (let ((map (make-keymap)))
-    (set-keymap-parent map text-mode-map)
-    (define-key map "\r" 'eww-submit)
-    (define-key map [(control a)] 'eww-beginning-of-text)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    (define-key map [(control e)] 'eww-end-of-text)
-    (define-key map [?\t] 'shr-next-link)
-    (define-key map [?\M-\t] 'shr-previous-link)
-    (define-key map [backtab] 'shr-previous-link)
-    map))
-
-(defvar eww-textarea-map
-  (let ((map (make-keymap)))
-    (set-keymap-parent map text-mode-map)
-    (define-key map "\r" 'forward-line)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    (define-key map [?\t] 'shr-next-link)
-    (define-key map [?\M-\t] 'shr-previous-link)
-    (define-key map [backtab] 'shr-previous-link)
-    map))
-
-(defvar eww-select-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\r" 'eww-change-select)
-    (define-key map [follow-link] 'mouse-face)
-    (define-key map [mouse-2] 'eww-change-select)
-    (define-key map [(control c) (control c)] 'eww-submit)
-    map))
+(defvar-keymap eww-submit-map
+  "\r" #'eww-submit
+  [(control c) (control c)] #'eww-submit)
+
+(defvar-keymap eww-submit-file
+  "\r" #'eww-select-file
+  [(control c) (control c)] #'eww-submit)
+
+(defvar-keymap eww-checkbox-map
+  " " #'eww-toggle-checkbox
+  "\r" #'eww-toggle-checkbox
+  [(control c) (control c)] #'eww-submit)
+
+(defvar-keymap eww-text-map
+  :full t :parent text-mode-map
+  "\r" #'eww-submit
+  [(control a)] #'eww-beginning-of-text
+  [(control c) (control c)] #'eww-submit
+  [(control e)] #'eww-end-of-text
+  [?\t] #'shr-next-link
+  [?\M-\t] #'shr-previous-link
+  [backtab] #'shr-previous-link)
+
+(defvar-keymap eww-textarea-map
+  :full t :parent text-mode-map
+  "\r" #'forward-line
+  [(control c) (control c)] #'eww-submit
+  [?\t] #'shr-next-link
+  [?\M-\t] #'shr-previous-link
+  [backtab] #'shr-previous-link)
+
+(defvar-keymap eww-select-map
+  :doc "Map for select buttons"
+  "\r" #'eww-change-select
+  [follow-link] 'mouse-face
+  [mouse-2] #'eww-change-select
+  [(control c) (control c)] #'eww-submit)
 
 (defun eww-beginning-of-text ()
   "Move to the start of the input field."
@@ -1781,6 +1842,17 @@ The browser to used is specified by the
   (funcall browse-url-secondary-browser-function
            (or url (plist-get eww-data :url))))
 
+(defun eww-remove-tracking (url)
+  "Remove the commong utm_ tracking cookies from URLs."
+  (replace-regexp-in-string ".utm_.*" "" url))
+
+(defun eww--transform-url (url)
+  "Appy `eww-url-transformers'."
+  (when url
+    (dolist (func eww-url-transformers)
+      (setq url (funcall func url)))
+    url))
+
 (defun eww-follow-link (&optional external mouse-event)
   "Browse the URL under point.
 If EXTERNAL is single prefix, browse the URL using
@@ -1791,7 +1863,8 @@ If EXTERNAL is double prefix, browse in new buffer."
    (list current-prefix-arg last-nonmenu-event)
    eww-mode)
   (mouse-set-point mouse-event)
-  (let ((url (get-text-property (point) 'shr-url)))
+  (let* ((orig-url (get-text-property (point) 'shr-url))
+         (url (eww--transform-url orig-url)))
     (cond
      ((not url)
       (message "No link under point"))
@@ -1810,7 +1883,7 @@ If EXTERNAL is double prefix, browse in new buffer."
        (plist-put eww-data :url url)
        (eww-display-html 'utf-8 url dom nil (current-buffer))))
      (t
-      (eww-browse-url url external)))))
+      (eww-browse-url orig-url external)))))
 
 (defun eww-same-page-p (url1 url2)
   "Return non-nil if URL1 and URL2 represent the same page.
@@ -1898,7 +1971,7 @@ Use link at point if there is one, else the current 
page's URL."
 (defun eww-set-character-encoding (charset)
   "Set character encoding to CHARSET.
 If CHARSET is nil then use UTF-8."
-  (interactive "zUse character set (default utf-8): " eww-mode)
+  (interactive "zUse character set (default `utf-8'): " eww-mode)
   (if (null charset)
       (eww-reload nil 'utf-8)
     (eww-reload nil charset)))
@@ -2097,23 +2170,18 @@ If ERROR-OUT, signal user-error if there are no 
bookmarks."
                                        'eww-bookmark)))
     (eww-browse-url (plist-get bookmark :url))))
 
-(defvar eww-bookmark-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(control k)] 'eww-bookmark-kill)
-    (define-key map [(control y)] 'eww-bookmark-yank)
-    (define-key map "\r" 'eww-bookmark-browse)
-
-    (easy-menu-define nil map
-      "Menu for `eww-bookmark-mode-map'."
-      '("Eww Bookmark"
-        ["Exit" quit-window t]
-        ["Browse" eww-bookmark-browse
-         :active (get-text-property (line-beginning-position) 'eww-bookmark)]
-        ["Kill" eww-bookmark-kill
-         :active (get-text-property (line-beginning-position) 'eww-bookmark)]
-        ["Yank" eww-bookmark-yank
-         :active eww-bookmark-kill-ring]))
-    map))
+(defvar-keymap eww-bookmark-mode-map
+  [(control k)] #'eww-bookmark-kill
+  [(control y)] #'eww-bookmark-yank
+  "\r" #'eww-bookmark-browse
+  :menu '("Eww Bookmark"
+          ["Exit" quit-window t]
+          ["Browse" eww-bookmark-browse
+           :active (get-text-property (line-beginning-position) 'eww-bookmark)]
+          ["Kill" eww-bookmark-kill
+           :active (get-text-property (line-beginning-position) 'eww-bookmark)]
+          ["Yank" eww-bookmark-yank
+           :active eww-bookmark-kill-ring]))
 
 (define-derived-mode eww-bookmark-mode special-mode "eww bookmarks"
   "Mode for listing bookmarks.
@@ -2178,19 +2246,15 @@ If ERROR-OUT, signal user-error if there are no 
bookmarks."
        (pop-to-buffer-same-window buffer)))
     (eww-restore-history history)))
 
-(defvar eww-history-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\r" 'eww-history-browse)
-    (define-key map "n" 'next-line)
-    (define-key map "p" 'previous-line)
-
-    (easy-menu-define nil map
-      "Menu for `eww-history-mode-map'."
-      '("Eww History"
-        ["Exit" quit-window t]
-        ["Browse" eww-history-browse
-         :active (get-text-property (line-beginning-position) 'eww-history)]))
-    map))
+(defvar-keymap eww-history-mode-map
+  "\r" #'eww-history-browse
+  "n" #'next-line
+  "p" #'previous-line
+  :menu '("Eww History"
+          ["Exit" quit-window t]
+          ["Browse" eww-history-browse
+           :active (get-text-property (line-beginning-position)
+                                      'eww-history)]))
 
 (define-derived-mode eww-history-mode special-mode "eww history"
   "Mode for listing eww-histories.
@@ -2301,22 +2365,18 @@ If ERROR-OUT, signal user-error if there are no 
bookmarks."
     (forward-line -1))
   (eww-buffer-show))
 
-(defvar eww-buffers-mode-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [(control k)] 'eww-buffer-kill)
-    (define-key map "\r" 'eww-buffer-select)
-    (define-key map "n" 'eww-buffer-show-next)
-    (define-key map "p" 'eww-buffer-show-previous)
-
-    (easy-menu-define nil map
-      "Menu for `eww-buffers-mode-map'."
-      '("Eww Buffers"
-        ["Exit" quit-window t]
-        ["Select" eww-buffer-select
-         :active (get-text-property (line-beginning-position) 'eww-buffer)]
-        ["Kill" eww-buffer-kill
-         :active (get-text-property (line-beginning-position) 'eww-buffer)]))
-    map))
+(defvar-keymap eww-buffers-mode-map
+  [(control k)] #'eww-buffer-kill
+  "\r" #'eww-buffer-select
+  "n" #'eww-buffer-show-next
+  "p" #'eww-buffer-show-previous
+  :menu '("Eww Buffers"
+          ["Exit" quit-window t]
+          ["Select" eww-buffer-select
+           :active (get-text-property (line-beginning-position) 'eww-buffer)]
+          ["Kill" eww-buffer-kill
+           :active (get-text-property (line-beginning-position)
+                                      'eww-buffer)]))
 
 (define-derived-mode eww-buffers-mode special-mode "eww buffers"
   "Mode for listing buffers.
@@ -2417,6 +2477,28 @@ Otherwise, the restored buffer will contain a prompt to 
do so by using
         (eww-previous-url))))
   (current-buffer))
 
+;;; bookmark.el support
+
+(declare-function bookmark-make-record-default
+                  "bookmark" (&optional no-file no-context posn))
+(declare-function bookmark-prop-get "bookmark" (bookmark prop))
+
+(defun eww-bookmark-name ()
+  "Create a default bookmark name for the current EWW buffer."
+  (plist-get eww-data :title))
+
+(defun eww-bookmark-make-record ()
+  "Create a bookmark for the current EWW buffer."
+  `(,(eww-bookmark-name)
+    ,@(bookmark-make-record-default t)
+    (location . ,(plist-get eww-data :url))
+    (handler . eww-bookmark-jump)))
+
+;;;###autoload
+(defun eww-bookmark-jump (bookmark)
+  "Default bookmark handler for EWW buffers."
+  (eww (bookmark-prop-get bookmark 'location)))
+
 (provide 'eww)
 
 ;;; eww.el ends here
diff --git a/lisp/net/hmac-def.el b/lisp/net/hmac-def.el
index 5af6d4324a..5778857ff8 100644
--- a/lisp/net/hmac-def.el
+++ b/lisp/net/hmac-def.el
@@ -37,6 +37,7 @@ a string and return a digest of it (in binary form).
 B is a byte length of a block size of H. (B=64 for both SHA1 and MD5.)
 L is a byte length of hash outputs.  (L=16 for MD5, L=20 for SHA1.)
 If BIT is non-nil, truncate output to specified bits."
+  (declare (indent defun))
   `(defun ,name (text key)
      ,(concat "Compute "
              (upcase (symbol-name name))
diff --git a/lisp/net/mailcap.el b/lisp/net/mailcap.el
index 83d0eeef9f..2c68755718 100644
--- a/lisp/net/mailcap.el
+++ b/lisp/net/mailcap.el
@@ -423,14 +423,6 @@ MAILCAPS if set; otherwise (on Unix) use the path from RFC 
1524, plus
   (interactive (list nil t))
   (when (or (not mailcap-parsed-p)
            force)
-    ;; Clear out all old data.
-    (setq mailcap--computed-mime-data nil)
-    ;; Add the Emacs-distributed defaults (which will be used as
-    ;; fallbacks).  Do it this way instead of just copying the list,
-    ;; since entries are destructively modified.
-    (cl-loop for (major . minors) in mailcap-mime-data
-             do (cl-loop for (minor . entry) in minors
-                         do (mailcap-add-mailcap-entry major minor entry)))
     (cond
      (path nil)
      ((getenv "MAILCAPS")
@@ -447,18 +439,29 @@ MAILCAPS if set; otherwise (on Unix) use the path from 
RFC 1524, plus
               ("/etc/mailcap" system)
               ("/usr/etc/mailcap" system)
              ("/usr/local/etc/mailcap" system)))))
-    ;; The ~/.mailcap entries will end up first in the resulting data.
-    (dolist (spec (reverse
-                   (if (stringp path)
-                       (split-string path path-separator t)
-                     path)))
-      (let ((source (and (consp spec) (cadr spec)))
-            (file-name (if (stringp spec)
-                           spec
-                         (car spec))))
-        (when (and (file-readable-p file-name)
-                   (file-regular-p file-name))
-          (mailcap-parse-mailcap file-name source))))
+    (when (seq-some (lambda (f)
+                      (file-has-changed-p (car f) 'mail-parse-mailcaps))
+                    path)
+      ;; Clear out all old data.
+      (setq mailcap--computed-mime-data nil)
+      ;; Add the Emacs-distributed defaults (which will be used as
+      ;; fallbacks).  Do it this way instead of just copying the list,
+      ;; since entries are destructively modified.
+      (cl-loop for (major . minors) in mailcap-mime-data
+               do (cl-loop for (minor . entry) in minors
+                           do (mailcap-add-mailcap-entry major minor entry)))
+      ;; The ~/.mailcap entries will end up first in the resulting data.
+      (dolist (spec (reverse
+                    (if (stringp path)
+                        (split-string path path-separator t)
+                      path)))
+       (let ((source (and (consp spec) (cadr spec)))
+             (file-name (if (stringp spec)
+                            spec
+                          (car spec))))
+         (when (and (file-readable-p file-name)
+                    (file-regular-p file-name))
+           (mailcap-parse-mailcap file-name source)))))
     (setq mailcap-parsed-p t)))
 
 (defun mailcap-parse-mailcap (fname &optional source)
@@ -1065,6 +1068,15 @@ For instance, \"foo.png\" will result in \"image/png\"."
        (match-string 1 file-name)
      "")))
 
+;;;###autoload
+(defun mailcap-mime-type-to-extension (mime-type)
+  "Return a file name extension based on a mime type.
+For instance, `image/png' will result in `png'."
+  (intern (cadr (split-string (if (symbolp mime-type)
+                                  (symbol-name mime-type)
+                                mime-type)
+                              "/"))))
+
 (defun mailcap-mime-types ()
   "Return a list of MIME media types."
   (mailcap-parse-mimetypes)
diff --git a/lisp/net/nsm.el b/lisp/net/nsm.el
index 2ac1df1d58..b067b23f8f 100644
--- a/lisp/net/nsm.el
+++ b/lisp/net/nsm.el
@@ -79,8 +79,7 @@ option."
                  (const :tag "Off" nil)
                  (function :tag "Custom function")))
 
-(defcustom nsm-settings-file (expand-file-name "network-security.data"
-                                                user-emacs-directory)
+(defcustom nsm-settings-file (locate-user-emacs-file "network-security.data")
   "The file the security manager settings will be stored in."
   :version "25.1"
   :type 'file)
diff --git a/lisp/net/ntlm.el b/lisp/net/ntlm.el
index 747a69fb5d..0e0146df96 100644
--- a/lisp/net/ntlm.el
+++ b/lisp/net/ntlm.el
@@ -436,7 +436,7 @@ PASSWD is truncated to 14 bytes if longer."
             (make-string (- 15 len) 0)))))
 
 (defun ntlm-smb-owf-encrypt (passwd c8)
-  "Return response string of 24 bytes long for password string PASSWD based on 
DES encryption.
+  "Return response string of 24 bytes long for PASSWD based on DES encryption.
 PASSWD is of at most 14 bytes long and the challenge string C8 of
 8 bytes long."
   (let* ((len (min (length passwd) 16))
@@ -459,7 +459,7 @@ PASSWD is of at most 14 bytes long and the challenge string 
C8 of
                         (substring p15 7) t)))
 
 (defun ntlm-smb-hash (in key forw)
-  "Return hash string of length 8 for a string IN of length 8 and a string KEY 
of length 8.
+  "Return hash string of length 8 for IN of length 8 and KEY of length 8.
 FORW is t or nil."
   (let ((out (make-string 8 0))
        (inb (make-string 64 0))
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index bc67562d2d..52d74a3394 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -4,7 +4,8 @@
 
 ;; Author: Ryan Yeske <rcyeske@gmail.com>
 ;; Maintainers: Ryan Yeske <rcyeske@gmail.com>,
-;;             Leo Liu <sdl.web@gmail.com>
+;;             Leo Liu <sdl.web@gmail.com>,
+;;              Philip Kaludercic <philipk@posteo.net>
 ;; Keywords: comm
 
 ;; This file is part of GNU Emacs.
@@ -189,21 +190,24 @@ If nil, no maximum is applied."
 (defvar-local rcirc-low-priority-flag nil
   "Non-nil means activity in this buffer is considered low priority.")
 
+(defvar-local rcirc-pending-requests '()
+  "List of pending requests.
+See `rcirc-omit-unless-requested'.")
+
+(defcustom rcirc-omit-unless-requested '()
+  "List of commands to only be requested if preceded by a command.
+For example, if \"TOPIC\" is added to this list, TOPIC commands
+will only be displayed if `rcirc-cmd-TOPIC' was previously
+invoked.  Commands will only be hidden if `rcirc-omit-mode' is
+enabled."
+  :version "28.1"
+  :type '(repeat string))
+
 (defcustom rcirc-omit-responses
   '("JOIN" "PART" "QUIT" "NICK")
   "Responses which will be hidden when `rcirc-omit-mode' is enabled."
   :type '(repeat string))
 
-(defcustom rcirc-omit-responses-after-join '()
-  "Types of messages to hide right after joining a channel."
-  :type '(repeat string)
-  :version "28.1")
-
-(defvar-local rcirc-joined nil
-  "Non-nil means we have just connected.
-This is used to hide the message types enumerated in
-`rcirc-omit-responses-after-join'.")
-
 (defvar-local rcirc-prompt-start-marker nil
   "Marker indicating the beginning of the message prompt.")
 
@@ -850,16 +854,17 @@ If QUIET is non-nil, no not emit a message."
                                  rcirc-failed-attempts
                                  rcirc-reconnect-attempts))
             (setq rcirc-reconnection-timer
-                  (run-at-time rcirc-timeout-seconds nil
+                  (run-at-time rcirc-reconnect-delay nil
                                #'rcirc-reconnect process t))))))))
 
 (defun rcirc-sentinel (process sentinel)
-  "Called when PROCESS receives SENTINEL."
-  (let ((sentinel (string-replace "\n" "" sentinel)))
+  "Called on a change of the state of PROCESS.
+SENTINEL describes the change in form of a string."
+  (let ((status (process-status process)))
     (rcirc-debug process (format "SENTINEL: %S %S\n" process sentinel))
     (with-rcirc-process-buffer process
       (cond
-       ((string= sentinel "open")
+       ((eq status 'open)
         (let* ((server (nth 0 rcirc-connection-info))
                (user-name (nth 3 rcirc-connection-info))
                (full-name (nth 4 rcirc-connection-info))
@@ -903,7 +908,7 @@ If QUIET is non-nil, no not emit a message."
           (dolist (buffer (cons nil (mapcar 'cdr rcirc-buffer-alist)))
            (with-current-buffer (or buffer (current-buffer))
              (setq mode-line-process nil)))))
-       ((string= sentinel "deleted")
+       ((eq status 'closed)
         (let ((now (current-time)))
           (with-rcirc-process-buffer process
             (when (and (< 0 rcirc-reconnect-delay)
@@ -911,7 +916,8 @@ If QUIET is non-nil, no not emit a message."
                                    (time-subtract now 
rcirc-last-connect-time)))
               (setq rcirc-last-connect-time now)
               (rcirc-reconnect process)))))
-       ((dolist (buffer (cons nil (mapcar 'cdr rcirc-buffer-alist)))
+       ((eq status 'failed)
+        (dolist (buffer (cons nil (mapcar 'cdr rcirc-buffer-alist)))
          (with-current-buffer (or buffer (current-buffer))
            (rcirc-print process "*rcirc*" "ERROR" rcirc-target
                         (format "%s: %s (%S)"
@@ -1564,8 +1570,7 @@ Create the buffer if it doesn't exist."
          (with-current-buffer new-buffer
             (unless (eq major-mode 'rcirc-mode)
              (rcirc-mode process target))
-            (setq mode-line-process nil)
-            (setq rcirc-joined (current-time)))
+            (setq mode-line-process nil))
          (rcirc-put-nick-channel process (rcirc-nick process) target
                                  rcirc-current-line)
          new-buffer)))))
@@ -1966,12 +1971,15 @@ connection."
               ;; make text omittable
              (let ((last-activity-lines (rcirc-elapsed-lines process sender 
target)))
                (if (and (not (string= (rcirc-nick process) sender))
-                        (or (member response rcirc-omit-responses)
-                             (and (member response 
rcirc-omit-responses-after-join)
-                                  (< (time-to-seconds (time-since 
rcirc-joined))
-                                     1)))
-                        (or (not last-activity-lines)
-                            (< rcirc-omit-threshold last-activity-lines)))
+                         (or (member response rcirc-omit-responses)
+                             (and (member response rcirc-omit-unless-requested)
+                                  (if (member response rcirc-pending-requests)
+                                      (ignore (setq rcirc-pending-requests
+                                                    (delete response 
rcirc-pending-requests)))
+                                    t)))
+                         (or (member response rcirc-omit-unless-requested)
+                             (not last-activity-lines)
+                             (< rcirc-omit-threshold last-activity-lines)))
                   (put-text-property (point-min) (point-max)
                                       'invisible 'rcirc-omit)
                  ;; otherwise increment the line count
@@ -2580,6 +2588,7 @@ that, an interactive form can specified."
                      (<= ,required (length ,argument) ,total)
                    (string-match ,regexp ,argument))
            (user-error "Malformed input (%s): %S" ',command ,argument))
+         (push ,(upcase (symbol-name command)) rcirc-pending-requests)
          (let ((process (or process (rcirc-buffer-process)))
               (target (or target rcirc-target)))
            (ignore target process)
@@ -2818,24 +2827,9 @@ keywords when no KEYWORD is given."
     string))
 
 (defvar rcirc-url-regexp
-  (concat
-   "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|"
-   "nntp\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)"
-   "\\(//[-a-z0-9_.]+:[0-9]*\\)?"
-   (if (string-match "[[:digit:]]" "1") ;; Support POSIX?
-       (let ((chars "-a-z0-9_=#$@~%&*+\\/[:word:]")
-            (punct "!?:;.,"))
-        (concat
-         "\\(?:"
-         ;; Match paired parentheses, e.g. in Wikipedia URLs:
-         "[" chars punct "]+" "(" "[" chars punct "]+" ")" "[" chars "]"
-         "\\|"
-         "[" chars punct     "]+" "[" chars "]"
-         "\\)"))
-     (concat ;; XEmacs 21.4 doesn't support POSIX.
-      "\\([-a-z0-9_=!?#$@~%&*+\\/:;.,]\\|\\w\\)+"
-      "\\([-a-z0-9_=#$@~%&*+\\/]\\|\\w\\)"))
-   "\\)")
+  (eval-when-compile
+    (require 'browse-url)
+    browse-url-button-regexp)
   "Regexp matching URLs.  Set to nil to disable URL features in rcirc.")
 
 ;; cf cl-remove-if-not
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index a8e15c1e0a..9b00ff6aa3 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -247,23 +247,21 @@ and other things:
 (defvar shr-target-id nil
   "Target fragment identifier anchor.")
 
-(defvar shr-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "a" #'shr-show-alt-text)
-    (define-key map "i" #'shr-browse-image)
-    (define-key map "z" #'shr-zoom-image)
-    (define-key map [?\t] #'shr-next-link)
-    (define-key map [?\M-\t] #'shr-previous-link)
-    (define-key map [follow-link] 'mouse-face)
-    (define-key map [mouse-2] #'shr-browse-url)
-    (define-key map [C-down-mouse-1] #'shr-mouse-browse-url-new-window)
-    (define-key map "I" #'shr-insert-image)
-    (define-key map "w" #'shr-maybe-probe-and-copy-url)
-    (define-key map "u" #'shr-maybe-probe-and-copy-url)
-    (define-key map "v" #'shr-browse-url)
-    (define-key map "O" #'shr-save-contents)
-    (define-key map "\r" #'shr-browse-url)
-    map))
+(defvar-keymap shr-map
+  "a" #'shr-show-alt-text
+  "i" #'shr-browse-image
+  "z" #'shr-zoom-image
+  [?\t] #'shr-next-link
+  [?\M-\t] #'shr-previous-link
+  [follow-link] 'mouse-face
+  [mouse-2] #'shr-browse-url
+  [C-down-mouse-1] #'shr-mouse-browse-url-new-window
+  "I" #'shr-insert-image
+  "w" #'shr-maybe-probe-and-copy-url
+  "u" #'shr-maybe-probe-and-copy-url
+  "v" #'shr-browse-url
+  "O" #'shr-save-contents
+  "\r" #'shr-browse-url)
 
 (defvar shr-image-map
   (let ((map (copy-keymap shr-map)))
@@ -1574,15 +1572,14 @@ ones, in case fg and bg are nil."
       (shr-urlify (or shr-start start) (shr-expand-url url) title))))
 
 (defun shr-tag-abbr (dom)
-  (when-let* ((title (dom-attr dom 'title))
-             (start (point)))
+  (let ((title (dom-attr dom 'title))
+       (start (point)))
     (shr-generic dom)
     (shr-add-font start (point) 'shr-abbreviation)
-    (add-text-properties
-     start (point)
-     (list
-      'help-echo title
-      'mouse-face 'highlight))))
+    (when title
+      (add-text-properties start (point)
+                           (list 'help-echo title
+                                 'mouse-face 'highlight)))))
 
 (defun shr-tag-acronym (dom)
   ;; `acronym' is deprecated in favor of `abbr'.
@@ -1629,6 +1626,14 @@ url if no type is specified.  The value should be a 
float in the range 0.0 to
   :version "24.4"
   :type '(alist :key-type regexp :value-type float))
 
+(defcustom shr-use-xwidgets-for-media nil
+  "If non-nil, use xwidgets to display video and audio elements.
+This also depends on Emacs being built with xwidgets capability.
+Note that this is experimental, and may lead to instability on
+some platforms."
+  :type 'boolean
+  :version "29.1")
+
 (defun shr--get-media-pref (elem)
   "Determine the preference for ELEM.
 The preference is a float determined from `shr-prefer-media-type'."
@@ -1665,16 +1670,39 @@ The preference is a float determined from 
`shr-prefer-media-type'."
                       pref (cdr ret)))))))))
   (cons url pref))
 
+(declare-function xwidget-webkit-execute-script "xwidget.c"
+                  (xwidget script &optional callback))
+
 (defun shr-tag-video (dom)
   (let ((image (dom-attr dom 'poster))
         (url (dom-attr dom 'src))
         (start (point)))
     (unless url
       (setq url (car (shr--extract-best-source dom))))
-    (if (> (length image) 0)
-       (shr-indirect-call 'img nil image)
-      (shr-insert " [video] "))
-    (shr-urlify start (shr-expand-url url))))
+    (if (and shr-use-xwidgets-for-media
+             (fboundp 'make-xwidget))
+        ;; Play the video.
+        (progn
+          (require 'xwidget)
+          (let ((widget (make-xwidget
+                         'webkit
+                        "Video"
+                         (truncate (* (window-pixel-width) 0.8))
+                         (truncate (* (window-pixel-width) 0.8 0.75)))))
+            (insert
+             (propertize
+              " [video] "
+              'display (list 'xwidget :xwidget widget)))
+            (xwidget-webkit-execute-script
+             widget (format "document.body.innerHTML = %S;"
+                            (format
+                             "<video autoplay loop muted><source src=%S 
type='video/mp4\'></source></video>"
+                             url)))))
+      ;; No xwidgets.
+      (if (> (length image) 0)
+         (shr-indirect-call 'img nil image)
+        (shr-insert " [video] "))
+      (shr-urlify start (shr-expand-url url)))))
 
 (defun shr-tag-audio (dom)
   (let ((url (dom-attr dom 'src))
diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el
index 6e10b5c4e3..b4aed27981 100644
--- a/lisp/net/soap-client.el
+++ b/lisp/net/soap-client.el
@@ -860,7 +860,7 @@ contains a reference, retrieve the type of the reference."
             (if complex-type
                 (setq type (soap-xs-parse-complex-type (car complex-type)))
               ;; else
-              (error "Soap-xs-parse-element: missing type or ref"))))))
+              (error "soap-xs-parse-element: Missing type or ref"))))))
 
     (make-soap-xs-element :name name
                           ;; Use the full namespace name for now, we will
@@ -2874,7 +2874,7 @@ decode function to perform the actual decoding."
       (unless wtype
         ;; The node has type info encoded in it, but we don't know how to
         ;; decode it...
-        (error "Soap-decode-array: node has unknown type: %s" type)))
+        (error "soap-decode-array: Node has unknown type: %s" type)))
     (dolist (e contents)
       (when (consp e)
         (push (if wtype
diff --git a/lisp/net/soap-inspect.el b/lisp/net/soap-inspect.el
index b994b0ed86..eca338eb22 100644
--- a/lisp/net/soap-inspect.el
+++ b/lisp/net/soap-inspect.el
@@ -114,7 +114,7 @@ This is a specialization of `soap-sample-value' for
    (cond
     ((soap-xs-simple-type-enumeration type)
      (let ((enumeration (soap-xs-simple-type-enumeration type)))
-       (nth (random (length enumeration)) enumeration)))
+       (and enumeration (seq-random-elt enumeration))))
     ((soap-xs-simple-type-pattern type)
      (format "a string matching %s" (soap-xs-simple-type-pattern type)))
     ((soap-xs-simple-type-length-range type)
@@ -134,7 +134,7 @@ This is a specialization of `soap-sample-value' for
         (t (random 100)))))
     ((consp (soap-xs-simple-type-base type)) ; an union of values
      (let ((base (soap-xs-simple-type-base type)))
-       (soap-sample-value (nth (random (length base)) base))))
+       (soap-sample-value (and base (seq-random-elt base)))))
     ((soap-xs-basic-type-p (soap-xs-simple-type-base type))
      (soap-sample-value (soap-xs-simple-type-base type))))))
 
@@ -220,7 +220,7 @@ to its sub elements.  If ELEMENT is the WSDL document 
itself, the
 entire WSDL can be inspected."
   (let ((inspect (get (soap-type-of element) 'soap-inspect)))
     (unless inspect
-      (error "Soap-inspect: no inspector for element"))
+      (error "soap-inspect: No inspector for element"))
 
     (with-current-buffer (get-buffer-create "*soap-inspect*")
       (setq buffer-read-only t)
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index d68d4c7b76..362a258f43 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -128,8 +128,7 @@ It is used for TCP/IP devices."
     (file-attributes . tramp-adb-handle-file-attributes)
     (file-directory-p . tramp-handle-file-directory-p)
     (file-equal-p . tramp-handle-file-equal-p)
-    ;; FIXME: This is too sloppy.
-    (file-executable-p . tramp-handle-file-exists-p)
+    (file-executable-p . tramp-adb-handle-file-executable-p)
     (file-exists-p . tramp-handle-file-exists-p)
     (file-in-directory-p . tramp-handle-file-in-directory-p)
     (file-local-copy . tramp-adb-handle-file-local-copy)
@@ -147,7 +146,7 @@ It is used for TCP/IP devices."
     (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
     (file-notify-valid-p . tramp-handle-file-notify-valid-p)
     (file-ownership-preserved-p . ignore)
-    (file-readable-p . tramp-handle-file-exists-p)
+    (file-readable-p . tramp-adb-handle-file-readable-p)
     (file-regular-p . tramp-handle-file-regular-p)
     (file-remote-p . tramp-handle-file-remote-p)
     (file-selinux-context . tramp-handle-file-selinux-context)
@@ -515,28 +514,31 @@ Emacs dired can't find files."
        (set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400)))
       tmpfile)))
 
+(defun tramp-adb-handle-file-executable-p (filename)
+  "Like `file-executable-p' for Tramp files."
+  (with-parsed-tramp-file-name filename nil
+    (with-tramp-file-property v localname "file-executable-p"
+      (tramp-adb-send-command-and-check
+       v (format "test -x %s" (tramp-shell-quote-argument localname))))))
+
+(defun tramp-adb-handle-file-readable-p (filename)
+  "Like `file-readable-p' for Tramp files."
+  (with-parsed-tramp-file-name filename nil
+    (with-tramp-file-property v localname "file-readable-p"
+      (or (tramp-handle-file-readable-p filename)
+         (tramp-adb-send-command-and-check
+          v (format "test -r %s" (tramp-shell-quote-argument localname)))))))
+
 (defun tramp-adb-handle-file-writable-p (filename)
-  "Like `file-writable-p' for Tramp files.
-But handle the case, if the \"test\" command is not available."
+  "Like `file-writable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-writable-p"
-      (if (tramp-adb-find-test-command v)
-         (if (file-exists-p filename)
-             (tramp-adb-send-command-and-check
-              v (format "test -w %s" (tramp-shell-quote-argument localname)))
-           (and
-            (file-directory-p (file-name-directory filename))
-            (file-writable-p (file-name-directory filename))))
-
-       ;; Missing "test" command on Android < 4.
-       (let ((rw-path "/data/data"))
-        (tramp-message
-         v 5
-         "Not implemented yet (assuming \"/data/data\" is writable): %s"
-         localname)
-        (and (>= (length localname) (length rw-path))
-             (string= (substring localname 0 (length rw-path))
-                      rw-path)))))))
+      (if (file-exists-p filename)
+         (tramp-adb-send-command-and-check
+          v (format "test -w %s" (tramp-shell-quote-argument localname)))
+       (and
+        (file-directory-p (file-name-directory filename))
+        (file-writable-p (file-name-directory filename)))))))
 
 (defun tramp-adb-handle-write-region
   (start end filename &optional append visit lockname mustbenew)
@@ -600,7 +602,7 @@ But handle the case, if the \"test\" command is not 
available."
 
       ;; The end.
       (when (and (null noninteractive)
-                (or (eq visit t) (null visit) (stringp visit)))
+                (or (eq visit t) (string-or-null-p visit)))
        (tramp-message v 0 "Wrote %s" filename))
       (run-hooks 'tramp-handle-write-region-hook))))
 
@@ -933,8 +935,8 @@ implementation will be used."
              (stderr (plist-get args :stderr)))
          (unless (stringp name)
            (signal 'wrong-type-argument (list #'stringp name)))
-         (unless (or (null buffer) (bufferp buffer) (stringp buffer))
-           (signal 'wrong-type-argument (list #'stringp buffer)))
+         (unless (or (bufferp buffer) (string-or-null-p buffer))
+           (signal 'wrong-type-argument (list #'bufferp buffer)))
          (unless (consp command)
            (signal 'wrong-type-argument (list #'consp command)))
          (unless (or (null coding)
@@ -947,11 +949,11 @@ implementation will be used."
            (setq connection-type 'pty))
          (unless (memq connection-type '(nil pipe pty))
            (signal 'wrong-type-argument (list #'symbolp connection-type)))
-         (unless (or (null filter) (functionp filter))
+         (unless (or (null filter) (eq filter t) (functionp filter))
            (signal 'wrong-type-argument (list #'functionp filter)))
          (unless (or (null sentinel) (functionp sentinel))
            (signal 'wrong-type-argument (list #'functionp sentinel)))
-         (unless (or (null stderr) (bufferp stderr) (stringp stderr))
+         (unless (or (bufferp stderr) (string-or-null-p stderr))
            (signal 'wrong-type-argument (list #'bufferp stderr)))
          (when (and (stringp stderr) (tramp-tramp-file-p stderr)
                     (not (tramp-equal-remote default-directory stderr)))
@@ -1043,12 +1045,13 @@ implementation will be used."
                               (rename-file remote-tmpstderr stderr))))
                          ;; Read initial output.  Remove the first
                          ;; line, which is the command echo.
-                         (while
-                             (progn
-                               (goto-char (point-min))
-                               (not (re-search-forward "[\n]" nil t)))
-                           (tramp-accept-process-output p 0))
-                         (delete-region (point-min) (point))
+                         (unless (eq filter t)
+                           (while
+                               (progn
+                                 (goto-char (point-min))
+                                 (not (re-search-forward "[\n]" nil t)))
+                             (tramp-accept-process-output p 0))
+                           (delete-region (point-min) (point)))
                          ;; Provide error buffer.  This shows only
                          ;; initial error messages; messages arriving
                          ;; later on will be inserted when the
@@ -1141,12 +1144,6 @@ error and non-nil on success."
     (let ((inhibit-read-only t)) (delete-region (point-min) (point-max)))
     (zerop (apply #'tramp-call-process vec tramp-adb-program nil t nil args))))
 
-(defun tramp-adb-find-test-command (vec)
-  "Check whether the ash has a builtin \"test\" command.
-This happens for Android >= 4.0."
-  (with-tramp-connection-property vec "test"
-    (tramp-adb-send-command-and-check vec "type test")))
-
 ;; Connection functions
 
 (defun tramp-adb-send-command (vec command &optional neveropen nooutput)
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index b28235924d..8bf25151df 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -353,6 +353,7 @@ arguments to pass to the OPERATION."
 ;;;###autoload
 (progn (defun tramp-archive-autoload-file-name-handler (operation &rest args)
   "Load Tramp archive file name handler, and perform OPERATION."
+  (defvar tramp-archive-autoload)
   (when tramp-archive-enabled
     ;; We cannot use `tramp-compat-temporary-file-directory' here due
     ;; to autoload.  When installing Tramp's GNU ELPA package, there
@@ -360,7 +361,6 @@ arguments to pass to the OPERATION."
     ;; overload this.
     (let ((default-directory temporary-file-directory)
           (tramp-archive-autoload t))
-      tramp-archive-autoload ; Silence byte compiler.
       (apply #'tramp-autoload-file-name-handler operation args)))))
 
 ;;;###autoload
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index 5a00915f4f..5e7d24ff72 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -101,8 +101,7 @@ details see the info pages."
                       (choice :tag "           Value" sexp))))
 
 ;;;###tramp-autoload
-(defcustom tramp-persistency-file-name
-  (expand-file-name (locate-user-emacs-file "tramp"))
+(defcustom tramp-persistency-file-name (locate-user-emacs-file "tramp")
   "File which keeps connection history for Tramp connections."
   :group 'tramp
   :type 'file)
@@ -319,12 +318,7 @@ KEY identifies the connection, it is either a process or a
 used to cache connection properties of the local machine.
 If KEY is `tramp-cache-undefined', or if the value is not set for
 the connection, return DEFAULT."
-  ;; Unify key by removing localname and hop from `tramp-file-name'
-  ;; structure.  Work with a copy in order to avoid side effects.
-  (when (tramp-file-name-p key)
-    (setq key (copy-tramp-file-name key))
-    (setf (tramp-file-name-localname key) nil
-         (tramp-file-name-hop key) nil))
+  (setq key (tramp-file-name-unify key))
   (let* ((hash (tramp-get-hash-table key))
         (cached (if (hash-table-p hash)
                     (gethash property hash tramp-cache-undefined)
@@ -350,12 +344,7 @@ used to cache connection properties of the local machine.  
If KEY
 is `tramp-cache-undefined', nothing is set.
 PROPERTY is set persistent when KEY is a `tramp-file-name' structure.
 Return VALUE."
-  ;; Unify key by removing localname and hop from `tramp-file-name'
-  ;; structure.  Work with a copy in order to avoid side effects.
-  (when (tramp-file-name-p key)
-    (setq key (copy-tramp-file-name key))
-    (setf (tramp-file-name-localname key) nil
-         (tramp-file-name-hop key) nil))
+  (setq key (tramp-file-name-unify key))
   (when-let ((hash (tramp-get-hash-table key)))
     (puthash property value hash))
   (setq tramp-cache-data-changed
@@ -379,12 +368,7 @@ KEY identifies the connection, it is either a process or a
 `tramp-file-name' structure.  A special case is nil, which is
 used to cache connection properties of the local machine.
 PROPERTY is set persistent when KEY is a `tramp-file-name' structure."
-  ;; Unify key by removing localname and hop from `tramp-file-name'
-  ;; structure.  Work with a copy in order to avoid side effects.
-  (when (tramp-file-name-p key)
-    (setq key (copy-tramp-file-name key))
-    (setf (tramp-file-name-localname key) nil
-         (tramp-file-name-hop key) nil))
+  (setq key (tramp-file-name-unify key))
   (when-let ((hash (tramp-get-hash-table key)))
     (remhash property hash))
   (setq tramp-cache-data-changed
@@ -397,12 +381,7 @@ PROPERTY is set persistent when KEY is a `tramp-file-name' 
structure."
 KEY identifies the connection, it is either a process or a
 `tramp-file-name' structure.  A special case is nil, which is
 used to cache connection properties of the local machine."
-  ;; Unify key by removing localname and hop from `tramp-file-name'
-  ;; structure.  Work with a copy in order to avoid side effects.
-  (when (tramp-file-name-p key)
-    (setq key (copy-tramp-file-name key))
-    (setf (tramp-file-name-localname key) nil
-         (tramp-file-name-hop key) nil))
+  (setq key (tramp-file-name-unify key))
   (tramp-message
    key 7 "%s %s" key
    (when-let ((hash (gethash key tramp-cache-data)))
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 5def3a4137..269560bfa9 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -293,9 +293,8 @@ arguments to pass to the OPERATION."
 
 (defun tramp-crypt-config-file-name (vec)
   "Return the encfs config file name for VEC."
-  (expand-file-name
-   (concat "tramp-" (tramp-file-name-host vec) tramp-crypt-encfs-config)
-   user-emacs-directory))
+  (locate-user-emacs-file
+   (concat "tramp-" (tramp-file-name-host vec) tramp-crypt-encfs-config)))
 
 (defun tramp-crypt-maybe-open-connection (vec)
   "Maybe open a connection VEC.
diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el
index 8c5afa7cf9..c359082dc1 100644
--- a/lisp/net/tramp-fuse.el
+++ b/lisp/net/tramp-fuse.el
@@ -156,34 +156,56 @@
        (tramp-file-name-host-port vec))
        tramp-compat-temporary-file-directory)))
 
+(defconst tramp-fuse-mount-timeout
+  (eval (car (get 'remote-file-name-inhibit-cache 'standard-value)) t)
+  "Time period to check whether the mount point still exists.
+It has the same meaning as `remote-file-name-inhibit-cache'.")
+
 (defun tramp-fuse-mounted-p (vec)
   "Check, whether fuse volume determined by VEC is mounted."
-  (when (tramp-get-connection-process vec)
-    ;; We cannot use `with-connection-property', because we don't want
-    ;; to cache a nil result.
-    (or (tramp-get-connection-property
-         (tramp-get-connection-process vec) "mounted" nil)
+  ;; Remember the mount status by using a file property on "/",
+  ;; instead of using a connection property, because a file property
+  ;; has a timeout.  Having a timeout lets us regularly recheck the
+  ;; mount status, as requested by `tramp-fuse-mount-timeout'.  We
+  ;; cannot use `with-tramp-file-property', because we don't want to
+  ;; cache a nil result.
+  (let ((remote-file-name-inhibit-cache tramp-fuse-mount-timeout))
+    (or (tramp-get-file-property vec "/" "mounted" nil)
         (let* ((default-directory tramp-compat-temporary-file-directory)
                (command (format "mount -t fuse.%s" (tramp-file-name-method 
vec)))
               (mount (shell-command-to-string command)))
           (tramp-message vec 6 "%s\n%s" command mount)
-          (tramp-set-connection-property
-           (tramp-get-connection-process vec) "mounted"
+          (tramp-set-file-property
+          vec "/" "mounted"
            (when (string-match
                  (format
                    "^\\(%s\\)\\s-" (regexp-quote (tramp-fuse-mount-spec vec)))
                  mount)
              (match-string 1 mount)))))))
 
+(defun tramp-fuse-get-fusermount ()
+  "Determine the local `fusermount' command."
+  ;; We use key nil for local connection properties.
+  (with-tramp-connection-property nil "fusermount"
+    (or (executable-find "fusermount3")
+       (executable-find "fusermount"))))
+
+(defvar tramp-fuse-mount-points nil
+  "List of fuse volume determined by a VEC.")
+
 (defun tramp-fuse-unmount (vec)
   "Unmount fuse volume determined by VEC."
-  (let ((default-directory tramp-compat-temporary-file-directory)
-        (command (format "fusermount3 -u %s" (tramp-fuse-mount-point vec))))
+  (let* ((default-directory tramp-compat-temporary-file-directory)
+        (mount-point (tramp-fuse-mount-point vec))
+         (command (format "%s -u %s" (tramp-fuse-get-fusermount) mount-point)))
     (tramp-message vec 6 "%s\n%s" command (shell-command-to-string command))
-    (tramp-flush-connection-property
-     (tramp-get-connection-process vec) "mounted")
+    (tramp-flush-file-property vec "/" "mounted")
+    (setq tramp-fuse-mount-points
+         (delete (tramp-file-name-unify vec) tramp-fuse-mount-points))
     ;; Give the caches a chance to expire.
-    (sleep-for 1)))
+    (sleep-for 1)
+    (when (tramp-compat-directory-empty-p mount-point)
+      (delete-directory mount-point))))
 
 (defun tramp-fuse-local-file-name (filename)
   "Return local mount name of FILENAME."
@@ -205,6 +227,36 @@
              (substring localname 1) localname)
          (tramp-fuse-mount-point v)))))))
 
+(defcustom tramp-fuse-unmount-on-cleanup nil
+  "Whether fuse volumes shall be unmounted on cleanup."
+  :group 'tramp
+  :version "28.1"
+  :type 'boolean)
+
+(defun tramp-fuse-cleanup (vec)
+  "Cleanup fuse volume determined by VEC."
+  (and tramp-fuse-unmount-on-cleanup
+       (member (tramp-file-name-unify vec) tramp-fuse-mount-points)
+       (tramp-fuse-unmount vec)))
+
+(defun tramp-fuse-cleanup-all ()
+  "Unmount all fuse volumes used by Tramp."
+  (and tramp-fuse-unmount-on-cleanup
+       (mapc #'tramp-fuse-unmount tramp-fuse-mount-points)))
+
+;; Add cleanup hooks.
+(add-hook 'tramp-cleanup-connection-hook #'tramp-fuse-cleanup)
+(add-hook 'tramp-cleanup-all-connections-hook #'tramp-fuse-cleanup-all)
+(add-hook 'kill-emacs-hook #'tramp-fuse-cleanup-all)
+(add-hook 'tramp-fuse-unload-hook
+         (lambda ()
+           (remove-hook 'tramp-cleanup-connection-hook
+                        #'tramp-fuse-cleanup)
+           (remove-hook 'tramp-cleanup-all-connections-hook
+                        #'tramp-fuse-cleanup-all)
+           (remove-hook 'kill-emacs-hook
+                        #'tramp-fuse-cleanup-all)))
+
 (add-hook 'tramp-unload-hook
          (lambda ()
            (unload-feature 'tramp-fuse 'force)))
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 5f0e7bcd98..cab912bd93 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -788,7 +788,7 @@ It has been changed in GVFS 1.14.")
     (file-notify-rm-watch . tramp-handle-file-notify-rm-watch)
     (file-notify-valid-p . tramp-handle-file-notify-valid-p)
     (file-ownership-preserved-p . ignore)
-    (file-readable-p . tramp-gvfs-handle-file-readable-p)
+    (file-readable-p . tramp-handle-file-readable-p)
     (file-regular-p . tramp-handle-file-regular-p)
     (file-remote-p . tramp-handle-file-remote-p)
     (file-selinux-context . tramp-handle-file-selinux-context)
@@ -1396,8 +1396,7 @@ If FILE-SYSTEM is non-nil, return file system attributes."
   "Like `file-executable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-executable-p"
-      (and (file-exists-p filename)
-          (tramp-check-cached-permissions v ?x)))))
+      (tramp-check-cached-permissions v ?x))))
 
 (defun tramp-gvfs-handle-file-name-all-completions (filename directory)
   "Like `file-name-all-completions' for Tramp files."
@@ -1519,31 +1518,6 @@ If FILE-SYSTEM is non-nil, return file system 
attributes."
     (when string (tramp-message proc 10 "Rest string:\n%s" string))
     (process-put proc 'rest-string string)))
 
-(defun tramp-gvfs-handle-file-readable-p (filename)
-  "Like `file-readable-p' for Tramp files."
-  (with-parsed-tramp-file-name filename nil
-    (with-tramp-file-property v localname "file-readable-p"
-      (and (file-exists-p filename)
-          (or (tramp-check-cached-permissions v ?r)
-              ;; `tramp-check-cached-permissions' doesn't handle
-              ;; symbolic links.
-              (and (stringp (file-symlink-p filename))
-                   (file-readable-p
-                    (concat
-                     (file-remote-p filename) (file-symlink-p filename))))
-              ;; If the user is different from what we guess to be
-              ;; the user, we don't know.  Let's check, whether
-              ;; access is restricted explicitly.
-              (and (/= (tramp-get-remote-uid v 'integer)
-                       (tramp-compat-file-attribute-user-id
-                        (file-attributes filename 'integer)))
-                   (not
-                    (string-equal
-                     "FALSE"
-                     (cdr (assoc
-                           "access::can-read"
-                           (tramp-gvfs-get-file-attributes filename)))))))))))
-
 (defun tramp-gvfs-handle-file-system-info (filename)
   "Like `file-system-info' for Tramp files."
   (setq filename (directory-file-name (expand-file-name filename)))
@@ -1833,8 +1807,9 @@ a downcased host name only."
        result))))
 
 (defun tramp-gvfs-handler-mounted-unmounted (mount-info)
-  "Signal handler for the \"org.gtk.vfs.MountTracker.mounted\" and \
-\"org.gtk.vfs.MountTracker.unmounted\" signals."
+  "Signal handler for the gvfs \"mounted\" and \"unmounted\" signals.
+Their full names are \"org.gtk.vfs.MountTracker.mounted\" and
+\"org.gtk.vfs.MountTracker.unmounted\"."
   (ignore-errors
     (let ((signal-name (dbus-event-member-name last-input-event))
          (elt mount-info))
@@ -1890,8 +1865,9 @@ a downcased host name only."
                    host (tramp-file-name-host v)
                    port (tramp-file-name-port v)))))
        (when (member method tramp-gvfs-methods)
-         (with-parsed-tramp-file-name
-             (tramp-make-tramp-file-name method user domain host port "") nil
+          (let ((v (make-tramp-file-name
+                   :method method :user user :domain domain
+                   :host host :port port)))
            (tramp-message
             v 6 "%s %s"
             signal-name (tramp-gvfs-stringify-dbus-message mount-info))
@@ -2090,8 +2066,10 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
     `(:struct ,(tramp-gvfs-dbus-string-to-byte-array mount-pref) ,mount-spec)))
 
 (defun tramp-gvfs-handler-volumeadded-volumeremoved (_dbus-name _id volume)
-  "Signal handler for the \"org.gtk.Private.RemoteVolumeMonitor.VolumeAdded\" \
-and \"org.gtk.Private.RemoteVolumeMonitor.VolumeRemoved\" signals."
+  "Signal handler for the gvfs \"VolumeAdded\" and \"VolumeRemoved\" signals.
+Their full names are
+\"org.gtk.Private.RemoteVolumeMonitor.VolumeAdded\" and
+\"org.gtk.Private.RemoteVolumeMonitor.VolumeRemoved\"."
   (ignore-errors
     (let* ((signal-name (dbus-event-member-name last-input-event))
           (uri (url-generic-parse-url (nth 5 volume)))
diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el
index 49e366c01c..812e06f3f1 100644
--- a/lisp/net/tramp-rclone.el
+++ b/lisp/net/tramp-rclone.el
@@ -386,6 +386,7 @@ connection if a previous connection has died for some 
reason."
          (tramp-cleanup-connection vec 'keep-debug 'keep-password))
 
        ;; Mark it as connected.
+       (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
        (tramp-set-connection-property
         (tramp-get-connection-process vec) "connected" t))))
 
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 7f1a52fa93..b20e5f8073 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -1580,9 +1580,7 @@ ID-FORMAT valid values are `string' and `integer'."
   "Like `file-readable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-readable-p"
-      ;; Examine `file-attributes' cache to see if request can be
-      ;; satisfied without remote operation.
-      (or (tramp-check-cached-permissions v ?r)
+      (or (tramp-handle-file-readable-p filename)
          (tramp-run-test "-r" filename)))))
 
 ;; Functions implemented using the basic functions above.
@@ -1628,9 +1626,7 @@ ID-FORMAT valid values are `string' and `integer'."
                 ;; On BSD-derived systems files always inherit the
                  ;; parent directory's group, so skip the group-gid
                  ;; test.
-                (string-match-p
-                 "BSD\\|DragonFly\\|Darwin"
-                 (tramp-get-connection-property v "uname" ""))
+                 (tramp-check-remote-uname v "BSD\\|DragonFly\\|Darwin")
                 (= (tramp-compat-file-attribute-group-id attributes)
                    (tramp-get-remote-gid v 'integer)))))))))
 
@@ -1701,7 +1697,7 @@ ID-FORMAT valid values are `string' and `integer'."
 ;; FIXME: Fix function to work with count parameter.
 (defun tramp-do-directory-files-and-attributes-with-stat
   (vec localname &optional id-format)
-  "Implement `directory-files-and-attributes' for Tramp files using stat(1) 
command."
+  "Implement `directory-files-and-attributes' for Tramp files with stat(1) 
command."
   (tramp-message vec 5 "directory-files-and-attributes with stat: %s" 
localname)
   (tramp-send-command-and-read
    vec
@@ -2498,9 +2494,14 @@ The method used must be an out-of-band method."
             (with-tramp-progress-reporter
                  v 0 (format "Uncompressing %s" file)
               (when (tramp-send-command-and-check
-                     v (concat (nth 2 suffix) " "
-                               (tramp-shell-quote-argument localname)))
-                (dired-remove-file file)
+                     v (if (string-match-p "%[io]" (nth 2 suffix))
+                            (replace-regexp-in-string
+                             "%i" (tramp-shell-quote-argument localname)
+                             (nth 2 suffix))
+                          (concat (nth 2 suffix) " "
+                                  (tramp-shell-quote-argument localname))))
+                (unless (string-match-p "\\.tar\\.gz" file)
+                   (dired-remove-file file))
                 (string-match (car suffix) file)
                 (concat (substring file 0 (match-beginning 0))))))
            (t
@@ -2508,14 +2509,21 @@ The method used must be an out-of-band method."
             ;; Try gzip.
             (with-tramp-progress-reporter v 0 (format "Compressing %s" file)
               (when (tramp-send-command-and-check
-                     v (concat "gzip -f "
-                               (tramp-shell-quote-argument localname)))
-                (dired-remove-file file)
-                (cond ((file-exists-p (concat file ".gz"))
-                       (concat file ".gz"))
-                      ((file-exists-p (concat file ".z"))
-                       (concat file ".z"))
-                      (t nil)))))))))
+                     v (if (file-directory-p file)
+                            (format "tar -cf - %s | gzip -c9 > %s.tar.gz"
+                                    (tramp-shell-quote-argument
+                                     (file-name-nondirectory localname))
+                                    (tramp-shell-quote-argument localname))
+                          (concat "gzip -f "
+                                 (tramp-shell-quote-argument localname))))
+                (unless (file-directory-p file)
+                   (dired-remove-file file))
+                (catch 'found nil
+                        (dolist (target (mapcar (lambda (suffix)
+                                                  (concat file suffix))
+                                                '(".tar.gz" ".gz" ".z")))
+                          (when (file-exists-p target)
+                            (throw 'found target)))))))))))
 
 (defun tramp-sh-handle-insert-directory
     (filename switches &optional wildcard full-directory-p)
@@ -2697,11 +2705,11 @@ the result will be a local, non-Tramp, file name."
     ;; Unless NAME is absolute, concat DIR and NAME.
     (unless (file-name-absolute-p name)
       (setq name (tramp-compat-file-name-concat dir name)))
-    ;; If connection is not established yet, run the real handler.
-    (if (not (tramp-connectable-p name))
-       (tramp-run-real-handler #'expand-file-name (list name nil))
-      ;; Dissect NAME.
-      (with-parsed-tramp-file-name name nil
+    ;; Dissect NAME.
+    (with-parsed-tramp-file-name name nil
+      ;; If connection is not established yet, run the real handler.
+      (if (not (tramp-connectable-p v))
+         (tramp-run-real-handler #'expand-file-name (list name nil))
        (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
          (setq localname (concat "~/" localname)))
        ;; Tilde expansion if necessary.  This needs a shell which
@@ -2773,8 +2781,8 @@ implementation will be used."
              (stderr (plist-get args :stderr)))
          (unless (stringp name)
            (signal 'wrong-type-argument (list #'stringp name)))
-         (unless (or (null buffer) (bufferp buffer) (stringp buffer))
-           (signal 'wrong-type-argument (list #'stringp buffer)))
+         (unless (or (bufferp buffer) (string-or-null-p buffer))
+           (signal 'wrong-type-argument (list #'bufferp buffer)))
          (unless (or (null command) (consp command))
            (signal 'wrong-type-argument (list #'consp command)))
          (unless (or (null coding)
@@ -2787,11 +2795,11 @@ implementation will be used."
            (setq connection-type 'pty))
          (unless (memq connection-type '(nil pipe pty))
            (signal 'wrong-type-argument (list #'symbolp connection-type)))
-         (unless (or (null filter) (functionp filter))
+         (unless (or (null filter) (eq filter t) (functionp filter))
            (signal 'wrong-type-argument (list #'functionp filter)))
          (unless (or (null sentinel) (functionp sentinel))
            (signal 'wrong-type-argument (list #'functionp sentinel)))
-         (unless (or (null stderr) (bufferp stderr) (stringp stderr))
+         (unless (or (bufferp stderr) (string-or-null-p stderr))
            (signal 'wrong-type-argument (list #'bufferp stderr)))
          (when (and (stringp stderr)
                     (not (tramp-equal-remote default-directory stderr)))
@@ -2937,8 +2945,11 @@ implementation will be used."
                            (setq p (tramp-get-connection-process v))
                            (process-put p 'remote-pid pid)
                            (tramp-set-connection-property p "remote-pid" pid))
-                         ;; Disable carriage return to newline translation.
-                         (when (memq connection-type '(nil pipe))
+                         ;; Disable carriage return to newline
+                         ;; translation.  This does not work on
+                         ;; macOS, see Bug#50748.
+                         (when (and (memq connection-type '(nil pipe))
+                                     (not (tramp-check-remote-uname v 
"Darwin")))
                            (tramp-send-command v "stty -icrnl"))
                          ;; `tramp-maybe-open-connection' and
                          ;; `tramp-send-command-and-read' could have
@@ -3512,7 +3523,7 @@ implementation will be used."
          (tramp-compat-funcall 'unlock-file lockname))
 
        (when (and (null noninteractive)
-                  (or (eq visit t) (null visit) (stringp visit)))
+                  (or (eq visit t) (string-or-null-p visit)))
          (tramp-message v 0 "Wrote %s" filename))
        (run-hooks 'tramp-handle-write-region-hook)))))
 
@@ -4008,10 +4019,7 @@ This function expects to be in the right *tramp* buffer."
       ;; number of words it returns.  "SunOS 5.10" (and maybe "SunOS
       ;; 5.11") have problems with this command, we disable the call
       ;; therefore.
-      (unless (or ignore-path
-                 (string-match-p
-                  tramp-sunos-unames
-                  (tramp-get-connection-property vec "uname" "")))
+      (unless (or ignore-path (tramp-check-remote-uname vec 
tramp-sunos-unames))
        (tramp-send-command vec (format "which \\%s | wc -w" progname))
        (goto-char (point-min))
        (if (looking-at-p "^\\s-*1$")
@@ -4221,9 +4229,7 @@ file exists and nonzero exit status otherwise."
                        ;; The default shell (ksh93) of OpenSolaris
                        ;; and Solaris is buggy.  We've got reports
                        ;; for "SunOS 5.10" and "SunOS 5.11" so far.
-                       (string-match-p
-                        tramp-sunos-unames
-                        (tramp-get-connection-property vec "uname" "")))
+                        (tramp-check-remote-uname vec tramp-sunos-unames))
 
                    (or (tramp-find-executable
                         vec "bash" (tramp-get-remote-path vec) t t)
@@ -5340,6 +5346,10 @@ Return ATTR."
 
 ;; Variables local to connection.
 
+(defun tramp-check-remote-uname (vec regexp)
+  "Check whether REGEXP matches the connection property \"uname\"."
+  (string-match-p regexp (tramp-get-connection-property vec "uname" "")))
+
 (defun tramp-get-remote-path (vec)
   "Compile list of remote directories for PATH.
 Nonexistent directories are removed from spec."
@@ -5564,8 +5574,7 @@ Nonexistent directories are removed from spec."
   (with-tramp-connection-property vec "stat"
     ;; stat on Solaris is buggy.  We've got reports for "SunOS 5.10"
     ;; and "SunOS 5.11" so far.
-    (unless (string-match-p
-            tramp-sunos-unames (tramp-get-connection-property vec "uname" ""))
+    (unless (tramp-check-remote-uname vec tramp-sunos-unames)
       (tramp-message vec 5 "Finding a suitable `stat' command")
       (let ((result (tramp-find-executable
                     vec "stat" (tramp-get-remote-path vec)))
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index 87f3665d91..49f049d3f3 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -1658,7 +1658,7 @@ errors for shares like \"C$/\", which are common in 
Microsoft Windows."
 
       ;; The end.
       (when (and (null noninteractive)
-                (or (eq visit t) (null visit) (stringp visit)))
+                (or (eq visit t) (string-or-null-p visit)))
        (tramp-message v 0 "Wrote %s" filename))
       (run-hooks 'tramp-handle-write-region-hook))))
 
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index 0019ac014f..a100786345 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -222,11 +222,14 @@ arguments to pass to the OPERATION."
 (defun tramp-sshfs-handle-insert-file-contents
   (filename &optional visit beg end replace)
   "Like `insert-file-contents' for Tramp files."
-  (let ((result
-        (insert-file-contents
-         (tramp-fuse-local-file-name filename) visit beg end replace)))
-    (when visit (setq buffer-file-name filename))
-    (cons (expand-file-name filename) (cdr result))))
+  (setq filename (expand-file-name filename))
+  (let (signal-hook-function result)
+    (unwind-protect
+        (setq result
+             (insert-file-contents
+              (tramp-fuse-local-file-name filename) visit beg end replace))
+      (when visit (setq buffer-file-name filename))
+      (cons filename (cdr result)))))
 
 (defun tramp-sshfs-handle-process-file
   (program &optional infile destination display &rest args)
@@ -317,7 +320,7 @@ arguments to pass to the OPERATION."
 
       ;; The end.
       (when (and (null noninteractive)
-                (or (eq visit t) (null visit) (stringp visit)))
+                (or (eq visit t) (string-or-null-p visit)))
        (tramp-message v 0 "Wrote %s" filename))
       (run-hooks 'tramp-handle-write-region-hook))))
 
@@ -346,30 +349,31 @@ connection if a previous connection has died for some 
reason."
       (tramp-set-connection-property p "lock-pid" (truncate (time-to-seconds)))
 
       ;; Set connection-local variables.
-      (tramp-set-connection-local-variables vec)
-
-      ;; Create directory.
-      (unless (file-directory-p (tramp-fuse-mount-point vec))
-       (make-directory (tramp-fuse-mount-point vec) 'parents))
-
-      (unless
-         (or (tramp-fuse-mounted-p vec)
-             (with-temp-buffer
-               (zerop
-                (apply
-                 #'tramp-call-process
-                 vec tramp-sshfs-program nil t nil
-                 (tramp-fuse-mount-spec vec)
-                 (tramp-fuse-mount-point vec)
-                 (tramp-expand-args
-                  vec 'tramp-mount-args
-                  ?p (or (tramp-file-name-port vec) "")))))
-         (tramp-error
-          vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec))))
-
-      ;; Mark it as connected.
-      (tramp-set-connection-property
-       (tramp-get-connection-process vec) "connected" t)))
+      (tramp-set-connection-local-variables vec)))
+
+  ;; Create directory.
+  (unless (file-directory-p (tramp-fuse-mount-point vec))
+    (make-directory (tramp-fuse-mount-point vec) 'parents))
+
+  (unless
+      (or (tramp-fuse-mounted-p vec)
+         (with-temp-buffer
+           (zerop
+            (apply
+             #'tramp-call-process
+             vec tramp-sshfs-program nil t nil
+             (tramp-fuse-mount-spec vec)
+             (tramp-fuse-mount-point vec)
+             (tramp-expand-args
+              vec 'tramp-mount-args
+              ?p (or (tramp-file-name-port vec) ""))))))
+    (tramp-error
+     vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec)))
+
+  ;; Mark it as connected.
+  (add-to-list 'tramp-fuse-mount-points (tramp-file-name-unify vec))
+  (tramp-set-connection-property
+   (tramp-get-connection-process vec) "connected" t)
 
   ;; In `tramp-check-cached-permissions', the connection properties
   ;; "{uid,gid}-{integer,string}" are used.  We set them to proper values.
diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el
index 516d46da37..845f31d09b 100644
--- a/lisp/net/tramp-sudoedit.el
+++ b/lisp/net/tramp-sudoedit.el
@@ -464,8 +464,9 @@ the result will be a local, non-Tramp, file name."
   "Like `file-readable-p' for Tramp files."
   (with-parsed-tramp-file-name filename nil
     (with-tramp-file-property v localname "file-readable-p"
-      (tramp-sudoedit-send-command
-       v "test" "-r" (tramp-compat-file-name-unquote localname)))))
+      (or (tramp-handle-file-readable-p filename)
+         (tramp-sudoedit-send-command
+          v "test" "-r" (tramp-compat-file-name-unquote localname))))))
 
 (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag)
   "Like `set-file-modes' for Tramp files."
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 2804b4d37d..a8972ce69e 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -1304,7 +1304,7 @@ let-bind this variable."
 ;; "getconf PATH" yields:
 ;; HP-UX: 
/usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
 ;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
-;; GNU/Linux (Debian, Suse, RHEL): /bin:/usr/bin
+;; GNU/Linux (Debian, Suse, RHEL, Cygwin, MINGW64): /bin:/usr/bin
 ;; FreeBSD, DragonFly: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
 ;; FreeBSD 12.1, Darwin: /usr/bin:/bin:/usr/sbin:/sbin
 ;; IRIX64: /usr/bin
@@ -1326,9 +1326,9 @@ tilde expansion, all directory names starting with \"~\" 
will be ignored.
 the command \"getconf PATH\".  It is recommended to use this
 entry on head of this list, because these are the default
 directories for POSIX compatible commands.  On remote hosts which
-do not offer the getconf command (like cygwin), the value
-\"/bin:/usr/bin\" is used instead.  This entry is represented in
-the list by the special value `tramp-default-remote-path'.
+do not offer the getconf command, the value \"/bin:/usr/bin\" is
+used instead.  This entry is represented in the list by the
+special value `tramp-default-remote-path'.
 
 `Private Directories' are the settings of the $PATH environment,
 as given in your `~/.profile'.  This entry is represented in
@@ -1450,16 +1450,24 @@ If nil, return `tramp-default-port'."
 
 (put #'tramp-file-name-port-or-default 'tramp-suppress-trace t)
 
+(defun tramp-file-name-unify (vec)
+  "Unify VEC by removing localname and hop from `tramp-file-name' structure.
+Objects returned by this function compare `equal' if they refer to the
+same connection.  Make a copy in order to avoid side effects."
+  (when (tramp-file-name-p vec)
+    (setq vec (copy-tramp-file-name vec))
+    (setf (tramp-file-name-localname vec) nil
+         (tramp-file-name-hop vec) nil))
+  vec)
+
+(put #'tramp-file-name-unify 'tramp-suppress-trace t)
+
 ;; Comparison of file names is performed by `tramp-equal-remote'.
 (defun tramp-file-name-equal-p (vec1 vec2)
   "Check, whether VEC1 and VEC2 denote the same `tramp-file-name'."
   (and (tramp-file-name-p vec1) (tramp-file-name-p vec2)
-       (string-equal (tramp-file-name-method vec1)
-                    (tramp-file-name-method vec2))
-       (string-equal (tramp-file-name-user-domain vec1)
-                    (tramp-file-name-user-domain vec2))
-       (string-equal (tramp-file-name-host-port vec1)
-                    (tramp-file-name-host-port vec2))))
+       (equal (tramp-file-name-unify vec1)
+             (tramp-file-name-unify vec2))))
 
 (defun tramp-get-method-parameter (vec param)
   "Return the method parameter PARAM.
@@ -1750,6 +1758,9 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME 
&optional HOP)."
            tramp-postfix-host-format
            localname)))
 
+(set-advertised-calling-convention
+ #'tramp-make-tramp-file-name '(vec &optional localname hop) "27.1")
+
 (defun tramp-make-tramp-hop-name (vec)
   "Construct a Tramp hop name from VEC."
   (replace-regexp-in-string
@@ -2079,8 +2090,7 @@ VEC-OR-PROC identifies the connection to use, SIGNAL is 
the
 signal identifier to be raised, remaining arguments passed to
 `tramp-message'.  Finally, signal SIGNAL is raised with
 FMT-STRING and ARGUMENTS."
-  (let ((inhibit-message t)
-       signal-hook-function)
+  (let (signal-hook-function)
     (tramp-backtrace vec-or-proc)
     (unless arguments
       ;; FMT-STRING could be just a file name, as in
@@ -2190,9 +2200,10 @@ the resulting error message."
   ;; `custom-initialize-*' functions provoke `void-variable' errors.
   ;; We don't want to see them in the backtrace.
   (unless (eq error-symbol 'void-variable)
-    (tramp-error
-     (car tramp-current-connection) error-symbol
-     (mapconcat (lambda (x) (format "%s" x)) data " "))))
+    (let ((inhibit-message t))
+      (tramp-error
+       (car tramp-current-connection) error-symbol
+       (mapconcat (lambda (x) (format "%s" x)) data " ")))))
 
 (put #'tramp-signal-hook-function 'tramp-suppress-trace t)
 
@@ -3267,10 +3278,18 @@ User is always nil."
 
 (defun tramp-handle-access-file (filename string)
   "Like `access-file' for Tramp files."
-  (unless (file-readable-p (file-truename filename))
-    (tramp-compat-file-missing
-     (tramp-dissect-file-name filename)
-     (format "%s: %s" string filename))))
+  (setq filename (file-truename filename))
+  (with-parsed-tramp-file-name filename v
+    (if (file-exists-p filename)
+       (unless
+           (funcall
+            (if (file-directory-p filename)
+                #'file-accessible-directory-p #'file-readable-p)
+            filename)
+         (tramp-error
+          v 'file-error (format "%s: Permission denied, %s" string filename)))
+      (tramp-compat-file-missing
+       v (format "%s: No such file or directory, %s" string filename)))))
 
 (defun tramp-handle-add-name-to-file
   (filename newname &optional ok-if-already-exists)
@@ -3465,7 +3484,7 @@ User is always nil."
      (tramp-get-method-parameter v 'tramp-case-insensitive)
 
      ;; There isn't.  So we must check, in case there's a connection already.
-     (and (file-remote-p filename nil 'connected)
+     (and (let ((non-essential t)) (tramp-connectable-p v))
           (with-tramp-connection-property v "case-insensitive"
            (ignore-errors
              (with-tramp-progress-reporter v 5 "Checking case-insensitive"
@@ -3560,6 +3579,17 @@ User is always nil."
        (tramp-compat-file-attribute-modification-time
        (file-attributes file1))))))
 
+(defun tramp-handle-file-readable-p (filename)
+  "Like `file-readable-p' for Tramp files."
+  (with-parsed-tramp-file-name filename nil
+    (with-tramp-file-property v localname "file-readable-p"
+      (or (tramp-check-cached-permissions v ?r)
+         ;; `tramp-check-cached-permissions' doesn't handle symbolic
+         ;; links.
+         (when-let ((symlink (file-symlink-p filename)))
+           (and (stringp symlink)
+                (file-readable-p (concat (file-remote-p filename) 
symlink))))))))
+
 (defun tramp-handle-file-regular-p (filename)
   "Like `file-regular-p' for Tramp files."
   (and (file-exists-p filename)
@@ -3743,7 +3773,8 @@ User is always nil."
     (with-parsed-tramp-file-name filename nil
       (unwind-protect
          (if (not (file-exists-p filename))
-             (tramp-compat-file-missing v filename)
+              (let ((tramp-verbose (if visit 0 tramp-verbose)))
+               (tramp-compat-file-missing v filename))
 
            (with-tramp-progress-reporter
                v 3 (format-message "Inserting `%s'" filename)
@@ -3845,7 +3876,7 @@ User is always nil."
          (delete-file (tramp-make-tramp-file-name v remote-copy 'nohop))))
 
       ;; Result.
-      (cons (expand-file-name filename) (cdr result)))))
+      (cons filename (cdr result)))))
 
 (defun tramp-get-lock-file (file)
   "Read lockfile info of FILE.
@@ -3920,7 +3951,8 @@ Return nil when there is no lockfile."
            (tramp-error v 'file-error "Unsafe lock file name")))
 
        ;; Do the lock.
-        (let (create-lockfiles signal-hook-function)
+        (let ((tramp-verbose 0)
+              create-lockfiles signal-hook-function)
          (condition-case nil
              (make-symbolic-link info lockname 'ok-if-already-exists)
            (error
@@ -4117,8 +4149,8 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
            (stderr (plist-get args :stderr)))
        (unless (stringp name)
          (signal 'wrong-type-argument (list #'stringp name)))
-       (unless (or (null buffer) (bufferp buffer) (stringp buffer))
-         (signal 'wrong-type-argument (list #'stringp buffer)))
+       (unless (or (bufferp buffer) (string-or-null-p buffer))
+         (signal 'wrong-type-argument (list #'bufferp buffer)))
        (unless (consp command)
          (signal 'wrong-type-argument (list #'consp command)))
        (unless (or (null coding)
@@ -4131,7 +4163,7 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
          (setq connection-type 'pty))
        (unless (memq connection-type '(nil pipe pty))
          (signal 'wrong-type-argument (list #'symbolp connection-type)))
-       (unless (or (null filter) (functionp filter))
+       (unless (or (null filter) (eq filter t) (functionp filter))
          (signal 'wrong-type-argument (list #'functionp filter)))
        (unless (or (null sentinel) (functionp sentinel))
          (signal 'wrong-type-argument (list #'functionp sentinel)))
@@ -4210,7 +4242,12 @@ substitution.  SPEC-LIST is a list of char/value pairs 
used for
                :name name :buffer buffer
                :command (append `(,login-program) login-args command)
                :coding coding :noquery noquery :connection-type connection-type
-               :filter filter :sentinel sentinel :stderr stderr))
+               :sentinel sentinel :stderr stderr))
+           ;; Set filter.  Prior Emacs 29.1, it doesn't work reliable
+           ;; to provide it as `make-process' argument when filter is
+           ;; t.  See Bug#51177.
+           (when filter
+             (set-process-filter p filter))
 
            (tramp-message v 6 "%s" (string-join (process-command p) " "))
            p))))))
@@ -4554,7 +4591,7 @@ of."
 
       ;; The end.
       (when (and (null noninteractive)
-                (or (eq visit t) (null visit) (stringp visit)))
+                (or (eq visit t) (string-or-null-p visit)))
        (tramp-message v 0 "Wrote %s" filename))
       (run-hooks 'tramp-handle-write-region-hook))))
 
@@ -4620,9 +4657,8 @@ of."
   (let ((user (or (tramp-file-name-user vec)
                  (with-tramp-connection-property vec "login-as"
                    (save-window-excursion
-                     (let ((enable-recursive-minibuffers t))
-                       (pop-to-buffer (tramp-get-connection-buffer vec))
-                       (read-string (match-string 0))))))))
+                     (pop-to-buffer (tramp-get-connection-buffer vec))
+                     (read-string (match-string 0)))))))
     (with-current-buffer (tramp-get-connection-buffer vec)
       (tramp-message vec 6 "\n%s" (buffer-string)))
     (tramp-message vec 3 "Sending login name `%s'" user)
@@ -4632,8 +4668,7 @@ of."
 (defun tramp-action-password (proc vec)
   "Query the user for a password."
   (with-current-buffer (process-buffer proc)
-    (let ((enable-recursive-minibuffers t)
-         (case-fold-search t))
+    (let ((case-fold-search t))
       ;; Let's check whether a wrong password has been sent already.
       ;; Sometimes, the process returns a new password request
       ;; immediately after rejecting the previous (wrong) one.
@@ -4664,14 +4699,13 @@ of."
 Send \"yes\" to remote process on confirmation, abort otherwise.
 See also `tramp-action-yn'."
   (save-window-excursion
-    (let ((enable-recursive-minibuffers t))
-      (pop-to-buffer (tramp-get-connection-buffer vec))
-      (unless (yes-or-no-p (match-string 0))
-       (kill-process proc)
-       (throw 'tramp-action 'permission-denied))
-      (with-current-buffer (tramp-get-connection-buffer vec)
-       (tramp-message vec 6 "\n%s" (buffer-string)))
-      (tramp-send-string vec (concat "yes" tramp-local-end-of-line))))
+    (pop-to-buffer (tramp-get-connection-buffer vec))
+    (unless (yes-or-no-p (match-string 0))
+      (kill-process proc)
+      (throw 'tramp-action 'permission-denied))
+    (with-current-buffer (tramp-get-connection-buffer vec)
+      (tramp-message vec 6 "\n%s" (buffer-string)))
+    (tramp-send-string vec (concat "yes" tramp-local-end-of-line)))
   t)
 
 (defun tramp-action-yn (proc vec)
@@ -4679,14 +4713,13 @@ See also `tramp-action-yn'."
 Send \"y\" to remote process on confirmation, abort otherwise.
 See also `tramp-action-yesno'."
   (save-window-excursion
-    (let ((enable-recursive-minibuffers t))
-      (pop-to-buffer (tramp-get-connection-buffer vec))
-      (unless (y-or-n-p (match-string 0))
-       (kill-process proc)
-       (throw 'tramp-action 'permission-denied))
-      (with-current-buffer (tramp-get-connection-buffer vec)
-       (tramp-message vec 6 "\n%s" (buffer-string)))
-      (tramp-send-string vec (concat "y" tramp-local-end-of-line))))
+    (pop-to-buffer (tramp-get-connection-buffer vec))
+    (unless (y-or-n-p (match-string 0))
+      (kill-process proc)
+      (throw 'tramp-action 'permission-denied))
+    (with-current-buffer (tramp-get-connection-buffer vec)
+      (tramp-message vec 6 "\n%s" (buffer-string)))
+    (tramp-send-string vec (concat "y" tramp-local-end-of-line)))
   t)
 
 (defun tramp-action-terminal (_proc vec)
@@ -4820,7 +4853,8 @@ performed successfully.  Any other value means an error."
   (save-restriction
     (with-tramp-progress-reporter
        proc 3 "Waiting for prompts from remote shell"
-      (let (exit)
+      (let ((enable-recursive-minibuffers t)
+           exit)
        (if timeout
            (with-timeout (timeout (setq exit 'timeout))
              (while (not exit)
@@ -5429,8 +5463,8 @@ this file, if that variable is non-nil."
     ;; Create directory.
     (unless (or (null tramp-auto-save-directory)
                (file-exists-p tramp-auto-save-directory))
-      (make-directory tramp-auto-save-directory t)
-      (set-file-modes tramp-auto-save-directory #o0700))
+      (with-file-modes #o0700
+        (make-directory tramp-auto-save-directory t)))
 
     (let ((system-type
           (if (and (stringp tramp-auto-save-directory)
diff --git a/lisp/obsolete/cc-compat.el b/lisp/obsolete/cc-compat.el
index 037a8e9e87..2c383d31c8 100644
--- a/lisp/obsolete/cc-compat.el
+++ b/lisp/obsolete/cc-compat.el
@@ -80,7 +80,7 @@ This is in addition to c-continued-statement-offset.")
 
 ;; these offsets are taken by brute force testing c-mode.el, since
 ;; there's no logic to what it does.
-(let* ((offsets        '(c-offsets-alist .
+(let* ((offsets        '((c-offsets-alist .
                    ((defun-block-intro     . cc-block-intro-offset)
                     (statement-block-intro . cc-block-intro-offset)
                     (defun-open            . 0)
@@ -95,7 +95,7 @@ This is in addition to c-continued-statement-offset.")
                     (case-label            . c-label-offset)
                     (access-label          . c-label-offset)
                     (label                 . c-label-offset)
-                    ))))
+                    )))))
   (c-add-style "BOCM" offsets))
 
 
diff --git a/lisp/obsolete/cl-compat.el b/lisp/obsolete/cl-compat.el
index 619bc06122..0dba366192 100644
--- a/lisp/obsolete/cl-compat.el
+++ b/lisp/obsolete/cl-compat.el
@@ -52,6 +52,7 @@
 ;;; Keyword routines not supported by new package.
 
 (defmacro defkeyword (x &optional doc)
+  (declare (indent defun))
   (cl-list* 'defconst x (list 'quote x) (and doc (list doc))))
 
 (defun keyword-of (sym)
diff --git a/lisp/obsolete/cl.el b/lisp/obsolete/cl.el
index 9df6231857..a892ed7c76 100644
--- a/lisp/obsolete/cl.el
+++ b/lisp/obsolete/cl.el
@@ -513,7 +513,8 @@ a temporary-variables list, a value-forms list, a 
store-variables list
 See `gv-define-expander', and `gv-define-setter' for better and
 simpler ways to define setf-methods."
   (declare (debug
-            (&define name cl-lambda-list cl-declarations-or-string def-body)))
+            (&define name cl-lambda-list cl-declarations-or-string def-body))
+           (indent defun))
   `(progn
      ,@(if (stringp (car body))
            (list `(put ',name 'setf-documentation ,(pop body))))
@@ -554,7 +555,8 @@ You can replace this form with `gv-define-setter'.
             (&define name
                      [&or [symbolp &optional stringp]
                           [cl-lambda-list (symbolp)]]
-                     cl-declarations-or-string def-body)))
+                     cl-declarations-or-string def-body))
+           (indent defun))
   (if (and (listp arg1) (consp args))
       ;; Like `gv-define-setter' but with `cl-function'.
       `(gv-define-expander ,name
@@ -615,7 +617,8 @@ arguments from ARGLIST using FUNC.  For example:
 You can replace this macro with `gv-letplace'."
   (declare (debug
             (&define name cl-lambda-list ;; should exclude &key
-                     symbolp &optional stringp)))
+                     symbolp &optional stringp))
+           (indent defun))
   (if (memq '&key arglist)
       (error "&key not allowed in define-modify-macro"))
   (require 'cl-macs)                    ;For cl--arglist-args.
diff --git a/lisp/obsolete/crisp.el b/lisp/obsolete/crisp.el
index 69bf3ed12b..ccf9aaa2b6 100644
--- a/lisp/obsolete/crisp.el
+++ b/lisp/obsolete/crisp.el
@@ -231,27 +231,13 @@ does not load the scroll-all package."
 
 ;; The cut and paste routines are different between XEmacs and Emacs
 ;; so we need to set up aliases for the functions.
-
-(defalias 'crisp-set-clipboard
-  (if (fboundp 'clipboard-kill-ring-save)
-      'clipboard-kill-ring-save
-    'copy-primary-selection))
-
-(defalias 'crisp-kill-region
-  (if (fboundp 'clipboard-kill-region)
-      'clipboard-kill-region
-    'kill-primary-selection))
-
-(defalias 'crisp-yank-clipboard
-  (if (fboundp 'clipboard-yank)
-      'clipboard-yank
-    'yank-clipboard-selection))
+(defalias 'crisp-set-clipboard 'clipboard-kill-ring-save)
+(defalias 'crisp-kill-region 'clipboard-kill-region)
+(defalias 'crisp-yank-clipboard 'clipboard-yank)
 
 (defun crisp-region-active ()
   "Compatibility function to test for an active region."
-  (if (featurep 'xemacs)
-      zmacs-region-active-p
-    mark-active))
+  mark-active)
 
 (defun crisp-version (&optional arg)
   "Version number of the CRiSP emulator package.
diff --git a/lisp/obsolete/cust-print.el b/lisp/obsolete/cust-print.el
index 01fcd38199..897b401588 100644
--- a/lisp/obsolete/cust-print.el
+++ b/lisp/obsolete/cust-print.el
@@ -643,11 +643,11 @@ See `custom-format' for the details."
 
    (let ((print-circle t))
      (or (equal (prin1-to-string circ-list) "#1=(a b [1 2 #1# 4] #1# e f)")
-        (error "circular object with array printing")))
+         (error "Circular object with array printing")))
 
    (let ((print-circle t))
      (or (equal (prin1-to-string dotted-circ-list) "#1=(a b c . #1#)")
-        (error "circular object with array printing")))
+         (error "Circular object with array printing")))
 
    (let* ((print-circle t)
          (x (list 'p 'q))
@@ -655,16 +655,16 @@ See `custom-format' for the details."
      (setcdr (cdr (cdr (cdr y))) (cdr y))
      (or (equal (prin1-to-string y) "((a b) . #1=(#2=(p q) foo #2# . #1#))"
                )
-        (error "circular list example from CL manual")))
+         (error "Circular list example from CL manual")))
 
    (let ((print-circle nil))
      ;; cl-packages.el is required to print uninterned symbols like #:FOO.
      ;; (require 'cl-packages)
      (or (equal (prin1-to-string circ-sym) "(#:FOO #:FOO)")
-        (error "uninterned symbols in list")))
+         (error "Uninterned symbols in list")))
    (let ((print-circle t))
      (or (equal (prin1-to-string circ-sym) "(#1=FOO #1#)")
-        (error "circular uninterned symbols in list")))
+         (error "Circular uninterned symbols in list")))
 
    (uninstall-custom-print)
    )
diff --git a/lisp/obsolete/eudcb-ph.el b/lisp/obsolete/eudcb-ph.el
index 187879ce2f..51a6780d90 100644
--- a/lisp/obsolete/eudcb-ph.el
+++ b/lisp/obsolete/eudcb-ph.el
@@ -176,9 +176,7 @@ SERVER is either a string naming the server or a list (NAME 
PORT)."
       (setq eudc-ph-process-buffer (get-buffer-create (format " *PH-%s*" 
host)))
       (with-current-buffer eudc-ph-process-buffer
        (erase-buffer)
-       (setq eudc-ph-read-point (point))
-       (and (featurep 'xemacs) (featurep 'mule)
-            (set-buffer-file-coding-system 'binary t)))
+        (setq eudc-ph-read-point (point)))
       (setq process (open-network-stream "ph" eudc-ph-process-buffer host 
port))
       (if (null process)
          (throw 'done nil))
diff --git a/lisp/obsolete/fast-lock.el b/lisp/obsolete/fast-lock.el
index 960233d562..1dee7120c0 100644
--- a/lisp/obsolete/fast-lock.el
+++ b/lisp/obsolete/fast-lock.el
@@ -283,10 +283,7 @@ If a number, only buffers greater than this size have 
processing messages."
                 (other :tag "always" t)
                 (integer :tag "size")))
 
-(defvar fast-lock-save-faces
-  (when (featurep 'xemacs)
-    ;; XEmacs uses extents for everything, so we have to pick the right ones.
-    font-lock-face-list)
+(defvar fast-lock-save-faces nil
   "Faces that will be saved in a Font Lock cache file.
 If nil, means information for all faces will be saved.")
 
@@ -707,35 +704,7 @@ See `fast-lock-get-face-properties'."
          (while regions
            (add-text-properties (nth 0 regions) (nth 1 regions) plist)
            (setq regions (nthcdr 2 regions))))))))
-
-;; Functions for XEmacs:
-
-(unless (boundp 'font-lock-syntactic-keywords)
-  (defvar font-lock-syntactic-keywords nil))
-
-(unless (boundp 'font-lock-inhibit-thing-lock)
-  (defvar font-lock-inhibit-thing-lock nil))
-
-(unless (fboundp 'font-lock-compile-keywords)
-  (defalias 'font-lock-compile-keywords #'identity))
-
-(unless (fboundp 'font-lock-eval-keywords)
-  (defun font-lock-eval-keywords (keywords)
-    (if (symbolp keywords)
-       (font-lock-eval-keywords (if (fboundp keywords)
-                                    (funcall keywords)
-                                  (eval keywords t)))
-      keywords)))
-
-(unless (fboundp 'font-lock-value-in-major-mode)
-  (defun font-lock-value-in-major-mode (alist)
-    (if (consp alist)
-       (cdr (or (assq major-mode alist) (assq t alist)))
-      alist)))
-
-(unless (fboundp 'current-message)
-  (defun current-message ()
-    ""))
+
 
 ;; Install ourselves:
 
diff --git a/lisp/obsolete/iswitchb.el b/lisp/obsolete/iswitchb.el
index a630baf354..807f5485d5 100644
--- a/lisp/obsolete/iswitchb.el
+++ b/lisp/obsolete/iswitchb.el
@@ -977,17 +977,7 @@ Return the modified list with the last element prepended 
to it."
          (set-buffer buf))
 
       (with-output-to-temp-buffer temp-buf
-       (if (featurep 'xemacs)
-
-           ;; XEmacs extents are put on by default, doesn't seem to be
-           ;; any way of switching them off.
-           (display-completion-list (or iswitchb-matches iswitchb-buflist)
-                                    :help-string "iswitchb "
-                                    :activate-callback
-                                    (lambda (_x _y _z)
-                                      (message "doesn't work yet, sorry!")))
-         ;; else running Emacs
-         (display-completion-list (or iswitchb-matches iswitchb-buflist))))
+        (display-completion-list (or iswitchb-matches iswitchb-buflist)))
       (setq iswitchb-common-match-inserted nil))))
 
 ;;; KILL CURRENT BUFFER
@@ -1326,9 +1316,7 @@ This is an example function which can be hooked on to
   "Return non-nil if we should ignore case when matching.
 See the variable `iswitchb-case' for details."
   (if iswitchb-case
-      (if (featurep 'xemacs)
-         (isearch-no-upper-case-p iswitchb-text)
-       (isearch-no-upper-case-p iswitchb-text t))))
+      (isearch-no-upper-case-p iswitchb-text t)))
 
 ;;;###autoload
 (define-minor-mode iswitchb-mode
diff --git a/lisp/obsolete/landmark.el b/lisp/obsolete/landmark.el
index cc4fd19c38..16c41c76ad 100644
--- a/lisp/obsolete/landmark.el
+++ b/lisp/obsolete/landmark.el
@@ -757,9 +757,9 @@ If the game is finished, this command requests for another 
game."
     (let ((square (landmark-point-square))
           score)
       (cond ((null square)
-            (error "Your point is not on a square. Retry!"))
+             (error "Your point is not on a square.  Retry!"))
            ((not (zerop (aref landmark-board square)))
-            (error "Your point is not on a free square. Retry!"))
+             (error "Your point is not on a free square.  Retry!"))
            (t
             (setq score (aref landmark-score-table square))
             (landmark-play-move square 1)
@@ -823,14 +823,14 @@ If the game is finished, this command requests for 
another game."
 (defun landmark-prompt-for-other-game ()
   "Ask for another game, and start it."
   (if (y-or-n-p "Another game? ")
-      (if (y-or-n-p "Retain learned weights ")
+      (if (y-or-n-p "Retain learned weights?")
          (landmark 2)
        (landmark 1))
     (message "Chicken!")))
 
 (defun landmark-offer-a-draw ()
   "Offer a draw and return t if Human accepted it."
-  (or (y-or-n-p "I offer you a draw. Do you accept it? ")
+  (or (y-or-n-p "I offer you a draw.  Do you accept it?")
       (not (setq landmark-human-refused-draw t))))
 
 
@@ -1470,7 +1470,7 @@ push him out of it."
   (mapc
    (lambda (direction) (put direction 'y_t 0))
    landmark-directions)
-  (dolist (direction (nth (random 8) landmark-8-directions))
+  (dolist (direction (seq-random-elt landmark-8-directions))
     (put direction 'y_t 1.0))
   (landmark-move))
 
@@ -1512,9 +1512,9 @@ If the game is finished, this command requests for 
another game."
    (t
     (let ((square (landmark-point-square)))
       (cond ((null square)
-            (error "Your point is not on a square. Retry!"))
+             (error "Your point is not on a square.  Retry!"))
            ((not (zerop (aref landmark-board square)))
-            (error "Your point is not on a free square. Retry!"))
+             (error "Your point is not on a free square.  Retry!"))
            (t
             (progn
               (landmark-plot-square square 1)
diff --git a/lisp/obsolete/otodo-mode.el b/lisp/obsolete/otodo-mode.el
index 47f5089452..a71d2b82e4 100644
--- a/lisp/obsolete/otodo-mode.el
+++ b/lisp/obsolete/otodo-mode.el
@@ -908,8 +908,7 @@ If INCLUDE-SEP is non-nil, return point after the 
separator."
 ;;;###autoload
 (define-derived-mode todo-mode nil "TODO"
   "Major mode for editing TODO lists."
-  (when (featurep 'xemacs)
-    (easy-menu-add todo-menu)))
+  nil)
 
 (with-suppressed-warnings ((lexical date entry))
   (defvar date)
diff --git a/lisp/obsolete/pgg-parse.el b/lisp/obsolete/pgg-parse.el
index 2c76365a41..3e4c216abe 100644
--- a/lisp/obsolete/pgg-parse.el
+++ b/lisp/obsolete/pgg-parse.el
@@ -496,8 +496,7 @@
 (defun pgg-parse-armor (string)
   (with-temp-buffer
     (buffer-disable-undo)
-    (unless (featurep 'xemacs)
-      (set-buffer-multibyte nil))
+    (set-buffer-multibyte nil)
     (insert string)
     (pgg-decode-armor-region (point-min)(point))))
 
diff --git a/lisp/obsolete/pgg.el b/lisp/obsolete/pgg.el
index 5ed59933f2..127e1dc15c 100644
--- a/lisp/obsolete/pgg.el
+++ b/lisp/obsolete/pgg.el
@@ -376,8 +376,7 @@ signer's public key from `pgg-default-keyserver-address'."
          (if (null signature) nil
            (with-temp-buffer
              (buffer-disable-undo)
-             (unless (featurep 'xemacs)
-               (set-buffer-multibyte nil))
+              (set-buffer-multibyte nil)
              (insert-file-contents signature)
              (cdr (assq 2 (pgg-decode-armor-region
                            (point-min)(point-max)))))))
diff --git a/lisp/obsolete/rcompile.el b/lisp/obsolete/rcompile.el
index ff7d1dcdce..c8fb9f2098 100644
--- a/lisp/obsolete/rcompile.el
+++ b/lisp/obsolete/rcompile.el
@@ -109,6 +109,9 @@ nil means run no commands."
 ;;;; entry point
 
 ;; We use the Tramp internal function `tramp-make-tramp-file-name'.
+;; It has changed its signature in Emacs 27.1, supporting still the
+;; old calling convention.  Let's assume rcompile.el has been removed
+;; once Tramp does not support it any longer.
 ;; Better would be, if there are functions to provide user, host and
 ;; localname of a remote filename, independent of Tramp's implementation.
 ;; The function calls are wrapped by `funcall' in order to pacify the byte
@@ -167,7 +170,8 @@ See \\[compile]."
     (with-current-buffer compilation-last-buffer
       (when (fboundp 'tramp-make-tramp-file-name)
        (set (make-local-variable 'comint-file-name-prefix)
-            (tramp-make-tramp-file-name
+            (funcall
+              #'tramp-make-tramp-file-name
              nil ;; method.
              remote-compile-user
              remote-compile-host
diff --git a/lisp/obsolete/tls.el b/lisp/obsolete/tls.el
index 5cba18d789..ff01008613 100644
--- a/lisp/obsolete/tls.el
+++ b/lisp/obsolete/tls.el
@@ -260,14 +260,14 @@ Fourth arg PORT is an integer specifying a port to 
connect to."
 NOT trusted." host))
                        (not (yes-or-no-p
                              (format-message "\
-The certificate presented by `%s' is NOT trusted. Accept anyway? " host)))))
+The certificate presented by `%s' is NOT trusted.  Accept anyway?" host)))))
                  (and tls-hostmismatch
                       (save-excursion
                         (goto-char (point-min))
                         (re-search-forward tls-hostmismatch nil t))
                       (not (yes-or-no-p
                             (format "Host name in certificate doesn't \
-match `%s'. Connect anyway? " host))))))
+match `%s'.  Connect anyway?" host))))))
        (setq done nil)
        (delete-process process))
       ;; Delete all the informational messages that could confuse
diff --git a/lisp/obsolete/tpu-edt.el b/lisp/obsolete/tpu-edt.el
index e0e89c390e..b59fb8c868 100644
--- a/lisp/obsolete/tpu-edt.el
+++ b/lisp/obsolete/tpu-edt.el
@@ -650,12 +650,8 @@ GOLD is the ASCII 7-bit escape sequence <ESC>OP.")
   (setq tpu-mark-flag (if transient-mark-mode "" (if (tpu-mark) " @" "  ")))
   (force-mode-line-update))
 
-(cond ((featurep 'xemacs)
-       (add-hook 'zmacs-deactivate-region-hook 'tpu-update-mode-line)
-       (add-hook 'zmacs-activate-region-hook 'tpu-update-mode-line))
-      (t
-       (add-hook 'activate-mark-hook 'tpu-update-mode-line)
-       (add-hook 'deactivate-mark-hook 'tpu-update-mode-line)))
+(add-hook 'activate-mark-hook 'tpu-update-mode-line)
+(add-hook 'deactivate-mark-hook 'tpu-update-mode-line)
 
 
 ;;;
@@ -727,15 +723,13 @@ Otherwise sets the tpu-match markers to nil and returns 
nil."
   "TPU-edt version of the mark function.
 Return the appropriate value of the mark for the current
 version of Emacs."
-  (cond ((featurep 'xemacs) (mark (not zmacs-regions)))
-       (t (and mark-active (mark (not transient-mark-mode))))))
+  (and mark-active (mark (not transient-mark-mode))))
 
 (defun tpu-set-mark (pos)
   "TPU-edt version of the `set-mark' function.
 Sets the mark at POS and activates the region according to the
 current version of Emacs."
-  (set-mark pos)
-  (when (featurep 'xemacs) (when pos (zmacs-activate-region))))
+  (set-mark pos))
 
 (defun tpu-string-prompt (prompt history-symbol)
   "Read a string with PROMPT."
@@ -2306,17 +2300,14 @@ Accepts a prefix argument for the number of 
tpu-pan-columns to scroll."
 ;;;
 (defun tpu-load-xkeys (file)
   "Load the TPU-edt X-windows key definitions FILE.
-If FILE is nil, try to load a default file.  The default file names are
-`~/.tpu-lucid-keys' for XEmacs, and `~/.tpu-keys' for Emacs."
+If FILE is nil, try to load a default file.  The default file name is
+`~/.tpu-keys'."
   (interactive "fX key definition file: ")
   (cond (file
         (setq file (expand-file-name file)))
        (tpu-xkeys-file
         (setq file (expand-file-name tpu-xkeys-file)))
-       ((featurep 'xemacs)
-        (setq file (convert-standard-filename
-                    (expand-file-name "~/.tpu-lucid-keys"))))
-       (t
+        (t
         (setq file (convert-standard-filename
                     (expand-file-name "~/.tpu-keys")))
         (and (not (file-exists-p file))
diff --git a/lisp/obsolete/tpu-mapper.el b/lisp/obsolete/tpu-mapper.el
index 5ae0a6558d..02ba363250 100644
--- a/lisp/obsolete/tpu-mapper.el
+++ b/lisp/obsolete/tpu-mapper.el
@@ -46,24 +46,14 @@
 ;;;
 (defun tpu-map-key (ident descrip func gold-func)
   (interactive)
-  (if (featurep 'xemacs)
-      (progn
-       (setq tpu-key-seq (read-key-sequence
-                           (format "Press %s%s: " ident descrip))
-              tpu-key (format "[%s]" (event-key (aref tpu-key-seq 0))))
-       (unless (equal tpu-key tpu-return)
-          (set-buffer "Keys")
-          (insert (format"(global-set-key %s %s)\n" tpu-key func))
-          (set-buffer "Gold-Keys")
-          (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key 
gold-func))))
-    (message "Press %s%s: " ident descrip)
-    (setq tpu-key-seq (read-event)
-          tpu-key (format "[%s]" tpu-key-seq))
-    (unless (equal tpu-key tpu-return)
-      (set-buffer "Keys")
-      (insert (format"(define-key tpu-global-map %s %s)\n" tpu-key func))
-      (set-buffer "Gold-Keys")
-      (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key gold-func))))
+  (message "Press %s%s: " ident descrip)
+  (setq tpu-key-seq (read-event)
+        tpu-key (format "[%s]" tpu-key-seq))
+  (unless (equal tpu-key tpu-return)
+    (set-buffer "Keys")
+    (insert (format"(define-key tpu-global-map %s %s)\n" tpu-key func))
+    (set-buffer "Gold-Keys")
+    (insert (format "(define-key tpu-gold-map %s %s)\n" tpu-key gold-func)))
   (set-buffer "Directions")
   tpu-key)
 
@@ -103,8 +93,7 @@ your local X guru can try to figure out why the key is being 
ignored."
 
   ;; Make sure the window is big enough to display the instructions
 
-  (if (featurep 'xemacs) (set-screen-size (selected-screen) 80 36)
-    (set-frame-size (selected-frame) 80 36))
+  (set-frame-size (selected-frame) 80 36)
 
   ;; Create buffers - Directions, Keys, Gold-Keys
 
@@ -162,14 +151,9 @@ your local X guru can try to figure out why the key is 
being ignored."
 
   ;; Save <CR> for future reference
 
-  (cond
-   ((featurep 'xemacs)
-    (setq tpu-return-seq (read-key-sequence "Hit carriage-return <CR> to 
continue "))
-    (setq tpu-return (concat "[" (format "%s" (event-key (aref tpu-return-seq 
0))) "]")))
-   (t
-    (message "Hit carriage-return <CR> to continue ")
-    (setq tpu-return-seq (read-event))
-    (setq tpu-return (concat "[" (format "%s" tpu-return-seq) "]"))))
+  (message "Hit carriage-return <CR> to continue ")
+  (setq tpu-return-seq (read-event))
+  (setq tpu-return (concat "[" (format "%s" tpu-return-seq) "]"))
 
   ;; Build the keymap file
 
@@ -308,24 +292,14 @@ your local X guru can try to figure out why the key is 
being ignored."
 ;;
 ")
 
-  (cond ((featurep 'xemacs)
-        (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter-seq))
-        (insert (format "(setq tpu-help-return \"%s\")\n" tpu-return-seq))
-        (insert "(setq tpu-help-N \"[#<keypress-event N>]\")\n")
-        (insert "(setq tpu-help-n \"[#<keypress-event n>]\")\n")
-        (insert "(setq tpu-help-P \"[#<keypress-event P>]\")\n")
-        (insert "(setq tpu-help-p \"[#<keypress-event p>]\")\n"))
-       (t
-        (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter))))
+  (insert (format "(setq tpu-help-enter \"%s\")\n" tpu-enter))
 
   (append-to-buffer "Keys" 1 (point))
   (set-buffer "Keys")
 
   ;; Save the key mapping program
 
-  (let ((file
-        (convert-standard-filename
-         (if (featurep 'xemacs) "~/.tpu-lucid-keys" "~/.tpu-keys"))))
+  (let ((file (convert-standard-filename "~/.tpu-keys")))
     (set-visited-file-name
      (read-file-name (format "Save key mapping to file (default %s): " file) 
"" file)))
   (save-buffer)
diff --git a/lisp/obsolete/vip.el b/lisp/obsolete/vip.el
index 16906b68a6..2fa8c95153 100644
--- a/lisp/obsolete/vip.el
+++ b/lisp/obsolete/vip.el
@@ -615,11 +615,11 @@ obtained so far, and COM is the command part obtained so 
far."
        (cond ((null arg) nil)
             ((consp arg) (car arg))
             ((numberp arg) arg)
-            (t (error "strange arg")))
+             (t (error "Strange arg")))
        (cond ((null arg) nil)
             ((consp arg) (cdr arg))
             ((numberp arg) nil)
-            (t (error "strange arg"))))
+             (t (error "Strange arg"))))
     (quit
      (setq vip-use-register nil)
      (signal 'quit nil))))
@@ -2248,7 +2248,7 @@ a token has type \(command, address, end-mark) and value."
           (setq ex-token-type "end-mark")
           (setq ex-token "goto"))
          (t
-          (error "invalid token")))))
+           (error "Invalid token")))))
 
 (defun vip-ex (&optional string)
   "ex commands within VIP."
@@ -2333,7 +2333,7 @@ a token has type \(command, address, end-mark) and value."
     (cond ((looking-at "[a-z]")
           (vip-get-ex-com-subr)
           (if (string= ex-token-type "non-command")
-              (error "%s: not an editor command" ex-token)))
+               (error "%s: Not an editor command" ex-token)))
          ((looking-at "[!=><&~]")
           (setq ex-token (char-to-string (following-char)))
           (forward-char 1))
@@ -2378,7 +2378,7 @@ a token has type \(command, address, end-mark) and value."
                 (progn
                   (setq ex-flag t)
                   (setq cont nil))
-            (error "address expected")))
+             (error "Address expected")))
            ((string= ex-token-type "end-mark")
             (setq cont nil))
            ((string= ex-token-type "whole")
@@ -2568,7 +2568,7 @@ a token has type \(command, address, end-mark) and value."
             (string= ex-token "insert")
             (string= ex-token "open")
             )
-        (error "%s: no such command from VIP" ex-token))
+         (error "%s: No such command from VIP" ex-token))
        ((or (string= ex-token "abbreviate")
             (string= ex-token "list")
             (string= ex-token "next")
@@ -2581,7 +2581,7 @@ a token has type \(command, address, end-mark) and value."
             (string= ex-token "xit")
             (string= ex-token "z")
             )
-        (error "%s: not implemented in VIP" ex-token))
+         (error "%s: Not implemented in VIP" ex-token))
        (t (error "%s: Not an editor command" ex-token))))
 
 (defun ex-goto ()
diff --git a/lisp/org/ob-C.el b/lisp/org/ob-C.el
index 6e33901793..842e0d3e8e 100644
--- a/lisp/org/ob-C.el
+++ b/lisp/org/ob-C.el
@@ -4,6 +4,7 @@
 
 ;; Author: Eric Schulte
 ;;      Thierry Banel
+;; Maintainer: Thierry Banel
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -94,8 +95,7 @@ This function calls `org-babel-execute:C++'."
   (org-babel-execute:C++ body params))
 
 (defun org-babel-expand-body:cpp (body params)
-  "Expand a block of C++ code with org-babel according to its
-header arguments."
+  "Expand a block of C++ code with org-babel according to its header 
arguments."
   (org-babel-expand-body:C++ body params))
 
 (defun org-babel-execute:C++ (body params)
@@ -104,8 +104,7 @@ This function is called by `org-babel-execute-src-block'."
   (let ((org-babel-c-variant 'cpp)) (org-babel-C-execute body params)))
 
 (defun org-babel-expand-body:C++ (body params)
-  "Expand a block of C++ code with org-babel according to its
-header arguments."
+  "Expand a block of C++ code with org-babel according to its header 
arguments."
   (let ((org-babel-c-variant 'cpp)) (org-babel-C-expand-C++ body params)))
 
 (defun org-babel-execute:D (body params)
@@ -114,8 +113,7 @@ This function is called by `org-babel-execute-src-block'."
   (let ((org-babel-c-variant 'd)) (org-babel-C-execute body params)))
 
 (defun org-babel-expand-body:D (body params)
-  "Expand a block of D code with org-babel according to its
-header arguments."
+  "Expand a block of D code with org-babel according to its header arguments."
   (let ((org-babel-c-variant 'd)) (org-babel-C-expand-D body params)))
 
 (defun org-babel-execute:C (body params)
@@ -124,8 +122,7 @@ This function is called by `org-babel-execute-src-block'."
   (let ((org-babel-c-variant 'c)) (org-babel-C-execute body params)))
 
 (defun org-babel-expand-body:C (body params)
-  "Expand a block of C code with org-babel according to its
-header arguments."
+  "Expand a block of C code with org-babel according to its header arguments."
   (let ((org-babel-c-variant 'c)) (org-babel-C-expand-C body params)))
 
 (defun org-babel-C-execute (body params)
@@ -196,13 +193,11 @@ or `org-babel-execute:C++' or `org-babel-execute:D'."
       )))
 
 (defun org-babel-C-expand-C++ (body params)
-  "Expand a block of C or C++ code with org-babel according to
-its header arguments."
+  "Expand a block of C/C++ code with org-babel according to its header 
arguments."
   (org-babel-C-expand-C body params))
 
 (defun org-babel-C-expand-C (body params)
-  "Expand a block of C or C++ code with org-babel according to
-its header arguments."
+  "Expand a block of C/C++ code with org-babel according to its header 
arguments."
   (let ((vars (org-babel--get-vars params))
        (colnames (cdr (assq :colname-names params)))
        (main-p (not (string= (cdr (assq :main params)) "no")))
@@ -257,15 +252,21 @@ its header arguments."
                (when colnames
                  (org-babel-C-utility-header-to-C))
                ;; tables headers
-               (mapconcat 'org-babel-C-header-to-C colnames "\n")
+               (mapconcat (lambda (head)
+                             (let* ((tblnm (car head))
+                                    (tbl (cdr (car (let* ((el vars))
+                                                     (while (not (or (equal 
tblnm (caar el)) (not el)))
+                                                       (setq el (cdr el)))
+                                                     el))))
+                                    (type (org-babel-C-val-to-base-type tbl)))
+                               (org-babel-C-header-to-C head type))) colnames 
"\n")
                ;; body
                (if main-p
                    (org-babel-C-ensure-main-wrap body)
                  body) "\n") "\n")))
 
 (defun org-babel-C-expand-D (body params)
-  "Expand a block of D code with org-babel according to
-its header arguments."
+  "Expand a block of D code with org-babel according to its header arguments."
   (let ((vars (org-babel--get-vars params))
        (colnames (cdr (assq :colname-names params)))
        (main-p (not (string= (cdr (assq :main params)) "no")))
@@ -289,7 +290,14 @@ its header arguments."
                (when colnames
                  (org-babel-C-utility-header-to-C))
                ;; tables headers
-               (mapconcat 'org-babel-C-header-to-C colnames "\n")
+               (mapconcat (lambda (head)
+                             (let* ((tblnm (car head))
+                                    (tbl (cdr (car (let* ((el vars))
+                                                     (while (not (or (equal 
tblnm (caar el)) (not el)))
+                                                       (setq el (cdr el)))
+                                                     el))))
+                                    (type (org-babel-C-val-to-base-type tbl)))
+                               (org-babel-C-header-to-C head type))) colnames 
"\n")
                ;; body
                (if main-p
                    (org-babel-C-ensure-main-wrap body)
@@ -333,7 +341,7 @@ FORMAT can be either a format string or a function which is 
called with VAL."
             (list
              (if (eq org-babel-c-variant 'd) "string" "const char*")
              "\"%s\""))
-           (_ (error "unknown type %S" basetype)))))
+            (_ (error "Unknown type %S" basetype)))))
     (cond
      ((integerp val) type) ;; an integer declared in the #+begin_src line
      ((floatp val) type) ;; a numeric declared in the #+begin_src line
@@ -341,7 +349,9 @@ FORMAT can be either a format string or a function which is 
called with VAL."
       `(,(car type)
        (lambda (val)
          (cons
-          (format "[%d][%d]" (length val) (length (car val)))
+           (pcase org-babel-c-variant
+             ((or `c `cpp) (format "[%d][%d]" (length val) (length (car val))))
+             (`d           (format "[%d][%d]" (length (car val)) (length 
val))))
           (concat
            (if (eq org-babel-c-variant 'd) "[\n" "{\n")
            (mapconcat
@@ -388,8 +398,7 @@ FORMAT can be either a format string or a function which is 
called with VAL."
    (t 'stringp)))
 
 (defun org-babel-C-var-to-C (pair)
-  "Convert an elisp val into a string of C code specifying a var
-of the same value."
+  "Convert an elisp val into a string of C code specifying a var of the same 
value."
   ;; TODO list support
   (let ((var (car pair))
        (val (cdr pair)))
@@ -402,11 +411,19 @@ of the same value."
           (formatted (org-babel-C-format-val type-data val))
           (suffix (car formatted))
           (data (cdr formatted)))
-      (format "%s %s%s = %s;"
-             type
-             var
-             suffix
-             data))))
+      (pcase org-babel-c-variant
+        ((or `c `cpp)
+         (format "%s %s%s = %s;"
+                type
+                var
+                suffix
+                data))
+        (`d
+         (format "%s%s %s = %s;"
+                type
+                suffix
+                var
+                data))))))
 
 (defun org-babel-C-table-sizes-to-C (pair)
   "Create constants of table dimensions, if PAIR is a table."
@@ -421,11 +438,15 @@ of the same value."
       (format "const int %s_cols = %d;" (car pair) (length (cdr pair)))))))
 
 (defun org-babel-C-utility-header-to-C ()
-  "Generate a utility function to convert a column name
-into a column number."
+  "Generate a utility function to convert a column name into a column number."
   (pcase org-babel-c-variant
     ((or `c `cpp)
-     "int get_column_num (int nbcols, const char** header, const char* column)
+     (concat
+      "
+#ifndef _STRING_H
+#include <string.h>
+#endif
+int get_column_num (int nbcols, const char** header, const char* column)
 {
   int c;
   for (c=0; c<nbcols; c++)
@@ -433,7 +454,7 @@ into a column number."
       return c;
   return -1;
 }
-")
+"))
     (`d
      "int get_column_num (string[] header, string column)
 {
@@ -444,29 +465,40 @@ into a column number."
 }
 ")))
 
-(defun org-babel-C-header-to-C (head)
+(defun org-babel-C-header-to-C (head type)
   "Convert an elisp list of header table into a C or D vector
 specifying a variable with the name of the table."
+  (message "%S" type)
   (let ((table (car head))
-        (headers (cdr head)))
+        (headers (cdr head))
+        (typename (pcase type
+                    (`integerp "int")
+                    (`floatp "double")
+                    (`stringp (pcase org-babel-c-variant
+                                ((or `c `cpp) "const char*")
+                                (`d "string"))))))
     (concat
-     (format
-      (pcase org-babel-c-variant
-       ((or `c `cpp) "const char* %s_header[%d] = {%s};")
-       (`d "string %s_header[%d] = [%s];"))
-      table
-      (length headers)
-      (mapconcat (lambda (h) (format "%S" h)) headers ","))
+     (pcase org-babel-c-variant
+       ((or `c `cpp)
+        (format "const char* %s_header[%d] = {%s};"
+                table
+                (length headers)
+                (mapconcat (lambda (h) (format "\"%s\"" h)) headers ",")))
+       (`d
+        (format "string[%d] %s_header = [%s];"
+                (length headers)
+                table
+                (mapconcat (lambda (h) (format "\"%s\"" h)) headers ","))))
      "\n"
      (pcase org-babel-c-variant
        ((or `c `cpp)
        (format
-        "const char* %s_h (int row, const char* col) { return 
%s[row][get_column_num(%d,%s_header,col)]; }"
-        table table (length headers) table))
+        "%s %s_h (int row, const char* col) { return 
%s[row][get_column_num(%d,%s_header,col)]; }"
+        typename table table (length headers) table))
        (`d
        (format
-        "string %s_h (size_t row, string col) { return 
%s[row][get_column_num(%s_header,col)]; }"
-        table table table))))))
+        "%s %s_h (size_t row, string col) { return 
%s[row][get_column_num(%s_header,col)]; }"
+         typename table table table))))))
 
 (provide 'ob-C)
 
diff --git a/lisp/org/ob-J.el b/lisp/org/ob-J.el
deleted file mode 100644
index 0c5591d5b7..0000000000
--- a/lisp/org/ob-J.el
+++ /dev/null
@@ -1,189 +0,0 @@
-;;; ob-J.el --- Babel Functions for J                -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
-
-;; Author: Oleh Krehel
-;; Maintainer: Joseph Novakovich <josephnovakovich@gmail.com>
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Org-Babel support for evaluating J code.
-;;
-;; Session interaction depends on `j-console' from package `j-mode'
-;; (available in MELPA).
-
-;;; Code:
-
-(require 'ob)
-(require 'org-macs)
-
-(declare-function j-console-ensure-session "ext:j-console" ())
-
-(defcustom org-babel-J-command "jconsole"
-  "Command to call J."
-  :group 'org-babel
-  :version "26.1"
-  :package-version '(Org . "9.0")
-  :type 'string)
-
-(defun org-babel-expand-body:J (body _params &optional _processed-params)
-  "Expand BODY according to PARAMS, return the expanded body.
-PROCESSED-PARAMS isn't used yet."
-  (org-babel-J-interleave-echos-except-functions body))
-
-(defun org-babel-J-interleave-echos (body)
-  "Interleave echo',' between each source line of BODY."
-  (mapconcat #'identity (split-string body "\n") "\necho','\n"))
-
-(defun org-babel-J-interleave-echos-except-functions (body)
-  "Interleave echo',' between source lines of BODY that aren't functions."
-  (if (obj-string-match-m 
"\\(?:^\\|\n\\)[^\n]*\\(?:0\\|1\\|2\\|3\\|4\\|dyad\\) : 0\n.*\n)\\(?:\n\\|$\\)" 
body)
-      (let ((s1 (substring body 0 (match-beginning 0)))
-           (s2 (match-string 0 body))
-           (s3 (substring body (match-end 0))))
-       (concat
-        (if (string= s1 "")
-            ""
-          (concat (org-babel-J-interleave-echos s1)
-                  "\necho','\n"))
-        s2
-        "\necho','\n"
-        (org-babel-J-interleave-echos-except-functions s3)))
-    (org-babel-J-interleave-echos body)))
-
-(defalias 'org-babel-execute:j 'org-babel-execute:J)
-
-(defun org-babel-execute:J (body params)
-  "Execute a block of J code BODY.
-PARAMS are given by org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (message "executing J source code block")
-  (let* ((processed-params (org-babel-process-params params))
-        (sessionp (cdr (assq :session params)))
-        (sit-time (let ((sit (assq :sit params)))
-                    (if sit (cdr sit) .1)))
-         (full-body (org-babel-expand-body:J
-                     body params processed-params))
-        (tmp-script-file (org-babel-temp-file "J-src")))
-    (org-babel-j-initiate-session sessionp)
-    (org-babel-J-strip-whitespace
-     (if (string= sessionp "none")
-        (progn
-          (with-temp-file tmp-script-file
-            (insert full-body))
-          (org-babel-eval (format "%s < %s" org-babel-J-command 
tmp-script-file) ""))
-       (org-babel-J-eval-string full-body sit-time)))))
-
-(defun org-babel-J-eval-string (str sit-time)
-  "Sends STR to the `j-console-cmd' session and executes it."
-  (let ((session (j-console-ensure-session)))
-    (with-current-buffer (process-buffer session)
-      (goto-char (point-max))
-      (insert (format "\n%s\n" str))
-      (let ((beg (point)))
-       (comint-send-input)
-       (sit-for sit-time)
-       (buffer-substring-no-properties
-        beg (point-max))))))
-
-(defun org-babel-J-strip-whitespace (str)
-  "Remove whitespace from jconsole output STR."
-  (mapconcat
-   #'identity
-   (delete "" (mapcar
-              #'org-babel-J-print-block
-              (split-string str "^ *,\n" t)))
-   "\n\n"))
-
-(defun obj-get-string-alignment (str)
-  "Return a number to describe STR alignment.
-STR represents a table.
-Positive/negative/zero result means right/left/undetermined.
-Don't trust first line."
-  (let* ((str (org-trim str))
-        (lines (split-string str "\n" t))
-        n1 n2)
-    (cond ((<= (length lines) 1)
-          0)
-         ((= (length lines) 2)
-          ;; numbers are right-aligned
-          (if (and
-               (numberp (read (car lines)))
-               (numberp (read (cadr lines)))
-               (setq n1 (obj-match-second-space-right (nth 0 lines)))
-               (setq n2 (obj-match-second-space-right (nth 1 lines))))
-              n2
-            0))
-         ((not (obj-match-second-space-left (nth 0 lines)))
-          0)
-         ((and
-           (setq n1 (obj-match-second-space-left (nth 1 lines)))
-           (setq n2 (obj-match-second-space-left (nth 2 lines)))
-           (= n1 n2))
-          n1)
-         ((and
-           (setq n1 (obj-match-second-space-right (nth 1 lines)))
-           (setq n2 (obj-match-second-space-right (nth 2 lines)))
-           (= n1 n2))
-          (- n1))
-         (t 0))))
-
-(defun org-babel-J-print-block (x)
-  "Prettify jconsole output X."
-  (let* ((x (org-trim x))
-        (a (obj-get-string-alignment x))
-        (lines (split-string x "\n" t))
-        b)
-    (cond ((< a 0)
-          (setq b (obj-match-second-space-right (nth 0 lines)))
-          (concat (make-string (+ a b) ? ) x))
-         ((> a 0)
-          (setq b (obj-match-second-space-left (nth 0 lines)))
-          (concat (make-string (- a b) ? ) x))
-         (t x))))
-
-(defun obj-match-second-space-left (s)
-  "Return position of leftmost space in second space block of S or nil."
-  (and (string-match "^ *[^ ]+\\( \\)" s)
-       (match-beginning 1)))
-
-(defun obj-match-second-space-right (s)
-  "Return position of rightmost space in second space block of S or nil."
-  (and (string-match "^ *[^ ]+ *\\( \\)[^ ]" s)
-       (match-beginning 1)))
-
-(defun obj-string-match-m (regexp string &optional start)
-  "Call (string-match REGEXP STRING START).
-REGEXP is modified so that .* matches newlines as well."
-  (string-match
-   (replace-regexp-in-string "\\.\\*" "[\0-\377[:nonascii:]]*" regexp)
-   string
-   start))
-
-(defun org-babel-j-initiate-session (&optional session)
-  "Initiate a J session.
-SESSION is a parameter given by org-babel."
-  (unless (string= session "none")
-    (require 'j-console)
-    (j-console-ensure-session)))
-
-(provide 'ob-J)
-
-;;; ob-J.el ends here
diff --git a/lisp/org/ob-R.el b/lisp/org/ob-R.el
index 309a0acf7e..169e1d6d6c 100644
--- a/lisp/org/ob-R.el
+++ b/lisp/org/ob-R.el
@@ -4,6 +4,7 @@
 
 ;; Author: Eric Schulte
 ;;     Dan Davison
+;; Maintainer: Jeremie Juste
 ;; Keywords: literate programming, reproducible research, R, statistics
 ;; Homepage: https://orgmode.org
 
@@ -39,6 +40,13 @@
 (declare-function ess-wait-for-process "ext:ess-inf"
                  (&optional proc sec-prompt wait force-redisplay))
 
+;; FIXME: Temporary declaration to silence the byte-compiler
+(defvar user-inject-src-param)
+(defvar ess-eval-visibly-tmp)
+(defvar ess-eval-visibly)
+(defvar ess-inject-source)
+(defvar user-inject-src-param)
+
 (defconst org-babel-header-args:R
   '((width              . :any)
     (height             . :any)
@@ -157,6 +165,7 @@ This function is called by `org-babel-execute-src-block'."
   (save-excursion
     (let* ((result-params (cdr (assq :result-params params)))
           (result-type (cdr (assq :result-type params)))
+           (async (org-babel-comint-use-async params))
            (session (org-babel-R-initiate-session
                     (cdr (assq :session params)) params))
           (graphics-file (and (member "graphics" (assq :result-params params))
@@ -183,7 +192,8 @@ This function is called by `org-babel-execute-src-block'."
                  (cdr (assq :colname-names params)) colnames-p))
             (or (equal "yes" rownames-p)
                 (org-babel-pick-name
-                 (cdr (assq :rowname-names params)) rownames-p)))))
+                 (cdr (assq :rowname-names params)) rownames-p))
+             async)))
       (if graphics-file nil result))))
 
 (defun org-babel-prep-session:R (session params)
@@ -321,7 +331,7 @@ Each member of this list is a list with three members:
         (device-info (or (assq (intern (concat ":" device))
                                org-babel-R-graphics-devices)
                           (assq :png org-babel-R-graphics-devices)))
-        (extra-args (cdr (assq :R-dev-args params))) filearg args)
+         (extra-args (cdr (assq :R-dev-args params))) filearg args)
     (setq device (nth 1 device-info))
     (setq filearg (nth 2 device-info))
     (setq args (mapconcat
@@ -348,7 +358,7 @@ Each member of this list is a list with three members:
                         {
                             tfile<-tempfile()
                             write.table(object, file=tfile, sep=\"\\t\",
-                                        na=\"nil\",row.names=%s,col.names=%s,
+                                        na=\"\",row.names=%s,col.names=%s,
                                         quote=FALSE)
                             file.rename(tfile,transfer.file)
                         },
@@ -370,11 +380,14 @@ Has four %s escapes to be filled in:
 4. The name of the file to write to")
 
 (defun org-babel-R-evaluate
-  (session body result-type result-params column-names-p row-names-p)
+    (session body result-type result-params column-names-p row-names-p async)
   "Evaluate R code in BODY."
   (if session
-      (org-babel-R-evaluate-session
-       session body result-type result-params column-names-p row-names-p)
+      (if async
+          (ob-session-async-org-babel-R-evaluate-session
+           session body result-type result-params column-names-p row-names-p)
+        (org-babel-R-evaluate-session
+         session body result-type result-params column-names-p row-names-p))
     (org-babel-R-evaluate-external-process
      body result-type result-params column-names-p row-names-p)))
 
@@ -450,11 +463,13 @@ last statement in BODY, as elisp."
                      (car (split-string line "\n")))
                     (substring line (match-end 1))
                   line))
-              (org-babel-comint-with-output (session org-babel-R-eoe-output)
-                (insert (mapconcat 'org-babel-chomp
-                                   (list body org-babel-R-eoe-indicator)
-                                   "\n"))
-                (inferior-ess-send-input)))))) "\n"))))
+              (with-current-buffer session
+                (let ((comint-prompt-regexp (concat "^" comint-prompt-regexp)))
+                  (org-babel-comint-with-output (session 
org-babel-R-eoe-output)
+                    (insert (mapconcat 'org-babel-chomp
+                                       (list body org-babel-R-eoe-indicator)
+                                       "\n"))
+                    (inferior-ess-send-input)))))))) "\n"))))
 
 (defun org-babel-R-process-value-result (result column-names-p)
   "R-specific processing of return value.
@@ -465,6 +480,91 @@ Insert hline if column names in output have been 
requested."
        (error "Could not parse R result"))
     result))
 
+
+;;; async evaluation
+
+(defconst ob-session-async-R-indicator "'ob_comint_async_R_%s_%s'")
+
+(defun ob-session-async-org-babel-R-evaluate-session
+    (session body result-type _ column-names-p row-names-p)
+  "Asynchronously evaluate BODY in SESSION.
+Returns a placeholder string for insertion, to later be replaced
+by `org-babel-comint-async-filter'."
+  (org-babel-comint-async-register
+   session (current-buffer)
+   "^\\(?:[>.+] \\)*\\[1\\] \"ob_comint_async_R_\\(.+?\\)_\\(.+\\)\"$"
+   'org-babel-chomp
+   'ob-session-async-R-value-callback)
+  (cl-case result-type
+    (value
+     (let ((tmp-file (org-babel-temp-file "R-")))
+       (with-temp-buffer
+         (insert
+          (org-babel-chomp body))
+         (let ((ess-local-process-name
+                (process-name (get-buffer-process session))))
+           (ess-eval-buffer nil)))
+       (with-temp-buffer
+        (insert
+         (mapconcat
+           'org-babel-chomp
+           (list (format org-babel-R-write-object-command
+                         (if row-names-p "TRUE" "FALSE")
+                         (if column-names-p
+                             (if row-names-p "NA" "TRUE")
+                           "FALSE")
+                         ".Last.value"
+                         (org-babel-process-file-name tmp-file 'noquote))
+                 (format ob-session-async-R-indicator
+                         "file" tmp-file))
+           "\n"))
+        (let ((ess-local-process-name
+               (process-name (get-buffer-process session))))
+          (ess-eval-buffer nil)))
+       tmp-file))
+    (output
+     (let ((uuid (md5 (number-to-string (random 100000000))))
+           (ess-local-process-name
+            (process-name (get-buffer-process session))))
+       (with-temp-buffer
+         (insert (format ob-session-async-R-indicator
+                        "start" uuid))
+         (insert "\n")
+         (insert body)
+         (insert "\n")
+         (insert (format ob-session-async-R-indicator
+                        "end" uuid))
+         (setq ess-eval-visibly-tmp ess-eval-visibly)
+         (setq user-inject-src-param ess-inject-source)
+         (setq ess-eval-visibly nil)
+         (setq ess-inject-source 'function-and-buffer)
+         (ess-eval-buffer nil))
+       (setq ess-eval-visibly ess-eval-visibly-tmp)
+       (setq ess-inject-source user-inject-src-param)
+       uuid))))
+
+(defun ob-session-async-R-value-callback (params tmp-file)
+  "Callback for async value results.
+Assigned locally to `ob-session-async-file-callback' in R
+comint buffers used for asynchronous Babel evaluation."
+  (let* ((graphics-file (and (member "graphics" (assq :result-params params))
+                            (org-babel-graphical-output-file params)))
+        (colnames-p (unless graphics-file (cdr (assq :colnames params)))))
+    (org-babel-R-process-value-result
+     (org-babel-result-cond (assq :result-params params)
+       (with-temp-buffer
+         (insert-file-contents tmp-file)
+         (org-babel-chomp (buffer-string) "\n"))
+       (org-babel-import-elisp-from-file tmp-file '(16)))
+     (or (equal "yes" colnames-p)
+        (org-babel-pick-name
+         (cdr (assq :colname-names params)) colnames-p)))))
+
+
+
+;;; ob-session-async-R.el ends here
+
+
 (provide 'ob-R)
 
 ;;; ob-R.el ends here
diff --git a/lisp/org/ob-abc.el b/lisp/org/ob-abc.el
deleted file mode 100644
index 404e39fc27..0000000000
--- a/lisp/org/ob-abc.el
+++ /dev/null
@@ -1,90 +0,0 @@
-;;; ob-abc.el --- Org Babel Functions for ABC -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
-
-;; Author: William Waites
-;; Keywords: literate programming, music
-;; Homepage: https://www.tardis.ed.ac.uk/~wwaites
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; This file adds support to Org Babel for music in ABC notation.
-;;; It requires that the abcm2ps program is installed.
-;;; See http://moinejf.free.fr/
-
-(require 'ob)
-
-;; optionally define a file extension for this language
-(add-to-list 'org-babel-tangle-lang-exts '("abc" . "abc"))
-
-;; optionally declare default header arguments for this language
-(defvar org-babel-default-header-args:abc
-  '((:results . "file") (:exports . "results"))
-  "Default arguments to use when evaluating an ABC source block.")
-
-(defun org-babel-expand-body:abc (body params)
-  "Expand BODY according to PARAMS, return the expanded body."
-  (let ((vars (org-babel--get-vars params)))
-    (mapc
-     (lambda (pair)
-       (let ((name (symbol-name (car pair)))
-            (value (cdr pair)))
-        (setq body
-              (replace-regexp-in-string
-               (concat "\\$" (regexp-quote name))
-               (if (stringp value) value (format "%S" value))
-               body))))
-     vars)
-    body))
-
-(defun org-babel-execute:abc (body params)
-  "Execute a block of ABC code with org-babel.  This function is
-   called by `org-babel-execute-src-block'"
-  (message "executing Abc source code block")
-  (let* ((cmdline (cdr (assq :cmdline params)))
-        (out-file (let ((file (cdr (assq :file params))))
-                    (if file (replace-regexp-in-string "\\.pdf$" ".ps" file)
-                      (error "abc code block requires :file header 
argument"))))
-        (in-file (org-babel-temp-file "abc-"))
-        (render (concat "abcm2ps" " " cmdline
-                     " -O " (org-babel-process-file-name out-file)
-                     " " (org-babel-process-file-name in-file))))
-    (with-temp-file in-file (insert (org-babel-expand-body:abc body params)))
-    (org-babel-eval render "")
-    ;;; handle where abcm2ps changes the file name (to support multiple files
-    (when (or (string= (file-name-extension out-file) "eps")
-             (string= (file-name-extension out-file) "svg"))
-      (rename-file (concat
-                   (file-name-sans-extension out-file) "001."
-                   (file-name-extension out-file))
-                  out-file t))
-    ;;; if we were asked for a pdf...
-    (when (string= (file-name-extension (cdr (assq :file params))) "pdf")
-      (org-babel-eval (concat "ps2pdf" " " out-file " " (cdr (assq :file 
params))) ""))
-    ;;; indicate that the file has been written
-    nil))
-
-;; This function should be used to assign any variables in params in
-;; the context of the session environment.
-(defun org-babel-prep-session:abc (_session _params)
-  "Return an error because abc does not support sessions."
-  (error "ABC does not support sessions"))
-
-(provide 'ob-abc)
-
-;;; ob-abc.el ends here
diff --git a/lisp/org/ob-asymptote.el b/lisp/org/ob-asymptote.el
deleted file mode 100644
index bfb5b79145..0000000000
--- a/lisp/org/ob-asymptote.el
+++ /dev/null
@@ -1,137 +0,0 @@
-;;; ob-asymptote.el --- Babel Functions for Asymptote -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
-
-;; Author: Eric Schulte
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Org-Babel support for evaluating asymptote source code.
-;;
-;; This differs from most standard languages in that
-;;
-;; 1) there is no such thing as a "session" in asymptote
-;;
-;; 2) we are generally only going to return results of type "file"
-;;
-;; 3) we are adding the "file" and "cmdline" header arguments, if file
-;;    is omitted then the -V option is passed to the asy command for
-;;    interactive viewing
-
-;;; Requirements:
-
-;; - The asymptote program :: http://asymptote.sourceforge.net/
-;;
-;; - asy-mode :: Major mode for editing asymptote files
-
-;;; Code:
-(require 'ob)
-
-(defvar org-babel-tangle-lang-exts)
-(add-to-list 'org-babel-tangle-lang-exts '("asymptote" . "asy"))
-
-(defvar org-babel-default-header-args:asymptote
-  '((:results . "file") (:exports . "results"))
-  "Default arguments when evaluating an Asymptote source block.")
-
-(defun org-babel-execute:asymptote (body params)
-  "Execute a block of Asymptote code.
-This function is called by `org-babel-execute-src-block'."
-  (let* ((out-file (cdr (assq :file params)))
-         (format (or (file-name-extension out-file)
-                     "pdf"))
-         (cmdline (cdr (assq :cmdline params)))
-         (in-file (org-babel-temp-file "asymptote-"))
-         (cmd
-         (concat "asy "
-                 (if out-file
-                     (concat
-                      "-globalwrite -f " format
-                      " -o " (org-babel-process-file-name out-file))
-                   "-V")
-                 " " cmdline
-                 " " (org-babel-process-file-name in-file))))
-    (with-temp-file in-file
-      (insert (org-babel-expand-body:generic
-              body params
-              (org-babel-variable-assignments:asymptote params))))
-    (message cmd) (shell-command cmd)
-    nil)) ;; signal that output has already been written to file
-
-(defun org-babel-prep-session:asymptote (_session _params)
-  "Return an error if the :session header argument is set.
-Asymptote does not support sessions."
-  (error "Asymptote does not support sessions"))
-
-(defun org-babel-variable-assignments:asymptote (params)
-  "Return list of asymptote statements assigning the block's variables."
-  (mapcar #'org-babel-asymptote-var-to-asymptote
-         (org-babel--get-vars params)))
-
-(defun org-babel-asymptote-var-to-asymptote (pair)
-  "Convert an elisp value into an Asymptote variable.
-The elisp value PAIR is converted into Asymptote code specifying
-a variable of the same value."
-  (let ((var (car pair))
-        (val (let ((v (cdr pair)))
-              (if (symbolp v) (symbol-name v) v))))
-    (cond
-     ((integerp val)
-      (format "int %S=%S;" var val))
-     ((floatp val)
-      (format "real %S=%S;" var val))
-     ((stringp val)
-      (format "string %S=\"%s\";" var val))
-     ((and (listp val) (not (listp (car val))))
-      (let* ((type (org-babel-asymptote-define-type val))
-            (fmt (if (eq 'string type) "\"%s\"" "%s"))
-            (vect (mapconcat (lambda (e) (format fmt e)) val ", ")))
-       (format "%s[] %S={%s};" type var vect)))
-     ((listp val)
-      (let* ((type (org-babel-asymptote-define-type val))
-            (fmt (if (eq 'string type) "\"%s\"" "%s"))
-             (array (mapconcat (lambda (row)
-                                (concat "{"
-                                        (mapconcat (lambda (e) (format fmt e))
-                                                   row ", ")
-                                        "}"))
-                              val ",")))
-        (format "%S[][] %S={%s};" type var array))))))
-
-(defun org-babel-asymptote-define-type (data)
-  "Determine type of DATA.
-
-DATA is a list.  Return type as a symbol.
-
-The type is `string' if any element in DATA is a string.
-Otherwise, it is either `real', if some elements are floats, or
-`int'."
-  (letrec ((type 'int)
-          (find-type
-           (lambda (row)
-             (dolist (e row type)
-               (cond ((listp e) (setq type (funcall find-type e)))
-                     ((stringp e) (throw 'exit 'string))
-                     ((floatp e) (setq type 'real)))))))
-    (catch 'exit (funcall find-type data)) type))
-
-(provide 'ob-asymptote)
-
-;;; ob-asymptote.el ends here
diff --git a/lisp/org/ob-awk.el b/lisp/org/ob-awk.el
index b41d70f12c..28e9d32757 100644
--- a/lisp/org/ob-awk.el
+++ b/lisp/org/ob-awk.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Tyler Smith <tyler@plantarum.ca>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -58,12 +59,12 @@ This function is called by `org-babel-execute-src-block'."
         (code-file (let ((file (org-babel-temp-file "awk-")))
                       (with-temp-file file (insert full-body)) file))
         (stdin (let ((stdin (cdr (assq :stdin params))))
-                  (when stdin
-                    (let ((tmp (org-babel-temp-file "awk-stdin-"))
-                          (res (org-babel-ref-resolve stdin)))
-                      (with-temp-file tmp
-                        (insert (org-babel-awk-var-to-awk res)))
-                      tmp))))
+                 (when stdin
+                   (let ((tmp (org-babel-temp-file "awk-stdin-"))
+                         (res (org-babel-ref-resolve stdin)))
+                     (with-temp-file tmp
+                       (insert (org-babel-awk-var-to-awk res)))
+                     tmp))))
          (cmd (mapconcat #'identity
                         (append
                          (list org-babel-awk-command
diff --git a/lisp/org/ob-calc.el b/lisp/org/ob-calc.el
index 39ebce1002..5962d38761 100644
--- a/lisp/org/ob-calc.el
+++ b/lisp/org/ob-calc.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Tom Gillespie <tgbugs@gmail.com>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -90,7 +91,7 @@
   (save-excursion
     (with-current-buffer (get-buffer "*Calculator*")
       (prog1
-        (calc-eval (calc-top 1))
+          (calc-eval (calc-top 1))
         (calc-pop 1)))))
 
 (defun org-babel-calc-maybe-resolve-var (el)
diff --git a/lisp/org/ob-clojure.el b/lisp/org/ob-clojure.el
index 9834509fb0..3b995d94ce 100644
--- a/lisp/org/ob-clojure.el
+++ b/lisp/org/ob-clojure.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
 ;; Author: Joel Boehland, Eric Schulte, Oleh Krehel, Frederick Giasson
+;; Maintainer: Bastien Guerry <bzg@gnu.org>
 ;;
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
diff --git a/lisp/org/ob-comint.el b/lisp/org/ob-comint.el
index b14849df69..20ae76fadc 100644
--- a/lisp/org/ob-comint.el
+++ b/lisp/org/ob-comint.el
@@ -93,12 +93,7 @@ or user `keyboard-quit' during execution of body."
                               (regexp-quote ,eoe-indicator) nil t)
                              (re-search-forward
                               comint-prompt-regexp nil t)))))
-          (accept-process-output (get-buffer-process (current-buffer)))
-          ;; thought the following this would allow async
-          ;; background running, but I was wrong...
-          ;; (run-with-timer .5 .5 'accept-process-output
-          ;;            (get-buffer-process (current-buffer)))
-          )
+          (accept-process-output (get-buffer-process (current-buffer))))
         ;; replace cut dangling text
         (goto-char (process-mark (get-buffer-process (current-buffer))))
         (insert dangling-text)
@@ -135,7 +130,7 @@ statement (not large blocks of code)."
       (accept-process-output (get-buffer-process buffer)))))
 
 (defun org-babel-comint-eval-invisibly-and-wait-for-file
-  (buffer file string &optional period)
+    (buffer file string &optional period)
   "Evaluate STRING in BUFFER invisibly.
 Don't return until FILE exists.  Code in STRING must ensure that
 FILE exists at end of evaluation."
@@ -147,6 +142,171 @@ FILE exists at end of evaluation."
    (if (= (aref string (1- (length string))) ?\n) string (concat string "\n")))
   (while (not (file-exists-p file)) (sit-for (or period 0.25))))
 
+
+;;; Async evaluation
+
+(defvar-local org-babel-comint-async-indicator nil
+  "Regular expression that `org-babel-comint-async-filter' scans for.
+It should have 2 parenthesized expressions,
+e.g. \"org_babel_async_\\(start\\|end\\|file\\)_\\(.*\\)\".  The
+first parenthesized expression determines whether the token is
+delimiting a result block, or whether the result is in a file.
+If delimiting a block, the second expression gives a UUID for the
+location to insert the result.  Otherwise, the result is in a tmp
+file, and the second expression gives the file name.")
+
+(defvar-local org-babel-comint-async-buffers nil
+  "List of Org mode buffers to check for Babel async output results.")
+
+(defvar-local org-babel-comint-async-file-callback nil
+  "Callback to clean and insert Babel async results from a temp file.
+The callback function takes two arguments: the alist of params of the Babel
+source block, and the name of the temp file.")
+
+(defvar-local org-babel-comint-async-chunk-callback nil
+  "Callback function to clean Babel async output results before insertion.
+Its single argument is a string consisting of output from the
+comint process.  It should return a string that will be be passed
+to `org-babel-insert-result'.")
+
+(defvar-local org-babel-comint-async-dangling nil
+  "Dangling piece of the last process output, in case
+`org-babel-comint-async-indicator' is spread across multiple
+comint outputs due to buffering.")
+
+(defun org-babel-comint-use-async (params)
+  "Determine whether to use session async evaluation.
+PARAMS are the header arguments as passed to
+`org-babel-execute:lang'."
+  (let ((async (assq :async params))
+        (session (assq :session params)))
+    (and async
+        (not org-babel-exp-reference-buffer)
+         (not (equal (cdr async) "no"))
+         (not (equal (cdr session) "none")))))
+
+(defun org-babel-comint-async-filter (string)
+  "Captures Babel async output from comint buffer back to Org mode buffers.
+This function is added as a hook to `comint-output-filter-functions'.
+STRING contains the output originally inserted into the comint buffer."
+  ;; Remove outdated Org mode buffers
+  (setq org-babel-comint-async-buffers
+       (cl-loop for buf in org-babel-comint-async-buffers
+                if (buffer-live-p buf)
+                collect buf))
+  (let* ((indicator org-babel-comint-async-indicator)
+        (org-buffers org-babel-comint-async-buffers)
+        (file-callback org-babel-comint-async-file-callback)
+        (combined-string (concat org-babel-comint-async-dangling string))
+        (new-dangling combined-string)
+        ;; list of UUID's matched by `org-babel-comint-async-indicator'
+        uuid-list)
+    (with-temp-buffer
+      (insert combined-string)
+      (goto-char (point-min))
+      (while (re-search-forward indicator nil t)
+       ;; update dangling
+       (setq new-dangling (buffer-substring (point) (point-max)))
+       (cond ((equal (match-string 1) "end")
+              ;; save UUID for insertion later
+              (push (match-string 2) uuid-list))
+             ((equal (match-string 1) "file")
+              ;; insert results from tmp-file
+              (let ((tmp-file (match-string 2)))
+                (cl-loop for buf in org-buffers
+                         until
+                         (with-current-buffer buf
+                           (save-excursion
+                             (goto-char (point-min))
+                             (when (search-forward tmp-file nil t)
+                               (org-babel-previous-src-block)
+                                (let* ((info (org-babel-get-src-block-info))
+                                       (params (nth 2 info))
+                                       (result-params
+                                        (cdr (assq :result-params params))))
+                                  (org-babel-insert-result
+                                   (funcall file-callback
+                                            (nth
+                                             2 (org-babel-get-src-block-info))
+                                            tmp-file)
+                                   result-params info))
+                               t))))))))
+      ;; Truncate dangling to only the most recent output
+      (when (> (length new-dangling) (length string))
+       (setq new-dangling string)))
+    (setq-local org-babel-comint-async-dangling new-dangling)
+    (when uuid-list
+      ;; Search for results in the comint buffer
+      (save-excursion
+       (goto-char (point-max))
+       (while uuid-list
+         (re-search-backward indicator)
+         (when (equal (match-string 1) "end")
+           (let* ((uuid (match-string-no-properties 2))
+                  (res-str-raw
+                   (buffer-substring
+                    ;; move point to beginning of indicator
+                     (- (match-beginning 0) 1)
+                    ;; find the matching start indicator
+                    (cl-loop
+                      do (re-search-backward indicator)
+                     until (and (equal (match-string 1) "start")
+                                (equal (match-string 2) uuid))
+                     finally return (+ 1 (match-end 0)))))
+                  ;; Apply callback to clean up the result
+                  (res-str (funcall org-babel-comint-async-chunk-callback
+                                     res-str-raw)))
+             ;; Search for uuid in associated org-buffers to insert results
+             (cl-loop for buf in org-buffers
+                      until (with-current-buffer buf
+                              (save-excursion
+                                (goto-char (point-min))
+                                (when (search-forward uuid nil t)
+                                  (org-babel-previous-src-block)
+                                   (let* ((info (org-babel-get-src-block-info))
+                                          (params (nth 2 info))
+                                          (result-params
+                                           (cdr (assq :result-params params))))
+                                    (org-babel-insert-result
+                                      res-str result-params info))
+                                  t))))
+             ;; Remove uuid from the list to search for
+             (setq uuid-list (delete uuid uuid-list)))))))))
+
+(defun org-babel-comint-async-register
+    (session-buffer org-buffer indicator-regexp
+                   chunk-callback file-callback)
+  "Set local org-babel-comint-async variables in SESSION-BUFFER.
+ORG-BUFFER is added to `org-babel-comint-async-buffers' if not
+present.  `org-babel-comint-async-indicator',
+`org-babel-comint-async-chunk-callback', and
+`org-babel-comint-async-file-callback' are set to
+INDICATOR-REGEXP, CHUNK-CALLBACK, and FILE-CALLBACK
+respectively."
+  (org-babel-comint-in-buffer session-buffer
+    (setq org-babel-comint-async-indicator indicator-regexp
+         org-babel-comint-async-chunk-callback chunk-callback
+         org-babel-comint-async-file-callback file-callback)
+    (unless (memq org-buffer org-babel-comint-async-buffers)
+      (setq org-babel-comint-async-buffers
+           (cons org-buffer org-babel-comint-async-buffers)))
+    (add-hook 'comint-output-filter-functions
+             'org-babel-comint-async-filter nil t)))
+
+(defmacro org-babel-comint-async-delete-dangling-and-eval
+    (session-buffer &rest body)
+  "Remove dangling text in SESSION-BUFFER and evaluate BODY.
+This is analogous to `org-babel-comint-with-output', but meant
+for asynchronous output, and much shorter because inserting the
+result is delegated to `org-babel-comint-async-filter'."
+  (declare (indent 1) (debug t))
+  `(org-babel-comint-in-buffer ,session-buffer
+     (goto-char (process-mark (get-buffer-process (current-buffer))))
+     (delete-region (point) (point-max))
+     ,@body))
+
 (provide 'ob-comint)
 
+
+
 ;;; ob-comint.el ends here
diff --git a/lisp/org/ob-coq.el b/lisp/org/ob-coq.el
deleted file mode 100644
index c77e8c9af6..0000000000
--- a/lisp/org/ob-coq.el
+++ /dev/null
@@ -1,80 +0,0 @@
-;;; ob-coq.el --- Babel Functions for Coq            -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Author: Eric Schulte
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Rudimentary support for evaluating Coq code blocks.  Currently only
-;; session evaluation is supported.  Requires both coq.el and
-;; coq-inferior.el, both of which are distributed with Coq.
-;;
-;; https://coq.inria.fr/
-
-;;; Code:
-(require 'ob)
-
-(declare-function run-coq "ext:coq-inferior.el" (cmd))
-(declare-function coq-proc "ext:coq-inferior.el" ())
-
-(defvar coq-program-name "coqtop"
-  "Name of the coq toplevel to run.")
-
-(defvar org-babel-coq-buffer "*coq*"
-  "Buffer in which to evaluate coq code blocks.")
-
-(defun org-babel-coq-clean-prompt (string)
-  (if (string-match "^[^[:space:]]+ < " string)
-      (substring string 0 (match-beginning 0))
-    string))
-
-(defun org-babel-execute:coq (body params)
-  (let ((full-body (org-babel-expand-body:generic body params))
-       (session (org-babel-coq-initiate-session))
-       (pt (lambda ()
-             (marker-position
-              (process-mark (get-buffer-process (current-buffer)))))))
-    (org-babel-coq-clean-prompt
-     (org-babel-comint-in-buffer session
-       (let ((start (funcall pt)))
-        (with-temp-buffer
-          (insert full-body)
-          (comint-send-region (coq-proc) (point-min) (point-max))
-          (comint-send-string (coq-proc)
-           (if (string= (buffer-substring (- (point-max) 1) (point-max)) ".")
-               "\n"
-             ".\n")))
-        (while (equal start (funcall pt)) (sleep-for 0.1))
-        (buffer-substring start (funcall pt)))))))
-
-(defun org-babel-coq-initiate-session ()
-  "Initiate a coq session.
-If there is not a current inferior-process-buffer in SESSION then
-create one.  Return the initialized session."
-  (unless (fboundp 'run-coq)
-    (error "`run-coq' not defined, load coq-inferior.el"))
-  (save-window-excursion (run-coq coq-program-name))
-  (sit-for 0.1)
-  (get-buffer org-babel-coq-buffer))
-
-(provide 'ob-coq)
-
-;;; ob-coq.el ends here
diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el
index b1fd694371..06a2a88cd4 100644
--- a/lisp/org/ob-core.el
+++ b/lisp/org/ob-core.el
@@ -290,9 +290,9 @@ environment, to override this check."
                     (format "Evaluate this %s code block%son your system? "
                             lang name-string)))
               (progn
-               (message "Evaluation of this %s code block%sis aborted."
-                        lang name-string)
-               nil)))
+                (message "Evaluation of this %s code block%sis aborted."
+                         lang name-string)
+                nil)))
       (x (error "Unexpected value `%s' from 
`org-babel-check-confirm-evaluate'" x)))))
 
 ;;;###autoload
@@ -472,7 +472,35 @@ For the format of SAFE-LIST, see 
`org-babel-safe-header-args'."
 (defvar org-babel-default-header-args
   '((:session . "none") (:results . "replace") (:exports . "code")
     (:cache . "no") (:noweb . "no") (:hlines . "no") (:tangle . "no"))
-  "Default arguments to use when evaluating a source block.")
+  "Default arguments to use when evaluating a source block.
+
+This is a list in which each element is an alist.  Each key
+corresponds to a header argument, and each value to that header's
+value.  The value can either be a string or a closure that
+evaluates to a string.  The closure is evaluated when the source
+block is being evaluated (e.g. during execution or export), with
+point at the source block.  It is not possible to use an
+arbitrary function symbol (e.g. 'some-func), since org uses
+lexical binding.  To achieve the same functionality, call the
+function within a closure (e.g. (lambda () (some-func))).
+
+To understand how closures can be used as default header
+arguments, imagine you'd like to set the file name output of a
+latex source block to a sha1 of its contents.  We could achieve
+this with:
+
+(defun org-src-sha ()
+  (let ((elem (org-element-at-point)))
+    (concat (sha1 (org-element-property :value elem)) \".svg\")))
+
+(setq org-babel-default-header-args:latex
+      `((:results . \"file link replace\")
+        (:file . (lambda () (org-src-sha)))))
+
+Because the closure is evaluated with point at the source block,
+the call to `org-element-at-point' above will always retrieve
+information about the current source block.")
+
 (put 'org-babel-default-header-args 'safe-local-variable
      (org-babel-header-args-safe-fn org-babel-safe-header-args))
 
@@ -538,7 +566,7 @@ to raise errors for all languages.")
   "Number of initial characters to show of a hidden results hash.")
 
 (defvar org-babel-after-execute-hook nil
-  "Hook for functions to be called after `org-babel-execute-src-block'")
+  "Hook for functions to be called after `org-babel-execute-src-block'.")
 
 (defun org-babel-named-src-block-regexp-for-name (&optional name)
   "Generate a regexp used to match a source block named NAME.
@@ -581,7 +609,17 @@ multiple blocks are being executed (e.g., in chained 
execution
 through use of the :var header argument) this marker points to
 the outer-most code block.")
 
-(defvar *this*)
+(defun org-babel-eval-headers (headers)
+  "Compute header list set with HEADERS.
+
+Evaluate all header arguments set to functions prior to returning
+the list of header arguments."
+  (let ((lst nil))
+    (dolist (elem headers)
+      (if (and (cdr elem) (functionp (cdr elem)))
+          (push `(,(car elem) . ,(funcall (cdr elem))) lst)
+        (push elem lst)))
+    (reverse lst)))
 
 (defun org-babel-get-src-block-info (&optional light datum)
   "Extract information from a source block or inline source block.
@@ -646,6 +684,16 @@ a list with the following pattern:
       (replace-regexp-in-string
        (org-src-coderef-regexp coderef) "" expand nil nil 1))))
 
+(defun org-babel--file-desc (params result)
+  "Retrieve file description."
+  (pcase (assq :file-desc params)
+    (`nil nil)
+    (`(:file-desc) result)
+    (`(:file-desc . ,(and (pred stringp) val)) val)))
+
+(defvar *this*) ; Dynamically bound in `org-babel-execute-src-block'
+                ; and `org-babel-read'
+
 ;;;###autoload
 (defun org-babel-execute-src-block (&optional arg info params)
   "Execute the current source code block.
@@ -749,8 +797,7 @@ block."
                    (let ((*this* (if (not file) result
                                    (org-babel-result-to-file
                                     file
-                                    (let ((desc (assq :file-desc params)))
-                                      (and desc (or (cdr desc) result)))))))
+                                    (org-babel--file-desc params result)))))
                      (setq result (org-babel-ref-resolve post))
                      (when file
                        (setq result-params (remove "file" result-params))))))
@@ -802,27 +849,6 @@ arguments and pop open the results in a preview buffer."
         expanded (concat "*Org-Babel Preview " (buffer-name) "[ " lang " ]*"))
       expanded)))
 
-(defun org-babel-edit-distance (s1 s2)
-  "Return the edit (levenshtein) distance between strings S1 S2."
-  (let* ((l1 (length s1))
-        (l2 (length s2))
-        (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil))
-                               (number-sequence 1 (1+ l1)))))
-        (in (lambda (i j) (aref (aref dist i) j))))
-    (setf (aref (aref dist 0) 0) 0)
-    (dolist (j (number-sequence 1 l2))
-      (setf (aref (aref dist 0) j) j))
-    (dolist (i (number-sequence 1 l1))
-      (setf (aref (aref dist i) 0) i)
-      (dolist (j (number-sequence 1 l2))
-       (setf (aref (aref dist i) j)
-             (min
-              (1+ (funcall in (1- i) j))
-              (1+ (funcall in i (1- j)))
-              (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1)
-                 (funcall in (1- i) (1- j)))))))
-    (funcall in l1 l2)))
-
 (defun org-babel-combine-header-arg-lists (original &rest others)
   "Combine a number of lists of header argument names and arguments."
   (let ((results (copy-sequence original)))
@@ -851,7 +877,7 @@ arguments and pop open the results in a preview buffer."
                                   (match-string 4))))))
       (dolist (name names)
        (when (and (not (string= header name))
-                  (<= (org-babel-edit-distance header name) too-close)
+                  (<= (org-string-distance header name) too-close)
                   (not (member header names)))
          (error "Supplied header \"%S\" is suspiciously close to \"%S\""
                 header name))))
@@ -1446,7 +1472,7 @@ portions of results lines."
 ;; Remove overlays when changing major mode
 (add-hook 'org-mode-hook
          (lambda () (add-hook 'change-major-mode-hook
-                         #'org-babel-show-result-all 'append 'local)))
+                              #'org-babel-show-result-all 'append 'local)))
 
 (defun org-babel-params-from-properties (&optional lang no-eval)
   "Retrieve source block parameters specified as properties.
@@ -1550,11 +1576,11 @@ balanced instances of \"[ \t]:\", set ALTS to ((32 9) . 
58)."
        (first= (lambda (str) (= ch (aref str 0)))))
     (reverse
      (cl-reduce (lambda (acc el)
-                  (let ((head (car acc)))
-                    (if (and head (or (funcall last= head) (funcall first= 
el)))
-                        (cons (concat head el) (cdr acc))
-                      (cons el acc))))
-                list :initial-value nil))))
+                 (let ((head (car acc)))
+                   (if (and head (or (funcall last= head) (funcall first= el)))
+                       (cons (concat head el) (cdr acc))
+                     (cons el acc))))
+               list :initial-value nil))))
 
 (defun org-babel-parse-header-arguments (string &optional no-eval)
   "Parse header arguments in STRING.
@@ -1628,7 +1654,7 @@ shown below.
                                (t 'value))))
      (cl-remove-if
       (lambda (x) (memq (car x) '(:colname-names :rowname-names :result-params
-                                           :result-type :var)))
+                                                :result-type :var)))
       params))))
 
 ;; row and column names
@@ -1698,9 +1724,12 @@ of the vars, cnames and rnames."
     (list
      (mapcar
       (lambda (var)
-        (when (listp (cdr var))
+        (when (proper-list-p (cdr var))
           (when (and (not (equal colnames "no"))
-                     (or colnames (and (eq (nth 1 (cdr var)) 'hline)
+                     ;; Compatibility note: avoid `length>', which
+                     ;; isn't available until Emacs 28.
+                     (or colnames (and (> (length (cdr var)) 1)
+                                       (eq (nth 1 (cdr var)) 'hline)
                                        (not (member 'hline (cddr (cdr 
var)))))))
             (let ((both (org-babel-get-colnames (cdr var))))
               (setq cnames (cons (cons (car var) (cdr both))
@@ -1720,7 +1749,7 @@ of the vars, cnames and rnames."
 (defun org-babel-reassemble-table (table colnames rownames)
   "Add column and row names to a table.
 Given a TABLE and set of COLNAMES and ROWNAMES add the names
-to the table for reinsertion to org-mode."
+to the table for reinsertion to `org-mode'."
   (if (listp table)
       (let ((table (if (and rownames (= (length table) (length rownames)))
                        (org-babel-put-rownames table rownames) table)))
@@ -1755,7 +1784,7 @@ If the point is not on a source block then return nil."
   "Go to the beginning of the current code block."
   (interactive)
   (let ((head (org-babel-where-is-src-block-head)))
-     (if head (goto-char head) (error "Not currently in a code block"))))
+    (if head (goto-char head) (error "Not currently in a code block"))))
 
 ;;;###autoload
 (defun org-babel-goto-named-src-block (name)
@@ -2199,6 +2228,10 @@ silent -- no results are inserted into the Org buffer but
           ingested by Emacs (a potentially time consuming
           process).
 
+none ---- no results are inserted into the Org buffer nor
+          echoed to the minibuffer. they are not processed into
+          Emacs-lisp objects at all.
+
 file ---- the results are interpreted as a file path, and are
           inserted into the buffer using the Org file syntax.
 
@@ -2256,9 +2289,8 @@ INFO may provide the values of these header arguments (in 
the
         (setq result (org-no-properties result))
         (when (member "file" result-params)
           (setq result (org-babel-result-to-file
-                        result (when (assq :file-desc (nth 2 info))
-                                 (or (cdr (assq :file-desc (nth 2 info)))
-                                     result))))))
+                        result
+                        (org-babel--file-desc (nth 2 info) result)))))
        ((listp result))
        (t (setq result (format "%S" result))))
   (if (and result-params (member "silent" result-params))
@@ -2324,7 +2356,7 @@ INFO may provide the values of these header arguments (in 
the
                      (if results-switches (concat " " results-switches) ""))
                (let ((wrap
                       (lambda (start finish &optional no-escape no-newlines
-                                inline-start inline-finish)
+                                     inline-start inline-finish)
                         (when inline
                           (setq start inline-start)
                           (setq finish inline-finish)
@@ -2553,8 +2585,9 @@ in the buffer."
         (let ((element (org-element-at-point)))
           (if (memq (org-element-type element)
                     ;; Possible results types.
-                    '(drawer example-block export-block fixed-width item
-                             plain-list special-block src-block table))
+                     '(drawer example-block export-block fixed-width
+                              special-block src-block item plain-list table
+                              latex-environment))
               (save-excursion
                 (goto-char (min (point-max) ;for narrowed buffers
                                 (org-element-property :end element)))
@@ -2570,9 +2603,9 @@ file's directory then expand relative links."
     (let ((same-directory?
           (and (buffer-file-name (buffer-base-buffer))
                (not (string= (expand-file-name default-directory)
-                           (expand-file-name
-                            (file-name-directory
-                             (buffer-file-name (buffer-base-buffer)))))))))
+                             (expand-file-name
+                              (file-name-directory
+                               (buffer-file-name (buffer-base-buffer)))))))))
       (format "[[file:%s]%s]"
              (if (and default-directory
                       (buffer-file-name (buffer-base-buffer)) same-directory?)
@@ -2706,12 +2739,17 @@ parameters when merging lists."
                                  results-exclusive-groups
                                  results
                                  (split-string
-                                  (if (stringp value) value (eval value t))))))
+                                  (cond ((stringp value) value)
+                                         ((functionp value) (funcall value))
+                                         (t (eval value t)))))))
          (`(:exports . ,value)
           (setq exports (funcall merge
                                  exports-exclusive-groups
                                  exports
-                                 (split-string (or value "")))))
+                                 (split-string
+                                   (cond ((and value (functionp value)) 
(funcall value))
+                                         (value value)
+                                         (t ""))))))
          ;; Regular keywords: any value overwrites the previous one.
          (_ (setq params (cons pair (assq-delete-all (car pair) params)))))))
     ;; Handle `:var' and clear out colnames and rownames for replaced
@@ -2726,14 +2764,14 @@ parameters when merging lists."
                              (cdr (assq param params))))
          (setq params
                (cl-remove-if (lambda (pair) (and (equal (car pair) param)
-                                            (null (cdr pair))))
+                                                 (null (cdr pair))))
                              params)))))
     ;; Handle other special keywords, which accept multiple values.
     (setq params (nconc (list (cons :results (mapconcat #'identity results " 
"))
                              (cons :exports (mapconcat #'identity exports " 
")))
                        params))
     ;; Return merged params.
-    params))
+    (org-babel-eval-headers params)))
 
 (defun org-babel-noweb-p (params context)
   "Check if PARAMS require expansion in CONTEXT.
@@ -2842,8 +2880,6 @@ block but are passed literally to the \"example-block\"."
                     (setq cache nil)
                     (let ((raw (org-babel-ref-resolve id)))
                       (if (stringp raw) raw (format "%S" raw))))
-                   ;; Retrieve from the Library of Babel.
-                   ((nth 2 (assoc-string id org-babel-library-of-babel)))
                    ;; Return the contents of headlines literally.
                    ((org-babel-ref-goto-headline-id id)
                     (org-babel-ref-headline-body))
@@ -2856,6 +2892,8 @@ block but are passed literally to the \"example-block\"."
                              (not (org-in-commented-heading-p))
                              (funcall expand-body
                                       (org-babel-get-src-block-info t))))))
+                   ;; Retrieve from the Library of Babel.
+                   ((nth 2 (assoc-string id org-babel-library-of-babel)))
                    ;; All Noweb references were cached in a previous
                    ;; run.  Extract the information from the cache.
                    ((hash-table-p cache)
@@ -2976,7 +3014,7 @@ block but are passed literally to the \"example-block\"."
 
 (defun org-babel-read (cell &optional inhibit-lisp-eval)
   "Convert the string value of CELL to a number if appropriate.
-Otherwise if CELL looks like lisp (meaning it starts with a
+Otherwise if CELL looks like Lisp (meaning it starts with a
 \"(\", \"\\='\", \"\\=`\" or a \"[\") then read and evaluate it as
 lisp, otherwise return it unmodified as a string.  Optional
 argument INHIBIT-LISP-EVAL inhibits lisp evaluation for
@@ -3148,7 +3186,7 @@ For the format of SAFE-LIST, see 
`org-babel-safe-header-args'."
          (and entry
               (consp entry)
               (cond ((functionp (cdr entry))
-                      (funcall (cdr entry) (cdr pair)))
+                     (funcall (cdr entry) (cdr pair)))
                     ((listp (cdr entry))
                      (member (cdr pair) (cdr entry)))
                     (t nil)))))))
@@ -3168,10 +3206,10 @@ Otherwise, the :file parameter is treated as a full 
file name,
 and the output file name is the directory (as calculated above)
 plus the parameter value."
   (let* ((file-cons (assq :file params))
-          (file-ext-cons (assq :file-ext params))
-          (file-ext (cdr-safe file-ext-cons))
-          (dir (cdr-safe (assq :output-dir params)))
-          fname)
+        (file-ext-cons (assq :file-ext params))
+        (file-ext (cdr-safe file-ext-cons))
+        (dir (cdr-safe (assq :output-dir params)))
+        fname)
     ;; create the output-dir if it does not exist
     (when dir
       (make-directory dir t))
diff --git a/lisp/org/ob-dot.el b/lisp/org/ob-dot.el
index d13261b340..8e05a59f20 100644
--- a/lisp/org/ob-dot.el
+++ b/lisp/org/ob-dot.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Justin Abrahms
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -25,7 +26,7 @@
 
 ;; Org-Babel support for evaluating dot source code.
 ;;
-;; For information on dot see http://www.graphviz.org/
+;; For information on dot see https://www.graphviz.org/
 ;;
 ;; This differs from most standard languages in that
 ;;
diff --git a/lisp/org/ob-ebnf.el b/lisp/org/ob-ebnf.el
deleted file mode 100644
index 58666a4ded..0000000000
--- a/lisp/org/ob-ebnf.el
+++ /dev/null
@@ -1,81 +0,0 @@
-;;; ob-ebnf.el --- Babel Functions for EBNF          -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
-
-;; Author: Michael Gauland
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Org-Babel support for using ebnf2ps to generate encapsulated postscript
-;; railroad diagrams. It recognizes these arguments:
-;;
-;;     :file is required; it must include the extension '.eps.' All the rules
-;;           in the block will be drawn in the same file. This is done by
-;;           inserting a '[<file>' comment at the start of the block (see the
-;;           documentation for ebnf-eps-buffer for more information).
-;;
-;;     :style specifies a value in ebnf-style-database. This provides the
-;;            ability to customize the output. The style can also specify the
-;;            grammar syntax (by setting ebnf-syntax); note that only ebnf,
-;;            iso-ebnf, and yacc are supported by this file.
-
-;;; Requirements:
-
-;;; Code:
-(require 'ob)
-(require 'ebnf2ps)
-
-;; optionally declare default header arguments for this language
-(defvar org-babel-default-header-args:ebnf '((:style . nil)))
-
-;; Use ebnf-eps-buffer to produce an encapsulated postscript file.
-;;
-(defun org-babel-execute:ebnf (body params)
-  "Execute a block of Ebnf code with org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (save-excursion
-    (let* ((dest-file (cdr (assq :file params)))
-          (dest-dir (file-name-directory dest-file))
-          (dest-root (file-name-sans-extension
-                      (file-name-nondirectory dest-file)))
-          (style (cdr (assq :style params)))
-          (result nil))
-      (with-temp-buffer
-       (when style (ebnf-push-style style))
-       (let ((comment-format
-              (cond ((string= ebnf-syntax 'yacc) "/*%s*/")
-                    ((string= ebnf-syntax 'ebnf) ";%s")
-                    ((string= ebnf-syntax 'iso-ebnf) "(*%s*)")
-                    (t (setq result
-                             (format "EBNF error: format %s not supported."
-                                     ebnf-syntax))))))
-         (setq ebnf-eps-prefix dest-dir)
-         (insert (format comment-format (format "[%s" dest-root)))
-         (newline)
-         (insert body)
-         (newline)
-         (insert (format comment-format (format "]%s" dest-root)))
-         (ebnf-eps-buffer)
-         (when style (ebnf-pop-style))))
-      result)))
-
-(provide 'ob-ebnf)
-
-;;; ob-ebnf.el ends here
diff --git a/lisp/org/ob-eshell.el b/lisp/org/ob-eshell.el
index 6ae0fc613d..d74c4fc43f 100644
--- a/lisp/org/ob-eshell.el
+++ b/lisp/org/ob-eshell.el
@@ -3,8 +3,9 @@
 ;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
 ;; Author: stardiviner <numbchild@gmail.com>
+;; Maintainer: stardiviner <numbchild@gmail.com>
+;; Homepage: https://github.com/stardiviner/ob-eshell
 ;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
 
 ;; This file is part of GNU Emacs.
 
diff --git a/lisp/org/ob-eval.el b/lisp/org/ob-eval.el
index b0fca7bd95..cfd8022255 100644
--- a/lisp/org/ob-eval.el
+++ b/lisp/org/ob-eval.el
@@ -41,20 +41,22 @@
     (display-buffer buf))
   (message "Babel evaluation exited with code %S" exit-code))
 
-(defun org-babel-eval (cmd body)
-  "Run CMD on BODY.
-If CMD succeeds then return its results, otherwise display
-STDERR with `org-babel-eval-error-notify'."
-  (let ((err-buff (get-buffer-create " *Org-Babel Error*")) exit-code)
-    (with-current-buffer err-buff (erase-buffer))
+(defun org-babel-eval (command query)
+  "Run COMMAND on QUERY.
+Writes QUERY into a temp-buffer that is processed with
+`org-babel--shell-command-on-region'.  If COMMAND succeeds then return
+its results, otherwise display STDERR with
+`org-babel-eval-error-notify'."
+  (let ((error-buffer (get-buffer-create " *Org-Babel Error*")) exit-code)
+    (with-current-buffer error-buffer (erase-buffer))
     (with-temp-buffer
-      (insert body)
+      (insert query)
       (setq exit-code
            (org-babel--shell-command-on-region
-            (point-min) (point-max) cmd err-buff))
+            command error-buffer))
       (if (or (not (numberp exit-code)) (> exit-code 0))
          (progn
-           (with-current-buffer err-buff
+           (with-current-buffer error-buffer
              (org-babel-eval-error-notify exit-code (buffer-string)))
            (save-excursion
              (when (get-buffer org-babel-error-buffer-name)
@@ -71,26 +73,19 @@ STDERR with `org-babel-eval-error-notify'."
   (with-temp-buffer (insert-file-contents file)
                    (buffer-string)))
 
-(defun org-babel--shell-command-on-region (start end command error-buffer)
+(defun org-babel--shell-command-on-region (command error-buffer)
   "Execute COMMAND in an inferior shell with region as input.
+Stripped down version of `shell-command-on-region' for internal use in
+Babel only.  This lets us work around errors in the original function
+in various versions of Emacs.  This expects the query to be run to be
+in the current temp buffer.  This is written into
+input-file.  ERROR-BUFFER is the name of the file which
+`org-babel-eval' has created to use for any error messages that are
+returned."
 
-Stripped down version of shell-command-on-region for internal use
-in Babel only.  This lets us work around errors in the original
-function in various versions of Emacs.
-"
   (let ((input-file (org-babel-temp-file "ob-input-"))
        (error-file (if error-buffer (org-babel-temp-file "ob-error-") nil))
-       ;; Unfortunately, `executable-find' does not support file name
-       ;; handlers.  Therefore, we could use it in the local case
-       ;; only.
-       (shell-file-name
-        (cond ((and (not (file-remote-p default-directory))
-                    (executable-find shell-file-name))
-               shell-file-name)
-              ((file-executable-p
-                (concat (file-remote-p default-directory) shell-file-name))
-               shell-file-name)
-              ("/bin/sh")))
+       (shell-file-name (org-babel--get-shell-file-name))
        exit-status)
     ;; There is an error in `process-file' when `error-file' exists.
     ;; This is fixed in Emacs trunk as of 2012-12-21; let's use this
@@ -99,18 +94,13 @@ function in various versions of Emacs.
       (delete-file error-file))
     ;; we always call this with 'replace, remove conditional
     ;; Replace specified region with output from command.
-    (let ((swap (< start end)))
-      (goto-char start)
-      (push-mark (point) 'nomsg)
-      (write-region start end input-file)
-      (delete-region start end)
-      (setq exit-status
-           (process-file shell-file-name input-file
-                         (if error-file
-                             (list t error-file)
-                           t)
-                         nil shell-command-switch command))
-      (when swap (exchange-point-and-mark)))
+    (org-babel--write-temp-buffer-input-file input-file)
+    (setq exit-status
+         (process-file shell-file-name input-file
+                       (if error-file
+                           (list t error-file)
+                         t)
+                       nil shell-command-switch command))
 
     (when (and input-file (file-exists-p input-file)
               ;; bind org-babel--debug-input around the call to keep
@@ -135,6 +125,16 @@ function in various versions of Emacs.
       (delete-file error-file))
     exit-status))
 
+(defun org-babel--write-temp-buffer-input-file (input-file)
+  "Write the contents of the current temp buffer into INPUT-FILE."
+  (let ((start (point-min))
+        (end (point-max)))
+    (goto-char start)
+    (push-mark (point) 'nomsg)
+    (write-region start end input-file)
+    (delete-region start end)
+    (exchange-point-and-mark)))
+
 (defun org-babel-eval-wipe-error-buffer ()
   "Delete the contents of the Org code block error buffer.
 This buffer is named by `org-babel-error-buffer-name'."
@@ -142,6 +142,19 @@ This buffer is named by `org-babel-error-buffer-name'."
     (with-current-buffer org-babel-error-buffer-name
       (delete-region (point-min) (point-max)))))
 
+(defun org-babel--get-shell-file-name ()
+  "Return system `shell-file-name', defaulting to /bin/sh.
+Unfortunately, `executable-find' does not support file name
+handlers.  Therefore, we could use it in the local case only."
+  ;; FIXME: This is generic enough that it should probably be in emacs, not 
org-mode
+  (cond ((and (not (file-remote-p default-directory))
+             (executable-find shell-file-name))
+        shell-file-name)
+       ((file-executable-p
+         (concat (file-remote-p default-directory) shell-file-name))
+        shell-file-name)
+       ("/bin/sh")))
+
 (provide 'ob-eval)
 
 ;;; ob-eval.el ends here
diff --git a/lisp/org/ob-exp.el b/lisp/org/ob-exp.el
index e851ff624a..d10d228eba 100644
--- a/lisp/org/ob-exp.el
+++ b/lisp/org/ob-exp.el
@@ -216,8 +216,11 @@ this template."
                             (delete-region begin end)
                             (insert replacement)))))
                      ((or `babel-call `inline-babel-call)
-                      (org-babel-exp-do-export (org-babel-lob-get-info element)
-                                               'lob)
+                       (org-babel-exp-do-export
+                        (or (org-babel-lob-get-info element)
+                            (user-error "Unknown Babel reference: %s"
+                                        (org-element-property :call element)))
+                        'lob)
                       (let ((rep
                              (org-fill-template
                               org-babel-exp-call-line-template
@@ -289,11 +292,11 @@ this template."
   "Return a string with the exported content of a code block.
 The function respects the value of the :exports header argument."
   (let ((silently (lambda () (let ((session (cdr (assq :session (nth 2 
info)))))
-                         (unless (equal "none" session)
-                           (org-babel-exp-results info type 'silent)))))
+                              (unless (equal "none" session)
+                                (org-babel-exp-results info type 'silent)))))
        (clean (lambda () (if (eq type 'inline)
-                        (org-babel-remove-inline-result)
-                      (org-babel-remove-result info)))))
+                             (org-babel-remove-inline-result)
+                           (org-babel-remove-result info)))))
     (pcase (or (cdr (assq :exports (nth 2 info))) "code")
       ("none" (funcall silently) (funcall clean) "")
       ("code" (funcall silently) (funcall clean) (org-babel-exp-code info 
type))
@@ -357,9 +360,12 @@ replaced with its value."
   (org-fill-template
    (if (eq type 'inline)
        org-babel-exp-inline-code-template
-       org-babel-exp-code-template)
+     org-babel-exp-code-template)
    `(("lang"  . ,(nth 0 info))
-     ("body"  . ,(org-escape-code-in-string (nth 1 info)))
+     ;; Inline source code should not be escaped.
+     ("body"  . ,(let ((body (nth 1 info)))
+                   (if (eq type 'inline) body
+                     (org-escape-code-in-string body))))
      ("switches" . ,(let ((f (nth 3 info)))
                      (and (org-string-nw-p f) (concat " " f))))
      ("flags" . ,(let ((f (assq :flags (nth 2 info))))
@@ -390,10 +396,10 @@ inhibit insertion of results into the buffer."
        (setf (nth 1 info) body)
        (setf (nth 2 info)
              (org-babel-exp--at-source
-               (org-babel-process-params
-                (org-babel-merge-params
-                 (nth 2 info)
-                 `((:results . ,(if silent "silent" "replace")))))))
+                 (org-babel-process-params
+                  (org-babel-merge-params
+                   (nth 2 info)
+                   `((:results . ,(if silent "silent" "replace")))))))
        (pcase type
          (`block (org-babel-execute-src-block nil info))
          (`inline
diff --git a/lisp/org/ob-forth.el b/lisp/org/ob-forth.el
index 3b521bc4d9..74dbc02170 100644
--- a/lisp/org/ob-forth.el
+++ b/lisp/org/ob-forth.el
@@ -75,8 +75,8 @@ This function is called by `org-babel-execute-src-block'."
                   ((string= "\n:" case)
                    ;; Report errors.
                    (org-babel-eval-error-notify 1
-                    (buffer-substring
-                     (+ (match-beginning 0) 1) (point-max)))
+                                                (buffer-substring
+                                                 (+ (match-beginning 0) 1) 
(point-max)))
                    nil))))
              (split-string (org-trim
                             (org-babel-expand-body:generic body params))
diff --git a/lisp/org/ob-fortran.el b/lisp/org/ob-fortran.el
index 99afa0d963..2e55498003 100644
--- a/lisp/org/ob-fortran.el
+++ b/lisp/org/ob-fortran.el
@@ -40,9 +40,11 @@
 
 (defvar org-babel-default-header-args:fortran '())
 
-(defvar org-babel-fortran-compiler "gfortran"
-  "fortran command used to compile a fortran source code file into an
-  executable.")
+(defcustom org-babel-fortran-compiler "gfortran"
+  "Fortran command used to compile Fortran source code file."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type  'string)
 
 (defun org-babel-execute:fortran (body params)
   "This function should only be called by `org-babel-execute:fortran'."
@@ -155,7 +157,7 @@ of the same value."
       (format "real, parameter :: %S(%d) = %s\n"
              var (length val) (org-babel-fortran-transform-list val)))
      (t
-      (error "the type of parameter %s is not supported by ob-fortran" var)))))
+      (error "The type of parameter %s is not supported by ob-fortran" var)))))
 
 (defun org-babel-fortran-transform-list (val)
   "Return a fortran representation of enclose syntactic lists."
diff --git a/lisp/org/ob-gnuplot.el b/lisp/org/ob-gnuplot.el
index 6489c23f57..8c4a5957b9 100644
--- a/lisp/org/ob-gnuplot.el
+++ b/lisp/org/ob-gnuplot.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Ihor Radchenko <yantar92@gmail.com>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -33,7 +34,7 @@
 
 ;;; Requirements:
 
-;; - gnuplot :: http://www.gnuplot.info/
+;; - gnuplot :: https://www.gnuplot.info/
 ;;
 ;; - gnuplot-mode :: you can search the web for the latest active one.
 
@@ -47,6 +48,8 @@
 (declare-function gnuplot-send-string-to-gnuplot "ext:gnuplot-mode" (str txt))
 (declare-function gnuplot-send-buffer-to-gnuplot "ext:gnuplot-mode" ())
 
+(defvar org-babel-temporary-directory)
+
 (defvar org-babel-default-header-args:gnuplot
   '((:results . "file") (:exports . "results") (:session . nil))
   "Default arguments to use when evaluating a gnuplot source block.")
@@ -85,14 +88,29 @@ code."
        (cons
        (car pair) ;; variable name
        (let* ((val (cdr pair)) ;; variable value
-              (lp  (listp val)))
+              (lp  (proper-list-p val)))
          (if lp
              (org-babel-gnuplot-table-to-data
               (let* ((first  (car val))
                      (tablep (or (listp first) (symbolp first))))
                 (if tablep val (mapcar 'list val)))
               (org-babel-temp-file "gnuplot-") params)
-         val))))
+           (if (and (stringp val)
+                    (file-remote-p val)  ;; check if val is a remote file
+                    (file-exists-p val)) ;; call to file-exists-p is slow, 
maybe remove it
+               (let* ((local-name (concat ;; create a unique filename to avoid 
multiple downloads
+                                   org-babel-temporary-directory
+                                   "/gnuplot/"
+                                   (file-remote-p val 'host)
+                                   (org-babel-local-file-name val))))
+                 (if (and (file-exists-p local-name) ;; only download file if 
remote is newer
+                          (file-newer-than-file-p local-name val))
+                     local-name
+                   (make-directory (file-name-directory local-name) t)
+                   (copy-file val local-name t)
+                   ))
+             val
+             )))))
      (org-babel--get-vars params))))
 
 (defun org-babel-expand-body:gnuplot (body params)
@@ -272,7 +290,7 @@ Pass PARAMS through to `orgtbl-to-generic' when exporting 
TABLE."
              (orgtbl-to-generic
               table
               (org-combine-plists
-               '(:sep "\t" :fmt org-babel-gnuplot-quote-tsv-field)
+               '(:sep "\t" :fmt org-babel-gnuplot-quote-tsv-field :raw t 
:backend ascii)
                params)))))
   data-file)
 
diff --git a/lisp/org/ob-groovy.el b/lisp/org/ob-groovy.el
index fa847dd0a2..b3ff34aac3 100644
--- a/lisp/org/ob-groovy.el
+++ b/lisp/org/ob-groovy.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
 
 ;; Author: Miro Bezjak
+;; Maintainer: Palak Mathur
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -25,7 +26,7 @@
 ;; Currently only supports the external execution.  No session support yet.
 
 ;;; Requirements:
-;; - Groovy language :: http://groovy.codehaus.org
+;; - Groovy language :: https://groovy-lang.org
 ;; - Groovy major mode :: Can be installed from MELPA or
 ;;   https://github.com/russel/Emacs-Groovy-Mode
 
diff --git a/lisp/org/ob-haskell.el b/lisp/org/ob-haskell.el
index d7ac1b04b3..971e1ce6af 100644
--- a/lisp/org/ob-haskell.el
+++ b/lisp/org/ob-haskell.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Lawrence Bottorff <borgauf@gmail.com>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -33,9 +34,9 @@
 
 ;;; Requirements:
 
-;; - haskell-mode: http://www.iro.umontreal.ca/~monnier/elisp/#haskell-mode
-;; - inf-haskell: http://www.iro.umontreal.ca/~monnier/elisp/#haskell-mode
-;; - (optionally) lhs2tex: http://people.cs.uu.nl/andres/lhs2tex/
+;; - haskell-mode: https://www.iro.umontreal.ca/~monnier/elisp/#haskell-mode
+;; - inf-haskell: https://www.iro.umontreal.ca/~monnier/elisp/#haskell-mode
+;; - (optionally) lhs2tex: https://people.cs.uu.nl/andres/lhs2tex/
 
 ;;; Code:
 (require 'ob)
@@ -69,11 +70,11 @@ a parameter, such as \"ghc -v\"."
   :package-version '(Org "9.4")
   :type 'string)
 
-(defconst org-babel-header-args:haskell '(compile . :any)
+(defconst org-babel-header-args:haskell '((compile . :any))
   "Haskell-specific header arguments.")
 
 (defun org-babel-haskell-execute (body params)
-  "This function should only be called by `org-babel-execute:haskell'"
+  "This function should only be called by `org-babel-execute:haskell'."
   (let* ((tmp-src-file (org-babel-temp-file "Haskell-src-" ".hs"))
          (tmp-bin-file
           (org-babel-process-file-name
diff --git a/lisp/org/ob-hledger.el b/lisp/org/ob-hledger.el
deleted file mode 100644
index 48dcb8cea1..0000000000
--- a/lisp/org/ob-hledger.el
+++ /dev/null
@@ -1,69 +0,0 @@
-;;; ob-hledger.el --- Babel Functions for hledger      -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Author: Simon Michael
-;; Keywords: literate programming, reproducible research, plain text accounting
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Babel support for evaluating hledger entries.
-;;
-;; Based on ob-ledger.el.
-;; If the source block is empty, hledger will use a default journal file,
-;; probably ~/.hledger.journal (it may not notice your $LEDGER_FILE env var).
-;; So make ~/.hledger.journal a symbolic link to the real file if necessary.
-
-;; TODO Unit tests are more than welcome, too.
-
-;;; Code:
-(require 'ob)
-
-(defvar org-babel-default-header-args:hledger
-  '((:results . "output") (:exports . "results") (:cmdline . "bal"))
-  "Default arguments to use when evaluating a hledger source block.")
-
-(defun org-babel-execute:hledger (body params)
-  "Execute a block of hledger entries with org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (message "executing hledger source code block")
-  (letrec ( ;(result-params (split-string (or (cdr (assq :results params)) 
"")))
-          (cmdline (cdr (assq :cmdline params)))
-          (in-file (org-babel-temp-file "hledger-"))
-          (out-file (org-babel-temp-file "hledger-output-"))
-          (hledgercmd (concat "hledger"
-                              (if (> (length body) 0)
-                                  (concat " -f " (org-babel-process-file-name 
in-file))
-                                "")
-                              " " cmdline)))
-    (with-temp-file in-file (insert body))
-;; TODO This is calling for some refactoring:
-;;  (concat "hledger" (if ...) " " cmdline)
-;; could be built only once and bound to a symbol.
-    (message "%s" hledgercmd)
-    (with-output-to-string
-      (shell-command (concat hledgercmd " > " (org-babel-process-file-name 
out-file))))
-    (with-temp-buffer (insert-file-contents out-file) (buffer-string))))
-
-(defun org-babel-prep-session:hledger (_session _params)
-  (error "hledger does not support sessions"))
-
-(provide 'ob-hledger)
-
-;;; ob-hledger.el ends here
diff --git a/lisp/org/ob-io.el b/lisp/org/ob-io.el
deleted file mode 100644
index 63d2b6cf35..0000000000
--- a/lisp/org/ob-io.el
+++ /dev/null
@@ -1,105 +0,0 @@
-;;; ob-io.el --- Babel Functions for Io              -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
-
-;; Author: Andrzej Lichnerowicz
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;; Currently only supports the external execution.  No session support yet.
-;; :results output -- runs in scripting mode
-;; :results output repl -- runs in repl mode
-
-;;; Requirements:
-;; - Io language :: http://iolanguage.org/
-;; - Io major mode :: Can be installed from Io sources
-;;  
https://github.com/stevedekorte/io/blob/master/extras/SyntaxHighlighters/Emacs/io-mode.el
-
-;;; Code:
-(require 'ob)
-
-(defvar org-babel-tangle-lang-exts) ;; Autoloaded
-(add-to-list 'org-babel-tangle-lang-exts '("io" . "io"))
-(defvar org-babel-default-header-args:io '())
-(defvar org-babel-io-command "io"
-  "Name of the command to use for executing Io code.")
-
-(defun org-babel-execute:io (body params)
-  "Execute a block of Io code with org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (message "executing Io source code block")
-  (let* ((processed-params (org-babel-process-params params))
-         (session (org-babel-io-initiate-session (nth 0 processed-params)))
-         (result-params (nth 2 processed-params))
-         (result-type (cdr (assq :result-type params)))
-         (full-body (org-babel-expand-body:generic
-                     body params))
-         (result (org-babel-io-evaluate
-                  session full-body result-type result-params)))
-
-    (org-babel-reassemble-table
-     result
-     (org-babel-pick-name
-      (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
-     (org-babel-pick-name
-      (cdr (assq :rowname-names params)) (cdr (assq :rownames params))))))
-
-(defvar org-babel-io-wrapper-method
-  "(
-%s
-) asString print
-")
-
-
-(defun org-babel-io-evaluate (session body &optional result-type result-params)
-  "Evaluate BODY in external Io process.
-If RESULT-TYPE equals `output' then return standard output as a string.
-If RESULT-TYPE equals `value' then return the value of the last statement
-in BODY as elisp."
-  (when session (error "Sessions are not (yet) supported for Io"))
-  (pcase result-type
-    (`output
-     (if (member "repl" result-params)
-         (org-babel-eval org-babel-io-command body)
-       (let ((src-file (org-babel-temp-file "io-")))
-         (progn (with-temp-file src-file (insert body))
-                (org-babel-eval
-                 (concat org-babel-io-command " " src-file) "")))))
-    (`value (let* ((src-file (org-babel-temp-file "io-"))
-                  (wrapper (format org-babel-io-wrapper-method body)))
-             (with-temp-file src-file (insert wrapper))
-             (let ((raw (org-babel-eval
-                         (concat org-babel-io-command " " src-file) "")))
-               (org-babel-result-cond result-params
-                 raw
-                 (org-babel-script-escape raw)))))))
-
-(defun org-babel-prep-session:io (_session _params)
-  "Prepare SESSION according to the header arguments specified in PARAMS."
-  (error "Sessions are not (yet) supported for Io"))
-
-(defun org-babel-io-initiate-session (&optional _session)
-  "If there is not a current inferior-process-buffer in SESSION
-then create.  Return the initialized session.  Sessions are not
-supported in Io."
-  nil)
-
-(provide 'ob-io)
-
-;;; ob-io.el ends here
diff --git a/lisp/org/ob-java.el b/lisp/org/ob-java.el
index b1d517e94a..dd3538743d 100644
--- a/lisp/org/ob-java.el
+++ b/lisp/org/ob-java.el
@@ -1,8 +1,10 @@
-;;; ob-java.el --- Babel Functions for Java          -*- lexical-binding: t; 
-*-
+;;; ob-java.el --- org-babel functions for java evaluation -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-;; Author: Eric Schulte
+;; Authors: Eric Schulte
+;;          Dan Davison
+;; Maintainer: Ian Martins <ianxm@jhu.edu>
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -23,8 +25,7 @@
 
 ;;; Commentary:
 
-;; Currently this only supports the external compilation and execution
-;; of java code blocks (i.e., no session support).
+;; Org-Babel support for evaluating java source code.
 
 ;;; Code:
 (require 'ob)
@@ -32,52 +33,457 @@
 (defvar org-babel-tangle-lang-exts)
 (add-to-list 'org-babel-tangle-lang-exts '("java" . "java"))
 
+(defvar org-babel-temporary-directory) ; from ob-core
+
+(defvar org-babel-default-header-args:java '((:results . "output")
+                                            (:dir . "."))
+  "Default header args for java source blocks.
+The docs say functional mode should be the default [1], but
+ob-java didn't originally support functional mode, so we keep
+scripting mode as the default for now to maintain previous
+behavior.
+
+Most languages write tempfiles to babel's temporary directory,
+but ob-java originally had to write them to the current
+directory, so we keep that as the default behavior.
+
+[1] https://orgmode.org/manual/Results-of-Evaluation.html";)
+
+(defconst org-babel-header-args:java '((imports . :any))
+  "Java-specific header arguments.")
+
 (defcustom org-babel-java-command "java"
   "Name of the java command.
-May be either a command in the path, like java
-or an absolute path name, like /usr/local/bin/java
-parameters may be used, like java -verbose"
+May be either a command in the path, like java or an absolute
+path name, like /usr/local/bin/java.  Parameters may be used,
+like java -verbose."
   :group 'org-babel
-  :version "24.3"
+  :package-version '(Org . "9.5")
   :type 'string)
 
 (defcustom org-babel-java-compiler "javac"
   "Name of the java compiler.
-May be either a command in the path, like javac
-or an absolute path name, like /usr/local/bin/javac
-parameters may be used, like javac -verbose"
+May be either a command in the path, like javac or an absolute
+path name, like /usr/local/bin/javac.  Parameters may be used,
+like javac -verbose."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'string)
+
+(defcustom org-babel-java-hline-to "null"
+  "Replace hlines in incoming tables with this when translating to java."
   :group 'org-babel
-  :version "24.3"
+  :package-version '(Org . "9.5")
   :type 'string)
 
+(defcustom org-babel-java-null-to 'hline
+  "Replace `null' in java tables with this before returning."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'symbol)
+
+(defconst org-babel-java--package-re (rx line-start (0+ space) "package"
+                                        (1+ space) (group (1+ (in alnum ?_ 
?.))) ; capture the package name
+                                        (0+ space) ?\; line-end)
+  "Regexp for the package statement.")
+(defconst org-babel-java--imports-re (rx line-start (0+ space) "import"
+                                         (opt (1+ space) "static")
+                                        (1+ space) (group (1+ (in alnum ?_ ?. 
?*))) ; capture the fully qualified class name
+                                        (0+ space) ?\; line-end)
+  "Regexp for import statements.")
+(defconst org-babel-java--class-re (rx line-start (0+ space) (opt (seq 
"public" (1+ space)))
+                                      "class" (1+ space)
+                                      (group (1+ (in alnum ?_))) ; capture the 
class name
+                                      (0+ space) ?{)
+  "Regexp for the class declaration.")
+(defconst org-babel-java--main-re
+  (rx line-start (0+ space) "public"
+      (1+ space) "static"
+      (1+ space) "void"
+      (1+ space) "main"
+      (0+ space) ?\(
+      (0+ space) "String"
+      (1+ (in alnum ?_ ?\[ ?\] space)) ; "[] args" or "args[]"
+      ?\)
+      (0+ space) (opt "throws" (1+ (in alnum ?_ ?, ?. space)))
+      ?{)
+  "Regexp for the main method declaration.")
+(defconst org-babel-java--any-method-re
+  (rx line-start
+      (0+ space) (opt (seq (1+ alnum) (1+ space)))   ; visibility
+      (opt (seq "static" (1+ space)))                ; binding
+      (1+ (in alnum ?_ ?\[ ?\]))                     ; return type
+      (1+ space) (1+ (in alnum ?_))                  ; method name
+      (0+ space) ?\(
+      (0+ (in alnum ?_ ?\[ ?\] ?, space)) ; params
+      ?\)
+      (0+ space) (opt "throws" (1+ (in alnum ?_ ?, ?. space)))
+      ?{)
+  "Regexp for any method.")
+(defconst org-babel-java--result-wrapper "\n    public static String 
__toString(Object val) {
+        if (val instanceof String) {
+            return \"\\\"\" + val + \"\\\"\";
+        } else if (val == null) {
+            return \"null\";
+        } else if (val.getClass().isArray()) {
+            StringBuffer sb = new StringBuffer();
+            Object[] vals = (Object[])val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.length; ii++) {
+                sb.append(__toString(vals[ii]));
+                if (ii<vals.length-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else if (val instanceof List) {
+            StringBuffer sb = new StringBuffer();
+            List vals = (List)val;
+            sb.append(\"[\");
+            for (int ii=0; ii<vals.size(); ii++) {
+                sb.append(__toString(vals.get(ii)));
+                if (ii<vals.size()-1)
+                    sb.append(\",\");
+            }
+            sb.append(\"]\");
+            return sb.toString();
+        } else {
+            return String.valueOf(val);
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        BufferedWriter output = new BufferedWriter(new FileWriter(\"%s\"));
+        output.write(__toString(_main(args)));
+        output.close();
+    }"
+  "Code to inject into a class so that we can capture the value it returns.
+This implementation was inspired by ob-python, although not as
+elegant.  This modified the source block to write out the value
+it wants to return to a temporary file so that ob-java can read
+it back.  The name of the temporary file to write must be
+replaced in this string.")
+
 (defun org-babel-execute:java (body params)
-  (let* ((classname (or (cdr (assq :classname params))
-                       (error
-                        "Can't compile a java block without a classname")))
-        (packagename (file-name-directory classname))
-        (src-file (concat classname ".java"))
-        (cmpflag (or (cdr (assq :cmpflag params)) ""))
-        (cmdline (or (cdr (assq :cmdline params)) ""))
-        (cmdargs (or (cdr (assq :cmdargs params)) ""))
-        (full-body (org-babel-expand-body:generic body params)))
-    (with-temp-file src-file (insert full-body))
-    (org-babel-eval
-     (concat org-babel-java-compiler " " cmpflag " " src-file) "")
+  "Execute a java source block with BODY code and PARAMS params."
+  (let* (;; allow header overrides
+         (org-babel-java-compiler
+          (or (cdr (assq :javac params))
+              org-babel-java-compiler))
+         (org-babel-java-command
+          (or (cdr (assq :java params))
+              org-babel-java-command))
+         ;; if true, run from babel temp directory
+         (run-from-temp (not (cdr (assq :dir params))))
+         ;; class and package
+         (fullclassname (or (cdr (assq :classname params))
+                            (org-babel-java-find-classname body)))
+         ;; just the class name
+         (classname (car (last (split-string fullclassname "\\."))))
+         ;; just the package name
+         (packagename (if (string-match-p "\\." fullclassname)
+                          (file-name-base fullclassname)))
+         ;; the base dir that contains the top level package dir
+         (basedir (file-name-as-directory (if run-from-temp
+                                              (if (file-remote-p 
default-directory)
+                                                  (concat
+                                                   (file-remote-p 
default-directory)
+                                                   
org-babel-remote-temporary-directory)
+                                                org-babel-temporary-directory)
+                                            default-directory)))
+         ;; the dir to write the source file
+         (packagedir (if (and (not run-from-temp) packagename)
+                         (file-name-as-directory
+                          (concat basedir (replace-regexp-in-string "\\." "/" 
packagename)))
+                       basedir))
+         ;; the filename of the source file
+         (src-file (concat packagedir classname ".java"))
+         ;; compiler flags
+         (cmpflag (or (cdr (assq :cmpflag params)) ""))
+         ;; runtime flags
+         (cmdline (or (cdr (assq :cmdline params)) ""))
+         ;; command line args
+         (cmdargs (or (cdr (assq :cmdargs params)) ""))
+         ;; the command to compile and run
+         (cmd (concat org-babel-java-compiler " " cmpflag " "
+                      (org-babel-process-file-name src-file 'noquote)
+                      " && " org-babel-java-command
+                      " -cp " (org-babel-process-file-name basedir 'noquote)
+                      " " cmdline " " (if run-from-temp classname 
fullclassname)
+                      " " cmdargs))
+         ;; header args for result processing
+         (result-type (cdr (assq :result-type params)))
+         (result-params (cdr (assq :result-params params)))
+         (result-file (and (eq result-type 'value)
+                           (org-babel-temp-file "java-")))
+         ;; the expanded body of the source block
+         (full-body (org-babel-expand-body:java body params)))
+
     ;; created package-name directories if missing
-    (unless (or (not packagename) (file-exists-p packagename))
-      (make-directory packagename 'parents))
-    (let ((results (org-babel-eval (concat org-babel-java-command
-                                           " " cmdline " " classname " " 
cmdargs) "")))
-      (org-babel-reassemble-table
-       (org-babel-result-cond (cdr (assq :result-params params))
-        (org-babel-read results t)
-         (let ((tmp-file (org-babel-temp-file "c-")))
-           (with-temp-file tmp-file (insert results))
-           (org-babel-import-elisp-from-file tmp-file)))
-       (org-babel-pick-name
-        (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
-       (org-babel-pick-name
-        (cdr (assq :rowname-names params)) (cdr (assq :rownames params)))))))
+    (unless (or (not packagedir) (file-exists-p packagedir))
+      (make-directory packagedir 'parents))
+
+    ;; write the source file
+    (setq full-body (org-babel-java--expand-for-evaluation
+                     full-body run-from-temp result-type result-file))
+    (with-temp-file src-file (insert full-body))
+
+    ;; compile, run, process result
+    (org-babel-reassemble-table
+     (org-babel-java-evaluate cmd result-type result-params result-file)
+     (org-babel-pick-name
+      (cdr (assoc :colname-names params)) (cdr (assoc :colnames params)))
+     (org-babel-pick-name
+      (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params))))))
+
+;; helper functions
+
+(defun org-babel-java-find-classname (body)
+  "Try to find fully qualified class name in BODY.
+Look through BODY for the package and class.  If found, put them
+together into a fully qualified class name and return.  Else just
+return class name.  If that isn't found either, default to Main."
+  (let ((package (if (string-match org-babel-java--package-re body)
+                     (match-string 1 body)))
+        (class (if (string-match org-babel-java--class-re body)
+                   (match-string 1 body))))
+    (or (and package class (concat package "." class))
+        (and class class)
+        (and package (concat package ".Main"))
+        "Main")))
+
+(defun org-babel-java--expand-for-evaluation (body suppress-package-p 
result-type result-file)
+  "Expand source block for evaluation.
+In order to return a value we have to add a __toString method.
+In order to prevent classes without main methods from erroring we
+add a dummy main method if one is not provided.  These
+manipulations are done outside of `org-babel--expand-body' so
+that they are hidden from tangles.
+
+BODY is the file content before instrumentation.
+
+SUPPRESS-PACKAGE-P if true, suppress the package statement.
+
+RESULT-TYPE is taken from params.
+
+RESULT-FILE is the temp file to write the result."
+  (with-temp-buffer
+    (insert body)
+
+    ;; suppress package statement
+    (goto-char (point-min))
+    (when (and suppress-package-p
+               (re-search-forward org-babel-java--package-re nil t))
+      (replace-match ""))
+
+    ;; add a dummy main method if needed
+    (goto-char (point-min))
+    (when (not (re-search-forward org-babel-java--main-re nil t))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert "\n    public static void main(String[] args) {
+        System.out.print(\"success\");
+    }\n\n"))
+
+    ;; special handling to return value
+    (when (eq result-type 'value)
+      (goto-char (point-min))
+      (org-babel-java--move-past org-babel-java--class-re)
+      (insert (format org-babel-java--result-wrapper
+                      (org-babel-process-file-name result-file 'noquote)))
+      (search-forward "public static void main(") ; rename existing main
+      (replace-match "public static Object _main("))
+
+    ;; add imports
+    (org-babel-java--import-maybe "java.util" "List")
+    (org-babel-java--import-maybe "java.util" "Arrays")
+    (org-babel-java--import-maybe "java.io" "BufferedWriter")
+    (org-babel-java--import-maybe "java.io" "FileWriter")
+    (org-babel-java--import-maybe "java.io" "IOException")
+
+    (buffer-string)))
+
+(defun org-babel-java--move-past (re)
+  "Move point past the first occurrence of the given regexp RE."
+  (while (re-search-forward re nil t)
+    (goto-char (1+ (match-end 0)))))
+
+(defun org-babel-java--import-maybe (package class)
+  "Import from PACKAGE the given CLASS if it is used and not already imported."
+  (let (class-found import-found)
+    (goto-char (point-min))
+    (setq class-found (re-search-forward class nil t))
+    (goto-char (point-min))
+    (setq import-found
+          (re-search-forward (concat "^import .*" package ".*\\(?:\\*\\|" 
class "\\);") nil t))
+    (when (and class-found (not import-found))
+      (org-babel-java--move-past org-babel-java--package-re)
+      (insert (concat "import " package "." class ";\n")))))
+
+(defun org-babel-expand-body:java (body params)
+  "Expand BODY with PARAMS.
+BODY could be a few statements, or could include a full class
+definition specifying package, imports, and class.  Because we
+allow this flexibility in what the source block can contain, it
+is simplest to expand the code block from the inside out."
+  (let* ((fullclassname (or (cdr (assq :classname params)) ; class and package
+                            (org-babel-java-find-classname body)))
+         (classname (car (last (split-string fullclassname "\\.")))) ; just 
class name
+         (packagename (if (string-match-p "\\." fullclassname)       ; just 
package name
+                          (file-name-base fullclassname)))
+         (var-lines (org-babel-variable-assignments:java params))
+         (imports-val (assq :imports params))
+         (imports (if imports-val
+                      (split-string (org-babel-read (cdr imports-val) nil) " ")
+                    nil)))
+    (with-temp-buffer
+      (insert body)
+
+      ;; wrap main.  If there are methods defined, but no main method
+      ;; and no class, wrap everything in a generic main method.
+      (goto-char (point-min))
+      (when (and (not (re-search-forward org-babel-java--main-re nil t))
+                 (not (re-search-forward org-babel-java--any-method-re nil t)))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is 
defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports 
are defined, move past them
+        (insert "public static void main(String[] args) {\n")
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+
+      ;; wrap class.  If there's no class, wrap everything in a
+      ;; generic class.
+      (goto-char (point-min))
+      (when (not (re-search-forward org-babel-java--class-re nil t))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is 
defined, move past it
+        (org-babel-java--move-past org-babel-java--imports-re) ; if imports 
are defined, move past them
+        (insert (concat "\npublic class " (file-name-base classname) " {\n"))
+        (indent-code-rigidly (point) (point-max) 4)
+        (goto-char (point-max))
+        (insert "\n}"))
+      (goto-char (point-min))
+
+      ;; insert variables from source block headers
+      (when var-lines
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--class-re)   ; move inside 
class
+        (insert (mapconcat 'identity var-lines "\n"))
+        (insert "\n"))
+
+      ;; add imports from source block headers
+      (when imports
+        (goto-char (point-min))
+        (org-babel-java--move-past org-babel-java--package-re) ; if package is 
defined, move past it
+        (insert (mapconcat (lambda (package) (concat "import " package ";")) 
imports "\n") "\n"))
+
+      ;; add package at the top
+      (goto-char (point-min))
+      (when (and packagename (not (re-search-forward 
org-babel-java--package-re nil t)))
+        (insert (concat "package " packagename ";\n")))
+
+      ;; return expanded body
+      (buffer-string))))
+
+(defun org-babel-variable-assignments:java (params)
+  "Return a list of java statements assigning the block's variables.
+variables are contained in PARAMS."
+  (mapcar
+   (lambda (pair)
+     (let* ((type-data (org-babel-java-val-to-type (cdr pair)))
+            (basetype (car type-data))
+            (var-to-java (lambda (var) (funcall #'org-babel-java-var-to-java 
var basetype))))
+       (format "    static %s %s = %s;"
+               (cdr type-data)                     ; type
+               (car pair)                          ; name
+               (funcall var-to-java (cdr pair))))) ; value
+   (org-babel--get-vars params)))
+
+(defun org-babel-java-var-to-java (var basetype)
+  "Convert an elisp value to a java variable.
+Convert an elisp value, VAR, of type BASETYPE into a string of
+java source code specifying a variable of the same value."
+  (cond ((and (sequencep var) (not (stringp var)))
+         (let ((var-to-java (lambda (var) (funcall 
#'org-babel-java-var-to-java var basetype))))
+           (concat "Arrays.asList(" (mapconcat var-to-java var ", ") ")")))
+        ((eq var 'hline) org-babel-java-hline-to)
+        ((eq basetype 'integerp) (format "%d" var))
+        ((eq basetype 'floatp) (format "%f" var))
+        ((eq basetype 'stringp) (if (and (stringp var) (string-match-p ".\n+." 
var))
+                                    (error "Java does not support multiline 
string literals")
+                                  (format "\"%s\"" var)))))
+
+(defun org-babel-java-val-to-type (val)
+  "Determine the type of VAL.
+Return (BASETYPE . LISTTYPE), where BASETYPE is a symbol
+representing the type of the individual items in VAL, and
+LISTTYPE is a string name of the type parameter for a container
+for BASETYPE items."
+  (let* ((basetype (org-babel-java-val-to-base-type val))
+         (basetype-str (pcase basetype
+                         (`integerp "Integer")
+                         (`floatp "Double")
+                         (`stringp "String")
+                         (_ (error "Unknown type %S" basetype)))))
+    (cond
+     ((and (listp val) (listp (car val))) ; a table
+      (cons basetype (format "List<List<%s>>" basetype-str)))
+     ((or (listp val) (vectorp val))      ; a list declared in the source 
block header
+      (cons basetype (format "List<%s>" basetype-str)))
+     (t                                   ; return base type
+      (cons basetype basetype-str)))))
+
+(defun org-babel-java-val-to-base-type (val)
+  "Determine the base type of VAL.
+VAL may be
+`integerp' if all base values are integers
+`floatp' if all base values are either floating points or integers
+`stringp' otherwise."
+  (cond
+   ((integerp val) 'integerp)
+   ((floatp val) 'floatp)
+   ((or (listp val) (vectorp val))
+    (let ((type nil))
+      (mapc (lambda (v)
+              (pcase (org-babel-java-val-to-base-type v)
+                (`stringp (setq type 'stringp))
+                (`floatp
+                 (when (or (not type) (eq type 'integerp))
+                   (setq type 'floatp)))
+                (`integerp
+                 (unless type (setq type 'integerp)))))
+            val)
+      type))
+   (t 'stringp)))
+
+(defun org-babel-java-table-or-string (results)
+  "Convert RESULTS into an appropriate elisp value.
+If the results look like a list or vector, then convert them into an
+Emacs-lisp table, otherwise return the results as a string."
+  (let ((res (org-babel-script-escape results)))
+    (if (listp res)
+        (mapcar (lambda (el) (if (eq 'null el)
+                                 org-babel-java-null-to
+                               el))
+                res)
+      res)))
+
+(defun org-babel-java-evaluate (cmd result-type result-params result-file)
+  "Evaluate using an external java process.
+CMD the command to execute.
+
+If RESULT-TYPE equals `output' then return standard output as a
+string.  If RESULT-TYPE equals `value' then return the value
+returned by the source block, as elisp.
+
+RESULT-PARAMS input params used to format the response.
+
+RESULT-FILE filename of the tempfile to store the returned value in
+for `value' RESULT-TYPE.  Not used for `output' RESULT-TYPE."
+  (let ((raw (pcase result-type
+               (`output (org-babel-eval cmd ""))
+               (`value (org-babel-eval cmd "")
+                       (org-babel-eval-read-file result-file)))))
+    (org-babel-result-cond result-params raw
+                           (org-babel-java-table-or-string raw))))
 
 (provide 'ob-java)
 
diff --git a/lisp/org/ob-js.el b/lisp/org/ob-js.el
index b2a971e2a5..5d1be61176 100644
--- a/lisp/org/ob-js.el
+++ b/lisp/org/ob-js.el
@@ -158,8 +158,8 @@ specifying a variable of the same value."
    (org-babel--get-vars params)))
 
 (defun org-babel-js-initiate-session (&optional session _params)
-  "If there is not a current inferior-process-buffer in `SESSION'
-then create.  Return the initialized session."
+  "If there is not a current inferior-process-buffer in `SESSION' then create.
+Return the initialized session."
   (cond
    ((string= session "none")
     (warn "Session evaluation of ob-js is not supported"))
diff --git a/lisp/org/ob-julia.el b/lisp/org/ob-julia.el
new file mode 100644
index 0000000000..4fae0d142b
--- /dev/null
+++ b/lisp/org/ob-julia.el
@@ -0,0 +1,331 @@
+;;; ob-julia.el --- org-babel functions for julia code evaluation  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
+;; Authors: G. Jay Kerns, based on ob-R.el by Eric Schulte and Dan Davison
+;; Maintainer: Pedro Bruel <pedro.bruel@gmail.com>
+;; Keywords: literate programming, reproducible research, scientific computing
+;; Homepage: https://github.com/phrb/ob-julia
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Org-Babel support for evaluating julia code
+
+;;; Code:
+(require 'cl-lib)
+(require 'ob)
+
+(declare-function orgtbl-to-csv "org-table" (table params))
+(declare-function julia "ext:ess-julia" (&optional start-args))
+(declare-function inferior-ess-send-input "ext:ess-inf" ())
+(declare-function ess-make-buffer-current "ext:ess-inf" ())
+(declare-function ess-eval-buffer "ext:ess-inf" (vis))
+(declare-function ess-wait-for-process "ext:ess-inf"
+                 (&optional proc sec-prompt wait force-redisplay))
+
+(defvar org-babel-header-args:julia
+  '((width              . :any)
+    (horizontal                 . :any)
+    (results             . ((file list vector table scalar verbatim)
+                           (raw org html latex code pp wrap)
+                           (replace silent append prepend)
+                           (output value graphics))))
+  "Julia-specific header arguments.")
+
+(add-to-list 'org-babel-tangle-lang-exts '("julia" . "jl"))
+
+(defvar org-babel-default-header-args:julia '())
+
+(defcustom org-babel-julia-command "julia"
+  "Name of command to use for executing julia code."
+  :version "24.3"
+  :package-version '(Org . "8.0")
+  :group 'org-babel
+  :type 'string)
+
+(defvar ess-current-process-name) ; dynamically scoped
+(defvar ess-local-process-name)   ; dynamically scoped
+(defvar ess-eval-visibly-p)       ; dynamically scoped
+(defun org-babel-edit-prep:julia (info)
+  (let ((session (cdr (assq :session (nth 2 info)))))
+    (when (and session
+              (string-prefix-p "*"  session)
+              (string-suffix-p "*" session))
+      (org-babel-julia-initiate-session session nil))))
+
+(defun org-babel-expand-body:julia (body params &optional _graphics-file)
+  "Expand BODY according to PARAMS, return the expanded body."
+  (mapconcat #'identity
+            (append
+             (when (cdr (assq :prologue params))
+               (list (cdr (assq :prologue params))))
+             (org-babel-variable-assignments:julia params)
+             (list body)
+             (when (cdr (assq :epilogue params))
+               (list (cdr (assq :epilogue params)))))
+            "\n"))
+
+(defun org-babel-execute:julia (body params)
+  "Execute a block of julia code.
+This function is called by `org-babel-execute-src-block'."
+  (save-excursion
+    (let* ((result-params (cdr (assq :result-params params)))
+          (result-type (cdr (assq :result-type params)))
+           (session (org-babel-julia-initiate-session
+                    (cdr (assq :session params)) params))
+          (graphics-file (and (member "graphics" (assq :result-params params))
+                              (org-babel-graphical-output-file params)))
+          (colnames-p (unless graphics-file (cdr (assq :colnames params))))
+          (full-body (org-babel-expand-body:julia body params graphics-file))
+          (result
+           (org-babel-julia-evaluate
+            session full-body result-type result-params
+            (or (equal "yes" colnames-p)
+                (org-babel-pick-name
+                 (cdr (assq :colname-names params)) colnames-p)))))
+      (if graphics-file nil result))))
+
+(defun org-babel-normalize-newline (result)
+  (replace-regexp-in-string
+   "\\(\n\r?\\)\\{2,\\}"
+   "\n"
+   result))
+
+(defun org-babel-prep-session:julia (session params)
+  "Prepare SESSION according to the header arguments specified in PARAMS."
+  (let* ((session (org-babel-julia-initiate-session session params))
+        (var-lines (org-babel-variable-assignments:julia params)))
+    (org-babel-comint-in-buffer session
+      (mapc (lambda (var)
+              (end-of-line 1) (insert var) (comint-send-input nil t)
+              (org-babel-comint-wait-for-output session)) var-lines))
+    session))
+
+(defun org-babel-load-session:julia (session body params)
+  "Load BODY into SESSION."
+  (save-window-excursion
+    (let ((buffer (org-babel-prep-session:julia session params)))
+      (with-current-buffer buffer
+        (goto-char (process-mark (get-buffer-process (current-buffer))))
+        (insert (org-babel-chomp body)))
+      buffer)))
+
+;; helper functions
+
+(defun org-babel-variable-assignments:julia (params)
+  "Return list of julia statements assigning the block's variables."
+  (let ((vars (org-babel--get-vars params)))
+    (mapcar
+     (lambda (pair) (org-babel-julia-assign-elisp (car pair) (cdr pair)))
+     (mapcar
+      (lambda (i)
+       (cons (car (nth i vars))
+             (org-babel-reassemble-table
+              (cdr (nth i vars))
+              (cdr (nth i (cdr (assq :colname-names params))))
+              (cdr (nth i (cdr (assq :rowname-names params)))))))
+      (number-sequence 0 (1- (length vars)))))))
+
+(defun org-babel-julia-quote-csv-field (s)
+  "Quote field S for export to julia."
+  (if (stringp s)
+      (concat "\"" (mapconcat #'identity (split-string s "\"") "\"\"") "\"")
+    (format "%S" s)))
+
+(defun org-babel-julia-assign-elisp (name value)
+  "Construct julia code assigning the elisp VALUE to a variable named NAME."
+  (if (listp value)
+      (let* ((lengths (mapcar #'length (cl-remove-if-not #'sequencep value)))
+             (max (if lengths (apply #'max lengths) 0))
+             (min (if lengths (apply #'min lengths) 0)))
+        ;; Ensure VALUE has an orgtbl structure (depth of at least 2).
+        (unless (listp (car value)) (setq value (list value)))
+        (let ((file (orgtbl-to-csv value '(:fmt 
org-babel-julia-quote-csv-field))))
+          (if (= max min)
+              (format "%s = begin
+    using CSV
+    CSV.read(\"%s\")
+end" name file)
+            (format "%s = begin
+    using CSV
+    CSV.read(\"%s\")
+end"
+                    name file))))
+    (format "%s = %s" name (org-babel-julia-quote-csv-field value))))
+
+(defvar ess-ask-for-ess-directory) ; dynamically scoped
+(defun org-babel-julia-initiate-session (session params)
+  "If there is not a current julia process then create one."
+  (unless (string= session "none")
+    (let ((session (or session "*Julia*"))
+         (ess-ask-for-ess-directory
+          (and (bound-and-true-p ess-ask-for-ess-directory)
+                (not (cdr (assq :dir params))))))
+      (if (org-babel-comint-buffer-livep session)
+         session
+       ;; FIXME: Depending on `display-buffer-alist', (julia) may end up
+        ;; popping up a new frame which `save-window-excursion' won't be able
+        ;; to "undo", so we really should call a kind of
+        ;; `julia-no-select' instead so we don't need to undo any
+        ;; window-changes afterwards.
+       (save-window-excursion
+         (when (get-buffer session)
+           ;; Session buffer exists, but with dead process
+           (set-buffer session))
+          (require 'ess) (set-buffer (julia))
+         (rename-buffer
+          (if (bufferp session)
+              (buffer-name session)
+            (if (stringp session)
+                session
+              (buffer-name))))
+         (current-buffer))))))
+
+(defun org-babel-julia-graphical-output-file (params)
+  "Name of file to which julia should send graphical output."
+  (and (member "graphics" (cdr (assq :result-params params)))
+       (cdr (assq :file params))))
+
+(defconst org-babel-julia-eoe-indicator "print(\"org_babel_julia_eoe\")")
+(defconst org-babel-julia-eoe-output "org_babel_julia_eoe")
+
+(defconst org-babel-julia-write-object-command "begin
+    local p_ans = %s
+    local p_tmp_file = \"%s\"
+
+    try
+        using CSV, DataFrames
+
+        if typeof(p_ans) <: DataFrame
+           p_ans_df = p_ans
+        else
+            p_ans_df = DataFrame(:ans => p_ans)
+        end
+
+        CSV.write(p_tmp_file,
+                  p_ans_df,
+                  writeheader = %s,
+                  transform = (col, val) -> something(val, missing),
+                  missingstring = \"nil\",
+                  quotestrings = false)
+        p_ans
+    catch e
+        err_msg = \"Source block evaluation failed. $e\"
+        CSV.write(p_tmp_file,
+                  DataFrame(:ans => err_msg),
+                  writeheader = false,
+                  transform = (col, val) -> something(val, missing),
+                  missingstring = \"nil\",
+                  quotestrings = false)
+
+        err_msg
+    end
+end")
+
+(defun org-babel-julia-evaluate
+    (session body result-type result-params column-names-p)
+  "Evaluate julia code in BODY."
+  (if session
+      (org-babel-julia-evaluate-session
+       session body result-type result-params column-names-p)
+    (org-babel-julia-evaluate-external-process
+     body result-type result-params column-names-p)))
+
+(defun org-babel-julia-evaluate-external-process
+    (body result-type result-params column-names-p)
+  "Evaluate BODY in external julia process.
+If RESULT-TYPE equals 'output then return standard output as a
+string.  If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (cl-case result-type
+    (value
+     (let ((tmp-file (org-babel-temp-file "julia-")))
+       (org-babel-eval org-babel-julia-command
+                      (format org-babel-julia-write-object-command
+                              (format "begin %s end" body)
+                              (org-babel-process-file-name tmp-file 'noquote)
+                               (if column-names-p "true" "false")
+                               ))
+       (org-babel-julia-process-value-result
+       (org-babel-result-cond result-params
+         (with-temp-buffer
+           (insert-file-contents tmp-file)
+           (buffer-string))
+         (org-babel-import-elisp-from-file tmp-file '(4)))
+       column-names-p)))
+    (output (org-babel-eval org-babel-julia-command body))))
+
+(defun org-babel-julia-evaluate-session
+    (session body result-type result-params column-names-p)
+  "Evaluate BODY in SESSION.
+If RESULT-TYPE equals 'output then return standard output as a
+string.  If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+  (cl-case result-type
+    (value
+     (with-temp-buffer
+       (insert (org-babel-chomp body))
+       (let ((ess-local-process-name
+             (process-name (get-buffer-process session)))
+            (ess-eval-visibly-p nil))
+        (ess-eval-buffer nil)))
+     (let ((tmp-file (org-babel-temp-file "julia-")))
+       (org-babel-comint-eval-invisibly-and-wait-for-file
+       session tmp-file
+       (format org-babel-julia-write-object-command
+                "ans"
+               (org-babel-process-file-name tmp-file 'noquote)
+                (if column-names-p "true" "false")
+                ))
+       (org-babel-julia-process-value-result
+       (org-babel-result-cond result-params
+         (with-temp-buffer
+           (insert-file-contents tmp-file)
+           (buffer-string))
+         (org-babel-import-elisp-from-file tmp-file '(4)))
+       column-names-p)))
+    (output
+     (mapconcat
+      #'org-babel-chomp
+      (butlast
+       (delq nil
+            (mapcar
+             (lambda (line) (when (> (length line) 0) line))
+             (mapcar
+              (lambda (line) ;; cleanup extra prompts left in output
+                (if (string-match
+                     "^\\([>+.]\\([ ][>.+]\\)*[ ]\\)"
+                     (car (split-string line "\n")))
+                    (substring line (match-end 1))
+                  line))
+              (org-babel-comint-with-output (session 
org-babel-julia-eoe-output)
+                (insert (mapconcat #'org-babel-chomp
+                                   (list body org-babel-julia-eoe-indicator)
+                                   "\n"))
+                 (inferior-ess-send-input))))))
+      "\n"))))
+
+(defun org-babel-julia-process-value-result (result column-names-p)
+  "Julia-specific processing of return value.
+Insert hline if column names in output have been requested."
+  (if column-names-p
+      (cons (car result) (cons 'hline (cdr result)))
+    result))
+
+(provide 'ob-julia)
+
+;;; ob-julia.el ends here
diff --git a/lisp/org/ob-latex.el b/lisp/org/ob-latex.el
index 138f474952..7c65256976 100644
--- a/lisp/org/ob-latex.el
+++ b/lisp/org/ob-latex.el
@@ -66,7 +66,46 @@
   "LaTeX-specific header arguments.")
 
 (defcustom org-babel-latex-htlatex "htlatex"
-  "The htlatex command to enable conversion of latex to SVG or HTML."
+  "The htlatex command to enable conversion of LaTeX to SVG or HTML."
+  :group 'org-babel
+  :type 'string)
+
+(defcustom org-babel-latex-preamble
+  (lambda (_)
+    "\\documentclass[preview]{standalone}
+\\def\\pgfsysdriver{pgfsys-tex4ht.def}
+")
+  "Closure which evaluates at runtime to the LaTeX preamble.
+
+It takes 1 argument which is the parameters of the source block."
+  :group 'org-babel
+  :type 'function)
+
+(defcustom org-babel-latex-begin-env
+  (lambda (_)
+    "\\begin{document}")
+  "Function that evaluates to the begin part of the document environment.
+
+It takes 1 argument which is the parameters of the source block.
+This allows adding additional code that will be ignored when
+exporting the literal LaTeX source."
+  :group 'org-babel
+  :type 'function)
+
+(defcustom org-babel-latex-end-env
+  (lambda (_)
+    "\\end{document}")
+  "Closure which evaluates at runtime to the end part of the document 
environment.
+
+It takes 1 argument which is the parameters of the source block.
+This allows adding additional code that will be ignored when
+exporting the literal LaTeX source."
+  :group 'org-babel
+  :type 'function)
+
+(defcustom org-babel-latex-pdf-svg-process
+  "inkscape --pdf-poppler %f -T -l -o %O"
+  "Command to convert a PDF file to an SVG file."
   :group 'org-babel
   :type 'string)
 
@@ -112,14 +151,28 @@ This function is called by `org-babel-execute-src-block'."
           (let ((org-format-latex-header
                 (concat org-format-latex-header "\n"
                         (mapconcat #'identity headers "\n"))))
-          (org-create-formula-image
-            body out-file org-format-latex-options in-buffer)))
+           (org-create-formula-image
+             body out-file org-format-latex-options in-buffer)))
+        ((string= "svg" extension)
+         (with-temp-file tex-file
+           (insert (concat (funcall org-babel-latex-preamble params)
+                           (mapconcat #'identity headers "\n")
+                           (funcall org-babel-latex-begin-env params)
+                           body
+                           (funcall org-babel-latex-end-env params))))
+         (let ((tmp-pdf (org-babel-latex-tex-to-pdf tex-file)))
+            (let* ((log-buf (get-buffer-create "*Org Babel LaTeX Output*"))
+                   (err-msg "org babel latex failed")
+                   (img-out (org-compile-file
+                            tmp-pdf
+                             (list org-babel-latex-pdf-svg-process)
+                             extension err-msg log-buf)))
+              (shell-command (format "mv %s %s" img-out out-file)))))
          ((string-suffix-p ".tikz" out-file)
          (when (file-exists-p out-file) (delete-file out-file))
          (with-temp-file out-file
            (insert body)))
-        ((and (or (string= "svg" extension)
-                  (string= "html" extension))
+        ((and (string= "html" extension)
               (executable-find org-babel-latex-htlatex))
          ;; TODO: this is a very different way of generating the
          ;; frame latex document than in the pdf case.  Ideally, both
diff --git a/lisp/org/ob-ledger.el b/lisp/org/ob-ledger.el
deleted file mode 100644
index a117f854e4..0000000000
--- a/lisp/org/ob-ledger.el
+++ /dev/null
@@ -1,68 +0,0 @@
-;;; ob-ledger.el --- Babel Functions for Ledger      -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Author: Eric S Fraga
-;; Keywords: literate programming, reproducible research, accounting
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Org-Babel support for evaluating ledger entries.
-;;
-;; This differs from most standard languages in that
-;;
-;; 1) there is no such thing as a "session" in ledger
-;;
-;; 2) we are generally only going to return output from the ledger program
-;;
-;; 3) we are adding the "cmdline" header argument
-;;
-;; 4) there are no variables
-
-;;; Code:
-(require 'ob)
-
-(defvar org-babel-default-header-args:ledger
-  '((:results . "output") (:cmdline . "bal"))
-  "Default arguments to use when evaluating a ledger source block.")
-
-(defun org-babel-execute:ledger (body params)
-  "Execute a block of Ledger entries with org-babel.  This function is
-called by `org-babel-execute-src-block'."
-  (message "executing Ledger source code block")
-  (let ((cmdline (cdr (assq :cmdline params)))
-        (in-file (org-babel-temp-file "ledger-"))
-       (out-file (org-babel-temp-file "ledger-output-")))
-    (with-temp-file in-file (insert body))
-    (message "%s" (concat "ledger"
-                         " -f " (org-babel-process-file-name in-file)
-                         " " cmdline))
-    (with-output-to-string
-      (shell-command (concat "ledger"
-                            " -f " (org-babel-process-file-name in-file)
-                            " " cmdline
-                            " > " (org-babel-process-file-name out-file))))
-    (with-temp-buffer (insert-file-contents out-file) (buffer-string))))
-
-(defun org-babel-prep-session:ledger (_session _params)
-  (error "Ledger does not support sessions"))
-
-(provide 'ob-ledger)
-
-;;; ob-ledger.el ends here
diff --git a/lisp/org/ob-lilypond.el b/lisp/org/ob-lilypond.el
index 47397e6625..410d53ba60 100644
--- a/lisp/org/ob-lilypond.el
+++ b/lisp/org/ob-lilypond.el
@@ -27,9 +27,9 @@
 ;; https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-lilypond.html
 ;;
 ;; Lilypond documentation can be found at
-;; http://lilypond.org/manuals.html
+;; https://lilypond.org/manuals.html
 ;;
-;; This depends on epstopdf --- See http://www.ctan.org/pkg/epstopdf.
+;; This depends on epstopdf --- See https://www.ctan.org/pkg/epstopdf.
 
 ;;; Code:
 (require 'ob)
@@ -43,6 +43,15 @@
 (defvar org-babel-default-header-args:lilypond '()
   "Default header arguments for lilypond code blocks.
 NOTE: The arguments are determined at lilypond compile time.
+See `org-babel-lilypond-set-header-args'
+To configure, see `ob-lilypond-header-args'
+.")
+
+(defvar ob-lilypond-header-args
+  '((:results . "file") (:exports . "results"))
+  "User-configurable header arguments for lilypond code blocks.
+NOTE: The final value used by org-babel is computed at compile-time
+and stored in  `org-babel-default-header-args:lilypond'
 See `org-babel-lilypond-set-header-args'.")
 
 (defvar org-babel-lilypond-compile-post-tangle t
@@ -196,9 +205,9 @@ specific arguments to =org-babel-tangle=."
 If error in compilation, attempt to mark the error in lilypond org file."
   (when org-babel-lilypond-compile-post-tangle
     (let ((org-babel-lilypond-tangled-file (org-babel-lilypond-switch-extension
-                            (buffer-file-name) ".lilypond"))
+                                            (buffer-file-name) ".lilypond"))
           (org-babel-lilypond-temp-file (org-babel-lilypond-switch-extension
-                         (buffer-file-name) ".ly")))
+                                         (buffer-file-name) ".ly")))
       (if (not (file-exists-p org-babel-lilypond-tangled-file))
          (error "Error: Tangle Failed!")
        (when (file-exists-p org-babel-lilypond-temp-file)
@@ -328,7 +337,9 @@ If TEST is non-nil, the shell command is returned and is 
not run."
 FILE-NAME is full path to lilypond file.
 If TEST is non-nil, the shell command is returned and is not run."
   (when org-babel-lilypond-play-midi-post-tangle
-    (let ((midi-file (org-babel-lilypond-switch-extension file-name ".midi")))
+    (let* ((ext (if (eq system-type 'windows-nt)
+                    ".mid" ".midi"))
+           (midi-file (org-babel-lilypond-switch-extension file-name ext)))
       (if (file-exists-p midi-file)
           (let ((cmd-string
                  (concat org-babel-lilypond-midi-command " " midi-file)))
@@ -392,7 +403,7 @@ If TEST is non-nil, the shell command is returned and is 
not run."
   "Utility command to swap current FILE-NAME extension with EXT."
   (concat (file-name-sans-extension
            file-name)
-        ext))
+         ext))
 
 (defun org-babel-lilypond-get-header-args (mode)
   "Default arguments to use when evaluating a lilypond source block.
@@ -404,8 +415,7 @@ These depend upon whether we are in Arrange mode i.e. MODE 
is t."
            (:cache . "yes")
            (:comments . "yes")))
         (t
-         '((:results . "file")
-           (:exports . "results")))))
+         ob-lilypond-header-args)))
 
 (defun org-babel-lilypond-set-header-args (mode)
   "Set org-babel-default-header-args:lilypond
diff --git a/lisp/org/ob-lisp.el b/lisp/org/ob-lisp.el
index 87b9241e75..b32b122cdb 100644
--- a/lisp/org/ob-lisp.el
+++ b/lisp/org/ob-lisp.el
@@ -33,7 +33,7 @@
 ;; Requires SLY (Sylvester the Cat's Common Lisp IDE) or SLIME
 ;; (Superior Lisp Interaction Mode for Emacs).  See:
 ;; - https://github.com/capitaomorte/sly
-;; - http://common-lisp.net/project/slime/
+;; - https://common-lisp.net/project/slime/
 
 ;;; Code:
 (require 'ob)
diff --git a/lisp/org/ob-lua.el b/lisp/org/ob-lua.el
index 11503e4747..a4a964afc4 100644
--- a/lisp/org/ob-lua.el
+++ b/lisp/org/ob-lua.el
@@ -21,6 +21,10 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Commentary:
+
+;; Org-Babel support for evaluating lua source code.
+
 ;; Requirements:
 ;; for session support, lua-mode is needed.
 ;; lua-mode is not part of GNU Emacs/orgmode, but can be obtained
@@ -30,8 +34,6 @@
 
 ;; However, sessions are not yet working.
 
-;; Org-Babel support for evaluating lua source code.
-
 ;;; Code:
 (require 'ob)
 (require 'org-macs)
diff --git a/lisp/org/ob-makefile.el b/lisp/org/ob-makefile.el
index 69ab6fe9ea..eae64cf4a9 100644
--- a/lisp/org/ob-makefile.el
+++ b/lisp/org/ob-makefile.el
@@ -37,8 +37,7 @@ This function is called by `org-babel-execute-src-block'."
   body)
 
 (defun org-babel-prep-session:makefile (_session _params)
-  "Return an error if the :session header argument is set.  Make
-does not support sessions."
+  "Signal error; Make does not support sessions."
   (error "Makefile sessions are nonsensical"))
 
 (provide 'ob-makefile)
diff --git a/lisp/org/ob-mscgen.el b/lisp/org/ob-mscgen.el
deleted file mode 100644
index 79c9f8702e..0000000000
--- a/lisp/org/ob-mscgen.el
+++ /dev/null
@@ -1,81 +0,0 @@
-;;; ob-mscgen.el --- Babel Functions for Mscgen         -*- lexical-binding: 
t; -*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Author: Juan Pechiar
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This software provides EMACS org-babel export support for message
-;; sequence charts.  The mscgen utility is used for processing the
-;; sequence definition, and must therefore be installed in the system.
-;;
-;; Mscgen is available and documented at
-;; http://www.mcternan.me.uk/mscgen/index.html
-;;
-;; This code is directly inspired by Eric Schulte's ob-dot.el
-;;
-;; Example:
-;;
-;; #+begin_src mscgen :file example.png
-;; msc {
-;;  A,B;
-;;  A -> B [ label = "send message" ];
-;;  A <- B [ label = "get answer" ];
-;; }
-;; #+end_src
-;;
-;; Header for alternative file type:
-;;
-;; #+begin_src mscgen :file ex2.svg :filetype svg
-
-;; This differs from most standard languages in that
-;;
-;; 1) there is no such thing as a "session" in mscgen
-;; 2) we are generally only going to return results of type "file"
-;; 3) we are adding the "file" and "filetype" header arguments
-;; 4) there are no variables
-
-;;; Code:
-(require 'ob)
-
-(defvar org-babel-default-header-args:mscgen
-  '((:results . "file") (:exports . "results"))
-  "Default arguments to use when evaluating a mscgen source block.")
-
-(defun org-babel-execute:mscgen (body params)
-  "Execute a block of Mscgen code with Babel.
-This function is called by `org-babel-execute-src-block'.
-Default filetype is png.  Modify by setting :filetype parameter to
-mscgen supported formats."
-  (let* ((out-file (or (cdr (assq :file params)) "output.png" ))
-         (filetype (or (cdr (assq :filetype params)) "png" )))
-    (unless (cdr (assq :file params))
-      (error "ERROR: no output file specified.  Add \":file name.png\" to the 
src header"))
-    (org-babel-eval (concat "mscgen -T " filetype " -o " out-file) body)
-    nil)) ;; signal that output has already been written to file
-
-(defun org-babel-prep-session:mscgen (_session _params)
-  "Raise an error because Mscgen doesn't support sessions."
-  (error "Mscgen does not support sessions"))
-
-(provide 'ob-mscgen)
-
-;;; ob-mscgen.el ends here
diff --git a/lisp/org/ob-ocaml.el b/lisp/org/ob-ocaml.el
index 5fd6d1e09f..faf117c407 100644
--- a/lisp/org/ob-ocaml.el
+++ b/lisp/org/ob-ocaml.el
@@ -32,7 +32,7 @@
 
 ;;; Requirements:
 
-;; - tuareg-mode :: https://www-rocq.inria.fr/~acohen/tuareg/
+;; - tuareg-mode :: https://elpa.nongnu.org/nongnu/tuareg.html
 
 ;;; Code:
 (require 'ob)
@@ -112,8 +112,8 @@
                                             session
                                           tuareg-interactive-buffer-name)))
     (save-window-excursion (if (fboundp 'tuareg-run-process-if-needed)
-        (tuareg-run-process-if-needed org-babel-ocaml-command)
-       (tuareg-run-caml)))
+                              (tuareg-run-process-if-needed 
org-babel-ocaml-command)
+                             (tuareg-run-caml)))
     (get-buffer tuareg-interactive-buffer-name)))
 
 (defun org-babel-variable-assignments:ocaml (params)
diff --git a/lisp/org/ob-octave.el b/lisp/org/ob-octave.el
index 166cd596a5..bfe3e2aeec 100644
--- a/lisp/org/ob-octave.el
+++ b/lisp/org/ob-octave.el
@@ -45,8 +45,8 @@
 
 (defvar org-babel-matlab-with-emacs-link nil
   "If non-nil use matlab-shell-run-region for session evaluation.
-  This will use EmacsLink if (matlab-with-emacs-link) evaluates
-  to a non-nil value.")
+This will use EmacsLink if (matlab-with-emacs-link) evaluates
+to a non-nil value.")
 
 (defvar org-babel-matlab-emacs-link-wrapper-method
   "%s
@@ -164,7 +164,7 @@ create.  Return the initialized session."
          (current-buffer))))))
 
 (defun org-babel-octave-evaluate
-  (session body result-type &optional matlabp)
+    (session body result-type &optional matlabp)
   "Pass BODY to the octave process in SESSION.
 If RESULT-TYPE equals `output' then return the outputs of the
 statements in BODY, if RESULT-TYPE equals `value' then return the
@@ -181,12 +181,12 @@ value of the last statement in BODY, as elisp."
     (pcase result-type
       (`output (org-babel-eval cmd body))
       (`value (let ((tmp-file (org-babel-temp-file "octave-")))
-              (org-babel-eval
-               cmd
-               (format org-babel-octave-wrapper-method body
-                       (org-babel-process-file-name tmp-file 'noquote)
-                       (org-babel-process-file-name tmp-file 'noquote)))
-              (org-babel-octave-import-elisp-from-file tmp-file))))))
+               (org-babel-eval
+                cmd
+                (format org-babel-octave-wrapper-method body
+                        (org-babel-process-file-name tmp-file 'noquote)
+                        (org-babel-process-file-name tmp-file 'noquote)))
+               (org-babel-octave-import-elisp-from-file tmp-file))))))
 
 (defun org-babel-octave-evaluate-session
     (session body result-type &optional matlabp)
diff --git a/lisp/org/ob-perl.el b/lisp/org/ob-perl.el
index 0cfac85007..4d405a8b6a 100644
--- a/lisp/org/ob-perl.el
+++ b/lisp/org/ob-perl.el
@@ -4,6 +4,7 @@
 
 ;; Authors: Dan Davison
 ;;      Eric Schulte
+;; Maintainer: Corwin Brust
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
diff --git a/lisp/org/ob-picolisp.el b/lisp/org/ob-picolisp.el
deleted file mode 100644
index b1587f2b86..0000000000
--- a/lisp/org/ob-picolisp.el
+++ /dev/null
@@ -1,185 +0,0 @@
-;;; ob-picolisp.el --- Babel Functions for Picolisp  -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Authors: Thorsten Jolitz
-;;      Eric Schulte
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This library enables the use of PicoLisp in the multi-language
-;; programming framework Org-Babel.  PicoLisp is a minimal yet
-;; fascinating lisp dialect and a highly productive application
-;; framework for web-based client-server applications on top of
-;; object-oriented databases.  A good way to learn PicoLisp is to first
-;; read Paul Grahams essay "The hundred year language"
-;; (http://www.paulgraham.com/hundred.html) and then study the various
-;; documents and essays published in the PicoLisp wiki
-;; (http://picolisp.com/5000/-2.html). PicoLisp is included in some
-;; GNU/Linux Distributions, and can be downloaded here:
-;; http://software-lab.de/down.html.  It ships with a picolisp-mode and
-;; an inferior-picolisp-mode for Emacs (to be found in the /lib/el/
-;; directory).
-
-;; Although it might seem more natural to use Emacs Lisp for most
-;; Lisp-based programming tasks inside Org, an Emacs library written
-;; in Emacs Lisp, PicoLisp has at least two outstanding features that
-;; make it a valuable addition to Org Babel:
-
-;; PicoLisp _is_ an object-oriented database with a Prolog-based query
-;; language implemented in PicoLisp (Pilog). Database objects are
-;; first-class members of the language.
-
-;; PicoLisp is an extremely productive framework for the development
-;; of interactive web-applications (on top of a database).
-
-;;; Requirements:
-
-;;; Code:
-(require 'ob)
-(require 'comint)
-
-(declare-function run-picolisp "ext:inferior-picolisp" (cmd))
-(defvar org-babel-tangle-lang-exts) ;; Autoloaded
-
-;; optionally define a file extension for this language
-(add-to-list 'org-babel-tangle-lang-exts '("picolisp" . "l"))
-
-;;; interferes with settings in org-babel buffer?
-;; optionally declare default header arguments for this language
-;; (defvar org-babel-default-header-args:picolisp
-;;   '((:colnames . "no"))
-;;   "Default arguments for evaluating a picolisp source block.")
-
-(defvar org-babel-picolisp-eoe "org-babel-picolisp-eoe"
-  "String to indicate that evaluation has completed.")
-
-(defcustom org-babel-picolisp-cmd "pil"
-  "Name of command used to evaluate picolisp blocks."
-  :group 'org-babel
-  :version "24.1"
-  :type 'string)
-
-(defun org-babel-expand-body:picolisp (body params)
-  "Expand BODY according to PARAMS, return the expanded body."
-  (let ((vars (org-babel--get-vars params))
-        (print-level nil)
-       (print-length nil))
-    (if (> (length vars) 0)
-        (concat "(prog (let ("
-                (mapconcat
-                 (lambda (var)
-                   (format "%S '%S)"
-                           (print (car var))
-                           (print (cdr var))))
-                 vars "\n      ")
-                " \n" body ") )")
-      body)))
-
-(defun org-babel-execute:picolisp (body params)
-  "Execute a block of Picolisp code with org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (message "executing Picolisp source code block")
-  (let* (
-        ;; Name of the session or "none".
-        (session-name (cdr (assq :session params)))
-        ;; Set the session if the session variable is non-nil.
-        (session (org-babel-picolisp-initiate-session session-name))
-        ;; Either OUTPUT or VALUE which should behave as described above.
-        (result-params (cdr (assq :result-params params)))
-        ;; Expand the body with `org-babel-expand-body:picolisp'.
-        (full-body (org-babel-expand-body:picolisp body params))
-         ;; Wrap body appropriately for the type of evaluation and results.
-         (wrapped-body
-          (cond
-           ((or (member "code" result-params)
-                (member "pp" result-params))
-            (format "(pretty (out \"%s\" %s))" null-device full-body))
-           ((and (member "value" result-params) (not session))
-            (format "(print (out \"%s\" %s))" null-device full-body))
-           ((member "value" result-params)
-            (format "(out \"%s\" %s)" null-device full-body))
-           (t full-body)))
-         (result
-          (if (not (string= session-name "none"))
-              ;; Session based evaluation.
-              (mapconcat ;; <- joins the list back into a single string
-               #'identity
-               (butlast ;; <- remove the org-babel-picolisp-eoe line
-                (delq nil
-                      (mapcar
-                       (lambda (line)
-                         (org-babel-chomp      ;; Remove trailing newlines.
-                          (when (> (length line) 0) ;; Remove empty lines.
-                            (cond
-                             ;; Remove leading "-> " from return values.
-                             ((and (>= (length line) 3)
-                                   (string= "-> " (substring line 0 3)))
-                              (substring line 3))
-                             ;; Remove trailing "-> <<return-value>>" on the
-                             ;; last line of output.
-                             ((and (member "output" result-params)
-                                   (string-match-p "->" line))
-                              (substring line 0 (string-match "->" line)))
-                             (t line)
-                             )
-                            ;;(if (and (>= (length line) 3);Remove leading "<-"
-                            ;;         (string= "-> " (substring line 0 3)))
-                            ;;    (substring line 3)
-                            ;;  line)
-                            )))
-                       ;; Returns a list of the output of each evaluated exp.
-                       (org-babel-comint-with-output
-                           (session org-babel-picolisp-eoe)
-                         (insert wrapped-body) (comint-send-input)
-                         (insert "'" org-babel-picolisp-eoe)
-                         (comint-send-input)))))
-               "\n")
-            ;; external evaluation
-            (let ((script-file (org-babel-temp-file "picolisp-script-")))
-              (with-temp-file script-file
-                (insert (concat wrapped-body "(bye)")))
-              (org-babel-eval
-               (format "%s %s"
-                       org-babel-picolisp-cmd
-                       (org-babel-process-file-name script-file))
-               "")))))
-    (org-babel-result-cond result-params
-      result
-      (read result))))
-
-(defun org-babel-picolisp-initiate-session (&optional session-name)
-  "If there is not a current inferior-process-buffer in SESSION
-then create.  Return the initialized session."
-  (unless (string= session-name "none")
-    (require 'inferior-picolisp)
-    ;; provide a reasonable default session name
-    (let ((session (or session-name "*inferior-picolisp*")))
-      ;; check if we already have a live session by this name
-      (if (org-babel-comint-buffer-livep session)
-          (get-buffer session)
-        (save-window-excursion
-          (run-picolisp org-babel-picolisp-cmd)
-          (rename-buffer session-name)
-          (current-buffer))))))
-
-(provide 'ob-picolisp)
-
-;;; ob-picolisp.el ends here
diff --git a/lisp/org/ob-plantuml.el b/lisp/org/ob-plantuml.el
index 93c653870c..fc621600c4 100644
--- a/lisp/org/ob-plantuml.el
+++ b/lisp/org/ob-plantuml.el
@@ -71,6 +71,12 @@ You can also configure extra arguments via 
`org-plantuml-executable-args'."
   :package-version '(Org . "9.4")
   :type '(repeat string))
 
+(defcustom org-babel-plantuml-svg-text-to-path nil
+  "When non-nil, export text in SVG images to paths using Inkscape."
+  :group 'org-babel
+  :package-version '(Org . "9.5")
+  :type 'boolean)
+
 (defun org-babel-variable-assignments:plantuml (params)
   "Return a list of PlantUML statements assigning the block's variables.
 PARAMS is a property list of source block parameters, which may
@@ -78,9 +84,9 @@ contain multiple entries for the key `:var'.  `:var' entries 
in PARAMS
 are expected to be scalar variables."
   (mapcar
    (lambda (pair)
-       (format "!define %s %s"
-              (car pair)
-              (replace-regexp-in-string "\"" "" (cdr pair))))
+     (format "!define %s %s"
+            (car pair)
+            (replace-regexp-in-string "\"" "" (cdr pair))))
    (org-babel--get-vars params)))
 
 (defun org-babel-plantuml-make-body (body params)
@@ -145,6 +151,9 @@ This function is called by `org-babel-execute-src-block'."
                         " ")))
     (with-temp-file in-file (insert full-body))
     (message "%s" cmd) (org-babel-eval cmd "")
+    (if (and (string= (file-name-extension out-file) "svg")
+             org-babel-plantuml-svg-text-to-path)
+        (org-babel-eval (format "inkscape %s -T -l %s" out-file out-file) ""))
     nil)) ;; signal that output has already been written to file
 
 (defun org-babel-prep-session:plantuml (_session _params)
diff --git a/lisp/org/ob-processing.el b/lisp/org/ob-processing.el
index 9e6572a5fd..84fd6a2964 100644
--- a/lisp/org/ob-processing.el
+++ b/lisp/org/ob-processing.el
@@ -47,7 +47,7 @@
 ;;; Requirements:
 
 ;; - processing2-emacs mode :: https://github.com/ptrv/processing2-emacs
-;; - Processing.js module :: http://processingjs.org/
+;; - Processing.js module :: https://processingjs.org/
 
 ;;; Code:
 (require 'ob)
diff --git a/lisp/org/ob-python.el b/lisp/org/ob-python.el
index 7911205d08..3c095ad463 100644
--- a/lisp/org/ob-python.el
+++ b/lisp/org/ob-python.el
@@ -81,15 +81,20 @@ This function is called by `org-babel-execute-src-block'."
                   (cdr (assq :session params))))
          (result-params (cdr (assq :result-params params)))
          (result-type (cdr (assq :result-type params)))
-        (return-val (when (and (eq result-type 'value) (not session))
+        (return-val (when (eq result-type 'value)
                       (cdr (assq :return params))))
         (preamble (cdr (assq :preamble params)))
+        (async (org-babel-comint-use-async params))
          (full-body
-         (org-babel-expand-body:generic
-          (concat body (if return-val (format "\nreturn %s" return-val) ""))
-          params (org-babel-variable-assignments:python params)))
+         (concat
+          (org-babel-expand-body:generic
+           body params
+           (org-babel-variable-assignments:python params))
+          (when return-val
+            (format (if session "\n%s" "\nreturn %s") return-val))))
          (result (org-babel-python-evaluate
-                 session full-body result-type result-params preamble)))
+                 session full-body result-type
+                 result-params preamble async)))
     (org-babel-reassemble-table
      result
      (org-babel-pick-name (cdr (assq :colname-names params))
@@ -149,7 +154,7 @@ Emacs-lisp table, otherwise return the results as a string."
   (let ((res (org-babel-script-escape results)))
     (if (listp res)
         (mapcar (lambda (el) (if (eq el 'None)
-                            org-babel-python-None-to el))
+                                 org-babel-python-None-to el))
                 res)
       res)))
 
@@ -275,11 +280,14 @@ else:
          (if (member "pp" result-params) "True" "False")))
 
 (defun org-babel-python-evaluate
-  (session body &optional result-type result-params preamble)
+    (session body &optional result-type result-params preamble async)
   "Evaluate BODY as Python code."
   (if session
-      (org-babel-python-evaluate-session
-       session body result-type result-params)
+      (if async
+         (org-babel-python-async-evaluate-session
+          session body result-type result-params)
+       (org-babel-python-evaluate-session
+        session body result-type result-params))
     (org-babel-python-evaluate-external-process
      body result-type result-params preamble)))
 
@@ -388,6 +396,49 @@ last statement in BODY, as elisp."
       (substring string 1 -1)
     string))
 
+;; Async session eval
+
+(defconst org-babel-python-async-indicator "print 
('ob_comint_async_python_%s_%s')")
+
+(defun org-babel-python-async-value-callback (params tmp-file)
+  (let ((result-params (cdr (assq :result-params params)))
+       (results (org-babel-eval-read-file tmp-file)))
+    (org-babel-result-cond result-params
+      results
+      (org-babel-python-table-or-string results))))
+
+(defun org-babel-python-async-evaluate-session
+    (session body &optional result-type result-params)
+  "Asynchronously evaluate BODY in SESSION.
+Returns a placeholder string for insertion, to later be replaced
+by `org-babel-comint-async-filter'."
+  (org-babel-comint-async-register
+   session (current-buffer)
+   "ob_comint_async_python_\\(.+\\)_\\(.+\\)"
+   'org-babel-chomp 'org-babel-python-async-value-callback)
+  (let ((python-shell-buffer-name (org-babel-python-without-earmuffs session)))
+    (pcase result-type
+      (`output
+       (let ((uuid (md5 (number-to-string (random 100000000)))))
+         (with-temp-buffer
+           (insert (format org-babel-python-async-indicator "start" uuid))
+           (insert "\n")
+           (insert body)
+           (insert "\n")
+           (insert (format org-babel-python-async-indicator "end" uuid))
+           (python-shell-send-buffer))
+         uuid))
+      (`value
+       (let ((tmp-results-file (org-babel-temp-file "python-"))
+             (tmp-src-file (org-babel-temp-file "python-")))
+         (with-temp-file tmp-src-file (insert body))
+         (with-temp-buffer
+           (insert (org-babel-python-format-session-value tmp-src-file 
tmp-results-file result-params))
+           (insert "\n")
+           (insert (format org-babel-python-async-indicator "file" 
tmp-results-file))
+           (python-shell-send-buffer))
+         tmp-results-file)))))
+
 (provide 'ob-python)
 
 ;;; ob-python.el ends here
diff --git a/lisp/org/ob-ruby.el b/lisp/org/ob-ruby.el
index ccc746e8df..b2483f1aa6 100644
--- a/lisp/org/ob-ruby.el
+++ b/lisp/org/ob-ruby.el
@@ -27,7 +27,7 @@
 
 ;;; Requirements:
 
-;; - ruby and irb executables :: http://www.ruby-lang.org/
+;; - ruby and irb executables :: https://www.ruby-lang.org/
 ;;
 ;; - ruby-mode :: Can be installed through ELPA, or from
 ;;   https://github.com/eschulte/rinari/raw/master/util/ruby-mode.el
diff --git a/lisp/org/ob-sass.el b/lisp/org/ob-sass.el
index 76cdfd8063..c8762cabae 100644
--- a/lisp/org/ob-sass.el
+++ b/lisp/org/ob-sass.el
@@ -23,7 +23,7 @@
 
 ;;; Commentary:
 
-;; For more information on sass see http://sass-lang.com/
+;; For more information on sass see https://sass-lang.com/
 ;;
 ;; This accepts a 'file' header argument which is the target of the
 ;; compiled sass.  The default output type for sass evaluation is
diff --git a/lisp/org/ob-scheme.el b/lisp/org/ob-scheme.el
index a18bfb5181..f4836b23fe 100644
--- a/lisp/org/ob-scheme.el
+++ b/lisp/org/ob-scheme.el
@@ -110,7 +110,7 @@
     geiser-impl--implementation))
 
 (defun org-babel-scheme-get-repl (impl name)
-  "Switch to a scheme REPL, creating it if it doesn't exist:"
+  "Switch to a scheme REPL, creating it if it doesn't exist."
   (let ((buffer (org-babel-scheme-get-session-buffer name)))
     (or buffer
        (progn
diff --git a/lisp/org/ob-screen.el b/lisp/org/ob-screen.el
index c3388c3d3d..7793825b60 100644
--- a/lisp/org/ob-screen.el
+++ b/lisp/org/ob-screen.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
 ;; Author: Benjamin Andresen
+;; Maintainer: Ken Mankoff
 ;; Keywords: literate programming, interactive shell
 ;; Homepage: https://orgmode.org
 
@@ -29,7 +30,7 @@
 ;; Adding :cmd and :terminal as header arguments
 ;; :terminal must support the -T (title) and -e (command) parameter
 ;;
-;; You can test the default setup. (xterm + sh) with
+;; You can test the default setup (xterm + sh) with
 ;; M-x org-babel-screen-test RET
 
 ;;; Code:
@@ -127,7 +128,7 @@ The terminal should shortly flicker."
     ;; XXX: need to find a better way to do the following
     (while (not (file-readable-p tmpfile))
       ;; do something, otherwise this will be optimized away
-      (sit-for 0.1))
+      (message "org-babel-screen: File not readable yet."))
     (setq tmp-string (with-temp-buffer
                        (insert-file-contents-literally tmpfile)
                        (buffer-substring (point-min) (point-max))))
diff --git a/lisp/org/ob-sed.el b/lisp/org/ob-sed.el
index b95f411858..4d3eeee616 100644
--- a/lisp/org/ob-sed.el
+++ b/lisp/org/ob-sed.el
@@ -70,12 +70,12 @@ function is called by `org-babel-execute-src-block'."
                        (insert body))
                      file))
         (stdin (let ((stdin (cdr (assq :stdin params))))
-                  (when stdin
-                    (let ((tmp (org-babel-temp-file "sed-stdin-"))
-                          (res (org-babel-ref-resolve stdin)))
-                      (with-temp-file tmp
-                        (insert res))
-                      tmp))))
+                 (when stdin
+                   (let ((tmp (org-babel-temp-file "sed-stdin-"))
+                         (res (org-babel-ref-resolve stdin)))
+                     (with-temp-file tmp
+                       (insert res))
+                     tmp))))
          (cmd (mapconcat #'identity
                         (remq nil
                               (list org-babel-sed-command
diff --git a/lisp/org/ob-shen.el b/lisp/org/ob-shen.el
deleted file mode 100644
index 6803b0bf68..0000000000
--- a/lisp/org/ob-shen.el
+++ /dev/null
@@ -1,79 +0,0 @@
-;;; ob-shen.el --- Babel Functions for Shen          -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
-
-;; Author: Eric Schulte
-;; Keywords: literate programming, reproducible research, shen
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Currently this only works using session evaluation as there is no
-;; defined method for executing shen code outside of a session.
-
-;;; Requirements:
-
-;; - shen-mode and inf-shen will soon be available through the GNU
-;;   elpa, however in the interim they are available at
-;;   https://github.com/eschulte/shen-mode
-
-;;; Code:
-(require 'ob)
-
-(declare-function shen-eval-defun "ext:inf-shen" (&optional and-go))
-(declare-function org-babel-ruby-var-to-ruby "ob-ruby" (var))
-
-(defvar org-babel-default-header-args:shen '()
-  "Default header arguments for shen code blocks.")
-
-(defun org-babel-expand-body:shen (body params)
-  "Expand BODY according to PARAMS, return the expanded body."
-  (let ((vars (org-babel--get-vars params)))
-    (if (> (length vars) 0)
-        (concat "(let "
-                (mapconcat (lambda (var)
-                            (format "%s %s" (car var)
-                                    (org-babel-shen-var-to-shen (cdr var))))
-                          vars " ")
-               body ")")
-      body)))
-
-(defun org-babel-shen-var-to-shen (var)
-  "Convert VAR into a shen variable."
-  (if (listp var)
-      (concat "[" (mapconcat #'org-babel-ruby-var-to-ruby var " ") "]")
-    (format "%S" var)))
-
-(defun org-babel-execute:shen (body params)
-  "Execute a block of Shen code with org-babel.
-This function is called by `org-babel-execute-src-block'."
-  (require 'inf-shen)
-  (let* ((result-params (cdr (assq :result-params params)))
-         (full-body (org-babel-expand-body:shen body params)))
-    (let ((results
-           (with-temp-buffer
-             (insert full-body)
-             (call-interactively #'shen-eval-defun))))
-      (org-babel-result-cond result-params
-        results
-        (condition-case nil (org-babel-script-escape results)
-          (error results))))))
-
-(provide 'ob-shen)
-
-;;; ob-shen.el ends here
diff --git a/lisp/org/ob-sql.el b/lisp/org/ob-sql.el
index 0a08925d4f..f512d2952c 100644
--- a/lisp/org/ob-sql.el
+++ b/lisp/org/ob-sql.el
@@ -40,6 +40,7 @@
 ;; - dbuser
 ;; - dbpassword
 ;; - dbconnection (to reference connections in sql-connection-alist)
+;; - dbinstance (currently only used by SAP HANA)
 ;; - database
 ;; - colnames (default, nil, means "yes")
 ;; - result-params
@@ -58,6 +59,7 @@
 ;; - postgresql (postgres)
 ;; - oracle
 ;; - vertica
+;; - saphana
 ;;
 ;; TODO:
 ;;
@@ -85,20 +87,30 @@
     (dbport           . :any)
     (dbuser           . :any)
     (dbpassword               . :any)
+    (dbinstance               . :any)
     (database         . :any))
   "SQL-specific header arguments.")
 
 (defun org-babel-expand-body:sql (body params)
   "Expand BODY according to the values of PARAMS."
-  (org-babel-sql-expand-vars
-   body (org-babel--get-vars params)))
+  (let ((prologue (cdr (assq :prologue params)))
+       (epilogue (cdr (assq :epilogue params))))
+    (mapconcat 'identity
+               (list
+                prologue
+                (org-babel-sql-expand-vars
+                 body (org-babel--get-vars params))
+                epilogue)
+               "\n")))
 
 (defun org-babel-edit-prep:sql (info)
   "Set `sql-product' in Org edit buffer.
 Set `sql-product' in Org edit buffer according to the
 corresponding :engine source block header argument."
   (let ((product (cdr (assq :engine (nth 2 info)))))
-    (sql-set-product product)))
+    (condition-case nil
+        (sql-set-product product)
+      (user-error "Cannot set `sql-product' in Org Src edit buffer"))))
 
 (defun org-babel-sql-dbstring-mysql (host port user password database)
   "Make MySQL cmd line args for database connection.  Pass nil to omit that 
arg."
@@ -167,13 +179,27 @@ SQL Server on Windows and Linux platform."
   "Make Vertica command line args for database connection.
 Pass nil to omit that arg."
   (mapconcat #'identity
-             (delq nil
-                   (list (when host     (format "-h %s" host))
-                         (when port     (format "-p %d" port))
-                         (when user     (format "-U %s" user))
-                         (when password (format "-w %s" (shell-quote-argument 
password) ))
-                         (when database (format "-d %s" database))))
-             " "))
+            (delq nil
+                  (list (when host     (format "-h %s" host))
+                        (when port     (format "-p %d" port))
+                        (when user     (format "-U %s" user))
+                        (when password (format "-w %s" (shell-quote-argument 
password) ))
+                        (when database (format "-d %s" database))))
+            " "))
+
+(defun org-babel-sql-dbstring-saphana (host port instance user password 
database)
+  "Make SAP HANA command line args for database connection.
+Pass nil to omit that arg."
+  (mapconcat #'identity
+             (delq nil
+                   (list (and host port (format "-n %s:%s" host port))
+                         (and host (not port) (format "-n %s" host))
+                         (and instance (format "-i %d" instance))
+                         (and user (format "-u %s" user))
+                         (and password (format "-p %s"
+                                               (shell-quote-argument 
password)))
+                         (and database (format "-d %s" database))))
+             " "))
 
 (defun org-babel-sql-convert-standard-filename (file)
   "Convert FILE to OS standard file name.
@@ -198,6 +224,7 @@ database connections."
                              (:dbport . sql-port)
                              (:dbuser . sql-user)
                              (:dbpassword . sql-password)
+                             (:dbinstance . sql-dbinstance)
                              (:database . sql-database)))
              (mapped-name (cdr (assq name name-mapping))))
         (cadr (assq mapped-name
@@ -213,6 +240,7 @@ This function is called by `org-babel-execute-src-block'."
          (dbport (org-babel-find-db-connection-param params :dbport))
          (dbuser (org-babel-find-db-connection-param params :dbuser))
          (dbpassword (org-babel-find-db-connection-param params :dbpassword))
+         (dbinstance (org-babel-find-db-connection-param params :dbinstance))
          (database (org-babel-find-db-connection-param params :database))
          (engine (cdr (assq :engine params)))
          (colnames-p (not (equal "no" (cdr (assq :colnames params)))))
@@ -246,11 +274,14 @@ This function is called by `org-babel-execute-src-block'."
                                   (org-babel-process-file-name in-file)
                                   (org-babel-process-file-name out-file)))
                    ((postgresql postgres) (format
-                                           "%spsql --set=\"ON_ERROR_STOP=1\" 
%s -A -P \
+                                           "%s%s --set=\"ON_ERROR_STOP=1\" %s 
-A -P \
 footer=off -F \"\t\"  %s -f %s -o %s %s"
                                            (if dbpassword
                                                (format "PGPASSWORD=%s " 
dbpassword)
                                              "")
+                                            (or (bound-and-true-p
+                                                 sql-postgres-program)
+                                                "psql")
                                            (if colnames-p "" "-t")
                                            (org-babel-sql-dbstring-postgresql
                                             dbhost dbport dbuser database)
@@ -277,6 +308,12 @@ footer=off -F \"\t\"  %s -f %s -o %s %s"
                              dbhost dbport dbuser dbpassword database)
                             (org-babel-process-file-name in-file)
                             (org-babel-process-file-name out-file)))
+                   (saphana (format "hdbsql %s -I %s -o %s %s"
+                                    (org-babel-sql-dbstring-saphana
+                                     dbhost dbport dbinstance dbuser 
dbpassword database)
+                                    (org-babel-process-file-name in-file)
+                                    (org-babel-process-file-name out-file)
+                                    (or cmdline "")))
                     (t (user-error "No support for the %s SQL engine" 
engine)))))
     (with-temp-file in-file
       (insert
@@ -310,7 +347,7 @@ SET COLSEP '|'
        (progn (insert-file-contents-literally out-file) (buffer-string)))
       (with-temp-buffer
        (cond
-        ((memq (intern engine) '(dbi mysql postgresql postgres sqsh vertica))
+        ((memq (intern engine) '(dbi mysql postgresql postgres saphana sqsh 
vertica))
          ;; Add header row delimiter after column-names header in first line
          (cond
           (colnames-p
@@ -347,8 +384,13 @@ SET COLSEP '|'
         (org-babel-pick-name (cdr (assq :rowname-names params))
                              (cdr (assq :rownames params))))))))
 
-(defun org-babel-sql-expand-vars (body vars)
-  "Expand the variables held in VARS in BODY."
+(defun org-babel-sql-expand-vars (body vars &optional sqlite)
+  "Expand the variables held in VARS in BODY.
+
+If SQLITE has been provided, prevent passing a format to
+`orgtbl-to-csv'.  This prevents overriding the default format, which if
+there were commas in the context of the table broke the table as an
+argument mechanism."
   (mapc
    (lambda (pair)
      (setq body
@@ -359,9 +401,11 @@ SET COLSEP '|'
                   (let ((data-file (org-babel-temp-file "sql-data-")))
                     (with-temp-file data-file
                       (insert (orgtbl-to-csv
-                               val '(:fmt (lambda (el) (if (stringp el)
-                                                      el
-                                                    (format "%S" el)))))))
+                               val (if sqlite
+                                       nil
+                                     '(:fmt (lambda (el) (if (stringp el)
+                                                             el
+                                                           (format "%S" 
el))))))))
                     data-file)
                 (if (stringp val) val (format "%S" val))))
            body)))
diff --git a/lisp/org/ob-sqlite.el b/lisp/org/ob-sqlite.el
index 6e21fa9fd9..7bfb66cf68 100644
--- a/lisp/org/ob-sqlite.el
+++ b/lisp/org/ob-sqlite.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
 ;; Author: Eric Schulte
+;; Maintainer: Nick Savage
 ;; Keywords: literate programming, reproducible research
 ;; Homepage: https://orgmode.org
 
@@ -27,6 +28,7 @@
 
 ;;; Code:
 (require 'ob)
+(require 'ob-sql)
 
 (declare-function org-table-convert-region "org-table"
                  (beg0 end0 &optional separator))
@@ -51,8 +53,8 @@
 
 (defun org-babel-expand-body:sqlite (body params)
   "Expand BODY according to the values of PARAMS."
-  (org-babel-sqlite-expand-vars
-   body (org-babel--get-vars params)))
+  (org-babel-sql-expand-vars
+   body (org-babel--get-vars params) t))
 
 (defvar org-babel-sqlite3-command "sqlite3")
 
@@ -112,22 +114,8 @@ This function is called by `org-babel-execute-src-block'."
 
 (defun org-babel-sqlite-expand-vars (body vars)
   "Expand the variables held in VARS in BODY."
-  ;; FIXME: Redundancy with org-babel-sql-expand-vars!
-  (mapc
-   (lambda (pair)
-     (setq body
-          (replace-regexp-in-string
-           (format "$%s" (car pair))
-           (let ((val (cdr pair)))
-              (if (listp val)
-                  (let ((data-file (org-babel-temp-file "sqlite-data-")))
-                    (with-temp-file data-file
-                      (insert (orgtbl-to-csv val nil)))
-                    data-file)
-                (if (stringp val) val (format "%S" val))))
-           body)))
-   vars)
-  body)
+  (declare (obsolete "use `org-babel-sql-expand-vars' instead." "9.5"))
+  (org-babel-sql-expand-vars body vars t))
 
 (defun org-babel-sqlite-table-or-scalar (result)
   "If RESULT looks like a trivial table, then unwrap it."
@@ -137,7 +125,7 @@ This function is called by `org-babel-execute-src-block'."
     (mapcar (lambda (row)
              (if (eq 'hline row)
                  'hline
-               (mapcar #'org-babel-string-read row)))
+               (mapcar #'org-babel-sqlite--read-cell row)))
            result)))
 
 (defun org-babel-sqlite-offset-colnames (table headers-p)
@@ -151,6 +139,10 @@ This function is called by `org-babel-execute-src-block'."
 Prepare SESSION according to the header arguments specified in PARAMS."
   (error "SQLite sessions not yet implemented"))
 
+(defun org-babel-sqlite--read-cell (cell)
+  "Process CELL to remove unnecessary characters."
+  (org-babel-read cell t))
+
 (provide 'ob-sqlite)
 
 ;;; ob-sqlite.el ends here
diff --git a/lisp/org/ob-stan.el b/lisp/org/ob-stan.el
deleted file mode 100644
index 1f2afdeeda..0000000000
--- a/lisp/org/ob-stan.el
+++ /dev/null
@@ -1,86 +0,0 @@
-;;; ob-stan.el --- Babel Functions for Stan          -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
-
-;; Author: Kyle Meyer
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Org-Babel support for evaluating Stan [1] source code.
-;;
-;; Evaluating a Stan block can produce two different results.
-;;
-;; 1) Dump the source code contents to a file.
-;;
-;;    This file can then be used as a variable in other blocks, which
-;;    allows interfaces like RStan to use the model.
-;;
-;; 2) Compile the contents to a model file.
-;;
-;;    This provides access to the CmdStan interface.  To use this, set
-;;    `org-babel-stan-cmdstan-directory' and provide a :file argument
-;;    that does not end in ".stan".
-;;
-;; For more information and usage examples, visit
-;; https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-stan.html
-;;
-;; [1] https://mc-stan.org/
-
-;;; Code:
-(require 'ob)
-(require 'org-compat)
-
-(defcustom org-babel-stan-cmdstan-directory nil
-  "CmdStan source directory.
-Call \"make\" from this directory to compile the Stan block.
-When nil, executing Stan blocks dumps the content to a file."
-  :group 'org-babel
-  :type '(choice
-         (directory :tag "Compilation directory")
-         (const :tag "Dump to a file" nil)))
-
-(defvar org-babel-default-header-args:stan
-  '((:results . "file")))
-
-(defun org-babel-execute:stan (body params)
-  "Generate Stan file from BODY according to PARAMS.
-A :file header argument must be given.  If
-`org-babel-stan-cmdstan-directory' is non-nil and the file name
-does not have a \".stan\" extension, save an intermediate
-\".stan\" file and compile the block to the named file.
-Otherwise, write the Stan code directly to the named file."
-  (let ((file (expand-file-name
-              (or (cdr (assq :file params))
-                  (user-error "Set :file argument to execute Stan blocks")))))
-    (if (or (not org-babel-stan-cmdstan-directory)
-           (string-match-p "\\.stan\\'" file))
-       (with-temp-file file (insert body))
-      (with-temp-file (concat file ".stan") (insert body))
-      (let ((default-directory org-babel-stan-cmdstan-directory))
-       (call-process-shell-command (concat "make " file))))
-    nil))              ; Signal that output has been written to file.
-
-(defun org-babel-prep-session:stan (_session _params)
-  "Return an error because Stan does not support sessions."
-  (user-error "Stan does not support sessions"))
-
-(provide 'ob-stan)
-
-;;; ob-stan.el ends here
diff --git a/lisp/org/ob-table.el b/lisp/org/ob-table.el
index 39a14a25d6..e081708701 100644
--- a/lisp/org/ob-table.el
+++ b/lisp/org/ob-table.el
@@ -78,7 +78,8 @@ So this `org-sbe' construct
 
 is the equivalent of the following source code block:
 
- #+begin_src emacs-lisp :var results=source-block(n=val_at_col_2, m=3) 
:results silent
+ #+begin_src emacs-lisp :var results=source-block(n=val_at_col_2, m=3) \\
+     :results silent
  results
  #+end_src
 
diff --git a/lisp/org/ob-tangle.el b/lisp/org/ob-tangle.el
index aa0373ab88..2dd1d031cb 100644
--- a/lisp/org/ob-tangle.el
+++ b/lisp/org/ob-tangle.el
@@ -43,6 +43,7 @@
 (declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
 (declare-function org-in-archived-heading-p "org" (&optional no-inheritance))
 (declare-function outline-previous-heading "outline" ())
+(defvar org-id-link-to-org-use-id nil) ; Dynamically scoped
 
 (defcustom org-babel-tangle-lang-exts
   '(("emacs-lisp" . "el")
@@ -169,11 +170,14 @@ evaluating BODY."
 (defun org-babel-tangle-file (file &optional target-file lang-re)
   "Extract the bodies of source code blocks in FILE.
 Source code blocks are extracted with `org-babel-tangle'.
+
 Optional argument TARGET-FILE can be used to specify a default
-export file for all source blocks.  Optional argument LANG-RE can
-be used to limit the exported source code blocks by languages
-matching a regular expression.  Return a list whose CAR is the
-tangled file name."
+export file for all source blocks.
+
+Optional argument LANG-RE can be used to limit the exported
+source code blocks by languages matching a regular expression.
+
+Return a list whose CAR is the tangled file name."
   (interactive "fFile to tangle: \nP")
   (let ((visited-p (find-buffer-visiting (expand-file-name file)))
        to-be-removed)
@@ -225,67 +229,55 @@ matching a regular expression."
               (or (cdr (assq :tangle (nth 2 (org-babel-get-src-block-info 
'light))))
                   (user-error "Point is not in a source code block"))))
            path-collector)
-       (mapc ;; map over all languages
-        (lambda (by-lang)
-          (let* ((lang (car by-lang))
-                 (specs (cdr by-lang))
-                 (ext (or (cdr (assoc lang org-babel-tangle-lang-exts)) lang))
-                 (lang-f (org-src-get-lang-mode lang))
-                 she-banged)
-            (mapc
-             (lambda (spec)
-               (let ((get-spec (lambda (name) (cdr (assoc name (nth 4 
spec))))))
-                 (let* ((tangle (funcall get-spec :tangle))
-                        (she-bang (let ((sheb (funcall get-spec :shebang)))
-                                     (when (> (length sheb) 0) sheb)))
-                        (tangle-mode (funcall get-spec :tangle-mode))
-                        (base-name (cond
-                                    ((string= "yes" tangle)
-                                     (file-name-sans-extension
-                                      (nth 1 spec)))
-                                    ((string= "no" tangle) nil)
-                                    ((> (length tangle) 0) tangle)))
-                        (file-name (when base-name
-                                     ;; decide if we want to add ext to 
base-name
-                                     (if (and ext (string= "yes" tangle))
-                                         (concat base-name "." ext) 
base-name))))
-                   (when file-name
-                     ;; Possibly create the parent directories for file.
-                     (let ((m (funcall get-spec :mkdirp))
-                           (fnd (file-name-directory file-name)))
-                       (and m fnd (not (string= m "no"))
-                            (make-directory fnd 'parents)))
-                     ;; delete any old versions of file
-                     (and (file-exists-p file-name)
-                          (not (member file-name (mapcar #'car 
path-collector)))
-                          (delete-file file-name))
-                     ;; drop source-block to file
-                     (with-temp-buffer
-                       (when (fboundp lang-f) (ignore-errors (funcall lang-f)))
-                       (when (and she-bang (not (member file-name she-banged)))
+       (mapc ;; map over file-names
+        (lambda (by-fn)
+          (let ((file-name (car by-fn)))
+            (when file-name
+               (let ((lspecs (cdr by-fn))
+                    (fnd (file-name-directory file-name))
+                    modes make-dir she-banged lang)
+                ;; drop source-blocks to file
+                ;; We avoid append-to-file as it does not work with tramp.
+                (with-temp-buffer
+                  (mapc
+                   (lambda (lspec)
+                     (let* ((block-lang (car lspec))
+                            (spec (cdr lspec))
+                            (get-spec (lambda (name) (cdr (assq name (nth 4 
spec)))))
+                            (she-bang (let ((sheb (funcall get-spec :shebang)))
+                                        (when (> (length sheb) 0) sheb)))
+                            (tangle-mode (funcall get-spec :tangle-mode)))
+                       (unless (string-equal block-lang lang)
+                         (setq lang block-lang)
+                         (let ((lang-f (org-src-get-lang-mode lang)))
+                           (when (fboundp lang-f) (ignore-errors (funcall 
lang-f)))))
+                       ;; if file contains she-bangs, then make it executable
+                       (when she-bang
+                         (unless tangle-mode (setq tangle-mode #o755)))
+                       (when tangle-mode
+                         (add-to-list 'modes tangle-mode))
+                       ;; Possibly create the parent directories for file.
+                       (let ((m (funcall get-spec :mkdirp)))
+                         (and m fnd (not (string= m "no"))
+                              (setq make-dir t)))
+                       ;; Handle :padlines unless first line in file
+                       (unless (or (string= "no" (funcall get-spec :padline))
+                                   (= (point) (point-min)))
+                         (insert "\n"))
+                       (when (and she-bang (not she-banged))
                          (insert (concat she-bang "\n"))
-                         (setq she-banged (cons file-name she-banged)))
-                       (org-babel-spec-to-string spec)
-                       ;; We avoid append-to-file as it does not work with 
tramp.
-                       (let ((content (buffer-string)))
-                         (with-temp-buffer
-                           (when (file-exists-p file-name)
-                             (insert-file-contents file-name))
-                           (goto-char (point-max))
-                           ;; Handle :padlines unless first line in file
-                           (unless (or (string= "no" (cdr (assq :padline (nth 
4 spec))))
-                                       (= (point) (point-min)))
-                             (insert "\n"))
-                           (insert content)
-                           (write-region nil nil file-name))))
-                     ;; if files contain she-bangs, then make the executable
-                     (when she-bang
-                       (unless tangle-mode (setq tangle-mode #o755)))
-                     ;; update counter
-                     (setq block-counter (+ 1 block-counter))
-                     (unless (assoc file-name path-collector)
-                       (push (cons file-name tangle-mode) path-collector))))))
-             specs)))
+                         (setq she-banged t))
+                       (org-babel-spec-to-string spec)
+                       (setq block-counter (+ 1 block-counter))))
+                   lspecs)
+                  (when make-dir
+                    (make-directory fnd 'parents))
+                   ;; erase previous file
+                   (when (file-exists-p file-name)
+                     (delete-file file-name))
+                  (write-region nil nil file-name)
+                  (mapc (lambda (mode) (set-file-modes file-name mode)) modes)
+                   (push file-name path-collector))))))
         (if (equal arg '(4))
             (org-babel-tangle-single-block 1 t)
           (org-babel-tangle-collect-blocks lang-re tangle-file)))
@@ -293,19 +285,18 @@ matching a regular expression."
                 (if (= block-counter 1) "" "s")
                 (file-name-nondirectory
                  (buffer-file-name
-                  (or (buffer-base-buffer) (current-buffer)))))
+                  (or (buffer-base-buffer)
+                       (current-buffer)
+                       (and (org-src-edit-buffer-p)
+                            (org-src-source-buffer))))))
        ;; run `org-babel-post-tangle-hook' in all tangled files
        (when org-babel-post-tangle-hook
          (mapc
           (lambda (file)
             (org-babel-with-temp-filebuffer file
               (run-hooks 'org-babel-post-tangle-hook)))
-          (mapcar #'car path-collector)))
-       ;; set permissions on tangled files
-       (mapc (lambda (pair)
-               (when (cdr pair) (set-file-modes (car pair) (cdr pair))))
-             path-collector)
-       (mapcar #'car path-collector)))))
+          path-collector))
+       path-collector))))
 
 (defun org-babel-tangle-clean ()
   "Remove comments inserted by `org-babel-tangle'.
@@ -366,12 +357,32 @@ that the appropriate major-mode is set.  SPEC has the 
form:
               (org-fill-template
                org-babel-tangle-comment-format-end link-data)))))
 
+(defun org-babel-effective-tangled-filename (buffer-fn src-lang src-tfile)
+  "Return effective tangled filename of a source-code block.
+BUFFER-FN is the name of the buffer, SRC-LANG the language of the
+block and SRC-TFILE is the value of the :tangle header argument,
+as computed by `org-babel-tangle-single-block'."
+  (let ((base-name (cond
+                    ((string= "yes" src-tfile)
+                     ;; Use the buffer name
+                     (file-name-sans-extension buffer-fn))
+                    ((string= "no" src-tfile) nil)
+                    ((> (length src-tfile) 0) src-tfile)))
+        (ext (or (cdr (assoc src-lang org-babel-tangle-lang-exts)) src-lang)))
+    (when base-name
+      ;; decide if we want to add ext to base-name
+      (if (and ext (string= "yes" src-tfile))
+          (concat base-name "." ext) base-name))))
+
 (defun org-babel-tangle-collect-blocks (&optional lang-re tangle-file)
   "Collect source blocks in the current Org file.
-Return an association list of source-code block specifications of
-the form used by `org-babel-spec-to-string' grouped by language.
+Return an association list of language and source-code block
+specifications of the form used by `org-babel-spec-to-string'
+grouped by tangled file name.
+
 Optional argument LANG-RE can be used to limit the collected
 source code blocks by languages matching a regular expression.
+
 Optional argument TANGLE-FILE can be used to limit the collected
 code blocks by target file."
   (let ((counter 0) last-heading-pos blocks)
@@ -390,12 +401,15 @@ code blocks by target file."
          (unless (or (string= src-tfile "no")
                      (and tangle-file (not (equal tangle-file src-tfile)))
                      (and lang-re (not (string-match-p lang-re src-lang))))
-           ;; Add the spec for this block to blocks under its
-           ;; language.
-           (let ((by-lang (assoc src-lang blocks))
-                 (block (org-babel-tangle-single-block counter)))
-             (if by-lang (setcdr by-lang (cons block (cdr by-lang)))
-               (push (cons src-lang (list block)) blocks)))))))
+           ;; Add the spec for this block to blocks under its tangled
+           ;; file name.
+           (let* ((block (org-babel-tangle-single-block counter))
+                   (src-tfile (cdr (assq :tangle (nth 4 block))))
+                  (file-name (org-babel-effective-tangled-filename
+                               (nth 1 block) src-lang src-tfile))
+                  (by-fn (assoc file-name blocks)))
+             (if by-fn (setcdr by-fn (cons (cons src-lang block) (cdr by-fn)))
+               (push (cons file-name (list (cons src-lang block))) 
blocks)))))))
     ;; Ensure blocks are in the correct order.
     (mapcar (lambda (b) (cons (car b) (nreverse (cdr b))))
            (nreverse blocks))))
@@ -414,10 +428,16 @@ non-nil, return the full association list to be used by
         (src-lang (nth 0 info))
         (params (nth 2 info))
         (extra (nth 3 info))
-        (cref-fmt (or (and (string-match "-l \"\\(.+\\)\"" extra)
-                           (match-string 1 extra))
-                      org-coderef-label-format))
-        (link (let ((l (org-no-properties (org-store-link nil))))
+         (coderef (nth 6 info))
+        (cref-regexp (org-src-coderef-regexp coderef))
+        (link (let* (
+                      ;; The created link is transient.  Using ID is
+                      ;; not necessary, but could have side-effects if
+                      ;; used.  An ID property may be added to
+                      ;; existing entries thus creatin unexpected file
+                      ;; modifications.
+                      (org-id-link-to-org-use-id nil)
+                      (l (org-no-properties (org-store-link nil))))
                  (and (string-match org-link-bracket-re l)
                       (match-string 1 l))))
         (source-name
@@ -445,8 +465,7 @@ non-nil, return the full association list to be used by
                                        (funcall assignments-cmd params))))))
              (when (string-match "-r" extra)
                (goto-char (point-min))
-               (while (re-search-forward
-                       (replace-regexp-in-string "%s" ".+" cref-fmt) nil t)
+               (while (re-search-forward cref-regexp nil t)
                  (replace-match "")))
              (run-hooks 'org-babel-tangle-body-hook)
              (buffer-string))))
@@ -488,7 +507,10 @@ non-nil, return the full association list to be used by
                  (org-trim (org-remove-indentation body)))
                comment)))
     (if only-this-block
-       (list (cons src-lang (list result)))
+        (let* ((src-tfile (cdr (assq :tangle (nth 4 result))))
+               (file-name (org-babel-effective-tangled-filename
+                           (nth 1 result) src-lang src-tfile)))
+          (list (cons file-name (list (cons src-lang result)))))
       result)))
 
 (defun org-babel-tangle-comment-links (&optional info)
@@ -501,7 +523,13 @@ by `org-babel-get-src-block-info'."
                                           (number-to-string
                                            (line-number-at-pos))))
                        ("file" . ,(buffer-file-name))
-                       ("link" . ,(org-no-properties (org-store-link nil)))
+                       ("link" . ,(let (;; The created link is transient.  
Using ID is
+                                         ;; not necessary, but could have 
side-effects if
+                                         ;; used.  An ID property may be added 
to
+                                         ;; existing entries thus creatin 
unexpected file
+                                         ;; modifications.
+                                         (org-id-link-to-org-use-id nil))
+                                     (org-no-properties (org-store-link nil))))
                        ("source-name" . ,name))))))
     (list (org-fill-template org-babel-tangle-comment-format-beg link-data)
          (org-fill-template org-babel-tangle-comment-format-end link-data))))
diff --git a/lisp/org/ob-vala.el b/lisp/org/ob-vala.el
deleted file mode 100644
index 6c3068a8b4..0000000000
--- a/lisp/org/ob-vala.el
+++ /dev/null
@@ -1,116 +0,0 @@
-;;; ob-vala.el --- Babel functions for Vala evaluation -*- lexical-binding: t; 
-*-
-
-;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
-
-;; Author: Christian Garbs <mitch@cgarbs.de>
-;; Keywords: literate programming, reproducible research
-;; Homepage: https://orgmode.org
-
-;;; License:
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; ob-vala.el provides Babel support for the Vala language
-;; (see https://live.gnome.org/Vala for details)
-
-;;; Requirements:
-
-;; - Vala compiler binary (valac)
-;; - Vala development environment (Vala libraries etc.)
-;;
-;; vala-mode.el is nice to have for code formatting, but is not needed
-;; for ob-vala.el
-
-;;; Code:
-
-(require 'ob)
-(require 'org-macs)
-
-;; File extension.
-(add-to-list 'org-babel-tangle-lang-exts '("vala" . "vala"))
-
-;; Header arguments empty by default.
-(defvar org-babel-default-header-args:vala '())
-
-(defcustom org-babel-vala-compiler "valac"
-  "Command used to compile a C source code file into an executable.
-May be either a command in the path, like \"valac\"
-or an absolute path name, like \"/usr/local/bin/valac\".
-Parameters may be used like this: \"valac -v\""
-  :group 'org-babel
-  :version "26.1"
-  :package-version '(Org . "9.1")
-  :type 'string)
-
-;; This is the main function which is called to evaluate a code
-;; block.
-;;
-;; - run Vala compiler and create a binary in a temporary file
-;;   - compiler/linker flags can be set via :flags header argument
-;; - if compilation succeeded, run the binary
-;;   - commandline parameters to the binary can be set via :cmdline
-;;     header argument
-;;   - stdout will be parsed as RESULT (control via :result-params
-;;     header argument)
-;;
-;; There is no session support because Vala is a compiled language.
-;;
-;; This function is heavily based on ob-C.el
-(defun org-babel-execute:vala (body params)
-  "Execute a block of Vala code with Babel.
-This function is called by `org-babel-execute-src-block'."
-  (message "executing Vala source code block")
-  (let* ((tmp-src-file (org-babel-temp-file
-                       "vala-src-"
-                       ".vala"))
-         (tmp-bin-file (org-babel-temp-file "vala-bin-" org-babel-exeext))
-         (cmdline (cdr (assq :cmdline params)))
-         (flags (cdr (assq :flags params))))
-    (with-temp-file tmp-src-file (insert body))
-    (org-babel-eval
-     (format "%s %s -o %s %s"
-            org-babel-vala-compiler
-            (mapconcat #'identity
-                       (if (listp flags) flags (list flags)) " ")
-            (org-babel-process-file-name tmp-bin-file)
-            (org-babel-process-file-name tmp-src-file)) "")
-    (when (file-executable-p tmp-bin-file)
-       (let ((results
-              (org-trim
-               (org-babel-eval
-                (concat tmp-bin-file (if cmdline (concat " " cmdline) "")) 
""))))
-         (org-babel-reassemble-table
-          (org-babel-result-cond (cdr (assq :result-params params))
-            (org-babel-read results)
-            (let ((tmp-file (org-babel-temp-file "vala-")))
-              (with-temp-file tmp-file (insert results))
-              (org-babel-import-elisp-from-file tmp-file)))
-          (org-babel-pick-name
-           (cdr (assq :colname-names params)) (cdr (assq :colnames params)))
-          (org-babel-pick-name
-           (cdr (assq :rowname-names params)) (cdr (assq :rownames 
params))))))))
-
-(defun org-babel-prep-session:vala (_session _params)
-  "Prepare a session.
-This function does nothing as Vala is a compiled language with no
-support for sessions."
-  (error "Vala is a compiled language -- no support for sessions"))
-
-(provide 'ob-vala)
-
-;;; ob-vala.el ends here
diff --git a/lisp/org/oc-basic.el b/lisp/org/oc-basic.el
new file mode 100644
index 0000000000..7b09db5f8b
--- /dev/null
+++ b/lisp/org/oc-basic.el
@@ -0,0 +1,779 @@
+;;; oc-basic.el --- basic back-end for citations  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; The `basic' citation processor provides "activate", "follow", "export" and
+;; "insert" capabilities.
+
+;; "activate" capability re-uses default fontification, but provides additional
+;; features on both correct and wrong keys according to the bibliography
+;; defined in the document.
+
+;; When the mouse is over a known key, it displays the corresponding
+;; bibliography entry.  Any wrong key, however, is highlighted with `error'
+;; face.  Moreover, moving the mouse onto it displays a list of suggested 
correct
+;; keys, and pressing <mouse-1> on the faulty key will try to fix it according 
to
+;; those suggestions.
+
+;; On a citation key, "follow" capability moves point to the corresponding 
entry
+;; in the current bibliography.  Elsewhere on the citation, it asks the user to
+;; follow any of the keys cited there, with completion.
+
+;; "export" capability supports the following citation styles:
+;;
+;;   - author (a), including caps (c) variant,
+;;   - noauthor (na) including bare (b) variant,
+;;   - text (t), including bare (b), caps (c), and bare-caps (bc) variants,
+;;   - note (ft, including bare (b), caps (c), and bare-caps (bc) variants,
+;;   - nocite (n)
+;;   - numeric (nb),
+;;   - default, including bare (b), caps (c), and bare-caps (bc) variants.
+;;
+;; It also supports the following styles for bibliography:
+;;   - plain
+;;   - numeric
+;;   - author-year (default)
+
+;; "insert" capability inserts or edits (with completion) citation style or
+;; citation reference keys.  In an appropriate place, it offers to insert a new
+;; citation.  With a prefix argument, it removes the one at point.
+
+;; It supports bibliography files in BibTeX (".bibtex"), biblatex (".bib") and
+;; JSON (".json") format.
+
+;; Disclaimer: this citation processor is meant to be a proof of concept, and
+;; possibly a fall-back mechanism when nothing else is available.  It is too
+;; limited for any serious use case.
+
+;;; Code:
+
+(require 'bibtex)
+(require 'json)
+(require 'oc)
+(require 'seq)
+
+(declare-function org-open-at-point "org" (&optional arg))
+
+(declare-function org-element-interpret-data "org-element" (data))
+(declare-function org-element-property "org-element" (property element))
+(declare-function org-element-type "org-element" (element))
+
+(declare-function org-export-data "org-export" (data info))
+(declare-function org-export-derived-backend-p "org-export" (backend &rest 
backends))
+(declare-function org-export-raw-string "org-export" (contents))
+
+
+;;; Customization
+(defcustom org-cite-basic-sorting-field 'author
+  "Field used to sort bibliography items as a symbol, or nil."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'symbol
+  :safe #'symbolp)
+
+(defcustom org-cite-basic-author-year-separator ", "
+  "String used to separate cites in an author-year configuration."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-cite-basic-max-key-distance 2
+  "Maximum (Levenshtein) distance between a wrong key and its suggestions."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'integer
+  :safe #'integerp)
+
+(defcustom org-cite-basic-author-column-end 25
+  "Column where author field ends in completion table, as an integer."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'integer
+  :safe #'integerp)
+
+(defcustom org-cite-basic-column-separator "  "
+  "Column separator in completion table, as a string."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-cite-basic-mouse-over-key-face 'highlight
+  "Face used when mouse is over a citation key."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'face
+  :safe #'facep)
+
+
+;;; Internal variables
+(defvar org-cite-basic--bibliography-cache nil
+  "Cache for parsed bibliography files.
+
+This is an association list following the pattern:
+
+  (FILE-ID . ENTRIES)
+
+FILE-ID is a cons cell (FILE . HASH), with FILE being the absolute file name of
+the bibliography file, and HASH a hash of its contents.
+
+ENTRIES is a hash table with citation references as keys and fields alist as
+values.")
+
+(defvar org-cite-basic--completion-cache (make-hash-table :test #'equal)
+  "Cache for key completion table.
+
+This is an a hash-table.")
+
+
+;;; Internal functions
+(defun org-cite-basic--parse-json ()
+  "Parse JSON entries in the current buffer.
+Return a hash table with citation references as keys and fields alist as 
values."
+  (let ((entries (make-hash-table :test #'equal)))
+    (let ((json-array-type 'list)
+          (json-key-type 'symbol))
+      (dolist (item (json-read))
+        (puthash (cdr (assq 'id item))
+                 (mapcar (pcase-lambda (`(,field . ,value))
+                           (pcase field
+                             ('author
+                              ;; Author is an array of objects, each
+                              ;; of them designing a person.  These
+                              ;; objects may contain multiple
+                              ;; properties, but for this basic
+                              ;; processor, we'll focus on `given' and
+                              ;; `family'.
+                              ;;
+                              ;; For compatibility with BibTeX, add
+                              ;; "and" between authors.
+                              (cons 'author
+                                    (mapconcat
+                                     (lambda (alist)
+                                       (concat (alist-get 'family alist)
+                                               " "
+                                               (alist-get 'given alist)))
+                                     value
+                                     " and ")))
+                             ('issued
+                              ;; Date are expressed as an array
+                              ;; (`date-parts') or a "string (`raw').
+                              ;; In both cases, extract the year and
+                              ;; associate it to `year' field, for
+                              ;; compatibility with BibTeX format.
+                              (let ((date (or (alist-get 'date-parts value)
+                                              (alist-get 'raw value))))
+                                (cons 'year
+                                      (cond
+                                       ((consp date)
+                                        (caar date))
+                                       ((stringp date)
+                                        (car (split-string date "-")))
+                                       (t
+                                        (error "Unknown CSL-JSON date format: 
%S"
+                                               date))))))
+                             (_
+                              (cons field value))))
+                         item)
+                 entries))
+      entries)))
+
+(defun org-cite-basic--parse-bibtex (dialect)
+  "Parse BibTeX entries in the current buffer.
+DIALECT is the BibTeX dialect used.  See `bibtex-dialect'.
+Return a hash table with citation references as keys and fields alist as 
values."
+  (let ((entries (make-hash-table :test #'equal))
+        (bibtex-sort-ignore-string-entries t))
+    (bibtex-set-dialect dialect t)
+    (bibtex-map-entries
+     (lambda (key &rest _)
+       ;; Normalize entries: field names are turned into symbols
+       ;; including special "=key=" and "=type=", and consecutive
+       ;; white spaces are removed from values.
+       (puthash key
+                (mapcar
+                 (pcase-lambda (`(,field . ,value))
+                   (pcase field
+                     ("=key=" (cons 'id key))
+                     ("=type=" (cons 'type value))
+                     (_
+                      (cons
+                       (intern (downcase field))
+                       (replace-regexp-in-string "[ \t\n]+" " " value)))))
+                 (bibtex-parse-entry t))
+                entries)))
+    entries))
+
+(defun org-cite-basic--parse-bibliography (&optional info)
+  "List all entries available in the buffer.
+
+Each association follows the pattern
+
+  (FILE . ENTRIES)
+
+where FILE is the absolute file name of the BibTeX file, and ENTRIES is a hash
+table where keys are references and values are association lists between 
fields,
+as symbols, and values as strings or nil.
+
+Optional argument INFO is the export state, as a property list."
+  (if (plist-member info :cite-basic/bibliography)
+      (plist-get info :cite-basic/bibliography)
+    (let ((results nil))
+      (dolist (file (org-cite-list-bibliography-files))
+        (when (file-readable-p file)
+          (with-temp-buffer
+            (insert-file-contents file)
+           (let* ((file-id (cons file (org-buffer-hash)))
+                   (entries
+                    (or (cdr (assoc file-id 
org-cite-basic--bibliography-cache))
+                        (let ((table
+                               (pcase (file-name-extension file)
+                                 ("json" (org-cite-basic--parse-json))
+                                 ("bib" (org-cite-basic--parse-bibtex 
'biblatex))
+                                 ("bibtex" (org-cite-basic--parse-bibtex 
'BibTeX))
+                                 (ext
+                                  (user-error "Unknown bibliography extension: 
%S"
+                                              ext)))))
+                          (push (cons file-id table) 
org-cite-basic--bibliography-cache)
+                          table))))
+              (push (cons file entries) results)))))
+      (when info (plist-put info :cite-basic/bibliography results))
+      results)))
+
+(defun org-cite-basic--key-number (key info)
+  "Return number associated to cited KEY.
+INFO is the export state, as a property list."
+  (let ((predicate
+         (org-cite-basic--field-less-p org-cite-basic-sorting-field info)))
+    (org-cite-key-number key info predicate)))
+
+(defun org-cite-basic--all-keys ()
+  "List all keys available in current bibliography."
+  (seq-mapcat (pcase-lambda (`(,_ . ,entries))
+                (map-keys entries))
+              (org-cite-basic--parse-bibliography)))
+
+(defun org-cite-basic--get-entry (key &optional info)
+  "Return BibTeX entry for KEY, as an association list.
+When non-nil, INFO is the export state, as a property list."
+  (catch :found
+    (pcase-dolist (`(,_ . ,entries) (org-cite-basic--parse-bibliography info))
+      (let ((entry (gethash key entries)))
+        (when entry (throw :found entry))))
+    nil))
+
+(defun org-cite-basic--get-field (field entry-or-key &optional info raw)
+  "Return FIELD value for ENTRY-OR-KEY, or nil.
+
+FIELD is a symbol.  ENTRY-OR-KEY is either an association list, as returned by
+`org-cite-basic--get-entry', or a string representing a citation key.
+
+Optional argument INFO is the export state, as a property list.
+
+Return value may be nil or a string.  If current export back-end is derived
+from `latex', return a raw string instead, unless optional argument RAW is
+non-nil."
+  (let ((value
+         (cdr
+          (assq field
+                (pcase entry-or-key
+                  ((pred stringp)
+                   (org-cite-basic--get-entry entry-or-key info))
+                  ((pred consp)
+                   entry-or-key)
+                  (_
+                   (error "Wrong value for ENTRY-OR-KEY: %S" 
entry-or-key)))))))
+    (if (and value
+             (not raw)
+             (org-export-derived-backend-p (plist-get info :back-end) 'latex))
+        (org-export-raw-string value)
+      value)))
+
+(defun org-cite-basic--number-to-suffix (n)
+  "Compute suffix associated to number N.
+This is used for disambiguation."
+  (let ((result nil))
+    (apply #'string
+           (mapcar (lambda (n) (+ 97 n))
+                   (catch :complete
+                     (while t
+                       (push (% n 26) result)
+                       (setq n (/ n 26))
+                       (cond
+                        ((= n 0) (throw :complete result))
+                        ((< n 27) (throw :complete (cons (1- n) result)))
+                        ((= n 27) (throw :complete (cons 0 (cons 0 result))))
+                        (t nil))))))))
+
+(defun org-cite-basic--get-year (entry-or-key info &optional no-suffix)
+  "Return year associated to ENTRY-OR-KEY.
+
+ENTRY-OR-KEY is either an association list, as returned by
+`org-cite-basic--get-entry', or a string representing a citation
+key.  INFO is the export state, as a property list.
+
+Year is obtained from the \"year\" field, if available, or from
+the \"date\" field if it starts with a year pattern.
+
+Unlike `org-cite-basic--get-field', this function disambiguates
+author-year patterns by adding a letter suffix to the year when
+necessary, unless optional argument NO-SUFFIX is non-nil."
+  ;; The cache is an association list with the following structure:
+  ;;
+  ;;    (AUTHOR-YEAR . KEY-SUFFIX-ALIST).
+  ;;
+  ;; AUTHOR-YEAR is the author year pair associated to current entry
+  ;; or key.
+  ;;
+  ;; KEY-SUFFIX-ALIST is an association (KEY . SUFFIX), where KEY is
+  ;; the cite key, as a string, and SUFFIX is the generated suffix
+  ;; string, or the empty string.
+  (let* ((author (org-cite-basic--get-field 'author entry-or-key info 'raw))
+         (year
+          (or (org-cite-basic--get-field 'year entry-or-key info 'raw)
+              (let ((date
+                     (org-cite-basic--get-field 'date entry-or-key info t)))
+                (and (stringp date)
+                     (string-match (rx string-start
+                                       (group (= 4 digit))
+                                       (or string-end (not digit)))
+                                   date)
+                     (match-string 1 date)))))
+         (cache-key (cons author year))
+         (key
+          (pcase entry-or-key
+            ((pred stringp) entry-or-key)
+            ((pred consp) (cdr (assq 'id entry-or-key)))
+            (_ (error "Wrong value for ENTRY-OR-KEY: %S" entry-or-key))))
+         (cache (plist-get info :cite-basic/author-date-cache)))
+    (pcase (assoc cache-key cache)
+      ('nil
+       (let ((value (cons cache-key (list (cons key "")))))
+         (plist-put info :cite-basic/author-date-cache (cons value cache))
+         year))
+      (`(,_ . ,alist)
+       (let ((suffix
+              (or (cdr (assoc key alist))
+                  (let ((new (org-cite-basic--number-to-suffix
+                              (1- (length alist)))))
+                    (push (cons key new) alist)
+                    new))))
+         (if no-suffix year (concat year suffix)))))))
+
+(defun org-cite-basic--print-entry (entry style &optional info)
+  "Format ENTRY according to STYLE string.
+ENTRY is an alist, as returned by `org-cite-basic--get-entry'.
+Optional argument INFO is the export state, as a property list."
+  (let ((author (org-cite-basic--get-field 'author entry info))
+        (title (org-cite-basic--get-field 'title entry info))
+        (from
+         (or (org-cite-basic--get-field 'publisher entry info)
+             (org-cite-basic--get-field 'journal entry info)
+             (org-cite-basic--get-field 'institution entry info)
+             (org-cite-basic--get-field 'school entry info))))
+    (pcase style
+      ("plain"
+       (let ((year (org-cite-basic--get-year entry info 'no-suffix)))
+         (org-cite-concat
+          author ". " title (and from (list ", " from)) ", " year ".")))
+      ("numeric"
+       (let ((n (org-cite-basic--key-number (cdr (assq 'id entry)) info))
+             (year (org-cite-basic--get-year entry info 'no-suffix)))
+         (org-cite-concat
+          (format "[%d] " n) author ", "
+          (org-cite-emphasize 'italic title)
+          (and from (list ", " from)) ", "
+          year ".")))
+      ;; Default to author-year.  Use year disambiguation there.
+      (_
+       (let ((year (org-cite-basic--get-year entry info)))
+         (org-cite-concat
+          author " (" year "). "
+          (org-cite-emphasize 'italic title)
+          (and from (list ", " from)) "."))))))
+
+
+;;; "Activate" capability
+(defun org-cite-basic--close-keys (key keys)
+  "List cite keys close to KEY in terms of string distance."
+  (seq-filter (lambda (k)
+                (>= org-cite-basic-max-key-distance
+                    (org-string-distance k key)))
+              keys))
+
+(defun org-cite-basic--set-keymap (beg end suggestions)
+  "Set keymap on citation key between BEG and END positions.
+
+When the key is know, SUGGESTIONS is nil.  Otherwise, it may be
+a list of replacement keys, as strings, which will be offered as
+substitutes for the unknown key.  Finally, it may be the symbol
+`all'."
+  (let ((km (make-sparse-keymap)))
+    (define-key km (kbd "<mouse-1>")
+      (pcase suggestions
+        ('nil #'org-open-at-point)
+        ('all #'org-cite-insert)
+        (_
+         (lambda ()
+           (interactive)
+           (setf (buffer-substring beg end)
+                 (concat "@"
+                         (if (= 1 (length suggestions))
+                             (car suggestions)
+                           (completing-read "Did you mean: "
+                                            suggestions nil t))))))))
+    (put-text-property beg end 'keymap km)))
+
+(defun org-cite-basic-activate (citation)
+  "Set various text properties on CITATION object.
+
+Fontify whole citation with `org-cite' face.  Fontify key with `error' face
+when it does not belong to known keys.  Otherwise, use `org-cite-key' face.
+
+Moreover, when mouse is on a known key, display the corresponding bibliography.
+On a wrong key, suggest a list of possible keys, and offer to substitute one of
+them with a mouse click."
+  (pcase-let ((`(,beg . ,end) (org-cite-boundaries citation))
+              (keys (org-cite-basic--all-keys)))
+    (put-text-property beg end 'font-lock-multiline t)
+    (add-face-text-property beg end 'org-cite)
+    (dolist (reference (org-cite-get-references citation))
+      (pcase-let* ((`(,beg . ,end) (org-cite-key-boundaries reference))
+                   (key (org-element-property :key reference)))
+        ;; Highlight key on mouse over.
+        (put-text-property beg end
+                           'mouse-face
+                           org-cite-basic-mouse-over-key-face)
+        (if (member key keys)
+            ;; Activate a correct key.  Face is `org-cite-key' and
+            ;; `help-echo' displays bibliography entry, for reference.
+            ;; <mouse-1> calls `org-open-at-point'.
+            (let* ((entry (org-cite-basic--get-entry key))
+                   (bibliography-entry
+                    (org-element-interpret-data
+                     (org-cite-basic--print-entry entry "plain"))))
+              (add-face-text-property beg end 'org-cite-key)
+              (put-text-property beg end 'help-echo bibliography-entry)
+              (org-cite-basic--set-keymap beg end nil))
+          ;; Activate a wrong key.  Face is `error', `help-echo'
+          ;; displays possible suggestions.
+          (add-face-text-property beg end 'error)
+          (let ((close-keys (org-cite-basic--close-keys key keys)))
+            (when close-keys
+              (put-text-property beg end 'help-echo
+                                 (concat "Suggestions (mouse-1 to substitute): 
"
+                                         (mapconcat #'identity close-keys " 
"))))
+            ;; When the are close know keys, <mouse-1> provides
+            ;; completion to fix the current one.  Otherwise, call
+            ;; `org-cite-insert'.
+            (org-cite-basic--set-keymap beg end (or close-keys 'all))))))))
+
+
+;;; "Export" capability
+(defun org-cite-basic--format-author-year (citation format-cite format-ref 
info)
+  "Format CITATION object according to author-year format.
+
+FORMAT-CITE is a function of three arguments: the global prefix, the contents,
+and the global suffix.  All arguments can be strings or secondary strings.
+
+FORMAT-REF is a function of four arguments: the reference prefix, as a string 
or
+secondary string, the author, the year, and the reference suffix, as a string 
or
+secondary string.
+
+INFO is the export state, as a property list."
+  (org-export-data
+   (funcall format-cite
+            (org-element-property :prefix citation)
+            (org-cite-mapconcat
+             (lambda (ref)
+               (let ((k (org-element-property :key ref))
+                     (prefix (org-element-property :prefix ref))
+                     (suffix (org-element-property :suffix ref)))
+                 (funcall format-ref
+                          prefix
+                          (org-cite-basic--get-field 'author k info)
+                          (org-cite-basic--get-year k info)
+                          suffix)))
+             (org-cite-get-references citation)
+             org-cite-basic-author-year-separator)
+            (org-element-property :suffix citation))
+   info))
+
+(defun org-cite-basic--citation-numbers (citation info)
+  "Return numbers associated to references in CITATION object.
+INFO is the export state as a property list."
+  (let* ((numbers
+          (sort (mapcar (lambda (k) (org-cite-basic--key-number k info))
+                        (org-cite-get-references citation t))
+                #'<))
+         (last (car numbers))
+         (result (list (number-to-string (pop numbers)))))
+    ;; Use compact number references, i.e., "1, 2, 3" becomes "1-3".
+    (while numbers
+      (let ((current (pop numbers))
+            (next (car numbers)))
+        (cond
+         ((and next
+               (= current (1+ last))
+               (= current (1- next)))
+          (unless (equal "-" (car result))
+            (push "-" result)))
+         ((equal "-" (car result))
+          (push (number-to-string current) result))
+         (t
+          (push (format ", %d" current) result)))
+        (setq last current)))
+    (apply #'concat (nreverse result))))
+
+(defun org-cite-basic--field-less-p (field info)
+  "Return a sort predicate comparing FIELD values for two citation keys.
+INFO is the export state, as a property list."
+  (and field
+       (lambda (a b)
+         (org-string-collate-lessp
+          (org-cite-basic--get-field field a info 'raw)
+          (org-cite-basic--get-field field b info 'raw)
+          nil t))))
+
+(defun org-cite-basic--sort-keys (keys info)
+  "Sort KEYS by author name.
+INFO is the export communication channel, as a property list."
+  (let ((predicate (org-cite-basic--field-less-p org-cite-basic-sorting-field 
info)))
+    (if predicate
+        (sort keys predicate)
+      keys)))
+
+(defun org-cite-basic-export-citation (citation style _ info)
+  "Export CITATION object.
+STYLE is the expected citation style, as a pair of strings or nil.  INFO is the
+export communication channel, as a property list."
+  (let ((has-variant-p
+         (lambda (variant type)
+           ;; Non-nil when style VARIANT has TYPE.  TYPE is either
+           ;; `bare' or `caps'.
+           (member variant
+                   (pcase type
+                     ('bare '("bare" "bare-caps" "b" "bc"))
+                     ('caps '("caps" "bare-caps" "c" "bc"))
+                     (_ (error "Invalid variant type: %S" type)))))))
+    (pcase style
+      ;; "author" style.
+      (`(,(or "author" "a") . ,variant)
+       (let ((caps (member variant '("caps" "c"))))
+         (org-export-data
+          (mapconcat
+           (lambda (key)
+             (let ((author (org-cite-basic--get-field 'author key info)))
+               (if caps (capitalize author) author)))
+           (org-cite-get-references citation t)
+           org-cite-basic-author-year-separator)
+          info)))
+      ;; "noauthor" style.
+      (`(,(or "noauthor" "na") . ,variant)
+       (format (if (funcall has-variant-p variant 'bare) "%s" "(%s)")
+               (mapconcat (lambda (key) (org-cite-basic--get-year key info))
+                          (org-cite-get-references citation t)
+                          org-cite-basic-author-year-separator)))
+      ;; "nocite" style.
+      (`(,(or "nocite" "n") . ,_) nil)
+      ;; "text" and "note" styles.
+      (`(,(and (or "text" "note" "t" "ft") style) . ,variant)
+       (when (and (member style '("note" "ft"))
+                  (not (org-cite-inside-footnote-p citation)))
+         (org-cite-adjust-note citation info)
+         (org-cite-wrap-citation citation info))
+       (let ((bare (funcall has-variant-p variant 'bare))
+             (caps (funcall has-variant-p variant 'caps)))
+         (org-cite-basic--format-author-year
+          citation
+          (lambda (p c s) (org-cite-concat p c s))
+          (lambda (p a y s)
+            (org-cite-concat p
+                             (if caps (capitalize a) a)
+                             (if bare " " " (")
+                             y s
+                             (and (not bare) ")")))
+          info)))
+      ;; "numeric" style.
+      ;;
+      ;; When using this style on citations with multiple references,
+      ;; use global affixes and ignore local ones.
+      (`(,(or "numeric" "nb") . ,_)
+       (pcase-let ((`(,prefix . ,suffix) (org-cite-main-affixes citation)))
+         (org-export-data
+          (org-cite-concat
+           "(" prefix (org-cite-basic--citation-numbers citation info) suffix 
")")
+          info)))
+      ;; Default ("nil") style.
+      (`(,_ . ,variant)
+       (let ((bare (funcall has-variant-p variant 'bare))
+             (caps (funcall has-variant-p variant 'caps)))
+         (org-cite-basic--format-author-year
+          citation
+          (lambda (p c s)
+            (org-cite-concat (and (not bare) "(") p c s (and (not bare) ")")))
+          (lambda (p a y s)
+            (org-cite-concat p (if caps (capitalize a) a) ", " y s))
+          info)))
+      ;; This should not happen.
+      (_ (error "Invalid style: %S" style)))))
+
+(defun org-cite-basic-export-bibliography (keys _files style _props backend 
info)
+  "Generate bibliography.
+KEYS is the list of cited keys, as strings.  STYLE is the expected bibliography
+style, as a string.  BACKEND is the export back-end, as a symbol.  INFO is the
+export state, as a property list."
+  (mapconcat
+   (lambda (k)
+     (let ((entry (org-cite-basic--get-entry k info)))
+       (org-export-data
+        (org-cite-make-paragraph
+         (and (org-export-derived-backend-p backend 'latex)
+              (org-export-raw-string "\\noindent\n"))
+         (org-cite-basic--print-entry entry style info))
+        info)))
+   (org-cite-basic--sort-keys keys info)
+   "\n"))
+
+
+;;; "Follow" capability
+(defun org-cite-basic-goto (datum _)
+  "Follow citation or citation reference DATUM.
+When DATUM is a citation reference, open bibliography entry referencing
+the citation key.  Otherwise, select which key to follow among all keys
+present in the citation."
+  (let* ((key
+          (if (eq 'citation-reference (org-element-type datum))
+              (org-element-property :key datum)
+            (pcase (org-cite-get-references datum t)
+              (`(,key) key)
+              (keys
+               (or (completing-read "Select citation key: " keys nil t)
+                   (user-error "Aborted"))))))
+         (file
+          (pcase (seq-find (pcase-lambda (`(,_ . ,entries))
+                             (gethash key entries))
+                           (org-cite-basic--parse-bibliography))
+            (`(,f . ,_) f)
+            (_  (user-error "Cannot find citation key: %S" key)))))
+    (org-open-file file '(4))
+    (pcase (file-name-extension file)
+      ("json"
+       ;; `rx' can not be used with Emacs <27.1 since `literal' form
+       ;; is not supported.
+       (let ((regexp (rx-to-string `(seq "\"id\":" (0+ (any "[ \t]")) "\"" 
,key "\"") t)))
+         (goto-char (point-min))
+         (re-search-forward regexp)
+         (search-backward "{")))
+      (_
+       (bibtex-set-dialect)
+       (bibtex-search-entry key)))))
+
+
+;;; "Insert" capability
+(defun org-cite-basic--complete-style (_)
+  "Offer completion for style.
+Return chosen style as a string."
+  (let* ((styles
+          (mapcar (pcase-lambda (`((,style . ,_) . ,_))
+                    style)
+                  (org-cite-supported-styles))))
+    (pcase styles
+      (`(,style) style)
+      (_ (completing-read "Style (\"\" for default): " styles nil t)))))
+
+(defun org-cite-basic--key-completion-table ()
+  "Return completion table for cite keys, as a hash table.
+In this hash table, keys are a strings with author, date, and title of the
+reference.  Values are the cite key."
+  (let ((cache-key (mapcar #'car org-cite-basic--bibliography-cache)))
+    (if (gethash cache-key org-cite-basic--completion-cache)
+        org-cite-basic--completion-cache
+      (clrhash org-cite-basic--completion-cache)
+      (dolist (key (org-cite-basic--all-keys))
+        (let ((completion
+               (concat
+                (let ((author (org-cite-basic--get-field 'author key nil t)))
+                  (if author
+                      (truncate-string-to-width
+                       (replace-regexp-in-string " and " "; " author)
+                       org-cite-basic-author-column-end nil ?\s)
+                    (make-string org-cite-basic-author-column-end ?\s)))
+                org-cite-basic-column-separator
+                (let ((date (org-cite-basic--get-year key nil 'no-suffix)))
+                  (format "%4s" (or date "")))
+                org-cite-basic-column-separator
+                (org-cite-basic--get-field 'title key nil t))))
+          (puthash completion key org-cite-basic--completion-cache)))
+      (puthash cache-key t org-cite-basic--completion-cache)
+      org-cite-basic--completion-cache)))
+
+(defun org-cite-basic--complete-key (&optional multiple)
+  "Prompt for a reference key and return a citation reference string.
+
+When optional argument MULTIPLE is non-nil, prompt for multiple keys, until one
+of them is nil.  Then return the list of reference strings selected.
+
+Raise an error when no bibliography is set in the buffer."
+  (let* ((table
+          (or (org-cite-basic--key-completion-table)
+              (user-error "No bibliography set")))
+         (prompt
+          (lambda (text)
+            (completing-read text table nil t))))
+    (if (null multiple)
+        (let ((key (gethash (funcall prompt "Key: ") table)))
+          (org-string-nw-p key))
+      (let* ((keys nil)
+             (build-prompt
+              (lambda ()
+                (if keys
+                    (format "Key (\"\" to exit) %s: "
+                            (mapconcat #'identity (reverse keys) ";"))
+                  "Key (\"\" to exit): "))))
+        (let ((key (funcall prompt (funcall build-prompt))))
+          (while (org-string-nw-p key)
+            (push (gethash key table) keys)
+            (setq key (funcall prompt (funcall build-prompt)))))
+        keys))))
+
+
+;;; Register processor
+(org-cite-register-processor 'basic
+  :activate #'org-cite-basic-activate
+  :export-citation #'org-cite-basic-export-citation
+  :export-bibliography #'org-cite-basic-export-bibliography
+  :follow #'org-cite-basic-goto
+  :insert (org-cite-make-insert-processor #'org-cite-basic--complete-key
+                                          #'org-cite-basic--complete-style)
+  :cite-styles
+  '((("author" "a") ("caps" "c"))
+    (("noauthor" "na") ("bare" "b"))
+    (("nocite" "n"))
+    (("note" "ft") ("bare-caps" "bc") ("caps" "c"))
+    (("numeric" "nb"))
+    (("text" "t") ("bare-caps" "bc") ("caps" "c"))
+    (("nil") ("bare" "b") ("bare-caps" "bc") ("caps" "c"))))
+
+(provide 'oc-basic)
+;;; oc-basic.el ends here
diff --git a/lisp/org/oc-biblatex.el b/lisp/org/oc-biblatex.el
new file mode 100644
index 0000000000..e985963816
--- /dev/null
+++ b/lisp/org/oc-biblatex.el
@@ -0,0 +1,318 @@
+;;; oc-biblatex.el --- biblatex citation processor for Org  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library registers the `biblatex' citation processor, which provides
+;; the "export" capability for citations.
+
+;; The processor relies on "biblatex" LaTeX package.  As such it ensures that
+;; the package is properly required in the document's preamble.  More
+;; accurately, it will re-use any "\usepackage{biblatex}" already present in
+;; the document (e.g., through `org-latex-packages-alist'), or insert one using
+;; options defined in `org-cite-biblatex-options'.
+
+;; In any case, the library will override style-related options with those
+;; specified with the citation processor, in `org-cite-export-processors' or
+;; "cite_export" keyword.  If you need to use different styles for bibliography
+;; and citations, you can separate them with "bibstyle/citestyle" syntax.  
E.g.,
+;;
+;;   #+cite_export: biblatex authortitle/authortitle-ibid
+
+;; The library supports the following citation styles:
+;;
+;; - author (a), including caps (c), full (f) and caps-full (cf) variants,
+;; - locators (l), including bare (b), caps (c) and bare-caps (bc) variants,
+;; - noauthor (na),
+;; - nocite (n),
+;; - text (t), including caps (c) variant,
+;; - default style, including bare (b), caps (c) and bare-caps (bc) variants.
+
+;; When citation and style permit, the library automatically generates
+;; "multicite" versions of the commands above.
+
+;; Bibliography is printed using "\printbibliography" command.  Additional
+;; options may be passed to it through a property list attached to the
+;; "print_bibliography" keyword.  E.g.,
+;;
+;;    #+print_bibliography: :section 2 :heading subbibliography
+;;
+;; Values including spaces must be surrounded with double quotes.  If you need
+;; to use a key multiple times, you can separate its values with commas, but
+;; without any space in-between:
+;;
+;;    #+print_bibliography: :keyword abc,xyz :title "Primary Sources"
+
+;;; Code:
+(require 'org-macs)
+(require 'oc)
+
+(declare-function org-element-property "org-element" (property element))
+(declare-function org-export-data "org-export" (data info))
+(declare-function org-export-get-next-element "org-export" (blob info 
&optional n))
+
+
+;;; Customization
+(defcustom org-cite-biblatex-options nil
+  "Options added to \"biblatex\" package.
+If \"biblatex\" package is already required in the document, e.g., through
+`org-latex-packages-alist' variable, these options are ignored."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice
+          (string :tag "Options (key=value,key2=value2...)")
+          (const :tag "No option" nil))
+  :safe #'string-or-null-p)
+
+
+;;; Internal functions
+(defun org-cite-biblatex--package-options (initial style)
+  "Return options string for \"biblatex\" package.
+
+INITIAL is an initial style of comma-separated options, as a string or nil.
+STYLE is the style definition as a string or nil.
+
+Return a string."
+  (let ((options-no-style
+         (and initial
+              (let ((re (rx string-start (or "bibstyle" "citestyle" "style"))))
+                (seq-filter
+                 (lambda (option) (not (string-match re option)))
+                 (split-string (org-unbracket-string "[" "]" initial)
+                               "," t " \t")))))
+        (style-options
+         (cond
+          ((null style) nil)
+          ((not (string-match "/" style)) (list (concat "style=" style)))
+          (t
+           (list (concat "bibstyle=" (substring style nil (match-beginning 0)))
+                 (concat "citestyle=" (substring style (match-end 0))))))))
+    (if (or options-no-style style-options)
+        (format "[%s]"
+                (mapconcat #'identity
+                           (append options-no-style style-options)
+                           ","))
+      "")))
+
+(defun org-cite-biblatex--multicite-p  (citation)
+  "Non-nil when citation could make use of a \"multicite\" command."
+  (let ((references (org-cite-get-references citation)))
+    (and (< 1 (length references))
+         (seq-some (lambda (r)
+                     (or (org-element-property :prefix r)
+                         (org-element-property :suffix r)))
+                   references))))
+
+(defun org-cite-biblatex--atomic-arguments (references info &optional no-opt)
+  "Build argument for the list of citation REFERENCES.
+When NO-OPT argument is non-nil, only provide mandatory arguments."
+  (let ((mandatory
+         (format "{%s}"
+                 (mapconcat (lambda (r) (org-element-property :key r))
+                            references
+                            ","))))
+    (if no-opt mandatory
+      (let* ((origin (pcase references
+                       (`(,reference) reference)
+                       (`(,reference . ,_)
+                        (org-element-property :parent reference))))
+             (suffix (org-element-property :suffix origin))
+             (prefix (org-element-property :prefix origin)))
+        (concat (and prefix
+                     (format "[%s]" (org-trim (org-export-data prefix info))))
+                (cond
+                 (suffix (format "[%s]"
+                                 (org-trim (org-export-data suffix info))))
+                 (prefix "[]")
+                 (t nil))
+                mandatory)))))
+
+(defun org-cite-biblatex--multi-arguments (citation info)
+  "Build \"multicite\" command arguments for CITATION object.
+INFO is the export state, as a property list."
+  (let ((global-prefix (org-element-property :prefix citation))
+        (global-suffix (org-element-property :suffix citation)))
+    (concat (and global-prefix
+                 (format "(%s)"
+                         (org-trim (org-export-data global-prefix info))))
+            (cond
+             ;; Global pre/post-notes.
+             (global-suffix
+              (format "(%s)"
+                      (org-trim (org-export-data global-suffix info))))
+             (global-prefix "()")
+             (t nil))
+            ;; All arguments.
+            (mapconcat (lambda (r)
+                         (org-cite-biblatex--atomic-arguments (list r) info))
+                       (org-cite-get-references citation)
+                       "")
+            ;; According to BibLaTeX manual, left braces or brackets
+            ;; following a multicite command could be parsed as other
+            ;; arguments. So we stop any further parsing by inserting
+            ;; a \relax unconditionally.
+            "\\relax")))
+
+(defun org-cite-biblatex--command (citation info base &optional multi no-opt)
+  "Return biblatex command using BASE name for CITATION object.
+
+INFO is the export state, as a property list.
+
+When optional argument MULTI is non-nil, generate a \"multicite\" command when
+appropriate.  When optional argument NO-OPT is non-nil, do not add optional
+arguments to the command."
+  (format "\\%s%s"
+          base
+          (if (and multi (org-cite-biblatex--multicite-p citation))
+              (concat "s" (org-cite-biblatex--multi-arguments citation info))
+            (org-cite-biblatex--atomic-arguments
+             (org-cite-get-references citation) info no-opt))))
+
+
+;;; Export capability
+(defun org-cite-biblatex-export-bibliography (_keys _files _style props &rest 
_)
+  "Print references from bibliography.
+PROPS is the local properties of the bibliography, as a property list."
+  (concat "\\printbibliography"
+          (and props
+               (let ((key nil)
+                     (results nil))
+                 (dolist (datum props)
+                   (cond
+                    ((keywordp datum)
+                     (when key (push key results))
+                     (setq key (substring (symbol-name datum) 1)))
+                    (t
+                     ;; Comma-separated values are associated to the
+                     ;; same keyword.
+                     (push (mapconcat (lambda (v) (concat key "=" v))
+                                      (split-string datum "," t)
+                                      ",")
+                           results)
+                     (setq key nil))))
+                 (format "[%s]"
+                         (mapconcat #'identity (nreverse results) ","))))))
+
+(defun org-cite-biblatex-export-citation (citation style _ info)
+  "Export CITATION object.
+STYLE is the citation style, as a pair of either strings or nil.
+INFO is the export state, as a property list."
+  (apply
+   #'org-cite-biblatex--command citation info
+   (pcase style
+     ;; "author" style.
+     (`(,(or "author" "a") . ,variant)
+      (pcase variant
+        ((or "caps" "c")            '("Citeauthor*"))
+        ((or "full" "f")            '("citeauthor"))
+        ((or "caps-full" "cf")      '("Citeauthor"))
+        (_                          '("citeauthor*"))))
+     ;; "locators" style.
+     (`(,(or "locators" "l") . ,variant)
+      (pcase variant
+        ((or "bare" "b")            '("notecite"))
+        ((or "caps" "c")            '("Pnotecite"))
+        ((or "bare-caps" "bc")      '("Notecite"))
+        (_                          '("pnotecite"))))
+     ;; "noauthor" style.
+     (`(,(or "noauthor" "na") . ,_) '("autocite*"))
+     ;; "nocite" style.
+     (`(,(or "nocite" "n") . ,_)    '("nocite" nil t))
+     ;; "text" style.
+     (`(,(or "text" "t") . ,variant)
+      (pcase variant
+        ((or "caps" "c")            '("Textcite" t))
+        (_                          '("textcite" t))))
+     ;; Default "nil" style.
+     (`(,_ . ,variant)
+      (pcase variant
+        ((or "bare" "b")            '("cite" t))
+        ((or "caps" "c")            '("Autocite" t))
+        ((or "bare-caps" "bc")      '("Cite" t))
+        (_                          '("autocite" t))))
+     ;; This should not happen.
+     (_ (error "Invalid style: %S" style)))))
+
+(defun org-cite-biblatex-prepare-preamble (output _keys files style &rest _)
+  "Prepare document preamble for \"biblatex\" usage.
+
+OUTPUT is the final output of the export process.  FILES is the list of file
+names used as the bibliography.
+
+This function ensures \"biblatex\" package is required.  It also adds resources
+to the document, and set styles."
+  (with-temp-buffer
+    (save-excursion (insert output))
+    (when (search-forward "\\begin{document}" nil t)
+      ;; Ensure there is a \usepackage{biblatex} somewhere or add one.
+      ;; Then set options.
+      (goto-char (match-beginning 0))
+      (let ((re (rx "\\usepackage"
+                    (opt (group "[" (*? anything) "]"))
+                    "{biblatex}")))
+        (cond
+         ;; No "biblatex" package loaded.  Insert "usepackage" command
+         ;; with appropriate options, including style.
+         ((not (re-search-backward re nil t))
+          (save-excursion
+            (insert
+             (format "\\usepackage%s{biblatex}\n"
+                     (org-cite-biblatex--package-options
+                      org-cite-biblatex-options style)))))
+         ;; "biblatex" package loaded, but without any option.
+         ;; Include style only.
+         ((not (match-beginning 1))
+          (search-forward "{" nil t)
+          (insert (org-cite-biblatex--package-options nil style)))
+         ;; "biblatex" package loaded with some options set.  Override
+         ;; style-related options with ours.
+         (t
+          (replace-match
+           (save-match-data
+             (org-cite-biblatex--package-options (match-string 1) style))
+           nil nil nil 1))))
+      ;; Insert resources below.
+      (forward-line)
+      (insert (mapconcat (lambda (f)
+                           (format "\\addbibresource%s{%s}"
+                                   (if (org-url-p f) "[location=remote]" "")
+                                   f))
+                         files
+                         "\n")
+              "\n"))
+    (buffer-string)))
+
+
+;;; Register `biblatex' processor
+(org-cite-register-processor 'biblatex
+  :export-bibliography #'org-cite-biblatex-export-bibliography
+  :export-citation #'org-cite-biblatex-export-citation
+  :export-finalizer #'org-cite-biblatex-prepare-preamble
+  :cite-styles
+  '((("author" "a") ("caps" "c") ("full" "f") ("caps-full" "cf"))
+    (("locators" "l") ("bare" "b") ("caps" "c") ("bare-caps" "bc"))
+    (("noauthor" "na"))
+    (("nocite" "n"))
+    (("text" "t") ("caps" "c"))
+    (("nil") ("bare" "b") ("caps" "c") ("bare-caps" "bc"))))
+
+(provide 'oc-biblatex)
+;;; oc-biblatex.el ends here
diff --git a/lisp/org/oc-csl.el b/lisp/org/oc-csl.el
new file mode 100644
index 0000000000..7cd63c3ff3
--- /dev/null
+++ b/lisp/org/oc-csl.el
@@ -0,0 +1,630 @@
+;;; oc-csl.el --- csl citation processor for Org -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library registers the `csl' citation processor, which provides
+;; the "export" capability for citations.
+
+;; The processor relies on the external Citeproc Emacs library, which must be
+;; available prior to loading this library.
+
+;; By default, citations are rendered in Chicago author-date CSL style.  You 
can
+;; use another style file by specifying it in `org-cite-export-processors' or
+;; from within the document by adding the file name to "cite_export" keyword
+;;
+;;    #+cite_export: csl /path/to/style-file.csl
+;;    #+cite_export: csl "/path/to/style-file.csl"
+;;
+;; With the variable `org-cite-csl-styles-dir' set appropriately, the
+;; above can even be shortened to
+;;
+;;     #+cite_export: csl style-file.csl
+;;
+;; Styles can be downloaded, for instance, from the Zotero Style Repository
+;; (<https://www.zotero.org/styles>).  Dependent styles (which are not "unique"
+;; in the Zotero Style Repository terminology) are not supported.
+
+;; The processor uses the "en-US" CSL locale file shipped with Org for 
rendering
+;; localized dates and terms in the references, independently of the language
+;; settings of the Org document.  Additional CSL locales can be made available
+;; by setting `org-cite-csl-locales-dir' to a directory containing the locale
+;; files in question (see <https://github.com/citation-style-language/locales>
+;; for such files).
+
+;; Bibliography is defined with the "bibliography" keyword.  It supports files
+;; with ".bib", ".bibtex", and ".json" extensions.  References are exported 
using
+;; the "print_bibliography" keyword.
+
+;; The library supports the following citation styles:
+;;
+;; - author (a), including caps (c), full (f), and caps-full (cf) variants,
+;; - noauthor (na), including bare (b), caps (c) and bare-caps (bc) variants,
+;; - year (y), including a bare (b) variant,
+;; - text (t). including caps (c), full (f), and caps-full (cf) variants,
+;; - default style, including bare (b), caps (c) and bare-caps (bc) variants.
+
+;; CSL styles recognize "locator" in citation references' suffix.  For example,
+;; in the citation
+;;
+;;     [cite:see @Tarski-1965 chapter 1, for an example]
+;;
+;; "chapter 1" is the locator.  The whole citation is rendered as
+;;
+;;     (see Tarski 1965, chap. 1 for an example)
+;;
+;; in the default CSL style.
+;;
+;; The locator starts with a locator term, among "bk.", "bks.", "book", 
"chap.",
+;; "chaps.", "chapter", "col.", "cols.", "column", "figure", "fig.", "figs.",
+;; "folio", "fol.", "fols.", "number", "no.", "nos.", "line", "l.", "ll.",
+;; "note", "n.", "nn.", "opus", "op.", "opp.", "page", "p.", "pp.", 
"paragraph",
+;; "para.", "paras.", "¶", "¶¶", "§", "§§", "part", "pt.", "pts.", "section",
+;; "sec.", "secs.", "sub verbo", "s.v.", "s.vv.", "verse", "v.", "vv.",
+;; "volume", "vol.", and "vols.".  It ends with the last comma or digit in the
+;; suffix, whichever comes last, or runs till the end of the suffix.
+;;
+;; The part of the suffix before the locator is appended to reference's prefix.
+;; If no locator term is used, but a number is present, then "page" is assumed.
+
+;; This library was heavily inspired by and borrows from András Simonyi's
+;; Citeproc Org (<https://github.com/andras-simonyi/citeproc-org>) library.
+;; Many thanks to him!
+
+;;; Code:
+(require 'bibtex)
+(require 'json)
+(require 'oc)
+
+(require 'citeproc nil t)
+(declare-function citeproc-style-cite-note "ext:citeproc")
+(declare-function citeproc-proc-style "ext:citeproc")
+(declare-function citeproc-bt-entry-to-csl "ext:citeproc")
+(declare-function citeproc-locale-getter-from-dir "ext:citeproc")
+(declare-function citeproc-create "ext:citeproc")
+(declare-function citeproc-citation-create "ext:citeproc")
+(declare-function citeproc-append-citations "ext:citeproc")
+(declare-function citeproc-render-citations "ext:citeproc")
+(declare-function citeproc-render-bib "ext:citeproc")
+(declare-function citeproc-hash-itemgetter-from-any "ext:citeproc")
+
+(declare-function org-element-interpret-data "org-element" (data))
+(declare-function org-element-map "org-element" (data types fun &optional info 
first-match no-recursion with-affiliated))
+(declare-function org-element-property "org-element" (property element))
+(declare-function org-element-put-property "org-element" (element property 
value))
+
+(declare-function org-export-data "org-export" (data info))
+(declare-function org-export-derived-backend-p "org-export" (backend &rest 
backends))
+(declare-function org-export-get-footnote-number "org-export" (footnote info 
&optional data body-first))
+
+
+;;; Customization
+
+;;;; Location of CSL directories
+(defcustom org-cite-csl-locales-dir nil
+  "Directory of CSL locale files.
+If nil then only the fallback en-US locale will be available."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice
+          (directory :tag "Locales directory")
+          (const :tag "Use en-US locale only" nil))
+  ;; It's not obvious to me that arbitrary locations are safe.
+;;;  :safe #'string-or-null-p
+  )
+
+(defcustom org-cite-csl-styles-dir nil
+  "Directory of CSL style files.
+When non-nil, relative style file names are expanded relatively to this
+directory.  This variable is ignored when style file is absolute."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice
+          (directory :tag "Styles directory")
+          (const :tag "Use absolute file names" nil))
+  ;; It's not obvious to me that arbitrary locations are safe.
+;;;  :safe #'string-or-null-p
+  )
+
+;;;; Citelinks
+(defcustom org-cite-csl-link-cites t
+  "When non-nil, link cites to references."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'boolean
+  :safe #'booleanp)
+
+(defcustom org-cite-csl-no-citelinks-backends '(ascii)
+  "List of export back-ends for which cite linking is disabled.
+Cite linking for export back-ends derived from any of the back-ends listed 
here,
+is also disabled."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(repeat symbol))
+
+;;;; Output-specific variables
+(defcustom org-cite-csl-html-hanging-indent "1.5em"
+  "Size of hanging-indent for HTML output in valid CSS units."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-cite-csl-html-label-width-per-char "0.6em"
+  "Character width in CSS units for calculating entry label widths.
+Used only when `second-field-align' is activated by the used CSL style."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-cite-csl-latex-hanging-indent "1.5em"
+  "Size of hanging-indent for LaTeX output in valid LaTeX units."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
+
+;;; Internal variables
+(defconst org-cite-csl--etc-dir
+  (let ((oc-root (file-name-directory (locate-library "oc"))))
+    (cond
+     ;; First check whether it looks like we're running from the main
+     ;; Org repository.
+     ((let ((csl-org (expand-file-name "../etc/csl/" oc-root)))
+        (and (file-directory-p csl-org) csl-org)))
+     ;; Next look for the directory alongside oc.el because package.el
+     ;; and straight will put all of org-mode/lisp/ in org-mode/.
+     ((let ((csl-pkg (expand-file-name "etc/csl/" oc-root)))
+        (and (file-directory-p csl-pkg) csl-pkg)))
+     ;; Finally fall back the location used by shared system installs
+     ;; and when running directly from Emacs repository.
+     (t
+      (expand-file-name "org/csl/" data-directory))))
+  "Directory containing CSL-related data files.")
+
+(defconst org-cite-csl--fallback-locales-dir org-cite-csl--etc-dir
+  "Fallback CSL locale files directory.")
+
+(defconst org-cite-csl--fallback-style-file
+  (expand-file-name "chicago-author-date.csl"
+                    org-cite-csl--etc-dir)
+  "Default CSL style file, or nil.
+If nil then the Chicago author-date style is used as a fallback.")
+
+(defconst org-cite-csl--label-alist
+  '(("bk."       . "book")
+    ("bks."      . "book")
+    ("book"      . "book")
+    ("chap."     . "chapter")
+    ("chaps."    . "chapter")
+    ("chapter"   . "chapter")
+    ("col."      . "column")
+    ("cols."     . "column")
+    ("column"    . "column")
+    ("figure"    . "figure")
+    ("fig."      . "figure")
+    ("figs."     . "figure")
+    ("folio"     . "folio")
+    ("fol."      . "folio")
+    ("fols."     . "folio")
+    ("number"    . "number")
+    ("no."       . "number")
+    ("nos."      . "number")
+    ("line"      . "line")
+    ("l."        . "line")
+    ("ll."       . "line")
+    ("note"      . "note")
+    ("n."        . "note")
+    ("nn."       . "note")
+    ("opus"      . "opus")
+    ("op."       . "opus")
+    ("opp."      . "opus")
+    ("page"      . "page")
+    ("p"         . "page")
+    ("p."        . "page")
+    ("pp."       . "page")
+    ("paragraph" . "paragraph")
+    ("para."     . "paragraph")
+    ("paras."    . "paragraph")
+    ("¶"         . "paragraph")
+    ("¶¶"        . "paragraph")
+    ("part"      . "part")
+    ("pt."       . "part")
+    ("pts."      . "part")
+    ("§"         . "section")
+    ("§§"        . "section")
+    ("section"   . "section")
+    ("sec."      . "section")
+    ("secs."     . "section")
+    ("sub verbo" . "sub verbo")
+    ("s.v."      . "sub verbo")
+    ("s.vv."     . "sub verbo")
+    ("verse"     . "verse")
+    ("v."        . "verse")
+    ("vv."       . "verse")
+    ("volume"    . "volume")
+    ("vol."      . "volume")
+    ("vols."     . "volume"))
+  "Alist mapping locator names to locators.")
+
+(defconst org-cite-csl--label-regexp
+  ;; Prior to Emacs-27.1 argument of `regexp' form must be a string literal.
+  ;; It is the reason why `rx' is avoided here.
+  (rx-to-string
+   `(seq (or line-start space)
+         (regexp ,(regexp-opt (mapcar #'car org-cite-csl--label-alist) t))
+         (0+ digit)
+         (or word-end line-end space " "))
+   t)
+  "Regexp matching a label in a citation reference suffix.
+Label is in match group 1.")
+
+
+;;; Internal functions
+(defun org-cite-csl--barf-without-citeproc ()
+  "Raise an error if Citeproc library is not loaded."
+  (unless (featurep 'citeproc) "Citeproc library is not loaded"))
+
+(defun org-cite-csl--note-style-p (info)
+  "Non-nil when bibliography style implies wrapping citations in footnotes.
+INFO is the export state, as a property list."
+  (citeproc-style-cite-note
+   (citeproc-proc-style
+    (org-cite-csl--processor info))))
+
+(defun org-cite-csl--create-structure-params (citation info)
+  "Return citeproc structure creation params for CITATION object.
+STYLE is the citation style, as a string or nil. INFO is the export state, as
+a property list."
+  (let ((style (org-cite-citation-style citation info)))
+    (pcase style
+      ;; "author" style.
+      (`(,(or "author" "a") . ,variant)
+       (pcase variant
+        ((or "caps" "c") '(:mode author-only :capitalize-first t))
+        ((or "full" "f") '(:mode author-only :ignore-et-al t))
+        ((or "caps-full" "cf") '(:mode author-only :capitalize-first t 
:ignore-et-al t))
+        (_ '(:mode author-only))))
+      ;; "noauthor" style.
+      (`(,(or "noauthor" "na") . ,variant)
+       (pcase variant
+        ((or "bare" "b") '(:mode suppress-author :suppress-affixes t))
+        ((or "caps" "c") '(:mode suppress-author :capitalize-first t))
+        ((or "bare-caps" "bc")
+          '(:mode suppress-author :suppress-affixes t :capitalize-first t))
+        (_ '(:mode suppress-author))))
+      ;; "year" style.
+      (`(,(or "year" "y") . ,variant)
+       (pcase variant
+        ((or "bare" "b") '(:mode year-only :suppress-affixes t))
+        (_ '(:mode year-only))))
+      ;; "text" style.
+      (`(,(or "text" "t") . ,variant)
+       (pcase variant
+         ((or "caps" "c") '(:mode textual :capitalize-first t))
+         ((or "full" "f") '(:mode textual :ignore-et-al t))
+         ((or "caps-full" "cf") '(:mode textual :ignore-et-al t 
:capitalize-first t))
+         (_ '(:mode textual))))
+      ;; Default "nil" style.
+      (`(,_ . ,variant)
+       (pcase variant
+         ((or "caps" "c") '(:capitalize-first t))
+         ((or "bare" "b") '(:suppress-affixes t))
+         ((or "bare-caps" "bc") '(:suppress-affixes t :capitalize-first t))
+         (_  nil)))
+      ;; This should not happen.
+      (_ (error "Invalid style: %S" style)))))
+
+(defun org-cite-csl--no-citelinks-p (info)
+  "Non-nil when export BACKEND should not create cite-reference links."
+  (or (not org-cite-csl-link-cites)
+      (and org-cite-csl-no-citelinks-backends
+           (apply #'org-export-derived-backend-p
+                  (plist-get info :back-end)
+                  org-cite-csl-no-citelinks-backends))
+      ;; No references are being exported anyway.
+      (not (org-element-map (plist-get info :parse-tree) 'keyword
+             (lambda (k)
+               (equal "PRINT_BIBLIOGRAPHY" (org-element-property :key k)))
+             info t))))
+
+(defun org-cite-csl--output-format (info)
+  "Return expected Citeproc's output format.
+INFO is the export state, as a property list.  The return value is a symbol
+corresponding to one of the output formats supported by Citeproc: `html',
+`latex', or `org'."
+  (let ((backend (plist-get info :back-end)))
+    (cond
+     ((org-export-derived-backend-p backend 'html) 'html)
+     ((org-export-derived-backend-p backend 'latex) 'latex)
+     (t 'org))))
+
+(defun org-cite-csl--style-file (info)
+  "Return style file associated to current export process.
+
+INFO is the export state, as a property list.
+
+When file name is relative, expand it according to `org-cite-csl-styles-dir',
+or raise an error if the variable is unset."
+  (pcase (org-cite-bibliography-style info)
+    ('nil org-cite-csl--fallback-style-file)
+    ((and (pred file-name-absolute-p) file) file)
+    ((and (guard org-cite-csl-styles-dir) file)
+     (expand-file-name file org-cite-csl-styles-dir))
+    (other
+     (user-error "Cannot handle relative style file name: %S" other))))
+
+(defun org-cite-csl--locale-getter ()
+  "Return a locale getter.
+The getter looks for locales in `org-cite-csl-locales-dir' directory.  If it
+cannot find them, it retrieves the default \"en_US\" from
+`org-cite-csl--fallback-locales-dir'."
+  (lambda (loc)
+    (or (and org-cite-csl-locales-dir
+             (ignore-errors
+               (funcall (citeproc-locale-getter-from-dir 
org-cite-csl-locales-dir)
+                        loc)))
+        (funcall (citeproc-locale-getter-from-dir
+                  org-cite-csl--fallback-locales-dir)
+                 loc))))
+
+(defun org-cite-csl--processor (info)
+  "Return Citeproc processor reading items from current bibliography.
+
+INFO is the export state, as a property list.
+
+Newly created processor is stored as the value of the 
`:cite-citeproc-processor'
+property in INFO."
+  (or (plist-get info :cite-citeproc-processor)
+      (let* ((bibliography (plist-get info :bibliography))
+             (locale (or (plist-get info :language) "en_US"))
+             (processor
+              (citeproc-create
+               (org-cite-csl--style-file info)
+               (citeproc-hash-itemgetter-from-any bibliography)
+               (org-cite-csl--locale-getter)
+               locale)))
+        (plist-put info :cite-citeproc-processor processor)
+        processor)))
+
+(defun org-cite-csl--parse-reference (reference info)
+  "Return Citeproc's structure associated to citation REFERENCE.
+
+INFO is the export state, as a property list.
+
+The result is a association list.  Keys are: `id', `prefix',`suffix',
+`location', `locator' and `label'."
+  (let (label location-start locator-start location locator prefix suffix)
+    ;; Parse suffix.  Insert it in a temporary buffer to find
+    ;; different parts: pre-label, label, locator, location (label +
+    ;; locator), and suffix.
+    (with-temp-buffer
+      (save-excursion
+        (insert (org-element-interpret-data
+                 (org-element-property :suffix reference))))
+      (cond
+       ((re-search-forward org-cite-csl--label-regexp nil t)
+        (setq location-start (match-beginning 0))
+        (setq label (cdr (assoc (match-string 1) org-cite-csl--label-alist)))
+        (goto-char (match-end 1))
+        (skip-chars-forward "[:space:] ")
+        (setq locator-start (point)))
+       ((re-search-forward (rx digit) nil t)
+        (setq location-start (match-beginning 0))
+        (setq label "page")
+        (setq locator-start location-start))
+       (t
+        (setq suffix (org-element-property :suffix reference))))
+      ;; Find locator's end, and suffix, if any. To that effect, look
+      ;; for the last comma or digit after label, whichever comes
+      ;; last.
+      (unless suffix
+        (goto-char (point-max))
+        (let ((re (rx (or "," (group digit)))))
+          (when (re-search-backward re location-start t)
+            (goto-char (or (match-end 1) (match-beginning 0)))
+            (setq location (buffer-substring location-start (point)))
+            (setq locator (org-trim (buffer-substring locator-start (point))))
+            ;; Skip comma in suffix.
+            (setq suffix
+                  (org-cite-parse-objects
+                   (buffer-substring (match-end 0) (point-max))
+                   t)))))
+      (setq prefix
+            (org-cite-concat
+             (org-element-property :prefix reference)
+             (and location-start
+                  (org-cite-parse-objects
+                   (buffer-substring 1 location-start)
+                   t)))))
+    ;; Return value.
+    (let ((export
+           (lambda (data)
+             (org-string-nw-p
+              (org-trim
+               ;; When Citeproc exports to Org syntax, avoid mix and
+               ;; matching output formats by also generating Org
+               ;; syntax for prefix and suffix.
+               (if (eq 'org (org-cite-csl--output-format info))
+                   (org-element-interpret-data data)
+                 (org-export-data data info)))))))
+      `((id . ,(org-element-property :key reference))
+        (prefix . ,(funcall export prefix))
+        (suffix . ,(funcall export suffix))
+        (locator . ,locator)
+        (label . ,label)
+        (location . ,location)))))
+
+(defun org-cite-csl--create-structure (citation info)
+  "Create Citeproc structure for CITATION object.
+INFO is the export state, as a property list."
+  (let* ((cites (mapcar (lambda (r)
+                          (org-cite-csl--parse-reference r info))
+                        (org-cite-get-references citation)))
+         (footnote (org-cite-inside-footnote-p citation)))
+    ;; Global prefix is inserted in front of the prefix of the first
+    ;; reference.
+    (let ((global-prefix (org-element-property :prefix citation)))
+      (when global-prefix
+        (let* ((first (car cites))
+               (prefix-item (assq 'prefix first)))
+          (setcdr prefix-item
+                  (concat (org-element-interpret-data global-prefix)
+                          " "
+                          (cdr prefix-item))))))
+    ;; Global suffix is appended to the suffix of the last reference.
+    (let ((global-suffix (org-element-property :suffix citation)))
+      (when global-suffix
+        (let* ((last (org-last cites))
+               (suffix-item (assq 'suffix last)))
+          (setcdr suffix-item
+                  (concat (cdr suffix-item)
+                          " "
+                          (org-element-interpret-data global-suffix))))))
+    ;; Check if CITATION needs wrapping, i.e., it should be wrapped in
+    ;; a footnote, but isn't yet.
+    (when (and (not footnote) (org-cite-csl--note-style-p info))
+      (org-cite-adjust-note citation info)
+      (setq footnote (org-cite-wrap-citation citation info)))
+    ;; Return structure.
+    (apply #'citeproc-citation-create
+           `(:note-index
+             ,(and footnote (org-export-get-footnote-number footnote info))
+             :cites ,cites
+             ,@(org-cite-csl--create-structure-params citation info)))))
+
+(defun org-cite-csl--rendered-citations (info)
+  "Return the rendered citations as an association list.
+
+INFO is the export state, as a property list.
+
+Return an alist (CITATION . OUTPUT) where CITATION object has been rendered as
+OUTPUT using Citeproc."
+  (or (plist-get info :cite-citeproc-rendered-citations)
+      (let* ((citations (org-cite-list-citations info))
+             (processor (org-cite-csl--processor info))
+             (structures
+              (mapcar (lambda (c) (org-cite-csl--create-structure c info))
+                      citations)))
+        (citeproc-append-citations structures processor)
+        (let* ((rendered
+                (citeproc-render-citations
+                 processor
+                 (org-cite-csl--output-format info)
+                 (org-cite-csl--no-citelinks-p info)))
+               (result (seq-mapn #'cons citations rendered)))
+          (plist-put info :cite-citeproc-rendered-citations result)
+          result))))
+
+
+;;; Export capability
+(defun org-cite-csl-render-citation (citation _style _backend info)
+  "Export CITATION object.
+INFO is the export state, as a property list."
+  (org-cite-csl--barf-without-citeproc)
+  (let ((output (cdr (assq citation (org-cite-csl--rendered-citations info)))))
+    (if (not (eq 'org (org-cite-csl--output-format info)))
+        output
+      ;; Parse Org output to re-export it during the regular export
+      ;; process.
+      (org-cite-parse-objects output))))
+
+(defun org-cite-csl-render-bibliography (_keys _files _style _props _backend 
info)
+  "Export bibliography.
+INFO is the export state, as a property list."
+  (org-cite-csl--barf-without-citeproc)
+  (pcase-let* ((format (org-cite-csl--output-format info))
+               (`(,output . ,parameters)
+                (citeproc-render-bib
+                 (org-cite-csl--processor info)
+                 format
+                 (org-cite-csl--no-citelinks-p info))))
+    (pcase format
+      ('html
+       (concat
+        (and (cdr (assq 'second-field-align parameters))
+             (let* ((max-offset (cdr (assq 'max-offset parameters)))
+                    (char-width
+                     (string-to-number org-cite-csl-html-label-width-per-char))
+                    (char-width-unit
+                     (progn
+                       (string-match (number-to-string char-width)
+                                     org-cite-csl-html-label-width-per-char)
+                       (substring org-cite-csl-html-label-width-per-char
+                                  (match-end 0)))))
+               (format
+                "<style>.csl-left-margin{float: left; padding-right: 0em;}
+ .csl-right-inline{margin: 0 0 0 %d%s;}</style>"
+                (* max-offset char-width)
+                char-width-unit)))
+        (and (cdr (assq 'hanging-indent parameters))
+             (format
+              "<style>.csl-entry{text-indent: -%s; margin-left: %s;}</style>"
+              org-cite-csl-html-hanging-indent
+              org-cite-csl-html-hanging-indent))
+        output))
+      ('latex
+       (if (cdr (assq 'hanging-indent parameters))
+           (format "\\begin{hangparas}{%s}{1}\n%s\n\\end{hangparas}"
+                   org-cite-csl-latex-hanging-indent
+                   output)
+         output))
+      (_
+       ;; Parse Org output to re-export it during the regular export
+       ;; process.
+       (org-cite-parse-elements output)))))
+
+(defun org-cite-csl-finalizer (output _keys _files _style _backend info)
+  "Add \"hanging\" package if missing from LaTeX output.
+OUTPUT is the export document, as a string.  INFO is the export state, as a
+property list."
+  (org-cite-csl--barf-without-citeproc)
+  (if (not (eq 'latex (org-cite-csl--output-format info)))
+      output
+    (with-temp-buffer
+      (save-excursion (insert output))
+      (when (search-forward "\\begin{document}" nil t)
+        ;; Ensure that \citeprocitem is defined for citeproc-el
+        (insert 
"\\makeatletter\n\\newcommand{\\citeprocitem}[2]{\\hyper@linkstart{cite}{citeproc_bib_item_#1}#2\\hyper@linkend}\n\\makeatother\n\n")
+        ;; Ensure there is a \usepackage{hanging} somewhere or add one.
+        (goto-char (match-beginning 0))
+        (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{hanging}")))
+          (unless (re-search-backward re nil t)
+            (insert "\\usepackage[notquote]{hanging}\n"))))
+      (buffer-string))))
+
+
+;;; Register `csl' processor
+(org-cite-register-processor 'csl
+  :export-citation #'org-cite-csl-render-citation
+  :export-bibliography #'org-cite-csl-render-bibliography
+  :export-finalizer #'org-cite-csl-finalizer
+  :cite-styles
+  '((("author" "a") ("full" "f") ("caps" "c") ("caps-full" "cf"))
+    (("noauthor" "na") ("bare" "b") ("caps" "c") ("bare-caps" "bc"))
+    (("year" "y") ("bare" "b"))
+    (("text" "t") ("caps" "c") ("full" "f") ("caps-full" "cf"))
+    (("nil") ("bare" "b") ("caps" "c") ("bare-caps" "bc"))))
+
+(provide 'oc-csl)
+;;; oc-csl.el ends here
diff --git a/lisp/org/oc-natbib.el b/lisp/org/oc-natbib.el
new file mode 100644
index 0000000000..bf086f36df
--- /dev/null
+++ b/lisp/org/oc-natbib.el
@@ -0,0 +1,193 @@
+;;; oc-natbib.el --- Citation processor using natbib LaTeX package  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library registers the `natbib' citation processor, which provides the
+;; "export" capability for citations.
+
+;; The processor relies on "natbib" LaTeX package.  As such it ensures that the
+;; package is properly required in the document's preamble.  More accurately, 
it
+;; will use any "\\usepackage{natbib}" command already present in the document
+;; (e.g., through `org-latex-packages-alist'), or insert one using options
+;; defined in `org-cite-natbib-options'.
+
+;; It supports the following citation styles:
+;;
+;; - author (a), including caps (c), and full (f) variants,
+;; - noauthor (na), including bare (b) variant,
+;; - text (t), including bare (b), caps (c), full (f), bare-caps (bc),
+;;   bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants,
+;; - default, including bare (b), caps (c), full (f), bare-caps (bc),
+;;   bare-full (bf), caps-full (cf), and bare-caps-full (bcf) variants.
+
+;; Bibliography accepts any style supported by "natbib" package.
+
+;;; Code:
+(require 'oc)
+
+(declare-function org-element-property "org-element" (property element))
+
+(declare-function org-export-data "org-export" (data info))
+
+
+;;; Customization
+(defcustom org-cite-natbib-options nil
+  "List of options added to \"natbib\" package.
+If \"natbib\" package is already required in the document, e.g., through
+`org-latex-packages-alist' variable, these options are ignored."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type
+  '(set
+    (const :tag "use round parentheses (default)" round)
+    (const :tag "use square brackets" square)
+    (const :tag "use curly braces" curly)
+    (const :tag "use angle brackets" angle)
+    (const :tag "separate multiple citations with colons (default)" colon)
+    (const :tag "separate multiple citations with comas" comma)
+    (const :tag "generate author-year citations" authoryear)
+    (const :tag "generate numerical citations" numbers)
+    (const :tag "generate superscripted numerical citations" super)
+    (const :tag "order multiple citations according to the list of references" 
sort)
+    (const :tag "order as above, but numerical citations are compressed if 
possible" sort&compress)
+    (const :tag "display full author list on first citation, abbreviate the 
others" longnamesfirst)
+    (const :tag "redefine \\thebibliography to issue \\section* instead of 
\\chapter*" sectionbib)
+    (const :tag "keep all the authors' names in a citation on one line" 
nonamebreak)))
+
+
+;;; Internal functions
+(defun org-cite-natbib--style-to-command (style)
+  "Return command name to use according to STYLE pair."
+  (pcase style
+    ;; "author" style.
+    (`(,(or "author" "a") . ,variant)
+     (pcase variant
+       ((or "caps" "c")             "\\Citeauthor")
+       ((or "full" "f")             "\\citeauthor*")
+       (_                           "\\citeauthor")))
+    ;; "noauthor" style.
+    (`(,(or "noauthor" "na") . ,variant)
+     (pcase variant
+       ((or "bare" "b")             "\\citeyear")
+       (_                           "\\citeyearpar")))
+    ;; "nocite" style.
+    (`(,(or "nocite" "n") . ,_)     "\\nocite")
+    ;; "text" style.
+    (`(,(or "text" "t") . ,variant)
+     (pcase variant
+       ((or "bare" "b")             "\\citealt")
+       ((or "caps" "c")             "\\Citet")
+       ((or "full" "f")             "\\citet*")
+       ((or "bare-caps" "bc")       "\\Citealt")
+       ((or "bare-full" "bf")       "\\citealt*")
+       ((or "caps-full" "cf")       "\\Citet*")
+       ((or "bare-caps-full" "bcf") "\\Citealt*")
+       (_ "\\citet")))
+    ;; Default ("nil") style.
+    (`(,_ . ,variant)
+     (pcase variant
+       ((or "bare" "b")             "\\citealp")
+       ((or "caps" "c")             "\\Citep")
+       ((or "full" "f")             "\\citep*")
+       ((or "bare-caps" "bc")       "\\Citealp")
+       ((or "bare-full" "bf")       "\\citealp*")
+       ((or "caps-full" "cf")       "\\Citep*")
+       ((or "bare-caps-full" "bcf") "\\Citealp*")
+       (_                           "\\citep")))
+    ;; This should not happen.
+    (_ (error "Invalid style: %S" style))))
+
+(defun org-cite-natbib--build-optional-arguments (citation info)
+  "Build optional arguments for citation command.
+CITATION is the citation object.  INFO is the export state, as a property 
list."
+  (pcase-let ((`(,prefix . ,suffix) (org-cite-main-affixes citation)))
+    (concat (and prefix (format "[%s]" (org-trim (org-export-data prefix 
info))))
+            (cond
+             (suffix (format "[%s]" (org-trim (org-export-data suffix info))))
+             (prefix "[]")
+             (t nil)))))
+
+(defun org-cite-natbib--build-arguments (citation)
+  "Build arguments for citation command for CITATION object."
+  (format "{%s}"
+          (mapconcat #'identity
+                     (org-cite-get-references citation t)
+                     ",")))
+
+
+;;; Export capability
+(defun org-cite-natbib-export-bibliography (_keys files style &rest _)
+  "Print references from bibliography FILES.
+FILES is a list of absolute file names.  STYLE is the bibliography style, as
+a string or nil."
+  (concat (and style (format "\\bibliographystyle{%s}\n" style))
+          (format "\\bibliography{%s}"
+                  (mapconcat #'file-name-sans-extension
+                             files
+                             ","))))
+
+(defun org-cite-natbib-export-citation (citation style _ info)
+  "Export CITATION object.
+STYLE is the citation style, as a pair of strings or nil.  INFO is the export
+state, as a property list."
+  (concat (org-cite-natbib--style-to-command style)
+          (org-cite-natbib--build-optional-arguments citation info)
+          (org-cite-natbib--build-arguments citation)))
+
+(defun org-cite-natbib-use-package (output &rest _)
+  "Ensure output requires \"natbib\" package.
+OUTPUT is the final output of the export process."
+  (with-temp-buffer
+    (save-excursion (insert output))
+    (when (search-forward "\\begin{document}" nil t)
+      ;; Ensure there is a \usepackage{natbib} somewhere or add one.
+      (goto-char (match-beginning 0))
+      (let ((re (rx "\\usepackage" (opt "[" (*? nonl) "]") "{natbib}")))
+        (unless (re-search-backward re nil t)
+          (insert
+           (format "\\usepackage%s{natbib}\n"
+                   (if (null org-cite-natbib-options)
+                       ""
+                     (format "[%s]"
+                             (mapconcat #'symbol-name
+                                        org-cite-natbib-options
+                                        ","))))))))
+    (buffer-string)))
+
+
+;;; Register `natbib' processor
+(org-cite-register-processor 'natbib
+  :export-bibliography #'org-cite-natbib-export-bibliography
+  :export-citation #'org-cite-natbib-export-citation
+  :export-finalizer #'org-cite-natbib-use-package
+  :cite-styles
+  '((("author" "a") ("caps" "a") ("full" "f"))
+    (("noauthor" "na") ("bare" "b"))
+    (("text" "t")
+     ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
+     ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))
+    (("nil")
+     ("bare" "b") ("caps" "c") ("full" "f") ("bare-caps" "bc")
+     ("bare-full" "bf") ("caps-full" "cf") ("bare-caps-full" "bcf"))))
+
+(provide 'oc-natbib)
+;;; oc-natbib.el ends here
diff --git a/lisp/org/oc.el b/lisp/org/oc.el
new file mode 100644
index 0000000000..41fd688c06
--- /dev/null
+++ b/lisp/org/oc.el
@@ -0,0 +1,1649 @@
+;;; oc.el --- Org Cite library                  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides tooling to handle citations in Org, e.g,
+;; activate, follow, insert, and export them, respectively called
+;; "activate", "follow", "insert" and "export" capabilities.
+;; Libraries responsible for providing some, or all, of these
+;; capabilities are called "citation processors".
+
+;; Such processors are defined using `org-cite-register-processor'.
+;; Using this function, it is possible, in addition to giving it a
+;; name, to attach functions associated to capabilities.  As such, a
+;; processor handling citation export must set the `:export-citation'
+;; property to an appropriate function.  Likewise, "activate"
+;; capability requires an appropriate `:activate' property, "insert"
+;; requires `:insert' property and, unsurprisingly, "follow"
+;; capability implies `:follow' property.
+
+;; As a user, the first thing to do is setting a bibliography, either
+;; globally with `org-cite-global-bibliography', or locally using one
+;; or more "bibliography" keywords.  Then one can select any
+;; registered processor for each capability by providing a processor
+;; name to the variables `org-cite-activate-processor' and
+;; `org-cite-follow-processor'.
+
+;; The "export" capability is slightly more involved as one need to
+;; select the processor providing it, but may also provide a default
+;; style for citations and bibliography.  Also, the choice of an
+;; export processor may depend of the current export back-end.  The
+;; association between export back-ends and triplets of parameters can
+;; be set in `org-cite-export-processors' variable, or in a document,
+;; through the "cite_export" keyword.
+
+;; Eventually, this library provides some tools, mainly targeted at
+;; processor implementors.  Most are export-specific and are located
+;; in the "Tools only available during export" and "Tools generating
+;; or operating on parsed data" sections.
+
+;; The few others can be used directly from an Org buffer, or operate
+;; on processors.  See "Generic tools" section.
+
+;;; Code:
+
+(require 'org-compat)
+(require 'org-macs)
+(require 'seq)
+
+(declare-function org-at-heading-p "org" (&optional _))
+(declare-function org-collect-keywords "org" (keywords &optional unique 
directory))
+
+(declare-function org-element-adopt-elements "org-element" (parent &rest 
children))
+(declare-function org-element-citation-parser "org-element" ())
+(declare-function org-element-citation-reference-parser "org-element" ())
+(declare-function org-element-class "org-element" (datum &optional parent))
+(declare-function org-element-contents "org-element" (element))
+(declare-function org-element-create "org-element" (type &optional props &rest 
children))
+(declare-function org-element-extract-element "org-element" (element))
+(declare-function org-element-insert-before "org-element" (element location))
+(declare-function org-element-lineage "org-element" (datum &optional types 
with-self))
+(declare-function org-element-map "org-element" (data types fun &optional info 
first-match no-recursion with-affiliated))
+(declare-function org-element-normalize-string "org-element" (s))
+(declare-function org-element-parse-buffer "org-element" (&optional 
granularity visible-only))
+(declare-function org-element-parse-secondary-string "org-element" (string 
restriction &optional parent))
+(declare-function org-element-context "org-element" (&optional element))
+(declare-function org-element-property "org-element" (property element))
+(declare-function org-element-put-property "org-element" (element property 
value))
+(declare-function org-element-restriction "org-element" (element))
+(declare-function org-element-set-element "org-element" (old new))
+(declare-function org-element-type "org-element" (element))
+
+(declare-function org-export-derived-backend-p "org-export" (backend &rest 
backends))
+(declare-function org-export-get-next-element "org-export" (blob info 
&optional n))
+(declare-function org-export-get-previous-element "org-export" (blob info 
&optional n))
+(declare-function org-export-raw-string "org-export" (s))
+
+(defvar org-complex-heading-regexp)
+(defvar org-element-all-objects)
+(defvar org-element-citation-key-re)
+(defvar org-element-citation-prefix-re)
+(defvar org-element-parsed-keywords)
+
+
+;;; Constants
+;; Borrowed from "citeproc.el" library.
+(defconst org-cite--default-region-alist
+  '(("af" . "za") ("ca" . "ad") ("cs" . "cz") ("cy" . "gb")
+    ("da" . "dk") ("el" . "gr") ("et" . "ee") ("fa" . "ir")
+    ("he" . "ir") ("ja" . "jp") ("km" . "kh") ("ko" . "kr")
+    ("nb" . "no") ("nn" . "no") ("sl" . "si") ("sr" . "rs")
+    ("sv" . "se") ("uk" . "ua") ("vi" . "vn") ("zh" . "cn"))
+  "Alist mapping those languages to their default region.
+Only those languages are given for which the default region is not simply the
+result of duplicating the language part.")
+
+
+;;; Configuration variables
+(defgroup org-cite nil
+  "Options concerning citations in Org mode."
+  :group 'org
+  :tag "Org Cite")
+
+(defcustom org-cite-global-bibliography nil
+  "List of bibliography files available in all documents.
+File names must be absolute."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "No global bibliography" nil)
+                (repeat :tag "List of bibliography files"
+                         (file :tag "Bibliography"))))
+
+(defcustom org-cite-activate-processor 'basic
+  "Processor used for activating citations, as a symbol."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "Default fontification" nil)
+                 (symbol :tag "Citation processor")))
+
+(defcustom org-cite-export-processors '((t basic))
+  "Processor used for exporting citations, as a triplet, or nil.
+
+When nil, citations and bibliography are not exported.
+
+When non-nil, the value is an association list between export back-ends and
+citation export processors:
+
+  (BACK-END . PROCESSOR)
+
+where BACK-END is the name of an export back-end or t, and PROCESSOR is a
+triplet following the pattern
+
+  (NAME BIBLIOGRAPHY-STYLE CITATION-STYLE)
+
+There, NAME is the name of a registered citation processor providing export
+functionality, as a symbol.  BIBLIOGRAPHY-STYLE (respectively CITATION-STYLE)
+is the desired default style to use when printing a bibliography (respectively
+exporting a citation), as a string or nil.  Both BIBLIOGRAPHY-STYLE and
+CITATION-STYLE are optional.  NAME is mandatory.
+
+The export process selects the citation processor associated to the current
+export back-end, or the most specific back-end the current one is derived from,
+or, if all are inadequate, to the processor associated to t.  For example, with
+the following value
+
+  ((beamer natbib)
+   (latex biblatex)
+   (t csl))
+
+exporting with `beamer' or any back-end derived from it will use `natbib',
+whereas exporting with `latex' or any back-end derived from it but different
+from `beamer' will use `biblatex' processor.  Any other back-end, such as
+`html', will use `csl' processor.
+
+CITATION-STYLE is overridden by adding a style to any citation object.  A nil
+style lets the export processor choose the default output.  Any style not
+recognized by the export processor is equivalent to nil.
+
+The citation triplet can also be set with the CITE_EXPORT keyword.
+E.g.,
+
+  #+CITE_EXPORT: basic note numeric
+
+or
+
+  #+CITE_EXPORT: basic
+
+In that case, `basic' processor is used on every export, independently on the
+back-end."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "No export" nil)
+                 (alist :key-type symbol
+                        :value-type
+                        (list :tag "Citation processor"
+                              (symbol :tag "Processor name")
+                              (choice
+                               (const :tag "Default bibliography style" nil)
+                               (string :tag "Use specific bibliography style"))
+                              (choice
+                               (const :tag "Default citation style" nil)
+                               (string :tag "Use specific citation style"))))))
+
+(defcustom org-cite-follow-processor 'basic
+  "Processor used for following citations, as a symbol."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "No following" nil)
+                 (symbol :tag "Citation processor")))
+
+(defcustom org-cite-insert-processor 'basic
+  "Processor used for inserting citations, as a symbol."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "No insertion" nil)
+                 (symbol :tag "Citation processor")))
+
+(defcustom org-cite-adjust-note-numbers t
+  "When non-nil, allow process to modify location of note numbers.
+
+When this variable is non-nil, it is possible to swap between author-date and
+note style without modifying the document.  To that effect, citations should
+always be located as in an author-date style.  Prior to turning the citation
+into a footnote, the citation processor moves the citation (i.e., the future
+note number), and the surrounding punctuation, according to rules defined in
+`org-cite-note-rules'.
+
+When nil, the note number is not moved."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(choice (const :tag "Automatic note number location" t)
+                 (const :tag "Place note numbers manually" nil))
+  :safe #'booleanp)
+
+(defcustom org-cite-note-rules
+  '(("en-us" inside outside after)
+    ("fr" adaptive same before))
+  "Alist between languages and typographic rules for citations in note style.
+
+When `org-cite-adjust-note-numbers' is non-nil, and note style is requested,
+citation processor is allowed to move the note marker according to some 
specific
+rules, detailed here.  More accurately, a rule is a list following the pattern
+
+    (LANGUAGE-TAG . RULE)
+
+  LANGUAGE-TAG is a down-cased string representing a language tag as defined in
+  RFC 4646.  It may constituted of a language and a region separated with an
+  hyphen (e.g., \"en-us\"), or the language alone (e.g., \"fr\").  A language
+  without a region applies to all regions.
+
+  RULE is a triplet
+
+    (PUNCTUATION NUMBER ORDER)
+
+  PUNCTUATION is the desired location of the punctuation with regards to the
+  quotation, if any.  It may be `inside', `outside', or `adaptive'.  The latter
+  permits subtler control over the punctuation: when there is no space between
+  the quotation mark and the punctuation, it is equivalent to `inside'.
+  Otherwise, it means `outside', as illustrated in the following examples:
+
+      \"A quotation ending without punctuation\" [cite:@org21].
+      \"A quotation ending with a period\"[cite:@org21].
+
+  Notwithstanding the above, a space always appear before the citation when it
+  is to become anything else than a note.
+
+  NUMBER is the desired location of the note number with regards to the
+  quotation mark, if any.  It may be `inside', `outside', or `same'.  When set
+  to `same', the number appears on the same side as the punctuation, unless
+  there is punctuation on both sides or on none.
+
+  ORDER is the relative position of the citation with regards to the closest
+  punctuation.  It may be `after' or `before'.
+
+For example (adaptive same before) corresponds to French typography.
+
+When the locale is unknown to this variable, the default rule is:
+
+  (adaptive outside after)
+
+This roughly follows the Oxford Guide to Style recommendations."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type
+  '(repeat
+    (list :tag "Typographic rule"
+          (string :tag "Language code")
+          (choice :tag "Location of punctuation"
+                  (const :tag "Punctuation inside quotation" inside)
+                  (const :tag "Punctuation outside quotation" outside)
+                  (const :tag "Location depends on spacing" adaptive))
+          (choice :tag "Location of citation"
+                  (const :tag "Citation inside quotation" inside)
+                  (const :tag "Citation outside quotation" outside)
+                  (const :tag "Citation next to punctuation" same))
+          (choice :tag "Order of citation and punctuation"
+                  (const :tag "Citation first" before)
+                  (const :tag "Citation last" after)))))
+
+(defcustom org-cite-punctuation-marks '("." "," ";" ":" "!" "?")
+  "List of strings that can be moved around when placing note numbers.
+
+When `org-cite-adjust-note-numbers' is non-nil, the citation processor is
+allowed to shuffle punctuation marks specified in this list in order to
+place note numbers according to rules defined in `org-cite-note-rules'."
+  :group 'org-cite
+  :package-version '(Org . "9.5")
+  :type '(repeat string))
+
+
+;;; Citation processors
+(cl-defstruct (org-cite-processor (:constructor org-cite--make-processor)
+                                 (:copier nil))
+  (name nil :read-only t)
+  (activate nil :read-only t)
+  (cite-styles nil :read-only t)
+  (export-bibliography nil :read-only t)
+  (export-citation nil :read-only t)
+  (export-finalizer nil :read-only t)
+  (follow nil :read-only t)
+  (insert nil :read-only t))
+
+(defvar org-cite--processors nil
+  "List of registered citation processors.
+See `org-cite-register-processor' for more information about
+processors.")
+
+(defun org-cite--get-processor (name)
+  "Return citation processor named after symbol NAME.
+Return nil if no such processor is found."
+  (seq-find (lambda (p) (eq name (org-cite-processor-name p)))
+           org-cite--processors))
+
+(defun org-cite-register-processor (name &rest body)
+  "Mark citation processor NAME as available.
+
+NAME is a symbol.  BODY is a property list, where the following
+optional keys can be set:
+
+  `:activate'
+
+    Function activating a citation.  It is called with a single
+    argument: a citation object extracted from the current
+    buffer.  It may add text properties to the buffer.  If it is
+    not provided, `org-cite-fontify-default' is used.
+
+  `:export-bibliography'
+
+    Function rendering a bibliography.  It is called with six
+    arguments: the list of citation keys used in the document, as
+    strings, a list of bibliography files, the style, as a string
+    or nil, the local properties, as a property list, the export
+    back-end, as a symbol, and the communication channel, as a
+    property list.
+
+    It is called at each \"print_bibliography\" keyword in the
+    parse tree.  It may return a string, a parsed element, a list
+    of parsed elements, or nil.  When it returns nil, the keyword
+    is ignored.  Otherwise, the value it returns replaces the
+    keyword in the export output.
+
+  `:export-citation'    (mandatory for \"export\" capability)
+
+    Function rendering citations.  It is called with four
+    arguments: a citation object, the style, as a pair, the
+    export back-end, as a symbol, and the communication channel,
+    as a property list.
+
+    It is called on each citation object in the parse tree.  It
+    may return a string, a parsed object, a secondary string, or
+    nil.  When it returns nil, the citation is ignored.
+    Otherwise, the value it returns replaces the citation object
+    in the export output.
+
+  `:export-finalizer'
+
+    Function called at the end of export process.  It must accept
+    six arguments: the output, as a string, a list of citation
+    keys used in the document, a list of bibliography files, the
+    expected bibliography style, as a string or nil, the export
+    back-end, as a symbol, and the communication channel, as a
+    property list.
+
+    It must return a string, which will become the final output
+    from the export process, barring subsequent modifications
+    from export filters.
+
+  `:follow'
+
+    Function called to follow a citation.  It accepts two
+    arguments, the citation or citation reference object at
+    point, and any prefix argument received during interactive
+    call of `org-open-at-point'.
+
+  `:insert'
+
+    Function called to insert a citation.  It accepts two
+    arguments, the citation or citation reference object at point
+    or nil, and any prefix argument received.
+
+  `:cite-styles'
+
+    When the processor has export capability, the value can
+    specify what cite styles, variants, and their associated
+    shortcuts are supported.  It can be useful information for
+    completion or linting.
+
+    The expected format is
+
+      ((STYLE . SHORTCUTS) . VARIANTS))
+
+    where STYLE is a string, SHORTCUTS a list of strings or nil,
+    and VARIANTS is a list of pairs (VARIANT . SHORTCUTS),
+    VARIANT being a string and SHORTCUTS a list of strings or
+    nil.
+
+    The \"nil\" style denotes the processor fall-back style.  It
+    should have a corresponding entry in the value.
+
+Return a non-nil value on a successful operation."
+  (declare (indent 1))
+  (unless (and name (symbolp name))
+    (error "Invalid processor name: %S" name))
+  (when (org-cite--get-processor name)
+    (org-cite-unregister-processor name))
+  (push (apply #'org-cite--make-processor :name name body)
+       org-cite--processors))
+
+(defun org-cite-unregister-processor (name)
+  "Unregister citation processor NAME.
+NAME is a symbol.  Raise an error if processor is not registered.
+Return a non-nil value on a successful operation."
+  (unless (and name (symbolp name))
+    (error "Invalid processor name: %S" name))
+  (pcase (org-cite--get-processor name)
+    ('nil (error "Processor %S not registered" name))
+    (processor
+     (setq org-cite--processors (delete processor org-cite--processors))))
+  t)
+
+(defun org-cite-processor-has-capability-p (processor capability)
+  "Return non-nil if PROCESSOR is able to handle CAPABILITY.
+PROCESSOR is the name of a cite processor, as a symbol.  CAPABILITY is
+`activate', `export', `follow', or `insert'."
+  (let ((p (org-cite--get-processor processor)))
+    (pcase capability
+      ((guard (not p)) nil)             ;undefined processor
+      ('activate (functionp (org-cite-processor-activate p)))
+      ('export (functionp (org-cite-processor-export-citation p)))
+      ('follow (functionp (org-cite-processor-follow p)))
+      ('insert (functionp (org-cite-processor-insert p)))
+      (other (error "Invalid capability: %S" other)))))
+
+
+;;; Internal functions
+(defun org-cite--set-post-blank (datum blanks)
+  "Set `:post-blank' property from element or object before DATUM to BLANKS.
+DATUM is an element or object.  BLANKS is an integer.  DATUM is modified
+by side-effect."
+  (if (not (eq 'plain-text (org-element-type datum)))
+      (org-element-put-property datum :post-blank blanks)
+    ;; Remove any blank from string before DATUM so it is exported
+    ;; with exactly BLANKS white spaces.
+    (org-element-set-element
+     datum
+     (replace-regexp-in-string
+      "[ \t\n]*\\'" (make-string blanks ?\s) datum))))
+
+(defun org-cite--set-previous-post-blank (datum blanks info)
+  "Set `:post-blank' property from element or object before DATUM to BLANKS.
+DATUM is an element or object.  BLANKS is an integer.  INFO is the export
+state, as a property list.  Previous element or object, if any, is modified by
+side-effect."
+  (let ((previous (org-export-get-previous-element datum info)))
+    (when previous
+      (org-cite--set-post-blank previous blanks))))
+
+(defun org-cite--insert-at-split (s citation n regexp)
+  "Split string S and insert CITATION object between the two parts.
+S is split at beginning of match group N upon matching REGEXP against it.
+This function assumes S precedes CITATION."
+  ;; When extracting the citation, remove white spaces before it, but
+  ;; preserve those after it.
+  (let ((post-blank (org-element-property :post-blank citation)))
+    (when (and post-blank (> post-blank 0))
+      (org-element-insert-before (make-string post-blank ?\s) citation)))
+  (org-element-insert-before
+   (org-element-put-property (org-element-extract-element citation)
+                             :post-blank 0)
+   s)
+  (string-match regexp s)
+  (let* ((split (match-beginning n))
+         (first-part (substring s nil split))
+         ;; Remove trailing white spaces as they are before the
+         ;; citation.
+         (last-part
+          (replace-regexp-in-string (rx (1+ (any blank ?\n)) string-end)
+                                    ""
+                                    (substring s split))))
+    (when (org-string-nw-p first-part)
+      (org-element-insert-before first-part citation))
+    (org-element-set-element s last-part)))
+
+(defun org-cite--move-punct-before (punct citation s info)
+  "Move punctuation PUNCT before CITATION object.
+String S contains PUNCT.  INFO is the export state, as a property list.
+The function assumes S follows CITATION.  Parse tree is modified by 
side-effect."
+  (if (equal s punct)
+      (org-element-extract-element s)   ;it would be empty anyway
+    (org-element-set-element s (substring s (length punct))))
+  ;; Remove blanks before citation.
+  (org-cite--set-previous-post-blank citation 0 info)
+  (org-element-insert-before
+   ;; Blanks between citation and punct are now before punct and
+   ;; citation.
+   (concat (make-string (or (org-element-property :post-blank citation) 0) ?\s)
+           punct)
+   citation))
+
+(defun org-cite--parse-as-plist (s)
+  "Parse string S as a property list.
+Values are always strings.  Return nil if S is nil."
+  (cond
+   ((null s) nil)
+   ((stringp s)
+    (with-temp-buffer
+      (save-excursion (insert s))
+      (skip-chars-forward " \t")
+      (let ((results nil)
+            (value-flag nil))
+        (while (not (eobp))
+          (pcase (char-after)
+            (?:
+             (push (read (current-buffer)) results)
+             (setq value-flag t))
+            ((guard (not value-flag))
+             (skip-chars-forward "^ \t"))
+            (?\"
+             (let ((origin (point)))
+               (condition-case _
+                   (progn
+                     (read (current-buffer))
+                     (push (buffer-substring (1+ origin) (1- (point))) 
results))
+                 (end-of-file
+                  (goto-char origin)
+                  (skip-chars-forward "^ \t")
+                  (push (buffer-substring origin (point)) results)))
+               (setq value-flag nil)))
+            (_
+             (let ((origin (point)))
+               (skip-chars-forward "^ \t")
+               (push (buffer-substring origin (point)) results)
+               (setq value-flag nil))))
+          (skip-chars-forward " \t"))
+        (nreverse results))))
+   (t (error "Invalid argument type: %S" s))))
+
+(defun org-cite--get-note-rule (info)
+  "Return punctuation rule according to language used for export.
+
+INFO is the export state, as a property list.
+
+Rule is found according to the language used for export and
+`org-cite-note-rules', which see.
+
+If there is no rule matching current language, the rule defaults
+to (adaptive outside after)."
+  (let* ((language-tags
+          ;; Normalize language as a language-region tag, as described
+          ;; in RFC 4646.
+          (pcase (split-string (plist-get info :language) "[-_]")
+            (`(,language)
+             (list language
+                   (or (cdr (assoc language org-cite--default-region-alist))
+                       language)))
+            (`(,language ,region)
+             (list language region))
+            (other
+             (error "Invalid language identifier: %S" other))))
+         (language-region (mapconcat #'downcase language-tags "-"))
+         (language (car language-tags)))
+    (or (cdr (assoc language-region org-cite-note-rules))
+        (cdr (assoc language org-cite-note-rules))
+        '(adaptive outside after))))
+
+
+;;; Generic tools
+(defun org-cite-list-bibliography-files ()
+  "List all bibliography files defined in the buffer."
+  (delete-dups
+   (append (mapcar (lambda (value)
+                    (pcase value
+                      (`(,f . ,d)
+                        (expand-file-name (org-strip-quotes f) d))))
+                  (pcase (org-collect-keywords
+                           '("BIBLIOGRAPHY") nil '("BIBLIOGRAPHY"))
+                    (`(("BIBLIOGRAPHY" . ,pairs)) pairs)))
+          org-cite-global-bibliography)))
+
+(defun org-cite-get-references (citation &optional keys-only)
+  "Return citations references contained in CITATION object.
+
+When optional argument KEYS-ONLY is non-nil, return the references' keys, as a
+list of strings.
+
+Assume CITATION object comes from either a full parse tree, e.g., during 
export,
+or from the current buffer."
+  (let ((contents (org-element-contents citation)))
+    (cond
+     ((null contents)
+      (org-with-point-at (org-element-property :contents-begin citation)
+        (narrow-to-region (point) (org-element-property :contents-end 
citation))
+        (let ((references nil))
+          (while (not (eobp))
+            (let ((reference (org-element-citation-reference-parser)))
+              (goto-char (org-element-property :end reference))
+              (push (if keys-only
+                        (org-element-property :key reference)
+                      reference)
+                    references)))
+          (nreverse references))))
+     (keys-only (mapcar (lambda (r) (org-element-property :key r)) contents))
+     (t contents))))
+
+(defun org-cite-boundaries (citation)
+  "Return the beginning and end strict position of CITATION.
+Returns a (BEG . END) pair."
+  (let ((beg (org-element-property :begin citation))
+       (end (org-with-point-at (org-element-property :end citation)
+              (skip-chars-backward " \t")
+              (point))))
+    (cons beg end)))
+
+(defun org-cite-key-boundaries (reference)
+  "Return citation REFERENCE's key boundaries as buffer positions.
+The function returns a pair (START . END) where START and END denote positions
+in the current buffer.  Positions include leading \"@\" character."
+  (org-with-point-at (org-element-property :begin reference)
+    (let ((end (org-element-property :end reference)))
+      (re-search-forward org-element-citation-key-re end t)
+      (cons (match-beginning 0) (match-end 0)))))
+
+(defun org-cite-main-affixes (citation)
+  "Return main affixes for CITATION object.
+
+Some export back-ends only support a single pair of affixes per
+citation, even if it contains multiple keys.  This function
+decides what affixes are the most appropriate.
+
+Return a pair (PREFIX . SUFFIX) where PREFIX and SUFFIX are
+parsed data."
+  (let ((source
+         ;; When there are multiple references, use global affixes.
+         ;; Otherwise, local affixes have priority.
+         (pcase (org-cite-get-references citation)
+           (`(,reference) reference)
+           (_ citation))))
+    (cons (org-element-property :prefix source)
+          (org-element-property :suffix source))))
+
+(defun org-cite-supported-styles (&optional processors)
+  "List of supported citation styles and variants.
+
+Supported styles are those handled by export processors from
+`org-cite-export-processors', or in PROCESSORS, as a list of symbols,
+when non-nil.
+
+Return value is a list with the following items:
+
+  ((STYLE . SHORTCUTS) . VARIANTS))
+
+where STYLE is a string, SHORTCUTS a list of strings, and VARIANTS is a list of
+pairs (VARIANT . SHORTCUTS), VARIANT being a string and SHORTCUTS a list of
+strings."
+  (let ((collection
+         (seq-mapcat
+          (lambda (name)
+            (org-cite-processor-cite-styles (org-cite--get-processor name)))
+          (or processors
+              (mapcar (pcase-lambda (`(,_ . (,name . ,_))) name)
+                      org-cite-export-processors))))
+        (result nil))
+    ;; Merge duplicate styles.  Each style full name is guaranteed to
+    ;; be unique, and associated to all shortcuts and all variants in
+    ;; the initial collection.
+    (pcase-dolist (`((,style . ,shortcuts) . ,variants) collection)
+      (let ((entry (assoc style result)))
+        (if (not entry)
+            (push (list style shortcuts variants) result)
+          (setf (nth 1 entry)
+                (seq-uniq (append shortcuts (nth 1 entry))))
+          (setf (nth 2 entry)
+                (append variants (nth 2 entry))))))
+    ;; Return value with the desired format.
+    (nreverse
+     (mapcar (pcase-lambda (`(,style ,shortcuts ,variants))
+               (cons (cons style (nreverse shortcuts))
+                     ;; Merge variant shortcuts.
+                     (let ((result nil))
+                       (pcase-dolist (`(,variant . ,shortcuts) variants)
+                         (let ((entry (assoc variant result)))
+                           (if (not entry)
+                               (push (cons variant shortcuts) result)
+                             (setf (cdr entry)
+                                   (seq-uniq (append shortcuts (cdr 
entry)))))))
+                       result)))
+             result))))
+
+(defun org-cite-delete-citation (datum)
+  "Delete citation or citation reference DATUM.
+When removing the last reference, also remove the whole citation."
+  (pcase (org-element-type datum)
+    ('citation
+     (pcase-let* ((`(,begin . ,end) (org-cite-boundaries datum))
+                  (pos-before-blank
+                   (org-with-point-at begin
+                     (skip-chars-backward " \t")
+                     (point)))
+                  (pos-after-blank (org-element-property :end datum))
+                  (first-on-line?
+                   (= pos-before-blank (line-beginning-position)))
+                  (last-on-line?
+                   (= pos-after-blank (line-end-position))))
+       (cond
+        ;; The citation is alone on its line.  Remove the whole line.
+        ;; Do not leave it blank as it might break a surrounding
+        ;; paragraph.
+        ((and first-on-line? last-on-line?)
+         (delete-region (line-beginning-position) (line-beginning-position 2)))
+        ;; When the citation starts the line, preserve indentation.
+        (first-on-line? (delete-region begin pos-after-blank))
+        ;; When the citation ends the line, remove any trailing space.
+        (last-on-line? (delete-region pos-before-blank (line-end-position)))
+        ;; Otherwise, delete blanks before the citation.
+        ;; Nevertheless, make sure there is at least one blank left,
+        ;; so as to not splice unrelated surroundings.
+        (t
+         (delete-region pos-before-blank end)
+         (when (= pos-after-blank end)
+           (org-with-point-at pos-before-blank (insert " ")))))))
+    ('citation-reference
+     (let* ((citation (org-element-property :parent datum))
+            (references (org-cite-get-references citation))
+            (begin (org-element-property :begin datum))
+            (end (org-element-property :end datum)))
+       (cond
+        ;; Single reference.
+        ((= 1 (length references))
+         (org-cite-delete-citation citation))
+        ;; First reference, no prefix.
+        ((and (= begin (org-element-property :contents-begin citation))
+              (not (org-element-property :prefix citation)))
+         (org-with-point-at (org-element-property :begin datum)
+           (skip-chars-backward " \t")
+           (delete-region (point) end)))
+        ;; Last reference, no suffix.
+        ((and (= end (org-element-property :contents-end citation))
+              (not (org-element-property :suffix citation)))
+         (delete-region (1- begin) (1- (cdr (org-cite-boundaries citation)))))
+        ;; Somewhere in-between.
+        (t
+         (delete-region begin end)))))
+    (other
+     (error "Invalid object type: %S" other))))
+
+
+;;; Tools only available during export
+(defun org-cite-citation-style (citation info)
+  "Return citation style used for CITATION object.
+
+Style is a pair (NAME . VARIANT) where NAME and VARIANT are strings or nil.
+A nil NAME means the default style for the current processor should be used.
+
+INFO is a plist used as a communication channel."
+  (let* ((separate
+          (lambda (s)
+            (cond
+             ((null s) (cons nil nil))
+             ((not (string-match "/" s)) (cons s nil))
+             (t (cons (substring s nil (match-beginning 0))
+                      (org-string-nw-p (substring s (match-end 0))))))))
+         (local (funcall separate (org-element-property :style citation)))
+         (global
+          (funcall separate (pcase (plist-get info :cite-export)
+                              (`(,_ ,_ ,style) style)
+                              (_ nil)))))
+    (cond
+     ((org-string-nw-p (car local))
+      (cons (org-not-nil (car local)) (cdr local)))
+     (t
+      (cons (org-not-nil (car global))
+            (or (cdr local) (cdr global)))))))
+
+(defun org-cite-bibliography-style (info)
+  "Return expected bibliography style.
+INFO is a plist used as a communication channel."
+  (pcase (plist-get info :cite-export)
+    (`(,_ ,style ,_) style)
+    (_ nil)))
+
+(defun org-cite-bibliography-properties (keyword)
+  "Return properties associated to \"print_bibliography\" KEYWORD object.
+Return value is a property list."
+  (org-cite--parse-as-plist (org-element-property :value keyword)))
+
+(defun org-cite-list-citations (info)
+  "List citations in the exported document.
+Citations are ordered by appearance in the document, when following footnotes.
+INFO is the export communication channel, as a property list."
+  (or (plist-get info :citations)
+      (letrec ((cites nil)
+               (tree (plist-get info :parse-tree))
+               (find-definition
+                ;; Find definition for standard reference LABEL.  At
+                ;; this point, it is impossible to rely on
+                ;; `org-export-get-footnote-definition' because the
+                ;; function caches results that could contain
+                ;; un-processed citation objects.  So we use
+                ;; a simplified version of the function above.
+                (lambda (label)
+                  (org-element-map tree 'footnote-definition
+                    (lambda (d)
+                      (and (equal label (org-element-property :label d))
+                           (or (org-element-contents d) "")))
+                    info t)))
+               (search-cites
+                (lambda (data)
+                  (org-element-map data '(citation footnote-reference)
+                    (lambda (datum)
+                      (pcase (org-element-type datum)
+                        ('citation (push datum cites))
+                       ;; Do not force entering inline definitions, since
+                       ;; `org-element-map' is going to enter it anyway.
+                        ((guard (eq 'inline (org-element-property :type 
datum))))
+                        ;; Walk footnote definition.
+                        (_
+                         (let ((label (org-element-property :label datum)))
+                           (funcall search-cites
+                                    (funcall find-definition label))))))
+                    info nil 'footnote-definition t))))
+        (funcall search-cites tree)
+        (let ((result (nreverse cites)))
+          (plist-put info :citations result)
+          result))))
+
+(defun org-cite-list-keys (info)
+  "List citation keys in the exported document.
+Keys are ordered by first appearance in the document, when following footnotes.
+Duplicate keys are removed.  INFO is the export communication channel, as a
+property list."
+  (delete-dups
+   (org-element-map (org-cite-list-citations info) 'citation-reference
+     (lambda (r) (org-element-property :key r))
+     info)))
+
+(defun org-cite-key-number (key info &optional predicate)
+  "Return number associated to string KEY.
+
+INFO is the export communication channel, as a property list.
+
+Optional argument PREDICATE is called with two keys, and returns non-nil
+if the first reference should sort before the second.  When nil, references
+are sorted in order cited."
+  (let* ((keys (org-cite-list-keys info))
+         (sorted-keys (if (functionp predicate)
+                          (sort keys predicate)
+                        keys))
+         (position (seq-position sorted-keys key #'string-equal)))
+    (and (integerp position)
+         (1+ position))))
+
+(defun org-cite-inside-footnote-p (citation &optional strict)
+  "Non-nil when CITATION object is contained within a footnote.
+
+When optional argument STRICT is non-nil, return t only if CITATION represents
+the sole contents of the footnote, e.g., after calling 
`org-cite-wrap-citation'.
+
+When non-nil, the return value if the footnote container."
+  (let ((footnote
+         (org-element-lineage citation
+                              '(footnote-definition footnote-reference))))
+    (and footnote
+         (or (not strict)
+             (equal (org-element-contents (org-element-property :parent 
citation))
+                    (list citation)))
+         ;; Return value.
+         footnote)))
+
+(defun org-cite-wrap-citation (citation info)
+  "Wrap an anonymous inline footnote around CITATION object in the parse tree.
+
+INFO is the export state, as a property list.
+
+White space before the citation, if any, are removed.  The parse tree is
+modified by side-effect.
+
+Return newly created footnote object."
+  (let ((footnote
+         (list 'footnote-reference
+               (list :label nil
+                     :type 'inline
+                     :contents-begin (org-element-property :begin citation)
+                     :contents-end (org-element-property :end citation)
+                     :post-blank (org-element-property :post-blank 
citation)))))
+    ;; Remove any white space before citation.
+    (org-cite--set-previous-post-blank citation 0 info)
+    ;; Footnote swallows citation.
+    (org-element-insert-before footnote citation)
+    (org-element-adopt-elements footnote
+      (org-element-extract-element citation))))
+
+(defun org-cite-adjust-note (citation info &optional rule punct)
+  "Adjust note number location for CITATION object, and punctuation around it.
+
+INFO is the export state, as a property list.
+
+Optional argument RULE is the punctuation rule used, as a triplet.  When nil,
+rule is determined according to `org-cite-note-rules', which see.
+
+Optional argument PUNCT is a list of punctuation marks to be considered.
+When nil, it defaults to `org-cite-punctuation-marks'.
+
+Parse tree is modified by side-effect.
+
+Note: when calling both `org-cite-adjust-note' and `org-cite-wrap-citation' on
+the same object, call `org-cite-adjust-note' first."
+  (when org-cite-adjust-note-numbers
+    (pcase-let* ((rule (or rule (org-cite--get-note-rule info)))
+                 (punct-re (regexp-opt (or punct org-cite-punctuation-marks)))
+                 ;; with Emacs <27.1. Argument of `regexp' form (PUNCT-RE this 
case)
+                 ;; must be a string literal.
+                 (previous-punct-re
+                  (rx-to-string `(seq (opt (group (regexp ,(rx (0+ (any blank 
?\n))))
+                                                  (regexp ,punct-re)))
+                                      (regexp ,(rx (opt (0+ (any blank ?\n)) 
(group ?\"))
+                                                   (opt (group (1+ (any blank 
?\n))))
+                                                   string-end)))
+                                t))
+                 (next-punct-re
+                  (rx-to-string `(seq string-start
+                                      (group (0+ (any blank ?\n)) (regexp 
,punct-re)))
+                                t))
+                 (next (org-export-get-next-element citation info))
+                 (final-punct
+                  (and (stringp next)
+                       (string-match next-punct-re next)
+                       (match-string 1 next)))
+                 (previous
+                  ;; Find the closest terminal object.  Consider
+                  ;; citation, subscript and superscript objects as
+                  ;; terminal.
+                  (org-last
+                   (org-element-map (org-export-get-previous-element citation 
info)
+                       '(citation code entity export-snippet footnote-reference
+                                  line-break latex-fragment link plain-text
+                                  radio-target statistics-cookie timestamp
+                                  verbatim)
+                     #'identity info nil '(citation subscript superscript))))
+                 (`(,punct ,quote ,spacing)
+                  (and (stringp previous)
+                       (string-match previous-punct-re previous)
+                       (list (match-string 1 previous)
+                             (match-string 2 previous)
+                             (match-string 3 previous)))))
+      ;; Bail you when there is no quote and either no punctuation, or
+      ;; punctuation on both sides.
+      (when (or quote (org-xor punct final-punct))
+        ;; Phase 1: handle punctuation rule.
+        (pcase rule
+          ((guard (not quote)) nil)
+          ;; Move punctuation inside.
+          (`(,(or `inside (and `adaptive (guard (not spacing)))) . ,_)
+           ;; This only makes sense if there is a quotation before the
+           ;; citation that does not end with some punctuation.
+           (when (and (not punct) final-punct)
+             ;; Quote guarantees there is a string object before
+             ;; citation.  Likewise, any final punctuation guarantees
+             ;; there is a string object following citation.
+             (let ((new-prev
+                    (replace-regexp-in-string
+                     previous-punct-re
+                     (concat final-punct "\"") previous nil nil 2))
+                   (new-next
+                    (replace-regexp-in-string
+                     ;; Before Emacs-27.1 `literal' `rx' form with a variable
+                     ;; as an argument is not available.
+                     (rx-to-string `(seq string-start ,final-punct) t)
+                     "" next)))
+               (org-element-set-element previous new-prev)
+               (org-element-set-element next new-next)
+               (setq previous new-prev)
+               (setq next new-next)
+               (setq punct final-punct)
+               (setq final-punct nil))))
+          ;; Move punctuation outside.
+          (`(,(or `outside (and `adaptive (guard spacing))) . ,_)
+           ;; This is only meaningful if there is some inner
+           ;; punctuation and no final punctuation already.
+           (when (and punct (not final-punct))
+             ;; Inner punctuation guarantees there is text object
+             ;; before the citation.  However, there is no information
+             ;; about the object following citation, if any.
+             ;; Therefore, we handle all the possible cases (string,
+             ;; other type, or none).
+             (let ((new-prev
+                    (replace-regexp-in-string
+                     previous-punct-re "" previous nil nil 1))
+                   (new-next (if (stringp next) (concat punct next) punct)))
+               (org-element-set-element previous new-prev)
+               (cond
+                ((stringp next)
+                 (org-element-set-element next new-next))
+                (next
+                 (org-element-insert-before new-next next))
+                (t
+                 (org-element-adopt-elements
+                     (org-element-property :parent citation)
+                   new-next)))
+               (setq previous new-prev)
+               (setq next new-next)
+               (setq final-punct punct)
+               (setq punct nil))))
+          (_
+           (error "Invalid punctuation rule: %S" rule))))
+      ;; Phase 2: move citation to its appropriate location.
+      ;;
+      ;; First transform relative citation location into a definitive
+      ;; location, according to the surrounding punctuation.
+      (pcase rule
+        (`(,punctuation same ,order)
+         (setf rule
+               (list punctuation
+                     (cond
+                      ;; When there is punctuation on both sides, the
+                      ;; citation is necessarily on the outside.
+                      ((and punct final-punct) 'outside)
+                      (punct 'inside)
+                      (final-punct 'outside)
+                      ;; No punctuation: bail out on next step.
+                      (t nil))
+                     order))))
+      (pcase rule
+        (`(,_ nil ,_) nil)
+        (`(,_ inside after)
+         ;; Citation has to be moved after punct, if there is
+         ;; a quotation mark, or after final punctuation.
+         (cond
+          (quote
+           (org-cite--insert-at-split previous citation 2 previous-punct-re))
+          (final-punct
+           (org-cite--move-punct-before final-punct citation next info))
+          ;; There is only punct, and we're already after it.
+          (t nil)))
+        (`(,_ inside before)
+         ;; Citation is already behind final-punct, so only consider
+         ;; other locations.
+         (when (or punct quote)
+           (org-cite--insert-at-split previous citation 0 previous-punct-re)))
+        (`(,_ outside after)
+         ;; Citation is already after any punct or quote.  It can only
+         ;; move past final punctuation, if there is one.
+         (when final-punct
+           (org-cite--move-punct-before final-punct citation next info)))
+        (`(,_ outside before)
+         ;; The only non-trivial case is when citation follows punct
+         ;; without a quote.
+         (when (and punct (not quote))
+           (org-cite--insert-at-split previous citation 0 previous-punct-re)))
+        (_
+         (error "Invalid punctuation rule: %S" rule))))))
+
+
+;;; Tools generating or operating on parsed data
+(defun org-cite-parse-elements (s)
+  "Parse string S as a list of Org elements.
+
+The return value is suitable as a replacement for a
+\"print_bibliography\" keyword.  As a consequence, the function
+raises an error if S contains a headline."
+  (with-temp-buffer
+    (insert s)
+    (pcase (org-element-contents (org-element-parse-buffer))
+      ('nil nil)
+      (`(,(and section (guard (eq 'section (org-element-type section)))))
+       (org-element-contents section))
+      (_
+       (error "Headlines cannot replace a keyword")))))
+
+(defun org-cite-parse-objects (s &optional affix)
+  "Parse string S as a secondary string.
+
+The return value is suitable as a replacement for a citation object.
+
+When optional argument AFFIX is non-nil, restrict the set of allowed object
+types to match the contents of a citation affix."
+  (org-element-parse-secondary-string
+   s (org-element-restriction (if affix 'citation-reference 'paragraph))))
+
+(defun org-cite-make-paragraph (&rest data)
+  "Return a paragraph element containing DATA.
+DATA are strings, objects or secondary strings."
+  (apply #'org-element-create 'paragraph nil (apply #'org-cite-concat data)))
+
+(defun org-cite-emphasize (type &rest data)
+  "Apply emphasis TYPE on DATA.
+TYPE is a symbol among `bold', `italic', `strike-through' and `underline'.
+DATA are strings, objects or secondary strings.  Return an object of type 
TYPE."
+  (declare (indent 1))
+  (unless (memq type '(bold italic strike-through underline))
+    (error "Wrong emphasis type: %S" type))
+  (apply #'org-element-create type nil (apply #'org-cite-concat data)))
+
+(defun org-cite-concat (&rest data)
+  "Concatenate all the DATA arguments and make the result a secondary string.
+Each argument may be a string, an object, or a secondary string."
+  (let ((results nil))
+    (dolist (datum (reverse data))
+      (pcase datum
+        ('nil nil)
+        ;; Element or object.
+        ((pred org-element-type) (push datum results))
+        ;; Secondary string.
+        ((pred consp) (setq results (append datum results)))
+        (_
+         (signal
+          'wrong-type-argument
+          (list (format "Argument is not a string or a secondary string: %S"
+                        datum))))))
+    results))
+
+(defun org-cite-mapconcat (function data separator)
+  "Apply FUNCTION to each element of DATA, and return a secondary string.
+
+In between each pair of results, stick SEPARATOR, which may be a string,
+an object, or a secondary string.  FUNCTION must be a function of one argument,
+and must return either a string, an object, or a secondary string."
+  (and data
+       (let ((result (list (funcall function (car data)))))
+         (dolist (datum (cdr data))
+           (setq result
+                 (org-cite-concat result separator (funcall function datum))))
+         result)))
+
+
+;;; Internal interface with fontification (activate capability)
+(defun org-cite-fontify-default (datum)
+  "Fontify DATUM with `org-cite' and `org-cite-key' face.
+DATUM is a citation object, or a citation reference.  In any case, apply
+`org-cite' face on the whole citation, and `org-cite-key' face on each key."
+  (let* ((cite (if (eq 'citation-reference (org-element-type datum))
+                   (org-element-property :parent datum)
+                 datum))
+         (beg (org-element-property :begin cite))
+         (end (org-with-point-at (org-element-property :end cite)
+                (skip-chars-backward " \t")
+                (point))))
+    (add-text-properties beg end '(font-lock-multiline t))
+    (add-face-text-property beg end 'org-cite)
+    (dolist (reference (org-cite-get-references cite))
+      (let ((boundaries (org-cite-key-boundaries reference)))
+        (add-face-text-property (car boundaries) (cdr boundaries)
+                                'org-cite-key)))))
+
+(defun org-cite-activate (limit)
+  "Activate citations from up to LIMIT buffer position.
+Each citation encountered is activated using the appropriate function
+from the processor set in `org-cite-activate-processor'."
+  (let ((name org-cite-activate-processor))
+    (let ((activate
+           (or (and name
+                    (org-cite-processor-has-capability-p name 'activate)
+                    (org-cite-processor-activate (org-cite--get-processor 
name)))
+               #'org-cite-fontify-default)))
+      (while (re-search-forward org-element-citation-prefix-re limit t)
+        (let ((cite (org-with-point-at (match-beginning 0)
+                      (org-element-citation-parser))))
+          (when cite (save-excursion (funcall activate cite))))))))
+
+
+;;; Internal interface with Org Export library (export capability)
+(defun org-cite-store-bibliography (info)
+  "Store bibliography in the communication channel.
+
+Bibliography is stored as a list of absolute file names in the `:bibliography'
+property.
+
+INFO is the communication channel, as a plist.  It is modified by side-effect."
+  (plist-put info :bibliography (org-cite-list-bibliography-files)))
+
+(defun org-cite-store-export-processor (info)
+  "Store export processor in the `:cite-export' property during export.
+
+Export processor is stored as a triplet, or nil.
+
+When non-nil, it is defined as (NAME BIBLIOGRAPHY-STYLE CITATION-STYLE) where
+NAME is a symbol, whereas BIBLIOGRAPHY-STYLE and CITATION-STYLE are strings,
+or nil.
+
+INFO is the communication channel, as a plist.  It is modified by side-effect."
+  (let* ((err
+          (lambda (s)
+            (user-error "Invalid cite export processor definition: %S" s)))
+         (processor
+          (pcase (plist-get info :cite-export)
+            ((or "" `nil) nil)
+            ;; Value is a string.  It comes from a "cite_export"
+            ;; keyword.  It may contain between 1 and 3 tokens, the
+            ;; first one being a symbol and the other (optional) two,
+            ;; strings.
+            ((and (pred stringp) s)
+             (with-temp-buffer
+               (save-excursion (insert s))
+               (let ((result (list (read (current-buffer)))))
+                 (dotimes (_ 2)
+                   (skip-chars-forward " \t")
+                   (cond
+                    ((eobp) (push nil result))
+                    ((char-equal ?\" (char-after))
+                     (condition-case _
+                         (push (org-not-nil (read (current-buffer))) result)
+                       (error (funcall err s))))
+                    (t
+                     (let ((origin (point)))
+                       (skip-chars-forward "^ \t")
+                       (push (org-not-nil (buffer-substring origin (point)))
+                             result)))))
+                 (unless (eobp) (funcall err s))
+                 (nreverse result))))
+            ;; Value is an alist.  It must come from
+            ;; `org-cite-export-processors' variable.  Find the most
+            ;; appropriate processor according to current export
+            ;; back-end.
+            ((and (pred consp) alist)
+             (let* ((backend (plist-get info :back-end))
+                    (candidates
+                     ;; Limit candidates to processors associated to
+                     ;; back-ends derived from or equal to the current
+                     ;; one.
+                     (sort (seq-filter
+                            (pcase-lambda (`(,key . ,_))
+                              (org-export-derived-backend-p backend key))
+                            alist)
+                           (lambda (a b)
+                             (org-export-derived-backend-p (car a) (car b))))))
+               ;; Select the closest candidate, or fallback to t.
+               (pcase (or (car candidates) (assq t alist))
+                 ('nil nil)
+                 (`(,_ . ,p)
+                  ;; Normalize value by turning it into a triplet.
+                  (pcase p
+                    (`(,(pred symbolp))
+                     (append p (list nil nil)))
+                    (`(,(pred symbolp) ,(pred string-or-null-p))
+                     (append p (list nil)))
+                    (`(,(pred symbolp)
+                       ,(pred string-or-null-p)
+                       ,(pred string-or-null-p))
+                     p)
+                    (_ (funcall err p))))
+                 (other (funcall err (cdr other))))))
+            (other (funcall err other)))))
+    (pcase processor
+      ('nil nil)
+      (`(,name . ,_)
+       (cond
+        ((not (org-cite--get-processor name))
+         (user-error "Unknown processor %S" name))
+        ((not (org-cite-processor-has-capability-p name 'export))
+         (user-error "Processor %S is unable to handle citation export" 
name)))))
+    (plist-put info :cite-export processor)))
+
+(defun org-cite-export-citation (citation _ info)
+  "Export CITATION object according to INFO property list.
+This function delegates the export of the current citation to the
+selected citation processor."
+  (pcase (plist-get info :cite-export)
+    ('nil nil)
+    (`(,p ,_ ,_)
+     (funcall (org-cite-processor-export-citation (org-cite--get-processor p))
+             citation
+              (org-cite-citation-style citation info)
+              (plist-get info :back-end)
+              info))
+    (other (error "Invalid `:cite-export' value: %S" other))))
+
+(defun org-cite-export-bibliography (keyword _ info)
+  "Return bibliography associated to \"print_bibliography\" KEYWORD.
+BACKEND is the export back-end, as a symbol.  INFO is a plist
+used as a communication channel."
+  (pcase (plist-get info :cite-export)
+    ('nil nil)
+    (`(,p ,_ ,_)
+     (let ((export-bibilography
+            (org-cite-processor-export-bibliography
+             (org-cite--get-processor p))))
+       (when export-bibilography
+         (funcall export-bibilography
+                 (org-cite-list-keys info)
+                  (plist-get info :bibliography)
+                  (org-cite-bibliography-style info)
+                  (org-cite-bibliography-properties keyword)
+                  (plist-get info :back-end)
+                  info))))
+    (other (error "Invalid `:cite-export' value: %S" other))))
+
+(defun org-cite-process-citations (info)
+  "Replace all citations in the parse tree.
+INFO is the communication channel, as a plist.  Parse tree is modified
+by side-effect."
+  (dolist (cite (org-cite-list-citations info))
+    (let ((replacement (org-cite-export-citation cite nil info))
+          (blanks (or (org-element-property :post-blank cite) 0)))
+      (if (null replacement)
+          ;; Before removing the citation, transfer its `:post-blank'
+          ;; property to the object before, if any.
+          (org-cite--set-previous-post-blank cite blanks info)
+        ;; Make sure there is a space between a quotation mark and
+        ;; a citation.  This is particularly important when using
+        ;; `adaptive' note rule.  See `org-cite-note-rules'.
+        (let ((previous (org-export-get-previous-element cite info)))
+          (when (and (org-string-nw-p previous)
+                     (string-suffix-p "\"" previous))
+            (org-cite--set-previous-post-blank cite 1 info)))
+        (pcase replacement
+          ;; String.
+          ((pred stringp)
+           ;; Handle `:post-blank' before replacing value.
+           (let ((output (concat (org-trim replacement)
+                                 (make-string blanks ?\s))))
+             (org-element-insert-before (org-export-raw-string output) cite)))
+          ;; Single element.
+          (`(,(pred symbolp) . ,_)
+           (org-cite--set-post-blank replacement blanks)
+           (org-element-insert-before replacement cite))
+          ;; Secondary string: splice objects at cite's place.
+          ;; Transfer `:post-blank' to the last object.
+          ((pred consp)
+           (let ((last nil))
+             (dolist (datum replacement)
+               (setq last datum)
+               (org-element-insert-before datum cite))
+             (org-cite--set-post-blank last blanks)))
+          (_
+           (error "Invalid return value from citation export processor: %S"
+                  replacement))))
+      (org-element-extract-element cite))))
+
+(defun org-cite-process-bibliography (info)
+  "Replace all \"print_bibliography\" keywords in the parse tree.
+
+INFO is the communication channel, as a plist.  Parse tree is modified
+by side effect."
+  (org-element-map (plist-get info :parse-tree) 'keyword
+    (lambda (keyword)
+      (when (equal "PRINT_BIBLIOGRAPHY" (org-element-property :key keyword))
+        (let ((replacement (org-cite-export-bibliography keyword nil info))
+              (blanks (or (org-element-property :post-blank keyword) 0)))
+          (pcase replacement
+            ;; Before removing the citation, transfer its
+            ;; `:post-blank' property to the element before, if any.
+            ('nil
+             (org-cite--set-previous-post-blank keyword blanks info)
+             (org-element-extract-element keyword))
+            ;; Handle `:post-blank' before replacing keyword with string.
+            ((pred stringp)
+             (let ((output (concat (org-element-normalize-string replacement)
+                                   (make-string blanks ?\n))))
+               (org-element-set-element keyword (org-export-raw-string 
output))))
+            ;; List of elements: splice contents before keyword and
+            ;; remove the latter.  Transfer `:post-blank' to last
+            ;; element.
+            ((and `(,(pred listp) . ,_) contents)
+             (let ((last nil))
+               (dolist (datum contents)
+                 (setq last datum)
+                 (org-element-insert-before datum keyword))
+               (org-cite--set-post-blank last blanks)
+               (org-element-extract-element keyword)))
+            ;; Single element: replace the keyword.
+            (`(,(pred symbolp) . ,_)
+             (org-cite--set-post-blank replacement blanks)
+             (org-element-set-element keyword replacement))
+            (_
+             (error "Invalid return value from citation export processor: %S"
+                    replacement))))))
+    info))
+
+(defun org-cite-finalize-export (output info)
+  "Finalizer for export process.
+OUTPUT is the full output of the export process.  INFO is the communication
+channel, as a property list."
+  (pcase (plist-get info :cite-export)
+    ('nil output)
+    (`(,p ,_ ,_)
+     (let ((finalizer
+            (org-cite-processor-export-finalizer (org-cite--get-processor p))))
+       (if (not finalizer)
+           output
+         (funcall finalizer
+                  output
+                  (org-cite-list-keys info)
+                  (plist-get info :bibliography)
+                  (org-cite-bibliography-style info)
+                  (plist-get info :back-end)
+                  info))))
+    (other (error "Invalid `:cite-export' value: %S" other))))
+
+
+;;; Internal interface with `org-open-at-point' (follow capability)
+(defun org-cite-follow (datum arg)
+  "Follow citation or citation-reference DATUM.
+Following is done according to the processor set in 
`org-cite-follow-processor'.
+ARG is the prefix argument received when calling `org-open-at-point', or nil."
+  (let ((name org-cite-follow-processor))
+    (cond
+     ((null name)
+      (user-error "No processor set to follow citations"))
+     ((not (org-cite--get-processor name))
+      (user-error "Unknown processor %S" name))
+     ((not (org-cite-processor-has-capability-p name 'follow))
+      (user-error "Processor %S cannot follow citations" name))
+     (t
+      (let ((follow (org-cite-processor-follow (org-cite--get-processor 
name))))
+        (funcall follow datum arg))))))
+
+
+;;; Meta-command for citation insertion (insert capability)
+(defun org-cite--allowed-p (context)
+  "Non-nil when a citation can be inserted at point.
+CONTEXT is the element or object at point, as returned by 
`org-element-context'."
+  (let ((type (org-element-type context)))
+    (cond
+     ;; No citation in attributes, except in parsed ones.
+     ;;
+     ;; XXX: Inserting citation in a secondary value is not allowed
+     ;; yet.  Is it useful?
+     ((let ((post (org-element-property :post-affiliated context)))
+       (and post (< (point) post)))
+      (let ((case-fold-search t))
+        (looking-back
+         (rx-to-string
+          `(seq line-start (0+ (any " \t"))
+                "#+"
+                (or ,@org-element-parsed-keywords)
+                ":"
+                (0+ nonl))
+          t)
+         (line-beginning-position))))
+     ;; Paragraphs and blank lines at top of document are fine.
+     ((memq type '(nil paragraph)))
+     ;; So are contents of verse blocks.
+     ((eq type 'verse-block)
+      (and (>= (point) (org-element-property :contents-begin context))
+          (< (point) (org-element-property :contents-end context))))
+     ;; In an headline or inlinetask, point must be either on the
+     ;; heading itself or on the blank lines below.
+     ((memq type '(headline inlinetask))
+      (or (not (org-at-heading-p))
+         (and (save-excursion
+                (beginning-of-line)
+                (and (let ((case-fold-search t))
+                       (not (looking-at-p "\\*+ END[ \t]*$")))
+                     (let ((case-fold-search nil))
+                       (looking-at org-complex-heading-regexp))))
+              (match-beginning 4)
+              (>= (point) (match-beginning 4))
+              (or (not (match-beginning 5))
+                  (< (point) (match-beginning 5))))))
+     ;; White spaces after an object or blank lines after an element
+     ;; are OK.
+     ((>= (point)
+         (save-excursion (goto-char (org-element-property :end context))
+                         (skip-chars-backward " \r\t\n")
+                         (if (eq (org-element-class context) 'object) (point)
+                           (line-beginning-position 2)))))
+     ;; At the beginning of a footnote definition, right after the
+     ;; label, is OK.
+     ((eq type 'footnote-definition) (looking-at (rx space)))
+     ;; At the start of a list item is fine, as long as the bullet is
+     ;; unaffected.
+     ((eq type 'item)
+      (> (point) (+ (org-element-property :begin context)
+                    (current-indentation)
+                    (if (org-element-property :checkbox context)
+                        5 1))))
+     ;; Other elements are invalid.
+     ((eq (org-element-class context) 'element) nil)
+     ;; Just before object is fine.
+     ((= (point) (org-element-property :begin context)))
+     ;; Within recursive object too, but not in a link.
+     ((eq type 'link) nil)
+     ((eq type 'table-cell)
+      ;; :contents-begin is not reliable on empty cells, so special
+      ;; case it.
+      (<= (save-excursion (skip-chars-backward " \t") (point))
+          (org-element-property :contents-end context)))
+     ((let ((cbeg (org-element-property :contents-begin context))
+           (cend (org-element-property :contents-end context)))
+       (and cbeg (>= (point) cbeg) (<= (point) cend)))))))
+
+(defun org-cite--insert-string-before (string reference)
+  "Insert STRING before citation REFERENCE object."
+  (org-with-point-at (org-element-property :begin reference)
+    (insert string ";")))
+
+(defun org-cite--insert-string-after (string reference)
+  "Insert STRING after citation REFERENCE object."
+  (org-with-point-at (org-element-property :end reference)
+    ;; Make sure to move forward when we're inserting at point, so the
+    ;; insertion can happen multiple times.
+    (if (char-equal ?\; (char-before))
+        (insert-before-markers  string ";")
+      (insert-before-markers ";" string))))
+
+(defun org-cite--keys-to-citation (keys)
+  "Build a citation object from a list of citation KEYS.
+Citation keys are strings without the leading \"@\"."
+  (apply #'org-element-create
+         'citation
+         nil
+         (mapcar (lambda (k)
+                   (org-element-create 'citation-reference (list :key k)))
+                 keys)))
+
+(defun org-cite-make-insert-processor (select-key select-style)
+  "Build a function appropriate as an insert processor.
+
+SELECT-KEY is a function called with one argument.  When it is nil, the 
function
+should return a citation key as a string, or nil.  Otherwise, the function
+should return a list of such keys, or nil.  The keys should not have any 
leading
+\"@\" character.
+
+SELECT-STYLE is a function called with one argument, the citation object being
+edited or constructed so far.  It should return a style string, or nil.
+
+The return value is a function of two arguments: CONTEXT and ARG.  CONTEXT is
+either a citation reference, a citation object, or nil.  ARG is a prefix
+argument.
+
+The generated function inserts or edit a citation at point.  More specifically,
+
+  On a citation reference:
+
+    - on the prefix or right before th \"@\" character, insert a new reference
+      before the current one,
+    - on the suffix, insert it after the reference,
+    - otherwise, update the cite key, preserving both affixes.
+
+    When ARG is non-nil, remove the reference, possibly removing the whole
+    citation if it contains a single reference.
+
+  On a citation object:
+
+    - on the style part, offer to update it,
+    - on the global prefix, add a new reference before the first one,
+    - on the global suffix, add a new reference after the last one,
+
+  Elsewhere, insert a citation at point.  When ARG is non-nil, offer to 
complete
+  style in addition to references."
+  (unless (and (functionp select-key) (functionp select-style))
+    (error "Wrong argument type(s)"))
+  (lambda (context arg)
+    (pcase (org-element-type context)
+      ;; When on a citation, check point is not on the blanks after it.
+      ;; Otherwise, consider we're after it.
+      ((and 'citation
+            (guard
+             (let ((boundaries (org-cite-boundaries context)))
+               (and (< (point) (cdr boundaries))
+                    (> (point) (car boundaries))))))
+       ;; When ARG is non-nil, delete the whole citation.  Otherwise,
+       ;; action depends on the point.
+       (if arg
+           (org-cite-delete-citation context)
+         (let* ((begin (org-element-property :begin context))
+                (style-end (1- (org-with-point-at begin (search-forward 
":")))))
+           (if (>= style-end (point))
+               ;; On style part, edit the style.
+               (let ((style-start (+ 5 begin))
+                     (style (funcall select-style)))
+                 (unless style (user-error "Aborted"))
+                 (org-with-point-at style-start
+                   (delete-region style-start style-end)
+                   (when (org-string-nw-p style) (insert "/" style))))
+             ;; On an affix, insert a new reference before or after
+             ;; point.
+             (let* ((references (org-cite-get-references context))
+                    (key (concat "@" (funcall select-key nil))))
+               (if (< (point) (org-element-property :contents-begin context))
+                   (org-cite--insert-string-before key (car references))
+                 (org-cite--insert-string-after key (org-last 
references))))))))
+      ;; On a citation reference.  If ARG is not nil, remove the
+      ;; reference.  Otherwise, action depends on the point.
+      ((and 'citation-reference (guard arg)) (org-cite-delete-citation 
context))
+      ('citation-reference
+       (pcase-let* ((`(,start . ,end) (org-cite-key-boundaries context))
+                    (key (concat "@"
+                                 (or (funcall select-key nil)
+                                     (user-error "Aborted")))))
+         ;; Right before the "@" character, do not replace the reference
+         ;; at point, but insert a new one before it.  It makes adding
+         ;; a new reference at the beginning easier in the following
+         ;; case: [cite:@key].
+         (cond
+          ((>= start (point)) (org-cite--insert-string-before key context))
+          ((<= end (point)) (org-cite--insert-string-after key context))
+          (t
+           (org-with-point-at start
+             (delete-region start end)
+             (insert key))))))
+      (_
+       (let ((keys (funcall select-key t)))
+         (unless keys (user-error "Aborted"))
+         (insert
+          (format "[cite%s:%s]"
+                  (if arg
+                      (let ((style (funcall select-style
+                                            (org-cite--keys-to-citation 
keys))))
+                        (if (org-string-nw-p style)
+                            (concat "/" style)
+                          ""))
+                    "")
+                  (mapconcat (lambda (k) (concat "@" k)) keys "; "))))))))
+
+;;;###autoload
+(defun org-cite-insert (arg)
+  "Insert a citation at point.
+Insertion is done according to the processor set in 
`org-cite-insert-processor'.
+ARG is the prefix argument received when calling interactively the function."
+  (interactive "P")
+  (let ((name org-cite-insert-processor))
+    (cond
+     ((null name)
+      (user-error "No processor set to insert citations"))
+     ((not (org-cite--get-processor name))
+      (user-error "Unknown processor %S" name))
+     ((not (org-cite-processor-has-capability-p name 'insert))
+      (user-error "Processor %S cannot insert citations" name))
+     (t
+      (let ((context (org-element-context))
+            (insert (org-cite-processor-insert (org-cite--get-processor 
name))))
+        (cond
+         ((memq (org-element-type context) '(citation citation-reference))
+          (funcall insert context arg))
+         ((org-cite--allowed-p context)
+          (funcall insert nil arg))
+         (t
+          (user-error "Cannot insert a citation here"))))))))
+
+(provide 'oc)
+;;; oc.el ends here
diff --git a/lisp/org/ol-bbdb.el b/lisp/org/ol-bbdb.el
index 01a1fe9325..f697f1f82b 100644
--- a/lisp/org/ol-bbdb.el
+++ b/lisp/org/ol-bbdb.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Authors: Carsten Dominik <carsten at orgmode dot org>
+;; Authors: Carsten Dominik <carsten.dominik@gmail.com>
 ;;       Thomas Baumann <thomas dot baumann at ch dot tum dot de>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
@@ -60,7 +60,7 @@
 ;;
 ;; CLASS-OR-FORMAT-STRING is one of two things:
 ;;
-;;  - an identifier for a class of anniversaries (eg. birthday or
+;;  - an identifier for a class of anniversaries (e.g. birthday or
 ;;    wedding) from `org-bbdb-anniversary-format-alist' which then
 ;;    defines the format string for this class
 ;;  - the (format) string displayed in the diary.
diff --git a/lisp/org/ol-bibtex.el b/lisp/org/ol-bibtex.el
index 6b591218c8..476095d3e0 100644
--- a/lisp/org/ol-bibtex.el
+++ b/lisp/org/ol-bibtex.el
@@ -88,7 +88,7 @@
 ;;
 ;; - All Bibtex information is taken from the document compiled by
 ;;   Andrew Roberts from the Bibtex manual, available at
-;;   http://www.andy-roberts.net/res/writing/latex/bibentries.pdf
+;;   https://www.andy-roberts.net/res/writing/latex/bibentries.pdf
 ;;
 ;;; History:
 ;;
@@ -145,59 +145,59 @@
   '((:article
      (:description . "An article from a journal or magazine")
      (:required :author :title :journal :year)
-     (:optional :volume :number :pages :month :note))
+     (:optional :volume :number :pages :month :note :doi))
     (:book
      (:description . "A book with an explicit publisher")
      (:required (:editor :author) :title :publisher :year)
-     (:optional (:volume :number) :series :address :edition :month :note))
+     (:optional (:volume :number) :series :address :edition :month :note :doi))
     (:booklet
      (:description . "A work that is printed and bound, but without a named 
publisher or sponsoring institution.")
      (:required :title)
-     (:optional :author :howpublished :address :month :year :note))
+     (:optional :author :howpublished :address :month :year :note :doi :url))
     (:conference
      (:description . "")
      (:required :author :title :booktitle :year)
-     (:optional :editor :pages :organization :publisher :address :month :note))
+     (:optional :editor :pages :organization :publisher :address :month :note 
:doi :url))
     (:inbook
      (:description . "A part of a book, which may be a chapter (or section or 
whatever) and/or a range of pages.")
      (:required (:author :editor) :title (:chapter :pages) :publisher :year)
-     (:optional :crossref (:volume :number) :series :type :address :edition 
:month :note))
+     (:optional :crossref (:volume :number) :series :type :address :edition 
:month :note :doi))
     (:incollection
      (:description . "A part of a book having its own title.")
      (:required :author :title :booktitle :publisher :year)
-     (:optional :crossref :editor (:volume :number) :series :type :chapter 
:pages :address :edition :month :note))
+     (:optional :crossref :editor (:volume :number) :series :type :chapter 
:pages :address :edition :month :note :doi))
     (:inproceedings
      (:description . "An article in a conference proceedings")
      (:required :author :title :booktitle :year)
-     (:optional :crossref :editor (:volume :number) :series :pages :address 
:month :organization :publisher :note))
+     (:optional :crossref :editor (:volume :number) :series :pages :address 
:month :organization :publisher :note :doi))
     (:manual
      (:description . "Technical documentation.")
      (:required :title)
-     (:optional :author :organization :address :edition :month :year :note))
+     (:optional :author :organization :address :edition :month :year :note 
:doi :url))
     (:mastersthesis
      (:description . "A Master’s thesis.")
      (:required :author :title :school :year)
-     (:optional :type :address :month :note))
+     (:optional :type :address :month :note :doi :url))
     (:misc
      (:description . "Use this type when nothing else fits.")
      (:required)
-     (:optional :author :title :howpublished :month :year :note))
+     (:optional :author :title :howpublished :month :year :note :doi :url))
     (:phdthesis
      (:description . "A PhD thesis.")
      (:required :author :title :school :year)
-     (:optional :type :address :month :note))
+     (:optional :type :address :month :note :doi :url))
     (:proceedings
      (:description . "The proceedings of a conference.")
      (:required :title :year)
-     (:optional :editor (:volume :number) :series :address :month 
:organization :publisher :note))
+     (:optional :editor (:volume :number) :series :address :month 
:organization :publisher :note :doi))
     (:techreport
      (:description . "A report published by a school or other institution.")
      (:required :author :title :institution :year)
-     (:optional :type :address :month :note))
+     (:optional :type :address :month :note :doi :url))
     (:unpublished
      (:description . "A document having an author and title, but not formally 
published.")
      (:required :author :title :note)
-     (:optional :month :year)))
+     (:optional :month :year :doi :url)))
   "Bibtex entry types with required and optional parameters.")
 
 (defvar org-bibtex-fields
@@ -207,6 +207,7 @@
     (:booktitle    . "Title of a book, part of which is being cited.  See the 
LaTeX book for how to type titles.  For book entries, use the title field 
instead.")
     (:chapter      . "A chapter (or section or whatever) number.")
     (:crossref     . "The database key of the entry being cross referenced.")
+    (:doi          . "The digital object identifier.")
     (:edition      . "The edition of a book for example, 'Second'.  This 
should be an ordinal, and should have the first letter capitalized, as shown 
here; the standard styles convert to lower case when necessary.")
     (:editor       . "Name(s) of editor(s), typed as indicated in the LaTeX 
book.  If there is also an author field, then the editor field gives the editor 
of the book or collection in which the reference appears.")
     (:howpublished . "How something strange has been published.  The first 
word should be capitalized.")
@@ -223,6 +224,7 @@
     (:series       . "The name of a series or set of books.  When citing an 
entire book, the title field gives its title and an optional series field gives 
the name of a series or multi-volume set in which the book is published.")
     (:title        . "The work’s title, typed as explained in the LaTeX book.")
     (:type         . "The type of a technical report for example, 'Research 
Note'.")
+    (:url          . "Uniform resource locator.")
     (:volume       . "The volume of a journal or multi-volume book.")
     (:year         . "The year of publication or, for an unpublished work, the 
year it was written.  Generally it should consist of four numerals, such as 
1984, although the standard styles can handle any year whose last four 
nonpunctuation characters are numerals, such as '(about 1984)'"))
   "Bibtex fields with descriptions.")
@@ -507,6 +509,7 @@ ARG, when non-nil, is a universal prefix argument.  See
       (org-link-store-props
        :key (cdr (assoc "=key=" entry))
        :author (or (cdr (assoc "author" entry)) "[no author]")
+       :doi (or (cdr (assoc "doi" entry)) "[no doi]")
        :editor (or (cdr (assoc "editor" entry)) "[no editor]")
        :title (or (cdr (assoc "title" entry)) "[no title]")
        :booktitle (or (cdr (assoc "booktitle" entry)) "[no booktitle]")
@@ -656,7 +659,7 @@ This uses `bibtex-parse-entry'."
   (interactive)
   (let ((keyword (lambda (str) (intern (concat ":" (downcase str)))))
        (clean-space (lambda (str) (replace-regexp-in-string
-                              "[[:space:]\n\r]+" " " str)))
+                                   "[[:space:]\n\r]+" " " str)))
        (strip-delim
         (lambda (str)               ; strip enclosing "..." and {...}
           (dolist (pair '((34 . 34) (123 . 125)))
@@ -674,7 +677,8 @@ This uses `bibtex-parse-entry'."
                        (_ field)))
                    (funcall clean-space (funcall strip-delim (cdr pair)))))
            (save-excursion (bibtex-beginning-of-entry) (bibtex-parse-entry)))
-          org-bibtex-entries)))
+          org-bibtex-entries)
+    (unless (car org-bibtex-entries) (pop org-bibtex-entries))))
 
 (defun org-bibtex-read-buffer (buffer)
   "Read all bibtex entries in BUFFER and save to `org-bibtex-entries'.
diff --git a/lisp/org/ol-doi.el b/lisp/org/ol-doi.el
new file mode 100644
index 0000000000..d2d16b27d5
--- /dev/null
+++ b/lisp/org/ol-doi.el
@@ -0,0 +1,72 @@
+;;; ol-doi.el --- DOI links support in Org           -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library introduces the "doi" link type in Org, and provides
+;; code for opening and exporting such links.
+
+;;; Code:
+
+(require 'ol)
+
+(defcustom org-link-doi-server-url "https://doi.org/";
+  "The URL of the DOI server."
+  :group 'org-link-follow
+  :version "24.3"
+  :type 'string
+  :safe #'stringp)
+
+(defun org-link-doi-open (path arg)
+  "Open a \"doi\" type link.
+PATH is a the path to search for, as a string."
+  (browse-url (url-encode-url (concat org-link-doi-server-url path)) arg))
+
+(defun org-link-doi-export (path desc backend info)
+  "Export a \"doi\" type link.
+PATH is the DOI name.  DESC is the description of the link, or
+nil.  BACKEND is a symbol representing the backend used for
+export.  INFO is a a plist containing the export parameters."
+  (let ((uri (concat org-link-doi-server-url path)))
+    (pcase backend
+      (`html
+       (format "<a href=\"%s\">%s</a>" uri (or desc uri)))
+      (`latex
+       (if desc (format "\\href{%s}{%s}" uri desc)
+        (format "\\url{%s}" uri)))
+      (`ascii
+       (if (not desc) (format "<%s>" uri)
+         (concat (format "[%s]" desc)
+                (and (not (plist-get info :ascii-links-to-notes))
+                     (format " (<%s>)" uri)))))
+      (`texinfo
+       (if (not desc) (format "@uref{%s}" uri)
+         (format "@uref{%s, %s}" uri desc)))
+      (_ uri))))
+
+(org-link-set-parameters "doi"
+                         :follow #'org-link-doi-open
+                         :export #'org-link-doi-export)
+
+
+(provide 'org-link-doi)
+(provide 'ol-doi)
+;;; ol-doi.el ends here
diff --git a/lisp/org/ol-eshell.el b/lisp/org/ol-eshell.el
index 8920e0afb0..a7550e3769 100644
--- a/lisp/org/ol-eshell.el
+++ b/lisp/org/ol-eshell.el
@@ -35,9 +35,9 @@
 
 (defun org-eshell-open (link _)
   "Switch to an eshell buffer and execute a command line.
-   The link can be just a command line (executed in the default
-   eshell buffer) or a command line prefixed by a buffer name
-   followed by a colon."
+The link can be just a command line (executed in the default
+eshell buffer) or a command line prefixed by a buffer name
+followed by a colon."
   (let* ((buffer-and-command
           (if (string-match "\\([A-Za-z0-9+*-]+\\):\\(.*\\)" link)
              (list (match-string 1 link)
@@ -55,7 +55,7 @@
 
 (defun org-eshell-store-link ()
   "Store a link that, when opened, switches back to the current eshell buffer
-   and the current working directory."
+and the current working directory."
   (when (eq major-mode 'eshell-mode)
     (let* ((command (concat "cd " (eshell/pwd)))
            (link  (concat (buffer-name) ":" command)))
diff --git a/lisp/org/ol-gnus.el b/lisp/org/ol-gnus.el
index 2d51447e0c..72bdd7310a 100644
--- a/lisp/org/ol-gnus.el
+++ b/lisp/org/ol-gnus.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;         Tassilo Horn <tassilo at member dot fsf dot org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
@@ -194,7 +194,7 @@ If `org-store-link' was called with a prefix arg the 
meaning of
                               (message-tokenize-header
                                (mail-fetch-field "gcc" nil t) " ,"))))
               (id (org-unbracket-string "<" ">"
-                                        (mail-fetch-field "Message-ID")))
+                    (mail-fetch-field "Message-ID")))
               (to (mail-fetch-field "To"))
               (from (mail-fetch-field "From"))
               (subject (mail-fetch-field "Subject"))
diff --git a/lisp/org/ol-info.el b/lisp/org/ol-info.el
index 8b1e5da516..a535ea581a 100644
--- a/lisp/org/ol-info.el
+++ b/lisp/org/ol-info.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -56,7 +56,7 @@
                        "#" Info-current-node)))
       (org-link-store-props :type "info" :file Info-current-file
                            :node Info-current-node
-                           :link link :desc desc)
+                           :link link :description desc)
       link)))
 
 (defun org-info-open (path _)
@@ -91,7 +91,7 @@
     "pgg" "rcirc" "reftex" "remember" "sasl" "sc" "semantic" "ses" "sieve"
     "smtpmail" "speedbar" "srecode" "todo-mode" "tramp" "url" "vip" "viper"
     "widget" "wisent" "woman")
-  "List of emacs documents available.
+  "List of Emacs documents available.
 Taken from <https://www.gnu.org/software/emacs/manual/html_mono/.>")
 
 (defconst org-info-other-documents
diff --git a/lisp/org/ol-man.el b/lisp/org/ol-man.el
new file mode 100644
index 0000000000..0d9ac7c8c7
--- /dev/null
+++ b/lisp/org/ol-man.el
@@ -0,0 +1,86 @@
+;;; ol-man.el --- Links to man pages -*- lexical-binding: t; -*-
+;;
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
+;; Maintainer: Bastien Guerry <bzg@gnu.org>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: https://orgmode.org
+;;
+;; This file is part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+(require 'ol)
+
+(org-link-set-parameters "man"
+                        :follow #'org-man-open
+                        :export #'org-man-export
+                        :store #'org-man-store-link)
+
+(defcustom org-man-command 'man
+  "The Emacs command to be used to display a man page."
+  :group 'org-link
+  :type '(choice (const man) (const woman)))
+
+(defun org-man-open (path _)
+  "Visit the manpage on PATH.
+PATH should be a topic that can be thrown at the man command.
+If PATH contains extra ::STRING which will use `occur' to search
+matched strings in man buffer."
+  (string-match "\\(.*?\\)\\(?:::\\(.*\\)\\)?$" path)
+  (let* ((command (match-string 1 path))
+        (search (match-string 2 path)))
+    (funcall org-man-command command)
+    (when search
+      (with-current-buffer (concat "*Man " command "*")
+       (goto-char (point-min))
+       (search-forward search)))))
+
+(defun org-man-store-link ()
+  "Store a link to a README file."
+  (when (memq major-mode '(Man-mode woman-mode))
+    ;; This is a man page, we do make this link
+    (let* ((page (org-man-get-page-name))
+           (link (concat "man:" page))
+           (description (format "Manpage for %s" page)))
+      (org-link-store-props
+       :type "man"
+       :link link
+       :description description))))
+
+(defun org-man-get-page-name ()
+  "Extract the page name from the buffer name."
+  ;; This works for both `Man-mode' and `woman-mode'.
+  (if (string-match " \\(\\S-+\\)\\*" (buffer-name))
+      (match-string 1 (buffer-name))
+    (error "Cannot create link to this man page")))
+
+(defun org-man-export (link description format)
+  "Export a man page link from Org files."
+  (let ((path (format "http://man.he.net/?topic=%s&section=all"; link))
+       (desc (or description link)))
+    (cond
+     ((eq format 'html) (format "<a target=\"_blank\" href=\"%s\">%s</a>" path 
desc))
+     ((eq format 'latex) (format "\\href{%s}{%s}" path desc))
+     ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
+     ((eq format 'ascii) (format "%s (%s)" desc path))
+     ((eq format 'md) (format "[%s](%s)" desc path))
+     (t path))))
+
+(provide 'ol-man)
+
+;;; ol-man.el ends here
diff --git a/lisp/org/ol-rmail.el b/lisp/org/ol-rmail.el
index a73060b50f..2593ebdf02 100644
--- a/lisp/org/ol-rmail.el
+++ b/lisp/org/ol-rmail.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
diff --git a/lisp/org/ol-w3m.el b/lisp/org/ol-w3m.el
index ebb11ce3d5..9e03269e11 100644
--- a/lisp/org/ol-w3m.el
+++ b/lisp/org/ol-w3m.el
@@ -82,26 +82,41 @@ so that it can be yanked into an Org  buffer with links 
working correctly."
         (setq temp-position (point))
         ;; move to next anchor when current point is not at anchor
         (or (get-text-property (point) 'w3m-href-anchor) 
(org-w3m-get-next-link-start))
-        (if (<= (point) transform-end) ; if point is inside transform bound
-            (progn
-              ;; get content between two links.
-              (when (> (point) temp-position)
-                (setq return-content (concat return-content
-                                             (buffer-substring
-                                              temp-position (point)))))
-              ;; get link location at current point.
-              (setq link-location (get-text-property (point) 'w3m-href-anchor))
-              ;; get link title at current point.
-              (setq link-title (buffer-substring (point)
-                                                 (org-w3m-get-anchor-end)))
-              ;; concat Org style url to `return-content'.
-              (setq return-content
-                   (concat return-content
-                           (if (org-string-nw-p link-location)
-                               (org-link-make-string link-location link-title)
-                             link-title))))
+        (cond
+         ((<= (point) transform-end) ; point is inside transform bound
+          ;; get content between two links.
+          (when (> (point) temp-position)
+            (setq return-content (concat return-content
+                                         (buffer-substring
+                                          temp-position (point)))))
+          (cond
+           ((setq link-location (get-text-property (point) 'w3m-href-anchor))
+            ;; current point is a link
+            ;; (we thus also got link location at current point)
+            ;; get link title at current point.
+            (setq link-title (buffer-substring (point)
+                                               (org-w3m-get-anchor-end)))
+            ;; concat Org style url to `return-content'.
+            (setq return-content
+                  (concat return-content
+                          (if (org-string-nw-p link-location)
+                              (org-link-make-string link-location link-title)
+                            link-title))))
+           ((setq link-location (get-text-property (point) 'w3m-image))
+            ;; current point is an image
+            ;; (we thus also got image link location at current point)
+            ;; get link title at current point.
+            (setq link-title (buffer-substring (point) 
(org-w3m-get-image-end)))
+            ;; concat Org style url to `return-content'.
+            (setq return-content
+                  (concat return-content
+                          (if (org-string-nw-p link-location)
+                              (org-link-make-string link-location link-title)
+                            link-title))))
+           (t nil))); current point is neither a link nor an image
+         (t ; point is NOT inside transform bound
           (goto-char temp-position) ; reset point before jump next anchor
-          (setq out-bound t)))     ; for break out `while' loop
+          (setq out-bound t))))            ; for break out `while' loop
       ;; add the rest until end of the region to be copied
       (when (< (point) transform-end)
         (setq return-content
@@ -114,6 +129,7 @@ so that it can be yanked into an Org  buffer with links 
working correctly."
 (defun org-w3m-get-anchor-start ()
   "Move cursor to the start of current anchor.  Return point."
   ;; get start position of anchor or current point
+  ;; NOTE: This function seems never to be used. Should it be removed?
   (goto-char (or (previous-single-property-change (point) 'w3m-anchor-sequence)
                  (point))))
 
@@ -123,26 +139,46 @@ so that it can be yanked into an Org  buffer with links 
working correctly."
   (goto-char (or (next-single-property-change (point) 'w3m-anchor-sequence)
                 (point))))
 
+(defun org-w3m-get-image-end ()
+  "Move cursor to the end of current image.  Return point."
+  ;; get end position of image or point
+  ;; NOTE: Function `org-w3m-get-image-start' was not created because
+  ;;       function `org-w3m-get-anchor-start' is never used.
+  (goto-char (or (next-single-property-change (point) 'w3m-image)
+                (point))))
+
 (defun org-w3m-get-next-link-start ()
-  "Move cursor to the start of next link.  Return point."
-  (catch 'reach
-    (while (next-single-property-change (point) 'w3m-anchor-sequence)
-      ;; jump to next anchor
-      (goto-char (next-single-property-change (point) 'w3m-anchor-sequence))
-      (when (get-text-property (point) 'w3m-href-anchor)
-        ;; return point when current is valid link
-        (throw 'reach nil))))
-  (point))
+  "Move cursor to the start of next link or image.  Return point."
+  (let (pos start-pos anchor-pos image-pos)
+    (setq pos (setq start-pos (point)))
+    (setq anchor-pos
+          (catch 'reach
+            (while (setq pos (next-single-property-change pos 
'w3m-anchor-sequence))
+              (when (get-text-property pos 'w3m-href-anchor)
+                (throw 'reach pos)))))
+    (setq pos start-pos)
+    (setq image-pos
+          (catch 'reach
+            (while (setq pos (next-single-property-change pos 'w3m-image))
+              (when (get-text-property pos 'w3m-image)
+                (throw 'reach pos)))))
+    (goto-char (min (or anchor-pos (point-max)) (or image-pos (point-max))))))
 
 (defun org-w3m-get-prev-link-start ()
   "Move cursor to the start of previous link.  Return point."
+  ;; NOTE: This function is only called by `org-w3m-no-prev-link-p',
+  ;;       which itself seems never to be used. Should it be removed?
+  ;;
+  ;; WARNING: This function has not been updated to account for
+  ;;      `w3m-image'. See `org-w3m-get-next-link-start'.
   (catch 'reach
-    (while (previous-single-property-change (point) 'w3m-anchor-sequence)
-      ;; jump to previous anchor
-      (goto-char (previous-single-property-change (point) 
'w3m-anchor-sequence))
-      (when (get-text-property (point) 'w3m-href-anchor)
-        ;; return point when current is valid link
-        (throw 'reach nil))))
+    (let ((pos (point)))
+      (while (setq pos (previous-single-property-change pos 
'w3m-anchor-sequence))
+        (when (get-text-property pos 'w3m-href-anchor)
+          ;; jump to previous anchor
+          (goto-char pos)
+          ;; return point when current is valid link
+          (throw 'reach nil)))))
   (point))
 
 (defun org-w3m-no-next-link-p ()
@@ -154,6 +190,7 @@ Return t if there is no next link; otherwise, return nil."
 (defun org-w3m-no-prev-link-p ()
   "Whether there is no previous link after the cursor.
 Return t if there is no previous link; otherwise, return nil."
+  ;; NOTE: This function seems never to be used. Should it be removed?
   (save-excursion
     (equal (point) (org-w3m-get-prev-link-start))))
 
diff --git a/lisp/org/ol.el b/lisp/org/ol.el
index 4b7f2081a8..aa1849715c 100644
--- a/lisp/org/ol.el
+++ b/lisp/org/ol.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -178,8 +178,7 @@ link.
   :group 'org-link
   :package-version '(Org . "9.1")
   :type '(alist :tag "Link display parameters"
-               :value-type plist)
-  :safe nil)
+               :value-type plist))
 
 (defcustom org-link-descriptive t
   "Non-nil means Org displays descriptive links.
@@ -214,13 +213,18 @@ relative  Relative to the current directory, i.e. the 
directory of the file
 absolute  Absolute path, if possible with ~ for home directory.
 noabbrev  Absolute path, no abbreviation of home directory.
 adaptive  Use relative path for files in the current directory and sub-
-          directories of it.  For other files, use an absolute path."
+          directories of it.  For other files, use an absolute path.
+
+Alternatively, users may supply a custom function that takes the
+full filename as an argument and returns the path."
   :group 'org-link
   :type '(choice
          (const relative)
          (const absolute)
          (const noabbrev)
-         (const adaptive))
+         (const adaptive)
+         (function))
+  :package-version '(Org . "9.5")
   :safe #'symbolp)
 
 (defcustom org-link-abbrev-alist nil
@@ -277,13 +281,6 @@ links created by planner."
   :type '(choice (const nil) (function))
   :safe #'null)
 
-(defcustom org-link-doi-server-url "https://doi.org/";
-  "The URL of the DOI server."
-  :group 'org-link-follow
-  :version "24.3"
-  :type 'string
-  :safe #'stringp)
-
 (defcustom org-link-frame-setup
   '((vm . vm-visit-folder-other-frame)
     (vm-imap . vm-visit-imap-folder-other-frame)
@@ -337,8 +334,7 @@ another window."
          (cons (const wl)
                (choice
                 (const wl)
-                (const wl-other-frame))))
-  :safe nil)
+                (const wl-other-frame)))))
 
 (defcustom org-link-search-must-match-exact-headline 'query-to-create
   "Non-nil means internal fuzzy links can only match headlines.
@@ -387,15 +383,13 @@ single keystroke rather than having to type \"yes\"."
   :type '(choice
          (const :tag "with yes-or-no (safer)" yes-or-no-p)
          (const :tag "with y-or-n (faster)" y-or-n-p)
-         (const :tag "no confirmation (dangerous)" nil))
-  :safe nil)
+         (const :tag "no confirmation (dangerous)" nil)))
 
 (defcustom org-link-shell-skip-confirm-regexp ""
   "Regexp to skip confirmation for shell links."
   :group 'org-link-follow
   :version "24.1"
-  :type 'regexp
-  :safe nil)
+  :type 'regexp)
 
 (defcustom org-link-elisp-confirm-function 'yes-or-no-p
   "Non-nil means ask for confirmation before executing Emacs Lisp links.
@@ -412,15 +406,13 @@ single keystroke rather than having to type \"yes\"."
   :type '(choice
          (const :tag "with yes-or-no (safer)" yes-or-no-p)
          (const :tag "with y-or-n (faster)" y-or-n-p)
-         (const :tag "no confirmation (dangerous)" nil))
-  :safe nil)
+         (const :tag "no confirmation (dangerous)" nil)))
 
 (defcustom org-link-elisp-skip-confirm-regexp ""
   "A regexp to skip confirmation for Elisp links."
   :group 'org-link-follow
   :version "24.1"
-  :type 'regexp
-  :safe nil)
+  :type 'regexp)
 
 (defgroup org-link-store nil
   "Options concerning storing links in Org mode."
@@ -508,13 +500,16 @@ links more efficient."
   "Regular expression matching radio targets in plain text.")
 
 (defvar org-link-types-re nil
-  "Matches a link that has a url-like prefix like \"http:\"")
+  "Matches a link that has a url-like prefix like \"http:\".")
 
 (defvar org-link-angle-re nil
   "Matches link with angular brackets, spaces are allowed.")
 
 (defvar org-link-plain-re nil
-  "Matches plain link, without spaces.")
+  "Matches plain link, without spaces.
+Group 1 must contain the link type (i.e. https).
+Group 2 must contain the link path (i.e. //example.com).
+Used by `org-element-link-parser'.")
 
 (defvar org-link-bracket-re nil
   "Matches a link in double brackets.")
@@ -802,15 +797,33 @@ This should be called after the variable 
`org-link-parameters' has changed."
          (format "<%s:\\([^>\n]*\\(?:\n[ \t]*[^> \t\n][^>\n]*\\)*\\)>"
                  types-re)
          org-link-plain-re
-         (concat
-          "\\<" types-re ":"
-          "\\([^][ \t\n()<>]+\\(?:([[:word:]0-9_]+)\\|\\([^[:punct:] 
\t\n]\\|/\\)\\)\\)")
-         ;;     "\\([^]\t\n\r<>() ]+[^]\t\n\r<>,.;() ]\\)")
-         org-link-bracket-re
-         (rx (seq "[["
-                  ;; URI part: match group 1.
-                  (group
-                   (one-or-more
+          (let* ((non-space-bracket "[^][ \t\n()<>]")
+                (parenthesis
+                 `(seq "("
+                       (0+ (or (regex ,non-space-bracket)
+                               (seq "("
+                                    (0+ (regex ,non-space-bracket))
+                                    ")")))
+                       ")")))
+           ;; Heuristics for an URL link inspired by
+           ;; 
https://daringfireball.net/2010/07/improved_regex_for_matching_urls
+           (rx-to-string
+            `(seq word-start
+                   ;; Link type: match group 1.
+                  (regexp ,types-re)
+                  ":"
+                   ;; Link path: match group 2.
+                   (group
+                   (1+ (or (regex ,non-space-bracket)
+                           ,parenthesis))
+                   (or (regexp "[^[:punct:] \t\n]")
+                       ?/
+                       ,parenthesis)))))
+          org-link-bracket-re
+          (rx (seq "[["
+                  ;; URI part: match group 1.
+                  (group
+                   (one-or-more
                      (or (not (any "[]\\"))
                         (and "\\" (zero-or-more "\\\\") (any "[]"))
                         (and (one-or-more "\\") (not (any "[]"))))))
@@ -910,7 +923,7 @@ and dates."
 
 (defun org-link-encode (text table)
   "Return percent escaped representation of string TEXT.
-TEXT is a string with the text to escape. TABLE is a list of
+TEXT is a string with the text to escape.  TABLE is a list of
 characters that should be escaped."
   (mapconcat
    (lambda (c)
@@ -1301,14 +1314,6 @@ If there is no description, use the link target."
 
 ;;; Built-in link types
 
-;;;; "doi" link type
-(defun org-link--open-doi (path arg)
-  "Open a \"doi\" type link.
-PATH is a the path to search for, as a string."
-  (browse-url (url-encode-url (concat org-link-doi-server-url path)) arg))
-
-(org-link-set-parameters "doi" :follow #'org-link--open-doi)
-
 ;;;; "elisp" link type
 (defun org-link--open-elisp (path _)
   "Open a \"elisp\" type link.
@@ -1335,11 +1340,27 @@ PATH is the sexp to evaluate, as a string."
   "Open a \"help\" type link.
 PATH is a symbol name, as a string."
   (pcase (intern path)
-    ((and (pred fboundp) variable) (describe-function variable))
-    ((and (pred boundp) function) (describe-variable function))
+    ((and (pred fboundp) function) (describe-function function))
+    ((and (pred boundp) variable) (describe-variable variable))
     (name (user-error "Unknown function or variable: %s" name))))
 
-(org-link-set-parameters "help" :follow #'org-link--open-help)
+(defun org-link--store-help ()
+  "Store \"help\" type link."
+  (when (eq major-mode 'help-mode)
+    (let ((symbol
+           (save-excursion
+            (goto-char (point-min))
+             ;; In case the help is about the key-binding, store the
+             ;; function instead.
+             (search-forward "runs the command " (line-end-position) t)
+             (read (current-buffer)))))
+      (org-link-store-props :type "help"
+                            :link (format "help:%s" symbol)
+                            :description nil))))
+
+(org-link-set-parameters "help"
+                         :follow #'org-link--open-help
+                         :store #'org-link--store-help)
 
 ;;;; "http", "https", "mailto", "ftp", and "news" link types
 (dolist (scheme '("ftp" "http" "https" "mailto" "news"))
@@ -1491,14 +1512,17 @@ non-nil."
                  (apply #'org-link-store-props
                         (cdr (assoc-string
                               (completing-read
-                               "Which function for creating the link? "
-                               (mapcar #'car results-alist)
-                               nil t (symbol-name name))
+                                (format "Store link with (default %s): " name)
+                                (mapcar #'car results-alist)
+                                nil t nil nil (symbol-name name))
                               results-alist)))
                  t))))
        (setq link (plist-get org-store-link-plist :link))
-       (setq desc (or (plist-get org-store-link-plist :description)
-                      link)))
+        ;; If store function actually set `:description' property, use
+        ;; it, even if it is nil.  Otherwise, fallback to link value.
+       (setq desc (if (plist-member org-store-link-plist :description)
+                       (plist-get org-store-link-plist :description)
+                    link)))
 
        ;; Store a link from a remote editing buffer.
        ((org-src-edit-buffer-p)
@@ -1556,19 +1580,6 @@ non-nil."
                              nil nil nil))))
          (org-link-store-props :type "calendar" :date cd)))
 
-       ((eq major-mode 'help-mode)
-       (let ((symbol (replace-regexp-in-string
-                      ;; Help mode escapes backquotes and backslashes
-                      ;; before displaying them.  E.g., "`" appears
-                      ;; as "\'" for reasons.  Work around this.
-                      (rx "\\" (group (or "`" "\\"))) "\\1"
-                      (save-excursion
-                        (goto-char (point-min))
-                        (looking-at "^[^ ]+")
-                        (match-string 0)))))
-         (setq link (concat "help:" symbol)))
-       (org-link-store-props :type "help"))
-
        ((eq major-mode 'w3-mode)
        (setq cpltxt (if (and (buffer-name)
                              (not (string-match "Untitled" (buffer-name))))
@@ -1602,9 +1613,8 @@ non-nil."
 
        ((and (buffer-file-name (buffer-base-buffer)) (derived-mode-p 
'org-mode))
        (org-with-limited-levels
-        (setq custom-id (org-entry-get nil "CUSTOM_ID"))
-        (cond
-         ;; Store a link using the target at point
+         (cond
+         ;; Store a link using the target at point.
          ((org-in-regexp "[^<]<<\\([^<>]+\\)>>[^>]" 1)
           (setq cpltxt
                 (concat "file:"
@@ -1612,6 +1622,15 @@ non-nil."
                          (buffer-file-name (buffer-base-buffer)))
                         "::" (match-string 1))
                 link cpltxt))
+          ;; Store a link using the CUSTOM_ID property.
+          ((setq custom-id (org-entry-get nil "CUSTOM_ID"))
+           (setq cpltxt
+                (concat "file:"
+                        (abbreviate-file-name
+                         (buffer-file-name (buffer-base-buffer)))
+                        "::#" custom-id)
+                link cpltxt))
+          ;; Store a link using (and perhaps creating) the ID property.
          ((and (featurep 'org-id)
                (or (eq org-id-link-to-org-use-id t)
                    (and interactive?
@@ -1620,14 +1639,13 @@ non-nil."
                                      'create-if-interactive-and-no-custom-id)
                                  (not custom-id))))
                    (and org-id-link-to-org-use-id (org-entry-get nil "ID"))))
-          ;; Store a link using the ID at point
           (setq link (condition-case nil
                          (prog1 (org-id-store-link)
                            (setq desc (or (plist-get org-store-link-plist
                                                      :description)
                                           "")))
                        (error
-                        ;; Probably before first headline, link only to file
+                        ;; Probably before first headline, link only to file.
                         (concat "file:"
                                 (abbreviate-file-name
                                  (buffer-file-name (buffer-base-buffer))))))))
@@ -1696,7 +1714,7 @@ non-nil."
       (if (not (and interactive? link))
          (or agenda-link (and link (org-link-make-string link desc)))
        (if (member (list link desc) org-stored-links)
-           (message "This link already exists")
+           (message "This link has already been stored")
          (push (list link desc) org-stored-links)
          (message "Stored: %s" (or desc link))
          (when custom-id
@@ -1791,12 +1809,13 @@ Use TAB to complete link prefixes, then RET for 
type-specific completion support
                             (reverse org-stored-links)
                             "\n")))
        (goto-char (point-min)))
-      (let ((cw (selected-window)))
-       (select-window (get-buffer-window "*Org Links*" 'visible))
-       (with-current-buffer "*Org Links*" (setq truncate-lines t))
-       (unless (pos-visible-in-window-p (point-max))
-         (org-fit-window-to-buffer))
-       (and (window-live-p cw) (select-window cw)))
+      (when (get-buffer-window "*Org Links*" 'visible)
+        (let ((cw (selected-window)))
+         (select-window (get-buffer-window "*Org Links*" 'visible))
+         (with-current-buffer "*Org Links*" (setq truncate-lines t))
+         (unless (pos-visible-in-window-p (point-max))
+           (org-fit-window-to-buffer))
+         (and (window-live-p cw) (select-window cw))))
       (setq all-prefixes (append (mapcar #'car abbrevs)
                                 (mapcar #'car org-link-abbrev-alist)
                                 (org-link-types)))
@@ -1877,6 +1896,9 @@ Use TAB to complete link prefixes, then RET for 
type-specific completion support
            (setq path (expand-file-name path)))
           ((eq org-link-file-path-type 'relative)
            (setq path (file-relative-name path)))
+          ((functionp org-link-file-path-type)
+           (setq path (funcall org-link-file-path-type
+                               (expand-file-name path))))
           (t
            (save-match-data
              (if (string-match (concat "^" (regexp-quote
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index 23c62809a2..354f408679 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -1,8 +1,8 @@
-;;; org-agenda.el --- Dynamic task and appointment lists for Org
+;;; org-agenda.el --- Dynamic task and appointment lists for Org  -*- 
lexical-binding: t; -*-
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -99,8 +99,8 @@
 (defvar org-agenda-buffer-name "*Org Agenda*")
 (defvar org-agenda-overriding-header nil)
 (defvar org-agenda-title-append nil)
-(with-no-warnings (defvar entry)) ;; unprefixed, from calendar.el
-(with-no-warnings (defvar date))  ;; unprefixed, from calendar.el
+;; (with-no-warnings (defvar entry)) ;; unprefixed, from calendar.el
+;; (with-no-warnings (defvar date))  ;; unprefixed, from calendar.el
 (defvar original-date) ; dynamically scoped, calendar.el does scope this
 
 (defvar org-agenda-undo-list nil
@@ -148,6 +148,8 @@ addresses the separator between the current and the 
previous block."
   :type 'boolean)
 
 (defcustom org-agenda-exporter-settings nil
+  ;; FIXME: Do we really want to evaluate those settings and thus force
+  ;; the user to use `quote' all the time?
   "Alist of variable/value pairs that should be active during agenda export.
 This is a good place to set options for ps-print and for htmlize.
 Note that the way this is implemented, the values will be evaluated
@@ -1188,11 +1190,11 @@ This function makes sure that dates are aligned for 
easy reading."
         (year (nth 2 date))
         (iso-week (org-days-to-iso-week
                    (calendar-absolute-from-gregorian date)))
-        (weekyear (cond ((and (= month 1) (>= iso-week 52))
-                         (1- year))
-                        ((and (= month 12) (<= iso-week 1))
-                         (1+ year))
-                        (t year)))
+        ;; (weekyear (cond ((and (= month 1) (>= iso-week 52))
+        ;;               (1- year))
+        ;;              ((and (= month 12) (<= iso-week 1))
+        ;;               (1+ year))
+        ;;              (t year)))
         (weekstring (if (= day-of-week 1)
                         (format " W%02d" iso-week)
                       "")))
@@ -1230,7 +1232,8 @@ For example, 9:30am would become 09:30 rather than  9:30."
      ":" minute ampm)))
 
 (defun org-agenda-time-of-day-to-ampm-maybe (time)
-  "Conditionally convert TIME to AM/PM format based on 
`org-agenda-timegrid-use-ampm'."
+  "Conditionally convert TIME to AM/PM format.
+This is based on `org-agenda-timegrid-use-ampm'."
   (if org-agenda-timegrid-use-ampm
       (org-agenda-time-of-day-to-ampm time)
     time))
@@ -2080,9 +2083,25 @@ For example, this value makes those two functions 
available:
 
 With selected entries in an agenda buffer, `B R' will call
 the custom function `set-category' on the selected entries.
-Note that functions in this alist don't need to be quoted."
-  :type '(alist :key-type character :value-type (group function))
-  :version "24.1"
+Note that functions in this alist don't need to be quoted.
+
+You can also specify a function which collects arguments to be
+used for each call to your bulk custom function.  The argument
+collecting function will be run once and should return a list of
+arguments to pass to the bulk function.  For example:
+
+  \\='((?R set-category get-category))
+
+Now, `B R' will call the custom `get-category' which would prompt
+the user once for a category.  That category is then passed as an
+argument to `set-category' for each entry it's called against."
+  :type
+  '(alist :key-type character
+         :value-type
+          (group (function :tag "Bulk Custom Function")
+                (choice (function :tag "Bulk Custom Argument Function")
+                        (const :tag "No Bulk Custom Argument Function" nil))))
+  :package-version '(Org . "9.5")
   :group 'org-agenda)
 
 (defmacro org-agenda-with-point-at-orig-entry (string &rest body)
@@ -2113,7 +2132,8 @@ works you probably want to add it to 
`org-agenda-custom-commands' for good."
 The inserted header depends on `org-agenda-overriding-header'.
 If the empty string, don't insert a header.  If any other string,
 insert it as a header.  If nil, insert DEFAULT, which should
-evaluate to a string."
+evaluate to a string.  If a function, call it and insert the
+string that it returns."
   (declare (debug (form)) (indent defun))
   `(cond
     ((not org-agenda-overriding-header) (insert ,default))
@@ -2122,6 +2142,8 @@ evaluate to a string."
      (insert (propertize org-agenda-overriding-header
                         'face 'org-agenda-structure)
             "\n"))
+    ((functionp org-agenda-overriding-header)
+     (insert (funcall org-agenda-overriding-header)))
     (t (user-error "Invalid value for `org-agenda-overriding-header': %S"
                   org-agenda-overriding-header))))
 
@@ -2238,26 +2260,26 @@ The following commands are available:
        (save (buffer-local-variables)))
     (kill-all-local-variables)
     (cl-flet ((reset-saved (var-set)
-                          "Reset variables in VAR-SET to possibly stored value 
in SAVE."
-                          (dolist (elem save)
-                            (pcase elem
-                              (`(,var . ,val)          ;ignore unbound 
variables
-                               (when (and val (memq var var-set))
-                                 (set var val)))))))
+               "Reset variables in VAR-SET to possibly stored value in SAVE."
+               (dolist (elem save)
+                 (pcase elem
+                   (`(,var . ,val)             ;ignore unbound variables
+                    (when (and val (memq var var-set))
+                      (set var val)))))))
       (cond (org-agenda-doing-sticky-redo
-            ;; Refreshing sticky agenda-buffer
-            ;;
-            ;; Preserve the value of `org-agenda-local-vars' variables.
-            (mapc #'make-local-variable org-agenda-local-vars)
-            (reset-saved org-agenda-local-vars)
-            (setq-local org-agenda-this-buffer-is-sticky t))
+             ;; Refreshing sticky agenda-buffer
+             ;;
+             ;; Preserve the value of `org-agenda-local-vars' variables.
+             (mapc #'make-local-variable org-agenda-local-vars)
+             (reset-saved org-agenda-local-vars)
+             (setq-local org-agenda-this-buffer-is-sticky t))
            (org-agenda-sticky
-            ;; Creating a sticky Agenda buffer for the first time
-            (mapc 'make-local-variable org-agenda-local-vars)
-            (setq-local org-agenda-this-buffer-is-sticky t))
+             ;; Creating a sticky Agenda buffer for the first time
+             (mapc #'make-local-variable org-agenda-local-vars)
+             (setq-local org-agenda-this-buffer-is-sticky t))
            (t
-            ;; Creating a non-sticky agenda buffer
-            (setq-local org-agenda-this-buffer-is-sticky nil)))
+             ;; Creating a non-sticky agenda buffer
+             (setq-local org-agenda-this-buffer-is-sticky nil)))
       (mapc #'make-local-variable agenda-local-vars-to-keep)
       (reset-saved agenda-local-vars-to-keep)))
   (setq org-agenda-undo-list nil
@@ -2271,8 +2293,8 @@ The following commands are available:
   (use-local-map org-agenda-mode-map)
   (when org-startup-truncated (setq truncate-lines t))
   (setq-local line-move-visual nil)
-  (add-hook 'post-command-hook 'org-agenda-update-agenda-type nil 'local)
-  (add-hook 'pre-command-hook 'org-unhighlight nil 'local)
+  (add-hook 'post-command-hook #'org-agenda-update-agenda-type nil 'local)
+  (add-hook 'pre-command-hook #'org-unhighlight nil 'local)
   ;; Make sure properties are removed when copying text
   (if (boundp 'filter-buffer-substring-functions)
       (add-hook 'filter-buffer-substring-functions
@@ -2300,11 +2322,9 @@ The following commands are available:
       '(org-edit-agenda-file-list)
       (not (get 'org-agenda-files 'org-restrict)))
      "--")
-    (mapcar 'org-file-menu-entry (org-agenda-files))))
+    (mapcar #'org-file-menu-entry (org-agenda-files))))
   (org-agenda-set-mode-name)
-  (apply
-   (if (fboundp 'run-mode-hooks) 'run-mode-hooks 'run-hooks)
-   (list 'org-agenda-mode-hook)))
+  (run-mode-hooks 'org-agenda-mode-hook))
 
 (substitute-key-definition #'undo #'org-agenda-undo
                           org-agenda-mode-map global-map)
@@ -2452,7 +2472,7 @@ The following commands are available:
 (when org-agenda-mouse-1-follows-link
   (org-defkey org-agenda-mode-map [follow-link] 'mouse-face))
 
-(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu"
+(easy-menu-define org-agenda-menu org-agenda-mode-map "Agenda menu."
   '("Agenda"
     ("Agenda Files")
     "--"
@@ -2644,7 +2664,7 @@ that have been changed along."
       (while (bufferp (setq buf (pop entry)))
        (when (pop entry)
          (with-current-buffer buf
-           (let ((last-undo-buffer buf)
+           (let (;; (last-undo-buffer buf)
                   (inhibit-read-only t))
              (unless (memq buf org-agenda-undo-has-started-in)
                (push buf org-agenda-undo-has-started-in)
@@ -2796,7 +2816,7 @@ to limit entries to in this type."
 (defvar org-keys nil)
 (defvar org-match nil)
 ;;;###autoload
-(defun org-agenda (&optional arg org-keys restriction)
+(defun org-agenda (&optional arg keys restriction)
   "Dispatch agenda commands to collect entries to the agenda buffer.
 Prompts for a command to execute.  Any prefix arg will be passed
 on to the selected command.  The default selections are:
@@ -2831,7 +2851,8 @@ Pressing `<' twice means to restrict to the current 
subtree or region
 \(if active)."
   (interactive "P")
   (catch 'exit
-    (let* ((prefix-descriptions nil)
+    (let* ((org-keys keys)
+          (prefix-descriptions nil)
           (org-agenda-buffer-name org-agenda-buffer-name)
           (org-agenda-window-setup (if (equal (buffer-name)
                                               org-agenda-buffer-name)
@@ -2853,9 +2874,9 @@ Pressing `<' twice means to restrict to the current 
subtree or region
           (org-agenda-custom-commands
            (org-contextualize-keys
             org-agenda-custom-commands org-agenda-custom-commands-contexts))
-          (buf (current-buffer))
+          ;; (buf (current-buffer))
           (bfn (buffer-file-name (buffer-base-buffer)))
-          entry key type org-match lprops ans)
+          entry type org-match lprops ans) ;; key
       ;; Turn off restriction unless there is an overriding one,
       (unless org-agenda-overriding-restriction
        (unless org-agenda-keep-restricted-file-list
@@ -2907,47 +2928,51 @@ Pressing `<' twice means to restrict to the current 
subtree or region
        ((setq entry (assoc org-keys org-agenda-custom-commands))
        (if (or (symbolp (nth 2 entry)) (functionp (nth 2 entry)))
            (progn
-             (setq type (nth 2 entry) org-match (eval (nth 3 entry))
+             ;; FIXME: Is (nth 3 entry) supposed to have access (via dynvars)
+              ;; to some of the local variables?  There's no doc about
+              ;; that for `org-agenda-custom-commands'.
+             (setq type (nth 2 entry) org-match (eval (nth 3 entry) t)
                    lprops (nth 4 entry))
              (when org-agenda-sticky
                (setq org-agenda-buffer-name
                      (or (and (stringp org-match) (format "*Org 
Agenda(%s:%s)*" org-keys org-match))
                          (format "*Org Agenda(%s)*" org-keys))))
              (put 'org-agenda-redo-command 'org-lprops lprops)
-             (cond
-              ((eq type 'agenda)
-               (org-let lprops '(org-agenda-list current-prefix-arg)))
-              ((eq type 'agenda*)
-               (org-let lprops '(org-agenda-list current-prefix-arg nil nil 
t)))
-              ((eq type 'alltodo)
-               (org-let lprops '(org-todo-list current-prefix-arg)))
-              ((eq type 'search)
-               (org-let lprops '(org-search-view current-prefix-arg org-match 
nil)))
-              ((eq type 'stuck)
-               (org-let lprops '(org-agenda-list-stuck-projects
-                                 current-prefix-arg)))
-              ((eq type 'tags)
-               (org-let lprops '(org-tags-view current-prefix-arg org-match)))
-              ((eq type 'tags-todo)
-               (org-let lprops '(org-tags-view '(4) org-match)))
-              ((eq type 'todo)
-               (org-let lprops '(org-todo-list org-match)))
-              ((eq type 'tags-tree)
-               (org-check-for-org-mode)
-               (org-let lprops '(org-match-sparse-tree current-prefix-arg 
org-match)))
-              ((eq type 'todo-tree)
-               (org-check-for-org-mode)
-               (org-let lprops
-                 '(org-occur (concat "^" org-outline-regexp "[ \t]*"
-                                     (regexp-quote org-match) "\\>"))))
-              ((eq type 'occur-tree)
-               (org-check-for-org-mode)
-               (org-let lprops '(org-occur org-match)))
-              ((functionp type)
-               (org-let lprops '(funcall type org-match)))
-              ((fboundp type)
-               (org-let lprops '(funcall type org-match)))
-              (t (user-error "Invalid custom agenda command type %s" type))))
+             (cl-progv
+                 (mapcar #'car lprops)
+                 (mapcar (lambda (binding) (eval (cadr binding) t)) lprops)
+               (pcase type
+                 (`agenda
+                  (org-agenda-list current-prefix-arg))
+                 (`agenda*
+                  (org-agenda-list current-prefix-arg nil nil t))
+                 (`alltodo
+                  (org-todo-list current-prefix-arg))
+                 (`search
+                  (org-search-view current-prefix-arg org-match nil))
+                 (`stuck
+                  (org-agenda-list-stuck-projects current-prefix-arg))
+                 (`tags
+                  (org-tags-view current-prefix-arg org-match))
+                 (`tags-todo
+                  (org-tags-view '(4) org-match))
+                 (`todo
+                  (org-todo-list org-match))
+                 (`tags-tree
+                  (org-check-for-org-mode)
+                  (org-match-sparse-tree current-prefix-arg org-match))
+                 (`todo-tree
+                  (org-check-for-org-mode)
+                  (org-occur (concat "^" org-outline-regexp "[ \t]*"
+                                     (regexp-quote org-match) "\\>")))
+                 (`occur-tree
+                  (org-check-for-org-mode)
+                  (org-occur org-match))
+                 ((pred functionp)
+                  (funcall type org-match))
+                 ;; FIXME: Will signal an error since it's not `functionp'!
+                 ((pred fboundp) (funcall type org-match))
+                 (_ (user-error "Invalid custom agenda command type %s" 
type)))))
          (org-agenda-run-series (nth 1 entry) (cddr entry))))
        ((equal org-keys "C")
        (setq org-agenda-custom-commands org-agenda-custom-commands-orig)
@@ -3226,70 +3251,79 @@ s   Search for keywords                 M   Like m, but 
only TODO entries
 (defvar org-agenda-overriding-cmd-arguments nil)
 
 (defun org-let (list &rest body) ;FIXME: So many kittens are suffering here.
-  (declare (indent 1))
+  (declare (indent 1) (obsolete cl-progv "2021"))
   (eval (cons 'let (cons list body))))
 
 (defun org-let2 (list1 list2 &rest body) ;FIXME: Where did our karma go?
-  (declare (indent 2))
+  (declare (indent 2) (obsolete cl-progv "2021"))
   (eval (cons 'let (cons list1 (list (cons 'let (cons list2 body)))))))
 
 (defun org-agenda-run-series (name series)
   "Run agenda NAME as a SERIES of agenda commands."
-  (org-let (nth 1 series) '(org-agenda-prepare name))
-  ;; We need to reset agenda markers here, because when constructing a
-  ;; block agenda, the individual blocks do not do that.
-  (org-agenda-reset-markers)
-  (let* ((org-agenda-multi t)
-        (redo (list 'org-agenda-run-series name (list 'quote series)))
-        (cmds (car series))
-        (gprops (nth 1 series))
-        match ;; The byte compiler incorrectly complains about this.  Keep it!
-        org-cmd type lprops)
-    (while (setq org-cmd (pop cmds))
-      (setq type (car org-cmd))
-      (setq match (eval (nth 1 org-cmd)))
-      (setq lprops (nth 2 org-cmd))
-      (let ((org-agenda-overriding-arguments
-            (if (eq org-agenda-overriding-cmd org-cmd)
-                (or org-agenda-overriding-arguments
-                    org-agenda-overriding-cmd-arguments))))
-       (cond
-        ((eq type 'agenda)
-         (org-let2 gprops lprops
-           '(call-interactively 'org-agenda-list)))
-        ((eq type 'agenda*)
-         (org-let2 gprops lprops
-           '(funcall 'org-agenda-list nil nil t)))
-        ((eq type 'alltodo)
-         (org-let2 gprops lprops
-           '(call-interactively 'org-todo-list)))
-        ((eq type 'search)
-         (org-let2 gprops lprops
-           '(org-search-view current-prefix-arg match nil)))
-        ((eq type 'stuck)
-         (org-let2 gprops lprops
-           '(call-interactively 'org-agenda-list-stuck-projects)))
-        ((eq type 'tags)
-         (org-let2 gprops lprops
-           '(org-tags-view current-prefix-arg match)))
-        ((eq type 'tags-todo)
-         (org-let2 gprops lprops
-           '(org-tags-view '(4) match)))
-        ((eq type 'todo)
-         (org-let2 gprops lprops
-           '(org-todo-list match)))
-        ((fboundp type)
-         (org-let2 gprops lprops
-           '(funcall type match)))
-        (t (error "Invalid type in command series")))))
-    (widen)
-    (let ((inhibit-read-only t))
-      (add-text-properties (point-min) (point-max)
-                          `(org-series t org-series-redo-cmd ,redo)))
-    (setq org-agenda-redo-command redo)
-    (goto-char (point-min)))
-  (org-agenda-fit-window-to-buffer)
-  (org-let (nth 1 series) '(org-agenda-finalize)))
+  (let* ((gprops (nth 1 series))
+         (gvars (mapcar #'car gprops))
+         (gvals (mapcar (lambda (binding) (eval (cadr binding) t)) gprops)))
+    (cl-progv gvars gvals (org-agenda-prepare name))
+    ;; We need to reset agenda markers here, because when constructing a
+    ;; block agenda, the individual blocks do not do that.
+    (org-agenda-reset-markers)
+    (with-no-warnings
+      (defvar match))          ;Used via the `eval' below.
+    (let* ((org-agenda-multi t)
+          ;; FIXME: Redo should contain lists of (FUNS . ARGS) rather
+           ;; than expressions, so you don't need to `quote' the args
+           ;; and you just need to `apply' instead of `eval' when using it.
+          (redo (list 'org-agenda-run-series name (list 'quote series)))
+          (cmds (car series))
+          match
+          org-cmd type lprops)
+      (while (setq org-cmd (pop cmds))
+        (setq type (car org-cmd))
+        (setq match (eval (nth 1 org-cmd) t))
+        (setq lprops (nth 2 org-cmd))
+        (let ((org-agenda-overriding-arguments
+              (if (eq org-agenda-overriding-cmd org-cmd)
+                  (or org-agenda-overriding-arguments
+                      org-agenda-overriding-cmd-arguments)))
+              (lvars (mapcar #'car lprops))
+              (lvals (mapcar (lambda (binding) (eval (cadr binding) t)) 
lprops)))
+          (cl-progv (append gvars lvars) (append gvals lvals)
+           (pcase type
+             (`agenda
+              (call-interactively 'org-agenda-list))
+             (`agenda*
+              (funcall 'org-agenda-list nil nil t))
+             (`alltodo
+              (call-interactively 'org-todo-list))
+             (`search
+              (org-search-view current-prefix-arg match nil))
+             (`stuck
+              (call-interactively 'org-agenda-list-stuck-projects))
+             (`tags
+              (org-tags-view current-prefix-arg match))
+             (`tags-todo
+              (org-tags-view '(4) match))
+             (`todo
+              (org-todo-list match))
+             ((pred fboundp)
+              (funcall type match))
+             (_ (error "Invalid type in command series"))))))
+      (widen)
+      (let ((inhibit-read-only t))
+       (add-text-properties (point-min) (point-max)
+                            `(org-series t org-series-redo-cmd ,redo)))
+      (setq org-agenda-redo-command redo)
+      (goto-char (point-min)))
+    (org-agenda-fit-window-to-buffer)
+    (cl-progv gvars gvals (org-agenda-finalize))))
+
+(defun org-agenda--split-plist (plist)
+  ;; We could/should arguably use `map-keys' and `map-values'.
+  (let (keys vals)
+    (while plist
+      (push (pop plist) keys)
+      (push (pop plist) vals))
+    (cons (nreverse keys) (nreverse vals))))
 
 ;;;###autoload
 (defmacro org-batch-agenda (cmd-key &rest parameters)
@@ -3299,7 +3333,13 @@ If CMD-KEY is a string of length 1, it is used as a key 
in
 longer string it is used as a tags/todo match string.
 Parameters are alternating variable names and values that will be bound
 before running the agenda command."
-  (org-eval-in-environment (org-make-parameter-alist parameters)
+  (pcase-let ((`(,vars . ,exps) (org-agenda--split-plist parameters)))
+    `(org--batch-agenda ,cmd-key ',vars (list ,@exps))))
+
+(defun org--batch-agenda (cmd-key vars vals)
+  ;; `org-batch-agenda' is a macro because every other "parameter" is
+  ;; a variable name rather than an expression to evaluate.  Yuck!
+  (cl-progv vars vals
     (let (org-agenda-sticky)
       (if (> (length cmd-key) 1)
          (org-tags-view nil cmd-key)
@@ -3344,11 +3384,18 @@ extra        String with extra planning info
 priority-l   The priority letter if any was given
 priority-n   The computed numerical priority
 agenda-day   The day in the agenda where this is listed"
-  (org-eval-in-environment (append '((org-agenda-remove-tags t))
-                                  (org-make-parameter-alist parameters))
-    (if (> (length cmd-key) 2)
-       (org-tags-view nil cmd-key)
-      (org-agenda nil cmd-key)))
+  (pcase-let ((`(,vars . ,exps) (org-agenda--split-plist parameters)))
+    `(org--batch-agenda-csv ,cmd-key ',vars (list ,@exps))))
+
+(defun org--batch-agenda-csv (cmd-key vars vals)
+  ;; `org-batch-agenda-csv' is a macro because every other "parameter" is
+  ;; a variable name rather than an expression to evaluate.  Yuck!
+  (let ((org-agenda-remove-tags t))
+    (cl-progv vars vals
+      ;; FIXME: Shouldn't this be 1 (see commit 10173ad6d610b)?
+      (if (> (length cmd-key) 2)
+         (org-tags-view nil cmd-key)
+       (org-agenda nil cmd-key))))
   (set-buffer org-agenda-buffer-name)
   (let ((lines (org-split-string (buffer-string) "\n")))
     (dolist (line lines)
@@ -3356,9 +3403,9 @@ agenda-day   The day in the agenda where this is listed"
        (setq org-agenda-info
              (org-fix-agenda-info (text-properties-at 0 line)))
        (princ
-        (mapconcat 'org-agenda-export-csv-mapper
+        (mapconcat #'org-agenda-export-csv-mapper
                    '(org-category txt type todo tags date time extra
-                                  priority-letter priority agenda-day)
+                                  priority-letter priority agenda-day)
                    ","))
        (princ "\n")))))
 
@@ -3367,7 +3414,7 @@ agenda-day   The day in the agenda where this is listed"
 This ensures the export commands can easily use it."
   (let (tmp re)
     (when (setq tmp (plist-get props 'tags))
-      (setq props (plist-put props 'tags (mapconcat 'identity tmp ":"))))
+      (setq props (plist-put props 'tags (mapconcat #'identity tmp ":"))))
     (when (setq tmp (plist-get props 'date))
       (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp)))
       (let ((calendar-date-display-form '(year "-" month "-" day)))
@@ -3403,19 +3450,22 @@ This ensures the export commands can easily use it."
     (org-trim (replace-regexp-in-string "," ";" res nil t))))
 
 ;;;###autoload
-(defun org-store-agenda-views (&rest parameters)
+(defun org-store-agenda-views (&rest _parameters)
   "Store agenda views."
   (interactive)
-  (eval (list 'org-batch-store-agenda-views)))
+  (org--batch-store-agenda-views nil nil))
 
 ;;;###autoload
 (defmacro org-batch-store-agenda-views (&rest parameters)
   "Run all custom agenda commands that have a file argument."
+  (pcase-let ((`(,vars . ,exps) (org-agenda--split-plist parameters)))
+    `(org--batch-store-agenda-views ',vars (list ,@exps))))
+
+(defun org--batch-store-agenda-views (vars vals)
   (let ((cmds (org-agenda-normalize-custom-commands 
org-agenda-custom-commands))
-       (pop-up-frames nil)
-       (dir default-directory)
-       (pars (org-make-parameter-alist parameters))
-       cmd thiscmdkey thiscmdcmd match files opts cmd-or-set bufname)
+        (pop-up-frames nil)
+        (dir default-directory)
+        cmd thiscmdkey thiscmdcmd match files opts cmd-or-set bufname)
     (save-window-excursion
       (while cmds
        (setq cmd (pop cmds)
@@ -3432,14 +3482,18 @@ This ensures the export commands can easily use it."
              files (nth (if (listp cmd-or-set) 4 5) cmd))
        (if (stringp files) (setq files (list files)))
        (when files
-         (org-eval-in-environment (append org-agenda-exporter-settings
-                                          opts pars)
-           (org-agenda nil thiscmdkey))
-         (set-buffer bufname)
-         (while files
-           (org-eval-in-environment (append org-agenda-exporter-settings
-                                            opts pars)
-             (org-agenda-write (expand-file-name (pop files) dir) nil t 
bufname)))
+         (let* ((opts (append org-agenda-exporter-settings opts))
+                (vars (append (mapcar #'car opts) vars))
+                (vals (append (mapcar (lambda (binding) (eval (cadr binding) 
t))
+                                      opts)
+                              vals)))
+           (cl-progv vars vals
+             (org-agenda nil thiscmdkey))
+           (set-buffer bufname)
+           (while files
+             (cl-progv vars vals
+               (org-agenda-write (expand-file-name (pop files) dir)
+                                 nil t bufname))))
          (and (get-buffer bufname)
               (kill-buffer bufname)))))))
 
@@ -3479,80 +3533,87 @@ the agenda to write."
               (if (called-interactively-p 'any)
                   (not (y-or-n-p (format "Overwrite existing file %s? " 
file))))))
       (user-error "Cannot write agenda to file %s" file))
-  (org-let (if nosettings nil org-agenda-exporter-settings)
-    '(save-excursion
-       (save-window-excursion
-        (let ((bs (copy-sequence (buffer-string)))
-              (extension (file-name-extension file))
-              (default-directory (file-name-directory file))
-              beg content)
-          (with-temp-buffer
-            (rename-buffer org-agenda-write-buffer-name t)
-            (set-buffer-modified-p nil)
-            (insert bs)
-            (org-agenda-remove-marked-text 'invisible 'org-filtered)
-            (run-hooks 'org-agenda-before-write-hook)
-            (cond
-             ((bound-and-true-p org-mobile-creating-agendas)
-              (org-mobile-write-agenda-for-mobile file))
-             ((string= "org" extension)
-              (let (content p m message-log-max)
-                (goto-char (point-min))
-                (while (setq p (next-single-property-change (point) 
'org-hd-marker nil))
-                  (goto-char p)
-                  (setq m (get-text-property (point) 'org-hd-marker))
-                  (when m
-                    (push (save-excursion
-                            (set-buffer (marker-buffer m))
-                            (goto-char m)
-                            (org-copy-subtree 1 nil t t)
-                            org-subtree-clip)
-                          content)))
-                (find-file file)
-                (erase-buffer)
-                (dolist (s content) (org-paste-subtree 1 s))
-                (write-file file)
-                (kill-buffer (current-buffer))
-                (message "Org file written to %s" file)))
-             ((member extension '("html" "htm"))
-              (or (require 'htmlize nil t)
-                  (error "Please install htmlize from 
https://github.com/hniksic/emacs-htmlize";))
-              (set-buffer (htmlize-buffer (current-buffer)))
-              (when org-agenda-export-html-style
-                ;; replace <style> section with org-agenda-export-html-style
-                (goto-char (point-min))
-                (kill-region (- (search-forward "<style") 6)
-                             (search-forward "</style>"))
-                (insert org-agenda-export-html-style))
-              (write-file file)
-              (kill-buffer (current-buffer))
-              (message "HTML written to %s" file))
-             ((string= "ps" extension)
-              (require 'ps-print)
-              (ps-print-buffer-with-faces file)
-              (message "Postscript written to %s" file))
-             ((string= "pdf" extension)
-              (require 'ps-print)
-              (ps-print-buffer-with-faces
-               (concat (file-name-sans-extension file) ".ps"))
-              (call-process "ps2pdf" nil nil nil
-                            (expand-file-name
-                             (concat (file-name-sans-extension file) ".ps"))
-                            (expand-file-name file))
-              (delete-file (concat (file-name-sans-extension file) ".ps"))
-              (message "PDF written to %s" file))
-             ((string= "ics" extension)
-              (require 'ox-icalendar)
-              (org-icalendar-export-current-agenda (expand-file-name file)))
-             (t
-              (let ((bs (buffer-string)))
-                (find-file file)
-                (erase-buffer)
-                (insert bs)
-                (save-buffer 0)
-                (kill-buffer (current-buffer))
-                (message "Plain text written to %s" file))))))))
+  (cl-progv
+      (if nosettings nil (mapcar #'car org-agenda-exporter-settings))
+      (if nosettings nil (mapcar (lambda (binding) (eval (cadr binding) t))
+                                 org-agenda-exporter-settings))
+    (save-excursion
+      (save-window-excursion
+       (let ((bs (copy-sequence (buffer-string)))
+             (extension (file-name-extension file))
+             (default-directory (file-name-directory file))
+             ) ;; beg content
+         (with-temp-buffer
+           (rename-buffer org-agenda-write-buffer-name t)
+           (set-buffer-modified-p nil)
+           (insert bs)
+           (org-agenda-remove-marked-text 'invisible 'org-filtered)
+           (run-hooks 'org-agenda-before-write-hook)
+           (cond
+            ((bound-and-true-p org-mobile-creating-agendas)
+             (org-mobile-write-agenda-for-mobile file))
+            ((string= "org" extension)
+             (let (content p m message-log-max)
+               (goto-char (point-min))
+               (while (setq p (next-single-property-change (point) 
'org-hd-marker nil))
+                 (goto-char p)
+                 (setq m (get-text-property (point) 'org-hd-marker))
+                 (when m
+                   (push (with-current-buffer (marker-buffer m)
+                           (goto-char m)
+                           (org-copy-subtree 1 nil t t)
+                           org-subtree-clip)
+                         content)))
+               (find-file file)
+               (erase-buffer)
+               (dolist (s content) (org-paste-subtree 1 s))
+               (write-file file)
+               (kill-buffer (current-buffer))
+               (message "Org file written to %s" file)))
+            ((member extension '("html" "htm"))
+             (or (require 'htmlize nil t)
+                 (error "Please install htmlize from 
https://github.com/hniksic/emacs-htmlize";))
+             (declare-function htmlize-buffer "htmlize" (&optional buffer))
+             (set-buffer (htmlize-buffer (current-buffer)))
+             (when org-agenda-export-html-style
+               ;; replace <style> section with org-agenda-export-html-style
+               (goto-char (point-min))
+               (kill-region (- (search-forward "<style") 6)
+                            (search-forward "</style>"))
+               (insert org-agenda-export-html-style))
+             (write-file file)
+             (kill-buffer (current-buffer))
+             (message "HTML written to %s" file))
+            ((string= "ps" extension)
+             (require 'ps-print)
+             (ps-print-buffer-with-faces file)
+             (message "Postscript written to %s" file))
+            ((string= "pdf" extension)
+             (require 'ps-print)
+             (ps-print-buffer-with-faces
+              (concat (file-name-sans-extension file) ".ps"))
+             (call-process "ps2pdf" nil nil nil
+                           (expand-file-name
+                            (concat (file-name-sans-extension file) ".ps"))
+                           (expand-file-name file))
+             (delete-file (concat (file-name-sans-extension file) ".ps"))
+             (message "PDF written to %s" file))
+            ((string= "ics" extension)
+             (require 'ox-icalendar)
+             (declare-function org-icalendar-export-current-agenda
+                               "ox-icalendar" (file))
+             (org-icalendar-export-current-agenda (expand-file-name file)))
+            (t
+             (let ((bs (buffer-string)))
+               (find-file file)
+               (erase-buffer)
+               (insert bs)
+               (save-buffer 0)
+               (kill-buffer (current-buffer))
+               (message "Plain text written to %s" file))))))))
     (set-buffer (or agenda-bufname
+                   ;; FIXME: I'm pretty sure called-interactively-p
+                    ;; doesn't do what we want here!
                    (and (called-interactively-p 'any) (buffer-name))
                    org-agenda-buffer-name)))
   (when open (org-open-file file)))
@@ -3708,15 +3769,14 @@ the global options and expect it to be applied to the 
entire view.")
     (tag . org-agenda-tag-filter)
     (effort . org-agenda-effort-filter)
     (regexp . org-agenda-regexp-filter))
-  "Alist of filter types and associated variables")
+  "Alist of filter types and associated variables.")
 (defun org-agenda-filter-any ()
   "Is any filter active?"
-  (let ((form (cons 'or (mapcar (lambda (x)
-                                 (if (or (symbol-value (cdr x))
-                                         (get :preset-filter x))
-                                     t nil))
-                               org-agenda-filter-variables))))
-    (eval form)))
+  (cl-some (lambda (x)
+            (or (symbol-value (cdr x))
+                (get :preset-filter x)))
+          org-agenda-filter-variables))
+
 (defvar org-agenda-category-filter-preset nil
   "A preset of the category filter used for secondary agenda filtering.
 This must be a list of strings, each string must be a single category
@@ -3928,7 +3988,7 @@ agenda display, configure `org-agenda-finalize-hook'."
                  (put-text-property (point-at-bol) (point-at-eol)
                                     'tags
                                     (org-with-point-at mrk
-                                      (mapcar #'downcase (org-get-tags)))))))))
+                                      (org-get-tags))))))))
        (setq org-agenda-represented-tags nil
              org-agenda-represented-categories nil)
        (when org-agenda-top-headline-filter
@@ -3954,7 +4014,7 @@ agenda display, configure `org-agenda-finalize-hook'."
        (when (get 'org-agenda-effort-filter :preset-filter)
          (org-agenda-filter-apply
           (get 'org-agenda-effort-filter :preset-filter) 'effort))
-       (add-hook 'kill-buffer-hook 'org-agenda-reset-markers 'append 'local))
+       (add-hook 'kill-buffer-hook #'org-agenda-reset-markers 'append 'local))
       (run-hooks 'org-agenda-finalize-hook))))
 
 (defun org-agenda-mark-clocking-task ()
@@ -4023,10 +4083,10 @@ agenda display, configure `org-agenda-finalize-hook'."
 
 (defvar org-depend-tag-blocked)
 
-(defun org-agenda-dim-blocked-tasks (&optional invisible)
+(defun org-agenda-dim-blocked-tasks (&optional _invisible)
   "Dim currently blocked TODOs in the agenda display.
 When INVISIBLE is non-nil, hide currently blocked TODO instead of
-dimming them."
+dimming them."                   ;FIXME: The arg isn't used, actually!
   (interactive "P")
   (when (called-interactively-p 'interactive)
     (message "Dim or hide blocked tasks..."))
@@ -4051,7 +4111,9 @@ dimming them."
            (overlay-put ov 'face 'org-agenda-dimmed-todo-face))
          (when invisible
            (org-agenda-filter-hide-line 'todo-blocked)))
-       (move-beginning-of-line 2))))
+        (if (= (point-max) (line-end-position))
+            (goto-char (point-max))
+         (move-beginning-of-line 2)))))
   (when (called-interactively-p 'interactive)
     (message "Dim or hide blocked tasks...done")))
 
@@ -4134,7 +4196,7 @@ functions do."
           (save-match-data
             (if fp
                 (funcall form)
-              (eval form)))))))
+              (eval form t)))))))
 
 (defvar org-agenda-markers nil
   "List of all currently active markers created by `org-agenda'.")
@@ -4208,6 +4270,9 @@ This check for agenda markers in all agenda buffers 
currently active."
   "Return the face DATE should be displayed with."
   (cond ((and (functionp org-agenda-day-face-function)
              (funcall org-agenda-day-face-function date)))
+       ((and (org-agenda-today-p date)
+              (memq (calendar-day-of-week date) org-agenda-weekend-days))
+         'org-agenda-date-weekend-today)
        ((org-agenda-today-p date) 'org-agenda-date-today)
        ((memq (calendar-day-of-week date) org-agenda-weekend-days)
         'org-agenda-date-weekend)
@@ -4250,7 +4315,7 @@ items if they have an hour specification like [h]h:mm."
     (setq span arg arg nil))
   (when (numberp span)
     (unless (< 0 span)
-      (user-error "Agenda creation impossible for this span(=%d days)." span)))
+      (user-error "Agenda creation impossible for this span(=%d days)" span)))
   (catch 'exit
     (setq org-agenda-buffer-name
          (org-agenda--get-buffer-name
@@ -4288,11 +4353,11 @@ items if they have an hour specification like [h]h:mm."
           (day-cnt 0)
           (inhibit-redisplay (not debug-on-error))
           (org-agenda-show-log-scoped org-agenda-show-log)
-          s e rtn rtnall file date d start-pos end-pos todayp
-          clocktable-start clocktable-end filter)
+          s rtn rtnall file date d start-pos end-pos todayp ;; e
+          clocktable-start clocktable-end) ;; filter
       (setq org-agenda-redo-command
            (list 'org-agenda-list (list 'quote arg) start-day (list 'quote 
span) with-hour))
-      (dotimes (n (1- ndays))
+      (dotimes (_ (1- ndays))
        (push (1+ (car day-numbers)) day-numbers))
       (setq day-numbers (nreverse day-numbers))
       (setq clocktable-start (car day-numbers)
@@ -4358,11 +4423,11 @@ items if they have an hour specification like [h]h:mm."
                (setq rtn (org-agenda-get-day-entries
                           file date :closed)))
               (org-agenda-show-log-scoped
-               (setq rtn (apply 'org-agenda-get-day-entries
+               (setq rtn (apply #'org-agenda-get-day-entries
                                 file date
                                 (append '(:closed) org-agenda-entry-types))))
               (t
-               (setq rtn (apply 'org-agenda-get-day-entries
+               (setq rtn (apply #'org-agenda-get-day-entries
                                 file date
                                 org-agenda-entry-types)))))
            (setq rtnall (append rtnall rtn)))) ;; all entries
@@ -4402,7 +4467,7 @@ items if they have an hour specification like [h]h:mm."
          (setq p (plist-put p :tstart clocktable-start))
          (setq p (plist-put p :tend clocktable-end))
          (setq p (plist-put p :scope 'agenda))
-         (setq tbl (apply 'org-clock-get-clocktable p))
+         (setq tbl (apply #'org-clock-get-clocktable p))
          (insert tbl)))
       (goto-char (point-min))
       (or org-agenda-multi (org-agenda-fit-window-to-buffer))
@@ -4623,7 +4688,7 @@ is active."
                      (setq re (regexp-quote (downcase w)))))
                  (if neg (push re regexps-) (push re regexps+)))
                words)
-       (push (mapconcat (lambda (w) (regexp-quote w)) words "\\s-+")
+       (push (mapconcat #'regexp-quote words "\\s-+")
              regexps+))
       (setq regexps+ (sort regexps+ (lambda (a b) (> (length a) (length b)))))
       (if (not regexps+)
@@ -4746,7 +4811,7 @@ is active."
                               (list 'face 'org-agenda-structure))
          (setq pos (point))
          (insert string "\n")
-         (add-text-properties pos (1- (point)) (list 'face 'org-warning))
+         (add-text-properties pos (1- (point)) (list 'face 
'org-agenda-structure-filter))
          (setq pos (point))
          (unless org-agenda-multi
            (insert (substitute-command-keys "\\<org-agenda-mode-map>\
@@ -4756,7 +4821,7 @@ Press `\\[org-agenda-manipulate-query-add]', \
 `\\[org-agenda-manipulate-query-subtract-re]' to add/sub regexp, \
 `\\[universal-argument] \\[org-agenda-redo]' for a fresh search\n"))
            (add-text-properties pos (1- (point))
-                                (list 'face 'org-agenda-structure)))
+                                (list 'face 'org-agenda-structure-secondary)))
          (buffer-string)))
       (org-agenda-mark-header-line (point-min))
       (when rtnall
@@ -4777,10 +4842,10 @@ Press `\\[org-agenda-manipulate-query-add]', \
   "Use `org-todo-keyword-faces' for the selected todo KEYWORDS."
   (concat
    (if (or (equal keywords "ALL") (not keywords))
-       (propertize "ALL" 'face 'warning)
+       (propertize "ALL" 'face 'org-agenda-structure-filter)
      (mapconcat
       (lambda (kw)
-        (propertize kw 'face (org-get-todo-face kw)))
+        (propertize kw 'face (list (org-get-todo-face kw) 
'org-agenda-structure)))
       (org-split-string keywords "|")
       "|"))
    "\n"))
@@ -4788,6 +4853,8 @@ Press `\\[org-agenda-manipulate-query-add]', \
 (defvar org-select-this-todo-keyword nil)
 (defvar org-last-arg nil)
 
+(defvar crm-separator)
+
 ;;;###autoload
 (defun org-todo-list (&optional arg)
   "Show all (not done) TODO entries from all agenda file in a single list.
@@ -4863,7 +4930,7 @@ to search again: (0)[ALL]"))
                     (insert "\n                     "))
                   (insert " " s))))
            (insert "\n"))
-         (add-text-properties pos (1- (point)) (list 'face 
'org-agenda-structure))
+         (add-text-properties pos (1- (point)) (list 'face 
'org-agenda-structure-secondary))
          (buffer-string)))
       (org-agenda-mark-header-line (point-min))
       (when rtnall
@@ -4954,7 +5021,7 @@ The prefix arg TODO-ONLY limits the search to TODO 
entries."
                                     (concat "Match: " match)))
          (setq pos (point))
          (insert match "\n")
-         (add-text-properties pos (1- (point)) (list 'face 'org-warning))
+         (add-text-properties pos (1- (point)) (list 'face 
'org-agenda-structure-filter))
          (setq pos (point))
          (unless org-agenda-multi
            (insert (substitute-command-keys
@@ -4962,7 +5029,7 @@ The prefix arg TODO-ONLY limits the search to TODO 
entries."
 \\<org-agenda-mode-map>`\\[universal-argument] \\[org-agenda-redo]' \
 to search again\n")))
          (add-text-properties pos (1- (point))
-                              (list 'face 'org-agenda-structure))
+                              (list 'face 'org-agenda-structure-secondary))
          (buffer-string)))
       (org-agenda-mark-header-line (point-min))
       (when rtnall
@@ -4988,10 +5055,11 @@ used by user-defined selections using 
`org-agenda-skip-function'.")
 (defvar org-agenda-overriding-header nil
   "When set during agenda, todo and tags searches it replaces the header.
 If an empty string, no header will be inserted.  If any other
-string, it will be inserted as a header.  If nil, a header will
-be generated automatically according to the command.  This
-variable should not be set directly, but custom commands can bind
-it in the options section.")
+string, it will be inserted as a header.  If a function, insert
+the string returned by the function as a header.  If nil, a
+header will be generated automatically according to the command.
+This variable should not be set directly, but custom commands can
+bind it in the options section.")
 
 (defun org-agenda-skip-entry-if (&rest conditions)
   "Skip entry if any of CONDITIONS is true.
@@ -5004,7 +5072,7 @@ See `org-agenda-skip-if' for details."
   (org-agenda-skip-if t conditions))
 
 (defun org-agenda-skip-if (subtree conditions)
-  "Checks current entity for CONDITIONS.
+  "Check current entity for CONDITIONS.
 If SUBTREE is non-nil, the entire subtree is checked.  Otherwise, only
 the entry (i.e. the text before the next heading) is checked.
 
@@ -5043,7 +5111,7 @@ If any of these conditions is met, this function returns 
the end point of
 the entity, causing the search to continue from there.  This is a function
 that can be put into `org-agenda-skip-function' for the duration of a command."
   (org-back-to-heading t)
-  (let* ((beg (point))
+  (let* (;; (beg (point))
         (end (if subtree (save-excursion (org-end-of-subtree t) (point))
                (org-entry-end-position)))
         (planning-end (if subtree end (line-end-position 2)))
@@ -5117,7 +5185,7 @@ a list of TODO keywords, or a state symbol `todo' or 
`done' or
       (`(,type . ,_) (error "Unknown TODO skip type: %S" type)))))
 
 ;;;###autoload
-(defun org-agenda-list-stuck-projects (&rest ignore)
+(defun org-agenda-list-stuck-projects (&rest _ignore)
   "Create agenda view for projects that are stuck.
 Stuck projects are project that have no next actions.  For the definitions
 of what a project is and how to check if it stuck, customize the variable
@@ -5155,12 +5223,12 @@ of what a project is and how to check if it stuck, 
customize the variable
         (org-agenda-skip-function
          ;; Skip entry if `org-agenda-skip-regexp' matches anywhere
          ;; in the subtree.
-         `(lambda ()
-            (and (save-excursion
-                   (let ((case-fold-search nil))
-                     (re-search-forward
-                      ,skip-re (save-excursion (org-end-of-subtree t)) t)))
-                 (progn (outline-next-heading) (point))))))
+         (lambda ()
+           (and (save-excursion
+                  (let ((case-fold-search nil))
+                    (re-search-forward
+                     skip-re (save-excursion (org-end-of-subtree t)) t)))
+                (progn (outline-next-heading) (point))))))
     (org-tags-view nil matcher)
     (setq org-agenda-buffer-name (buffer-name))
     (with-current-buffer org-agenda-buffer-name
@@ -5176,24 +5244,28 @@ of what a project is and how to check if it stuck, 
customize the variable
 (defvar org-disable-agenda-to-diary nil)          ;Dynamically-scoped param.
 (defvar diary-list-entries-hook)
 (defvar diary-time-regexp)
+(defvar diary-modify-entry-list-string-function)
+(defvar diary-file-name-prefix)
+(defvar diary-display-function)
+
 (defun org-get-entries-from-diary (date)
   "Get the (Emacs Calendar) diary entries for DATE."
   (require 'diary-lib)
+  (declare-function diary-fancy-display "diary-lib" ())
   (let* ((diary-fancy-buffer "*temporary-fancy-diary-buffer*")
-        (diary-display-function 'diary-fancy-display)
+        (diary-display-function #'diary-fancy-display)
         (pop-up-frames nil)
         (diary-list-entries-hook
          (cons 'org-diary-default-entry diary-list-entries-hook))
         (diary-file-name-prefix nil) ; turn this feature off
-        (diary-modify-entry-list-string-function 
'org-modify-diary-entry-string)
+        (diary-modify-entry-list-string-function
+         #'org-modify-diary-entry-string)
         (diary-time-regexp (concat "^" diary-time-regexp))
         entries
         (org-disable-agenda-to-diary t))
     (save-excursion
       (save-window-excursion
-       (funcall (if (fboundp 'diary-list-entries)
-                    'diary-list-entries 'list-diary-entries)
-                date 1)))
+        (diary-list-entries date 1)))
     (if (not (get-buffer diary-fancy-buffer))
        (setq entries nil)
       (with-current-buffer diary-fancy-buffer
@@ -5268,15 +5340,7 @@ each date.  It also removes lines that contain only 
whitespace."
 Needed to avoid empty dates which mess up holiday display."
   ;; Catch the error if dealing with the new add-to-diary-alist
   (when org-disable-agenda-to-diary
-    (condition-case nil
-       (org-add-to-diary-list original-date "Org mode dummy" "")
-      (error
-       (org-add-to-diary-list original-date  "Org mode dummy" "" nil)))))
-
-(defun org-add-to-diary-list (&rest args)
-  (if (fboundp 'diary-add-to-list)
-      (apply 'diary-add-to-list args)
-    (apply 'add-to-diary-list args)))
+    (diary-add-to-list original-date "Org mode dummy" "")))
 
 (defvar org-diary-last-run-time nil)
 
@@ -5307,6 +5371,7 @@ So the example above may also be written as
 The function expects the lisp variables `entry' and `date' to be provided
 by the caller, because this is how the calendar works.  Don't use this
 function from a program - use `org-agenda-get-day-entries' instead."
+  (with-no-warnings (defvar date) (defvar entry))
   (when (> (- (float-time)
              org-agenda-last-marker-time)
           5)
@@ -5331,7 +5396,7 @@ function from a program - use 
`org-agenda-get-day-entries' instead."
     ;; the calendar.  Org Agenda will list these entries itself.
     (when org-disable-agenda-to-diary (setq files nil))
     (while (setq file (pop files))
-      (setq rtn (apply 'org-agenda-get-day-entries file date args))
+      (setq rtn (apply #'org-agenda-get-day-entries file date args))
       (setq results (append results rtn)))
     (when results
       (setq results
@@ -5392,27 +5457,29 @@ the documentation of `org-diary'."
              (setf args (cons :deadline* (delq :deadline* args)))))
            ;; Collect list of headlines.  Return them flattened.
            (let ((case-fold-search nil) results deadlines)
-             (dolist (arg args (apply #'nconc (nreverse results)))
-               (pcase arg
-                 ((and :todo (guard (org-agenda-today-p date)))
-                  (push (org-agenda-get-todos) results))
-                 (:timestamp
-                  (push (org-agenda-get-blocks) results)
-                  (push (org-agenda-get-timestamps deadlines) results))
-                 (:sexp
-                  (push (org-agenda-get-sexps) results))
-                 (:scheduled
-                  (push (org-agenda-get-scheduled deadlines) results))
-                 (:scheduled*
-                  (push (org-agenda-get-scheduled deadlines t) results))
-                 (:closed
-                  (push (org-agenda-get-progress) results))
-                 (:deadline
-                  (setf deadlines (org-agenda-get-deadlines))
-                  (push deadlines results))
-                 (:deadline*
-                  (setf deadlines (org-agenda-get-deadlines t))
-                  (push deadlines results)))))))))))
+              (org-dlet
+                  ((date date))
+               (dolist (arg args (apply #'nconc (nreverse results)))
+                 (pcase arg
+                   ((and :todo (guard (org-agenda-today-p date)))
+                    (push (org-agenda-get-todos) results))
+                   (:timestamp
+                    (push (org-agenda-get-blocks) results)
+                    (push (org-agenda-get-timestamps deadlines) results))
+                   (:sexp
+                    (push (org-agenda-get-sexps) results))
+                   (:scheduled
+                    (push (org-agenda-get-scheduled deadlines) results))
+                   (:scheduled*
+                    (push (org-agenda-get-scheduled deadlines t) results))
+                   (:closed
+                    (push (org-agenda-get-progress) results))
+                   (:deadline
+                    (setf deadlines (org-agenda-get-deadlines))
+                    (push deadlines results))
+                   (:deadline*
+                    (setf deadlines (org-agenda-get-deadlines t))
+                    (push deadlines results))))))))))))
 
 (defsubst org-em (x y list)
   "Is X or Y a member of LIST?"
@@ -5474,11 +5541,12 @@ and the timestamp type relevant for the sorting 
strategy in
                           org-todo-regexp)
                          (org-select-this-todo-keyword
                           (concat "\\("
-                                  (mapconcat 'identity
+                                  (mapconcat #'identity
                                              (org-split-string
                                               org-select-this-todo-keyword
                                               "|")
-                                             "\\|") "\\)"))
+                                             "\\|")
+                                  "\\)"))
                          (t org-not-done-regexp))))
         marker priority category level tags todo-state
         ts-date ts-date-type ts-date-pair
@@ -5618,6 +5686,7 @@ This function is invoked if 
`org-agenda-todo-ignore-deadlines',
   "Return the date stamp information for agenda display.
 Optional argument DEADLINES is a list of deadline items to be
 displayed in agenda view."
+  (with-no-warnings (defvar date))
   (let* ((props (list 'face 'org-agenda-calendar-event
                      'org-not-done-regexp org-not-done-regexp
                      'org-todo-regexp org-todo-regexp
@@ -5760,12 +5829,15 @@ displayed in agenda view."
 (defun org-agenda-get-sexps ()
   "Return the sexp information for agenda display."
   (require 'diary-lib)
+  (with-no-warnings (defvar date) (defvar entry))
   (let* ((props (list 'face 'org-agenda-calendar-sexp
                      'mouse-face 'highlight
                      'help-echo
                      (format "mouse-2 or RET jump to org file %s"
                              (abbreviate-file-name buffer-file-name))))
         (regexp "^&?%%(")
+        ;; FIXME: Is this `entry' binding intended to be dynamic,
+         ;; so as to "hide" any current binding for it?
         marker category extra level ee txt tags entry
         result beg b sexp sexp-entry todo-state warntime inherited-tags)
     (goto-char (point-min))
@@ -5846,6 +5918,7 @@ item should be skipped.  If any of the SKIP-WEEKS 
arguments is the symbol
 `holidays', then any date that is known by the Emacs calendar to be a
 holiday will also be skipped.  If SKIP-WEEKS arguments are holiday strings,
 then those holidays will be skipped."
+  (with-no-warnings (defvar date) (defvar entry))
   (let* ((date1 (calendar-absolute-from-gregorian (list m1 d1 y1)))
         (date2 (calendar-absolute-from-gregorian (list m2 d2 y2)))
         (d (calendar-absolute-from-gregorian date))
@@ -5862,9 +5935,10 @@ then those holidays will be skipped."
              (delq nil (mapcar (lambda(g) (member g skip-weeks)) h))))
      entry)))
 
-(defalias 'org-get-closed 'org-agenda-get-progress)
+(defalias 'org-get-closed #'org-agenda-get-progress)
 (defun org-agenda-get-progress ()
   "Return the logged TODO entries for agenda display."
+  (with-no-warnings (defvar date))
   (let* ((props (list 'mouse-face 'highlight
                      'org-not-done-regexp org-not-done-regexp
                      'org-todo-regexp org-todo-regexp
@@ -5884,7 +5958,7 @@ then those holidays will be skipped."
                 (when (memq 'clock items) (concat "\\<" org-clock-string))
                 (when (memq 'state items)
                   (format "- +State \"%s\".*?" org-todo-regexp)))))
-        (parts-re (if parts (mapconcat 'identity parts "\\|")
+        (parts-re (if parts (mapconcat #'identity parts "\\|")
                     (error "`org-agenda-log-mode-items' is empty")))
         (regexp (concat
                  "\\(" parts-re "\\)"
@@ -5995,7 +6069,7 @@ See also the user option 
`org-agenda-clock-consistency-checks'."
                       '((:background "DarkRed") (:foreground "white"))))
         issue face m te ts dt ov)
     (goto-char (point-min))
-    (while (re-search-forward " Clocked: +(-\\|\\([0-9]+:[0-9]+\\))" nil t)
+    (while (re-search-forward " Clocked: +(\\(?:-\\|\\([0-9]+:[0-9]+\\)\\))" 
nil t)
       (setq issue nil face def-face)
       (catch 'next
        (setq m (org-get-at-bol 'org-marker)
@@ -6096,6 +6170,7 @@ See also the user option 
`org-agenda-clock-consistency-checks'."
   "Return the deadline information for agenda display.
 When WITH-HOUR is non-nil, only return deadlines with an hour
 specification like [h]h:mm."
+  (with-no-warnings (defvar date))
   (let* ((props (list 'mouse-face 'highlight
                      'org-not-done-regexp org-not-done-regexp
                      'org-todo-regexp org-todo-regexp
@@ -6254,6 +6329,7 @@ FRACTION is what fraction of the head-warning time has 
passed."
 Optional argument DEADLINES is a list of deadline items to be
 displayed in agenda view.  When WITH-HOUR is non-nil, only return
 scheduled items with an hour specification like [h]h:mm."
+  (with-no-warnings (defvar date))
   (let* ((props (list 'org-not-done-regexp org-not-done-regexp
                      'org-todo-regexp org-todo-regexp
                      'org-complex-heading-regexp org-complex-heading-regexp
@@ -6454,6 +6530,7 @@ scheduled items with an hour specification like [h]h:mm."
 
 (defun org-agenda-get-blocks ()
   "Return the date-range information for agenda display."
+  (with-no-warnings (defvar date))
   (let* ((props (list 'face nil
                      'org-not-done-regexp org-not-done-regexp
                      'org-todo-regexp org-todo-regexp
@@ -6585,14 +6662,14 @@ The flag is set if the currently compiled format 
contains a `%b'.")
          (cl-return (cadr entry))
        (cl-return (apply #'create-image (cdr entry)))))))
 
-(defun org-agenda-format-item (extra txt &optional level category tags dotime
+(defun org-agenda-format-item (extra txt &optional with-level with-category 
tags dotime
                                     remove-re habitp)
   "Format TXT to be inserted into the agenda buffer.
 In particular, add the prefix and corresponding text properties.
 
 EXTRA must be a string to replace the `%s' specifier in the prefix format.
-LEVEL may be a string to replace the `%l' specifier.
-CATEGORY (a string, a symbol or nil) may be used to overrule the default
+WITH-LEVEL may be a string to replace the `%l' specifier.
+WITH-CATEGORY (a string, a symbol or nil) may be used to overrule the default
 category taken from local variable or file name.  It will replace the `%c'
 specifier in the format.
 DOTIME, when non-nil, indicates that a time-of-day should be extracted from
@@ -6622,7 +6699,14 @@ Any match of REMOVE-RE will be removed from TXT."
                 org-agenda-show-inherited-tags
                 org-agenda-hide-tags-regexp))
 
-      (let* ((category (or category
+      (with-no-warnings
+       ;; `time', `tag', `effort' are needed for the eval of the prefix format.
+       ;; Based on what I see in `org-compile-prefix-format', I added
+       ;; a few more.
+        (defvar breadcrumbs) (defvar category) (defvar category-icon)
+        (defvar effort) (defvar extra)
+        (defvar level) (defvar tag) (defvar time))
+      (let* ((category (or with-category
                           (if buffer-file-name
                               (file-name-sans-extension
                                (file-name-nondirectory buffer-file-name))
@@ -6633,9 +6717,9 @@ Any match of REMOVE-RE will be removed from TXT."
                              ""))
             (effort (and (not (string= txt ""))
                          (get-text-property 1 'effort txt)))
-            ;; time, tag, effort are needed for the eval of the prefix format
             (tag (if tags (nth (1- (length tags)) tags) ""))
             (time-grid-trailing-characters (nth 2 org-agenda-time-grid))
+            (extra (or (and (not habitp) extra) ""))
             time
             (ts (when dotime (concat
                               (if (stringp dotime) dotime "")
@@ -6665,10 +6749,9 @@ Any match of REMOVE-RE will be removed from TXT."
                           (= (match-beginning 0) 0)
                         t))
              (setq txt (replace-match "" nil nil txt))))
-         ;; Normalize the time(s) to 24 hour
-         (when s1 (setq s1 (org-get-time-of-day s1 'string t)))
-         (when s2 (setq s2 (org-get-time-of-day s2 'string t)))
-
+          ;; Normalize the time(s) to 24 hour.
+         (when s1 (setq s1 (org-get-time-of-day s1 t)))
+         (when s2 (setq s2 (org-get-time-of-day s2 t)))
          ;; Try to set s2 if s1 and
          ;; `org-agenda-default-appointment-duration' are set
          (when (and s1 (not s2) org-agenda-default-appointment-duration)
@@ -6677,12 +6760,13 @@ Any match of REMOVE-RE will be removed from TXT."
                   (+ (org-duration-to-minutes s1 t)
                      org-agenda-default-appointment-duration)
                   nil t)))
-
          ;; Compute the duration
          (when s2
            (setq duration (- (org-duration-to-minutes s2)
-                             (org-duration-to-minutes s1)))))
-
+                             (org-duration-to-minutes s1))))
+          ;; Format S1 and S2 for display.
+         (when s1 (setq s1 (org-get-time-of-day s1 'overtime)))
+         (when s2 (setq s2 (org-get-time-of-day s2 'overtime))))
        (when (string-match org-tag-group-re txt)
          ;; Tags are in the string
          (if (or (eq org-agenda-remove-tags t)
@@ -6719,9 +6803,8 @@ Any match of REMOVE-RE will be removed from TXT."
                                   (concat time-grid-trailing-characters " ")
                                 time-grid-trailing-characters)))
                         (t ""))
-             extra (or (and (not habitp) extra) "")
              category (if (symbolp category) (symbol-name category) category)
-             level (or level ""))
+             level (or with-level ""))
        (if (string-match org-link-bracket-re category)
            (progn
              (setq l (string-width (or (match-string 2) (match-string 1))))
@@ -6734,14 +6817,14 @@ Any match of REMOVE-RE will be removed from TXT."
                     (>= (length category) org-prefix-category-max-length))
            (setq category (substring category 0 (1- 
org-prefix-category-max-length)))))
        ;; Evaluate the compiled format
-       (setq rtn (concat (eval formatter) txt))
+       (setq rtn (concat (eval formatter t) txt))
 
        ;; And finally add the text properties
        (remove-text-properties 0 (length rtn) '(line-prefix t wrap-prefix t) 
rtn)
        (org-add-props rtn nil
          'org-category category
-         'tags (mapcar 'org-downcase-keep-props tags)
-         'org-priority-highest org-priority-highest
+          'tags tags
+          'org-priority-highest org-priority-highest
          'org-priority-lowest org-priority-lowest
          'time-of-day time-of-day
          'duration duration
@@ -6785,12 +6868,6 @@ The modified list may contain inherited tags, and tags 
matched by
                          (if have-i "::" ":"))))))
   txt)
 
-(defun org-downcase-keep-props (s)
-  (let ((props (text-properties-at 0 s)))
-    (setq s (downcase s))
-    (add-text-properties 0 (length s) props s)
-    s))
-
 (defvar org-agenda-sorting-strategy) ;; because the def is in a let form
 
 (defun org-agenda-add-time-grid-maybe (list ndays todayp)
@@ -6853,8 +6930,8 @@ and stored in the variable `org-prefix-format-compiled'."
             (cdr (assq key org-agenda-prefix-format)))
            (t "  %-12:c%?-12t% s")))
        (start 0)
-       varform vars var e c f opt)
-    (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ 
.;,:!?=|/<>]?\\)\\([cltseib]\\|(.+)\\)"
+       varform vars var c f opt) ;; e
+    (while (string-match "%\\(\\?\\)?\\([-+]?[0-9.]*\\)\\([ 
.;,:!?=|/<>]?\\)\\([cltseib]\\|(.+?)\\)"
                         s start)
       (setq var (or (cdr (assoc (match-string 4 s)
                                '(("c" . category) ("t" . time) ("l" . level) 
("s" . extra)
@@ -6878,17 +6955,21 @@ and stored in the variable 
`org-prefix-format-compiled'."
                  (and (string-match "\\.[0-9]+" x)
                       (string-to-number (substring (match-string 0 x) 1)))))))
       (if (eq var 'eval)
-         (setq varform `(format ,f (org-eval ,(read (match-string 4 s)))))
+         (setq varform `(format ,f (org-eval ,(read (substring s 
(match-beginning 4))))))
        (if opt
            (setq varform
-                 `(if (or (equal "" ,var) (equal nil ,var))
+                 `(if (member ,var '("" nil))
                       ""
                     (format ,f (concat ,var ,c))))
          (setq varform
-               `(format ,f (if (or (equal ,var "")
-                                   (equal ,var nil)) ""
+               `(format ,f (if (member ,var '("" nil)) ""
                              (concat ,var ,c (get-text-property 0 'extra-space 
,var)))))))
-      (setq s (replace-match "%s" t nil s))
+      (if (eq var 'eval)
+          (setf (substring s (match-beginning 0)
+                           (+ (match-beginning 4)
+                              (length (format "%S" (read (substring s 
(match-beginning 4)))))))
+                "%s")
+        (setq s (replace-match "%s" t nil s)))
       (push varform vars))
     (setq vars (nreverse vars))
     (with-current-buffer (or org-agenda-buffer (current-buffer))
@@ -6902,43 +6983,57 @@ and stored in the variable 
`org-prefix-format-compiled'."
             `(format ,s ,@vars))))))
 
 (defun org-set-sorting-strategy (key)
-  (if (symbolp (car org-agenda-sorting-strategy))
-      ;; the old format
-      (setq org-agenda-sorting-strategy-selected org-agenda-sorting-strategy)
-    (setq org-agenda-sorting-strategy-selected
+  (setq org-agenda-sorting-strategy-selected
+        (if (symbolp (car org-agenda-sorting-strategy))
+            ;; the old format
+            org-agenda-sorting-strategy
          (or (cdr (assq key org-agenda-sorting-strategy))
              (cdr (assq 'agenda org-agenda-sorting-strategy))
              '(time-up category-keep priority-down)))))
 
-(defun org-get-time-of-day (s &optional string mod24)
+(defun org-get-time-of-day (s &optional string)
   "Check string S for a time of day.
+
 If found, return it as a military time number between 0 and 2400.
 If not found, return nil.
+
 The optional STRING argument forces conversion into a 5 character wide string
-HH:MM."
-  (save-match-data
-    (when
-       (and
-        (or (string-match 
"\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)\\([AaPp][Mm]\\)?\\> *" s)
-            (string-match 
"\\<\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?\\([AaPp][Mm]\\)\\> *" s))
-        (not (eq (get-text-property 1 'face s) 'org-link)))
-      (let* ((h (string-to-number (match-string 1 s)))
-            (m (if (match-end 3) (string-to-number (match-string 3 s)) 0))
-            (ampm (when (match-end 4) (downcase (match-string 4 s))))
-            (am-p (equal ampm "am"))
-            (h1   (cond ((not ampm) h)
-                        ((= h 12) (if am-p 0 12))
-                        (t (+ h (if am-p 0 12)))))
-            (h2 (if (and string mod24 (not (and (= m 0) (= h1 24))))
-                    (mod h1 24) h1))
-            (t0 (+ (* 100 h2) m))
-            (t1 (concat (if (>= h1 24) "+" " ")
-                        (if (and org-agenda-time-leading-zero
-                                 (< t0 1000)) "0" "")
-                        (if (< t0 100) "0" "")
-                        (if (< t0 10)  "0" "")
-                        (number-to-string t0))))
-       (if string (concat (substring t1 -4 -2) ":" (substring t1 -2)) t0)))))
+HH:MM.  When it is `overtime', any time above 24:00 is turned into \"+H:MM\"
+where H:MM is the duration above midnight."
+  (let ((case-fold-search t)
+        (time-regexp
+         (rx word-start
+             (group (opt (any "012")) digit)           ;group 1: hours
+             (or (and ":" (group (any "012345") digit) ;group 2: minutes
+                      (opt (group (or "am" "pm"))))    ;group 3: am/pm
+                 ;; Special "HHam/pm" case.
+                 (group-n 3 (or "am" "pm")))
+             word-end)))
+    (save-match-data
+      (when (and (string-match time-regexp s)
+                 (not (eq 'org-link (get-text-property 1 'face s))))
+        (let ((hours
+               (let* ((ampm (and (match-end 3) (downcase (match-string 3 s))))
+                      (am-p (equal ampm "am")))
+                 (pcase (string-to-number (match-string 1 s))
+                   ((and (guard (not ampm)) h) h)
+                   (12 (if am-p 0 12))
+                   (h (+ h (if am-p 0 12))))))
+              (minutes
+               (if (match-end 2)
+                   (string-to-number (match-string 2 s))
+                 0)))
+          (pcase string
+            (`nil (+ minutes (* hours 100)))
+            ((and `overtime
+                  (guard (or (> hours 24)
+                             (and (= hours 24)
+                                  (> minutes 0)))))
+             (format "+%d:%02d" (- hours 24) minutes))
+            ((guard org-agenda-time-leading-zero)
+             (format "%02d:%02d" hours minutes))
+            (_
+             (format "%d:%02d" hours minutes))))))))
 
 (defvar org-agenda-before-sorting-filter-function nil
   "Function to be applied to agenda items prior to sorting.
@@ -6980,8 +7075,8 @@ The optional argument TYPE tells the agenda type."
            (delq nil
                  (mapcar
                   org-agenda-before-sorting-filter-function list))))
-    (setq list (mapcar 'org-agenda-highlight-todo list)
-         list (mapcar 'identity (sort list 'org-entries-lessp)))
+    (setq list (mapcar #'org-agenda-highlight-todo list)
+         list (mapcar #'identity (sort list #'org-entries-lessp)))
     (when max-effort
       (setq list (org-agenda-limit-entries
                  list 'effort-minutes max-effort
@@ -6995,7 +7090,7 @@ The optional argument TYPE tells the agenda type."
       (setq list (org-agenda-limit-entries list 'org-hd-marker max-entries)))
     (when (and org-agenda-dim-blocked-tasks org-blocker-hook)
       (setq list (mapcar #'org-agenda--mark-blocked-entry list)))
-    (mapconcat 'identity list "\n")))
+    (mapconcat #'identity list "\n")))
 
 (defun org-agenda-limit-entries (list prop limit &optional fn)
   "Limit the number of agenda entries."
@@ -7081,13 +7176,14 @@ The optional argument TYPE tells the agenda type."
            (setq x
                  (concat
                   (substring x 0 (match-end 1))
-                  (format org-agenda-todo-keyword-format
-                          (match-string 2 x))
-                  ;; Remove `display' property as the icon could leak
+                   (unless (string= org-agenda-todo-keyword-format "")
+                    (format org-agenda-todo-keyword-format
+                            (match-string 2 x)))
+                   ;; Remove `display' property as the icon could leak
                   ;; on the white space.
                   (org-add-props " " (org-plist-delete (text-properties-at 0 x)
-                                                       'display))
-                  (substring x (match-end 3)))))))
+                                                        'display))
+                   (substring x (match-end 3)))))))
       x)))
 
 (defsubst org-cmp-values (a b property)
@@ -7210,8 +7306,9 @@ their type."
   "Predicate for sorting agenda entries."
   ;; The following variables will be used when the form is evaluated.
   ;; So even though the compiler complains, keep them.
-  (let* ((ss org-agenda-sorting-strategy-selected)
-        (timestamp-up    (and (org-em 'timestamp-up 'timestamp-down ss)
+  (let ((ss org-agenda-sorting-strategy-selected))
+    (org-dlet
+       ((timestamp-up    (and (org-em 'timestamp-up 'timestamp-down ss)
                               (org-cmp-ts a b "")))
         (timestamp-down  (if timestamp-up (- timestamp-up) nil))
         (scheduled-up    (and (org-em 'scheduled-up 'scheduled-down ss)
@@ -7257,14 +7354,14 @@ their type."
         (alpha-down      (if alpha-up (- alpha-up) nil))
         (need-user-cmp   (org-em 'user-defined-up 'user-defined-down ss))
         user-defined-up user-defined-down)
-    (when (and need-user-cmp org-agenda-cmp-user-defined
-              (functionp org-agenda-cmp-user-defined))
-      (setq user-defined-up
-           (funcall org-agenda-cmp-user-defined a b)
-           user-defined-down (if user-defined-up (- user-defined-up) nil)))
-    (cdr (assoc
-         (eval (cons 'or org-agenda-sorting-strategy-selected))
-         '((-1 . t) (1 . nil) (nil . nil))))))
+      (when (and need-user-cmp org-agenda-cmp-user-defined
+                (functionp org-agenda-cmp-user-defined))
+       (setq user-defined-up
+             (funcall org-agenda-cmp-user-defined a b)
+             user-defined-down (if user-defined-up (- user-defined-up) nil)))
+      (cdr (assoc
+           (eval (cons 'or org-agenda-sorting-strategy-selected) t)
+           '((-1 . t) (1 . nil) (nil . nil)))))))
 
 ;;; Agenda restriction lock
 
@@ -7299,7 +7396,7 @@ When in a restricted subtree, remove it.
 
 The restriction will span over the entire file if TYPE is `file',
 or if type is '(4), or if the cursor is before the first headline
-in the file. Otherwise, only apply the restriction to the current
+in the file.  Otherwise, only apply the restriction to the current
 subtree."
   (interactive "P")
   (if (and org-agenda-overriding-restriction
@@ -7466,7 +7563,7 @@ This is used when toggling sticky agendas."
     (dolist (buf (buffer-list))
       (when (with-current-buffer buf (eq major-mode 'org-agenda-mode))
        (push buf blist)))
-    (mapc 'kill-buffer blist)))
+    (mapc #'kill-buffer blist)))
 
 (defun org-agenda-execute (arg)
   "Execute another agenda command, keeping same window.
@@ -7479,6 +7576,7 @@ in the agenda."
 (defun org-agenda-redo (&optional all)
   "Rebuild possibly ALL agenda view(s) in the current buffer."
   (interactive "P")
+  (defvar org-agenda-tag-filter-while-redo) ;FIXME: Where is this var used?
   (let* ((p (or (and (looking-at "\\'") (1- (point))) (point)))
         (cpa (unless (eq all t) current-prefix-arg))
         (org-agenda-doing-sticky-redo org-agenda-sticky)
@@ -7517,8 +7615,11 @@ in the agenda."
     (and cols (org-columns-quit))
     (message "Rebuilding agenda buffer...")
     (if series-redo-cmd
-       (eval series-redo-cmd)
-      (org-let lprops redo-cmd))
+       (eval series-redo-cmd t)
+      (cl-progv
+         (mapcar #'car lprops)
+         (mapcar (lambda (binding) (eval (cadr binding) t)) lprops)
+       (eval redo-cmd t)))
     (setq org-agenda-undo-list nil
          org-agenda-pending-undo-list nil
          org-agenda-tag-filter tag-filter
@@ -7720,7 +7821,7 @@ A single `\\[universal-argument]' prefix arg 
STRIP-OR-ACCUMULATE will negate the
 entire filter, which can be useful in connection with the prompt history.
 
 A double `\\[universal-argument] \\[universal-argument]' prefix arg will add 
the new filter elements to the
-existing ones. A shortcut for this is to add an additional `+' at the
+existing ones.  A shortcut for this is to add an additional `+' at the
 beginning of the string, like `+-John'.
 
 With a triple prefix argument, execute the computed filtering defined in
@@ -7744,7 +7845,7 @@ the variable `org-agenda-auto-exclude-function'."
           (negate (equal strip-or-accumulate '(4)))
           (cf (mapconcat #'identity org-agenda-category-filter ""))
           (tf (mapconcat #'identity org-agenda-tag-filter ""))
-          (rpl-fn (lambda (c) (replace-regexp-in-string "^\\+" "" (or (car c) 
""))))
+          ;; (rpl-fn (lambda (c) (replace-regexp-in-string "^\\+" "" (or (car 
c) ""))))
           (ef (replace-regexp-in-string "^\\+" "" (or (car 
org-agenda-effort-filter) "")))
           (rf (replace-regexp-in-string "^\\+" "" (or (car 
org-agenda-regexp-filter) "")))
           (ff (concat cf tf ef (when (not (equal rf "")) (concat "/" rf "/"))))
@@ -7752,7 +7853,7 @@ the variable `org-agenda-auto-exclude-function'."
                      (concat
                       (if negate "Negative filter" "Filter")
                       " [+cat-tag<0:10-/regexp/]: ")
-                     'org-agenda-filter-completion-function
+                     #'org-agenda-filter-completion-function
                      nil nil ff))
           (keep (or (if (string-match "^\\+[+-]" f-string)
                         (progn (setq f-string (substring f-string 1)) t))
@@ -7778,20 +7879,20 @@ the variable `org-agenda-auto-exclude-function'."
                   "~~~" "-" (match-string 3 f-string)))
          (cond
           ((member s tag-list)
-           (add-to-list 'ft (concat pm s) 'append 'equal))
+           (org-pushnew-to-end (concat pm s) ft))
           ((member s category-list)
-           (add-to-list 'fc (concat pm ; Remove temporary double quotes.
-                                    (replace-regexp-in-string "\"\\(.*\\)\"" 
"\\1" s))
-                        'append 'equal))
+           (org-pushnew-to-end (concat pm ; Remove temporary double quotes.
+                                       (replace-regexp-in-string 
"\"\\(.*\\)\"" "\\1" s))
+                               fc))
           (t (message
               "`%s%s' filter ignored because tag/category is not represented"
               pm s))))
         ((match-beginning 4)
          ;; effort
-         (add-to-list 'fe (concat pm (match-string 4 f-string)) t 'equal))
+         (org-pushnew-to-end (concat pm (match-string 4 f-string)) fe))
         ((match-beginning 5)
          ;; regexp
-         (add-to-list 'fr (concat pm (match-string 6 f-string)) t 'equal)))
+         (org-pushnew-to-end (concat pm (match-string 6 f-string)) fr)))
        (setq f-string (substring f-string (match-end 0))))
       (org-agenda-filter-remove-all)
       (and fc (org-agenda-filter-apply
@@ -7871,7 +7972,7 @@ With a `\\[universal-argument] \\[universal-argument] 
\\[universal-argument]' pr
 i.e. don't
 filter on all its group members.
 
-A lisp caller can specify CHAR.  EXCLUDE means that the new tag
+A Lisp caller can specify CHAR.  EXCLUDE means that the new tag
 should be used to exclude the search - the interactive user can
 also press `-' or `+' to switch between filtering and excluding."
   (interactive "P")
@@ -7893,7 +7994,7 @@ also press `-' or `+' to switch between filtering and 
excluding."
         (expand (not (equal strip-or-accumulate '(64))))
         (inhibit-read-only t)
         (current org-agenda-tag-filter)
-        a n tag)
+        a tag) ;; n
     (unless char
       (while (not (memq char valid-char-list))
        (org-unlogged-message
@@ -7974,19 +8075,20 @@ These will be lower-case, for filtering."
            (if tt (push tt tags-lists)))
          (setq tags-lists
                (nreverse (org-uniquify
-                          (delq nil (apply 'append tags-lists)))))
+                          (delq nil (apply #'append tags-lists)))))
          (dolist (tag tags-lists)
            (mapc
             (lambda (group)
-              (when (member tag (mapcar #'downcase group))
-                (push (downcase (car group)) tags-lists)))
+              (when (member tag group)
+                (push (car group) tags-lists)))
             org-tag-groups-alist-for-agenda))
          (setq org-agenda-represented-tags tags-lists)))))
 
 (defun org-agenda-filter-make-matcher (filter type &optional expand)
-  "Create the form that tests a line for agenda filter.  Optional
-argument EXPAND can be used for the TYPE tag and will expand the
-tags in the FILTER if any of the tags in FILTER are grouptags."
+  "Create the form that tests a line for agenda filter.
+Optional argument EXPAND can be used for the TYPE tag and will
+expand the tags in the FILTER if any of the tags in FILTER are
+grouptags."
   (let ((multi-pos-cats
         (and (eq type 'category)
              (string-match-p "\\+.*\\+"
@@ -8053,7 +8155,7 @@ function to set the right switches in the returned form."
                 ((and (string-match-p "\\`{" tag) (string-match-p "}\\'" tag))
                  ;; TAG is a regexp.
                  (list 'org-match-any-p (substring tag 1 -1) 'tags))
-                (t (list 'member (downcase tag) 'tags)))))
+                (t (list 'member tag 'tags)))))
        (push (if (eq op ?-) (list 'not f) f) form)))))
 
 (defun org-agenda-filter-effort-form (e)
@@ -8084,7 +8186,7 @@ If the line does not have an effort defined, return nil."
 When NO-OPERATOR is non-nil, do not add the + operator to
 returned tags."
   (if org-group-tags
-      (let ((case-fold-search t) rtn)
+      (let (case-fold-search rtn)
        (mapc
         (lambda (f)
           (let (f0 dir)
@@ -8092,7 +8194,7 @@ returned tags."
                 (setq dir (match-string 1 f) f0 (match-string 2 f))
               (setq dir (if no-operator "" "+") f0 f))
             (setq rtn (append (mapcar (lambda(f1) (concat dir f1))
-                                      (org-tags-expand f0 t t))
+                                      (org-tags-expand f0 t))
                               rtn))))
         filter)
        (reverse rtn))
@@ -8118,10 +8220,11 @@ grouptags."
     (while (not (eobp))
       (when (or (org-get-at-bol 'org-hd-marker)
                (org-get-at-bol 'org-marker))
-       (let ((tags (org-get-at-bol 'tags))
-             (cat (org-agenda-get-category))
-             (txt (or (org-get-at-bol 'txt) "")))
-         (unless (eval org-agenda-filter-form)
+       (org-dlet
+           ((tags (org-get-at-bol 'tags))
+            (cat (org-agenda-get-category))
+            (txt (or (org-get-at-bol 'txt) "")))
+         (unless (eval org-agenda-filter-form t)
            (org-agenda-filter-hide-line type))))
       (beginning-of-line 2)))
   (when (get-char-property (point) 'invisible)
@@ -8231,13 +8334,13 @@ Negative selection means regexp must not match for 
selection of an entry."
 (defun org-add-to-string (var string)
   (set var (concat (symbol-value var) string)))
 
-(defun org-agenda-goto-date (span)
+(defun org-agenda-goto-date (date)
   "Jump to DATE in agenda."
-  (interactive "P")
-  (let* ((org-read-date-prefer-future
-         (eval org-agenda-jump-prefer-future))
-        (date (org-read-date))
-        (day (time-to-days (org-time-string-to-time date)))
+  (interactive
+   (list
+    (let ((org-read-date-prefer-future org-agenda-jump-prefer-future))
+      (org-read-date))))
+  (let* ((day (time-to-days (org-time-string-to-time date)))
         (org-agenda-sticky-orig org-agenda-sticky)
         (org-agenda-buffer-tmp-name (buffer-name))
         (args (get-text-property (min (1- (point-max)) (point)) 
'org-last-args))
@@ -8304,12 +8407,12 @@ When optional argument BACKWARD is set, go backward."
          "Cannot execute this command outside of org-agenda-mode buffers"))
        ((looking-at (if backward "\\`" "\\'"))
         (message "Already at the %s block" (if backward "first" "last")))
-       (t (let ((pos (prog1 (point)
-                       (ignore-errors (if backward (backward-char 1)
-                                        (move-end-of-line 1)))))
+       (t (let ((_pos (prog1 (point)
+                        (ignore-errors (if backward (backward-char 1)
+                                         (move-end-of-line 1)))))
                 (f (if backward
-                       'previous-single-property-change
-                     'next-single-property-change))
+                       #'previous-single-property-change
+                     #'next-single-property-change))
                 moved dest)
             (while (and (setq dest (funcall
                                     f (point) 'org-agenda-structural-header))
@@ -8327,7 +8430,8 @@ When optional argument BACKWARD is set, go backward."
 With prefix ARG, go forward that many times the current span."
   (interactive "p")
   (org-agenda-check-type t 'agenda)
-  (let* ((args (get-text-property (min (1- (point-max)) (point)) 
'org-last-args))
+  (let* ((wstart (window-start))
+         (args (get-text-property (min (1- (point-max)) (point)) 
'org-last-args))
         (span (or (nth 2 args) org-agenda-current-span))
         (sd (or (nth 1 args) (org-get-at-bol 'day) org-starting-day))
         (greg (calendar-gregorian-from-absolute sd))
@@ -8360,7 +8464,8 @@ With prefix ARG, go forward that many times the current 
span."
          (org-agenda-overriding-arguments
           (list (car args) sd span)))
       (org-agenda-redo)
-      (org-agenda-find-same-or-today-or-agenda cnt))))
+      (org-agenda-find-same-or-today-or-agenda cnt))
+    (set-window-start nil wstart)))
 
 (defun org-agenda-earlier (arg)
   "Go backward in time by the current span.
@@ -8480,7 +8585,7 @@ SPAN may be `day', `week', `fortnight', `month', `year'.  
The return value
 is a cons cell with the starting date and the number of days,
 so that the date SD will be in that range."
   (let* ((greg (calendar-gregorian-from-absolute sd))
-        (dg (nth 1 greg))
+        ;; (dg (nth 1 greg))
         (mg (car greg))
         (yg (nth 2 greg)))
     (cond
@@ -8552,7 +8657,7 @@ so that the date SD will be in that range."
 
 (defun org-unhighlight-once ()
   "Remove the highlight from its position, and this function from the hook."
-  (remove-hook 'pre-command-hook 'org-unhighlight-once)
+  (remove-hook 'pre-command-hook #'org-unhighlight-once)
   (org-unhighlight))
 
 (defvar org-agenda-pre-follow-window-conf nil)
@@ -8689,7 +8794,8 @@ When called with a prefix argument, include all archive 
files as well."
              (if org-agenda-include-deadlines " Ddl"  "")
              (if org-agenda-use-time-grid   " Grid"   "")
              (if (and (boundp 'org-habit-show-habits)
-                      org-habit-show-habits) " Habit"   "")
+                      org-habit-show-habits)
+                 " Habit"   "")
              (cond
               ((consp org-agenda-show-log) " LogAll")
               ((eq org-agenda-show-log 'clockcheck) " ClkCk")
@@ -8701,36 +8807,39 @@ When called with a prefix argument, include all archive 
files as well."
                  '(:eval (propertize
                           (concat "["
                                   (mapconcat
-                                   'identity
+                                    #'identity
                                    (append
                                     (get 'org-agenda-category-filter 
:preset-filter)
                                     org-agenda-category-filter)
                                    "")
                                   "]")
                           'face 'org-agenda-filter-category
-                          'help-echo "Category used in filtering")) "")
+                           'help-echo "Category used in filtering"))
+                "")
              (if (or org-agenda-tag-filter
                      (get 'org-agenda-tag-filter :preset-filter))
                  '(:eval (propertize
                           (concat (mapconcat
-                                   'identity
+                                   #'identity
                                    (append
                                     (get 'org-agenda-tag-filter :preset-filter)
                                     org-agenda-tag-filter)
                                    ""))
                           'face 'org-agenda-filter-tags
-                          'help-echo "Tags used in filtering")) "")
+                          'help-echo "Tags used in filtering"))
+               "")
              (if (or org-agenda-effort-filter
                      (get 'org-agenda-effort-filter :preset-filter))
                  '(:eval (propertize
                           (concat (mapconcat
-                                   'identity
+                                   #'identity
                                    (append
                                     (get 'org-agenda-effort-filter 
:preset-filter)
                                     org-agenda-effort-filter)
                                    ""))
                           'face 'org-agenda-filter-effort
-                          'help-echo "Effort conditions used in filtering")) 
"")
+                          'help-echo "Effort conditions used in filtering"))
+               "")
              (if (or org-agenda-regexp-filter
                      (get 'org-agenda-regexp-filter :preset-filter))
                  '(:eval (propertize
@@ -8741,7 +8850,8 @@ When called with a prefix argument, include all archive 
files as well."
                                     org-agenda-regexp-filter)
                                    ""))
                           'face 'org-agenda-filter-regexp
-                          'help-echo "Regexp used in filtering")) "")
+                          'help-echo "Regexp used in filtering"))
+               "")
              (if org-agenda-archives-mode
                  (if (eq org-agenda-archives-mode t)
                      " Archives"
@@ -8772,7 +8882,7 @@ When called with a prefix argument, include all archive 
files as well."
   "Move cursor to next agenda item."
   (interactive "p")
   (let ((col (current-column)))
-    (dotimes (c n)
+    (dotimes (_ n)
       (when (next-single-property-change (point-at-eol) 'org-marker)
        (move-end-of-line 1)
        (goto-char (next-single-property-change (point) 'org-marker))))
@@ -8782,7 +8892,7 @@ When called with a prefix argument, include all archive 
files as well."
 (defun org-agenda-previous-item (n)
   "Move cursor to next agenda item."
   (interactive "p")
-  (dotimes (c n)
+  (dotimes (_ n)
     (let ((col (current-column))
          (goto (save-excursion
                  (move-end-of-line 0)
@@ -8808,7 +8918,7 @@ When called with a prefix argument, include all archive 
files as well."
   (let* ((tags (org-get-at-bol 'tags)))
     (if tags
        (message "Tags are :%s:"
-                (org-no-properties (mapconcat 'identity tags ":")))
+                (org-no-properties (mapconcat #'identity tags ":")))
       (message "No tags associated with this line"))))
 
 (defun org-agenda-goto (&optional highlight)
@@ -8949,6 +9059,8 @@ Pass ARG, FORCE-ARG, DELETE and BODY to 
`org-agenda-do-in-region'."
   (funcall-interactively
    #'org-agenda-archive-with 'org-archive-to-archive-sibling))
 
+(defvar org-archive-from-agenda)
+
 (defun org-agenda-archive-with (cmd &optional confirm)
   "Move the entry to the archive sibling."
   (interactive)
@@ -9025,7 +9137,7 @@ When NO-UPDATE is non-nil, don't redo the agenda buffer."
           (marker (or (org-get-at-bol 'org-hd-marker)
                       (org-agenda-error)))
           (buffer (marker-buffer marker))
-          (pos (marker-position marker))
+          ;; (pos (marker-position marker))
           (rfloc (or rfloc
                      (org-refile-get-location
                       (if goto "Goto" "Refile to") buffer
@@ -9311,6 +9423,8 @@ by a remote command from the agenda.")
   (interactive)
   (org-agenda-todo 'previousset))
 
+(defvar org-agenda-headline-snapshot-before-repeat)
+
 (defun org-agenda-todo (&optional arg)
   "Cycle TODO state of line at point, also in Org file.
 This changes the line at point, all other lines in the agenda referring to
@@ -9335,11 +9449,14 @@ the same tree node, and the headline of the tree node 
in the Org file."
         (goto-char pos)
         (org-show-context 'agenda)
         (let ((current-prefix-arg arg))
-          (call-interactively 'org-todo))
+          (call-interactively 'org-todo)
+           ;; Make sure that log is recorded in current undo.
+           (when (and org-log-setup
+                      (not (eq org-log-note-how 'note)))
+             (org-add-log-note)))
         (and (bolp) (forward-char 1))
         (setq newhead (org-get-heading))
-        (when (and (bound-and-true-p
-                    org-agenda-headline-snapshot-before-repeat)
+        (when (and org-agenda-headline-snapshot-before-repeat
                    (not (equal org-agenda-headline-snapshot-before-repeat
                                newhead))
                    todayp)
@@ -9358,15 +9475,15 @@ the same tree node, and the headline of the tree node 
in the Org file."
        (org-move-to-column col)
        (org-agenda-mark-clocking-task)))))
 
-(defun org-agenda-add-note (&optional arg)
+(defun org-agenda-add-note (&optional _arg)
   "Add a time-stamped note to the entry at point."
-  (interactive "P")
+  (interactive) ;; "P"
   (org-agenda-check-no-diary)
   (let* ((marker (or (org-get-at-bol 'org-marker)
                     (org-agenda-error)))
         (buffer (marker-buffer marker))
         (pos (marker-position marker))
-        (hdmarker (org-get-at-bol 'org-hd-marker))
+        (_hdmarker (org-get-at-bol 'org-hd-marker))
         (inhibit-read-only t))
     (with-current-buffer buffer
       (widen)
@@ -9389,7 +9506,7 @@ If FORCE-TAGS is non-nil, the car of it returns the new 
tags."
         (org-agenda-buffer (current-buffer))
         (thetags (with-current-buffer (marker-buffer hdmarker)
                    (org-get-tags hdmarker)))
-        props m pl undone-face done-face finish new dotime level cat tags)
+        props m undone-face done-face finish new dotime level cat tags) ;; pl
     (save-excursion
       (goto-char (point-max))
       (beginning-of-line 1)
@@ -9411,7 +9528,7 @@ If FORCE-TAGS is non-nil, the car of it returns the new 
tags."
                  (with-current-buffer (marker-buffer hdmarker)
                    (org-with-wide-buffer
                     (org-agenda-format-item extra newhead level cat tags 
dotime))))
-               pl (text-property-any (point-at-bol) (point-at-eol) 
'org-heading t)
+               ;; pl (text-property-any (point-at-bol) (point-at-eol) 
'org-heading t)
                undone-face (org-get-at-bol 'undone-face)
                done-face (org-get-at-bol 'done-face))
          (beginning-of-line 1)
@@ -9490,33 +9607,35 @@ current line."
 
 (defun org-agenda-priority (&optional force-direction)
   "Set the priority of line at point, also in Org file.
-This changes the line at point, all other lines in the agenda referring to
-the same tree node, and the headline of the tree node in the Org file.
-Called with a universal prefix arg, show the priority instead of setting it."
+This changes the line at point, all other lines in the agenda
+referring to the same tree node, and the headline of the tree
+node in the Org file.
+
+Called with one universal prefix arg, show the priority instead
+of setting it.
+
+When called programmatically, FORCE-DIRECTION can be `set', `up',
+`down', or a character."
   (interactive "P")
-  (if (equal force-direction '(4))
-      (org-priority-show)
-    (unless org-priority-enable-commands
-      (user-error "Priority commands are disabled"))
-    (org-agenda-check-no-diary)
-    (let* ((col (current-column))
-          (marker (or (org-get-at-bol 'org-marker)
-                      (org-agenda-error)))
-          (hdmarker (org-get-at-bol 'org-hd-marker))
-          (buffer (marker-buffer hdmarker))
-          (pos (marker-position hdmarker))
-          (inhibit-read-only t)
-          newhead)
-      (org-with-remote-undo buffer
-       (with-current-buffer buffer
-         (widen)
-         (goto-char pos)
-         (org-show-context 'agenda)
-         (org-priority force-direction)
-         (end-of-line 1)
-         (setq newhead (org-get-heading)))
-       (org-agenda-change-all-lines newhead hdmarker)
-       (org-move-to-column col)))))
+  (unless org-priority-enable-commands
+    (user-error "Priority commands are disabled"))
+  (org-agenda-check-no-diary)
+  (let* ((col (current-column))
+        (hdmarker (org-get-at-bol 'org-hd-marker))
+        (buffer (marker-buffer hdmarker))
+        (pos (marker-position hdmarker))
+        (inhibit-read-only t)
+        newhead)
+    (org-with-remote-undo buffer
+      (with-current-buffer buffer
+       (widen)
+       (goto-char pos)
+       (org-show-context 'agenda)
+       (org-priority force-direction)
+       (end-of-line 1)
+       (setq newhead (org-get-heading)))
+      (org-agenda-change-all-lines newhead hdmarker)
+      (org-move-to-column col))))
 
 ;; FIXME: should fix the tags property of the agenda line.
 (defun org-agenda-set-tags (&optional tag onoff)
@@ -9555,7 +9674,7 @@ Called with a universal prefix arg, show the priority 
instead of setting it."
          (buffer (marker-buffer hdmarker))
          (pos (marker-position hdmarker))
          (inhibit-read-only t)
-         newhead)
+         ) ;; newhead
      (org-with-remote-undo buffer
        (with-current-buffer buffer
         (widen)
@@ -9716,7 +9835,12 @@ Called with a universal prefix arg, show the priority 
instead of setting it."
                                  (line-end-position)
                                  '(display nil))
          (org-move-to-column
-          (- (/ (window-width nil t) (window-font-width)) (length stamp)) t)
+           (- (if (fboundp 'window-font-width)
+                  (/ (window-width nil t) (window-font-width))
+                ;; Fall back to pre-9.3.3 behavior on Emacs <25.
+                (window-width))
+              (length stamp))
+           t)
           (add-text-properties
           (1- (point)) (point-at-eol)
           (list 'display (org-add-props stamp nil
@@ -9756,7 +9880,7 @@ ARG is passed through to `org-schedule'."
    #'org-agenda-schedule arg t nil
    (let* ((marker (or (org-get-at-bol 'org-marker)
                      (org-agenda-error)))
-         (type (marker-insertion-type marker))
+         ;; (type (marker-insertion-type marker))
          (buffer (marker-buffer marker))
          (pos (marker-position marker))
          ts)
@@ -9831,9 +9955,9 @@ ARG is passed through to `org-deadline'."
     (org-move-to-column col)
     (org-agenda-unmark-clocking-task)))
 
-(defun org-agenda-clock-cancel (&optional arg)
+(defun org-agenda-clock-cancel (&optional _arg)
   "Cancel the currently running clock."
-  (interactive "P")
+  (interactive) ;; "P"
   (unless (marker-buffer org-clock-marker)
     (user-error "No running clock"))
   (org-with-remote-undo (marker-buffer org-clock-marker)
@@ -10077,7 +10201,7 @@ entries in that Org file."
        (unwind-protect
            (progn
              (fset 'calendar-cursor-to-date
-                   (lambda (&optional error dummy)
+                   (lambda (&optional _error _dummy)
                      (calendar-gregorian-from-absolute
                       (get-text-property point 'day))))
              (call-interactively cmd))
@@ -10092,18 +10216,19 @@ entries in that Org file."
   (let* ((oldf (symbol-function 'calendar-cursor-to-date))
         (point (point))
         (date (calendar-gregorian-from-absolute
-               (get-text-property point 'day)))
-         ;; the following 2 vars are needed in the calendar
-        (displayed-month (car date))
+               (get-text-property point 'day))))
+    ;; the following 2 vars are needed in the calendar
+    (org-dlet
+       ((displayed-month (car date))
         (displayed-year (nth 2 date)))
-    (unwind-protect
-       (progn
-         (fset 'calendar-cursor-to-date
-               (lambda (&optional error dummy)
-                 (calendar-gregorian-from-absolute
-                  (get-text-property point 'day))))
-         (call-interactively cmd))
-      (fset 'calendar-cursor-to-date oldf))))
+      (unwind-protect
+         (progn
+           (fset 'calendar-cursor-to-date
+                 (lambda (&optional _error _dummy)
+                   (calendar-gregorian-from-absolute
+                    (get-text-property point 'day))))
+           (call-interactively cmd))
+       (fset 'calendar-cursor-to-date oldf)))))
 
 (defun org-agenda-phases-of-moon ()
   "Display the phases of the moon for the 3 months around the cursor date."
@@ -10208,7 +10333,7 @@ When ARG is greater than one mark ARG lines."
     (setq arg (count-lines (region-beginning) (region-end)))
     (goto-char (region-beginning))
     (deactivate-mark))
-  (dotimes (i (or arg 1))
+  (dotimes (_ (or arg 1))
     (unless (org-get-at-bol 'org-agenda-diary-link)
       (let* ((m (org-get-at-bol 'org-hd-marker))
             ov)
@@ -10405,7 +10530,7 @@ The prefix arg is passed through to the command if 
possible."
                          (find-buffer-visiting (nth 1 refile-location))
                          (error "This should not happen")))))
 
-          (setq cmd `(lambda () (org-agenda-refile nil ',refile-location t)))
+          (setq cmd (lambda () (org-agenda-refile nil refile-location t)))
           (setq redo-at-end t)))
 
        (?t
@@ -10413,10 +10538,10 @@ The prefix arg is passed through to the command if 
possible."
                       "Todo state: "
                       (with-current-buffer (marker-buffer (car entries))
                         (mapcar #'list org-todo-keywords-1)))))
-          (setq cmd `(lambda ()
-                       (let ((org-inhibit-blocking t)
-                             (org-inhibit-logging 'note))
-                         (org-agenda-todo ,state))))))
+          (setq cmd (lambda ()
+                      (let ((org-inhibit-blocking t)
+                            (org-inhibit-logging 'note))
+                        (org-agenda-todo state))))))
 
        ((and (or ?- ?+) action)
         (let ((tag (completing-read
@@ -10426,9 +10551,9 @@ The prefix arg is passed through to the command if 
possible."
                             (mapcar (lambda (x) (and (stringp (car x)) x))
                                     org-current-tag-alist))))))
           (setq cmd
-                `(lambda ()
-                   (org-agenda-set-tags ,tag
-                                        ,(if (eq action ?+) ''on ''off))))))
+                (lambda ()
+                  (org-agenda-set-tags tag
+                                       (if (eq action ?+) 'on 'off))))))
 
        ((and (or ?s ?d) c)
         (let* ((schedule? (eq c ?s))
@@ -10450,13 +10575,13 @@ The prefix arg is passed through to the command if 
possible."
           ;; depending on the number of marked items.
           (setq cmd
                 (if schedule?
-                    `(lambda ()
-                       (let ((org-log-reschedule
-                              (and org-log-reschedule 'time)))
-                         (org-agenda-schedule arg ,time)))
-                  `(lambda ()
-                     (let ((org-log-redeadline (and org-log-redeadline 'time)))
-                       (org-agenda-deadline arg ,time)))))))
+                    (lambda ()
+                      (let ((org-log-reschedule
+                             (and org-log-reschedule 'time)))
+                        (org-agenda-schedule arg time)))
+                  (lambda ()
+                    (let ((org-log-redeadline (and org-log-redeadline 'time)))
+                      (org-agenda-deadline arg time)))))))
 
        (?S
         (unless (org-agenda-check-type nil 'agenda 'todo)
@@ -10466,29 +10591,29 @@ The prefix arg is passed through to the command if 
possible."
                              (if arg "week" ""))
                      7)))
           (setq cmd
-                `(lambda ()
-                   (let ((distance (1+ (random ,days))))
-                     (when arg
-                       (let ((dist distance)
-                             (day-of-week
-                              (calendar-day-of-week
-                               (calendar-gregorian-from-absolute 
(org-today)))))
-                         (dotimes (i (1+ dist))
-                           (while (member day-of-week org-agenda-weekend-days)
-                             (cl-incf distance)
-                             (cl-incf day-of-week)
-                             (when (= day-of-week 7)
-                               (setq day-of-week 0)))
-                           (cl-incf day-of-week)
-                           (when (= day-of-week 7)
-                             (setq day-of-week 0)))))
-                     ;; Silently fail when try to replan a sexp entry.
-                     (ignore-errors
-                       (let* ((date (calendar-gregorian-from-absolute
-                                     (+ (org-today) distance)))
-                              (time (encode-time 0 0 0 (nth 1 date) (nth 0 
date)
-                                                 (nth 2 date))))
-                         (org-agenda-schedule nil time))))))))
+                (lambda ()
+                  (let ((distance (1+ (random days))))
+                    (when arg
+                      (let ((dist distance)
+                            (day-of-week
+                             (calendar-day-of-week
+                              (calendar-gregorian-from-absolute (org-today)))))
+                        (dotimes (_ (1+ dist))
+                          (while (member day-of-week org-agenda-weekend-days)
+                            (cl-incf distance)
+                            (cl-incf day-of-week)
+                            (when (= day-of-week 7)
+                              (setq day-of-week 0)))
+                          (cl-incf day-of-week)
+                          (when (= day-of-week 7)
+                            (setq day-of-week 0)))))
+                    ;; Silently fail when try to replan a sexp entry.
+                    (ignore-errors
+                      (let* ((date (calendar-gregorian-from-absolute
+                                    (+ (org-today) distance)))
+                             (time (encode-time 0 0 0 (nth 1 date) (nth 0 date)
+                                                (nth 2 date))))
+                        (org-agenda-schedule nil time))))))))
 
        (?f
         (setq cmd
@@ -10496,10 +10621,15 @@ The prefix arg is passed through to the command if 
possible."
                (completing-read "Function: " obarray #'fboundp t nil nil))))
 
        (action
-        (pcase (assoc action org-agenda-bulk-custom-functions)
-          (`(,_ ,f) (setq cmd f) (setq redo-at-end t))
-          (_ (user-error "Invalid bulk action: %c" action)))))
-
+         (setq cmd
+               (pcase (assoc action org-agenda-bulk-custom-functions)
+                 (`(,_ ,fn)
+                  fn)
+                 (`(,_ ,fn ,arg-fn)
+                  (apply #'apply-partially fn (funcall arg-fn)))
+                 (_
+                  (user-error "Invalid bulk action: %c" action))))
+         (setq redo-at-end t)))
       ;; Sort the markers, to make sure that parents are handled
       ;; before children.
       (setq entries (sort entries
@@ -10523,9 +10653,7 @@ The prefix arg is passed through to the command if 
possible."
              (let (org-loop-over-headlines-in-active-region) (funcall cmd))
              ;; `post-command-hook' is not run yet.  We make sure any
              ;; pending log note is processed.
-             (when (or (memq 'org-add-log-note (default-value 
'post-command-hook))
-                       (memq 'org-add-log-note post-command-hook))
-               (org-add-log-note))
+             (when org-log-setup (org-add-log-note))
              (cl-incf processed))))
        (when redo-at-end (org-agenda-redo))
        (unless org-agenda-persistent-marks (org-agenda-bulk-unmark-all))
@@ -10570,7 +10698,7 @@ When the optional argument `backward' is non-nil, move 
backward."
   (let ((inhibit-read-only t) lst line)
     (if (or (not (get-text-property (point) 'txt))
            (save-excursion
-             (dotimes (n arg)
+             (dotimes (_ arg)
                (move-beginning-of-line (if backward 0 2))
                (push (not (get-text-property (point) 'txt)) lst))
              (delq nil lst)))
@@ -10599,7 +10727,7 @@ tag and (if present) the flagging note."
   (interactive)
   (let ((hdmarker (org-get-at-bol 'org-hd-marker))
        (win (selected-window))
-       note heading newhead)
+       note) ;; heading newhead
     (unless hdmarker
       (user-error "No linked entry at point"))
     (if (and (eq this-command last-command)
@@ -10627,11 +10755,11 @@ tag and note")))))
 
 (defun org-agenda-remove-flag (marker)
   "Remove the FLAGGED tag and any flagging note in the entry."
-  (let (newhead)
-    (org-with-point-at marker
-      (org-toggle-tag "FLAGGED" 'off)
-      (org-entry-delete nil "THEFLAGGINGNOTE")
-      (setq newhead (org-get-heading)))
+  (let ((newhead
+         (org-with-point-at marker
+           (org-toggle-tag "FLAGGED" 'off)
+           (org-entry-delete nil "THEFLAGGINGNOTE")
+           (org-get-heading))))
     (org-agenda-change-all-lines newhead marker)
     (message "Entry unflagged")))
 
@@ -10699,7 +10827,7 @@ to override `appt-message-warning-time'."
       (setq entries
             (delq nil
                   (append entries
-                          (apply 'org-agenda-get-day-entries
+                          (apply #'org-agenda-get-day-entries
                                  file today scope)))))
     ;; Map through entries and find if we should filter them out
     (mapc
diff --git a/lisp/org/org-archive.el b/lisp/org/org-archive.el
index 73cd83ebf3..0943869a88 100644
--- a/lisp/org/org-archive.el
+++ b/lisp/org/org-archive.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
diff --git a/lisp/org/org-attach-git.el b/lisp/org/org-attach-git.el
index 2091cbc610..4c6bdc9023 100644
--- a/lisp/org/org-attach-git.el
+++ b/lisp/org/org-attach-git.el
@@ -24,7 +24,7 @@
 ;;; Commentary:
 
 ;; An extension to org-attach.  If `org-attach-id-dir' is initialized
-;; as a Git repository, then org-attach-git will automatically commit
+;; as a Git repository, then `org-attach-git' will automatically commit
 ;; changes when it sees them.  Requires git-annex.
 
 ;;; Code:
@@ -52,9 +52,25 @@ If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If 
nil, never get."
          (const :tag "always get from annex if necessary" t)
          (const :tag "never get from annex" nil)))
 
+(defcustom org-attach-git-dir 'default
+  "Attachment directory with the Git repository to use.
+The default value is to use `org-attach-id-dir'.  When set to
+`individual-repository', then the directory attached to the
+current node, if correctly initialized as a Git repository, will
+be used instead."
+  :group 'org-attach
+  :package-version '(Org . "9.5")
+  :type '(choice
+          (const :tag "Default" default)
+          (const :tag "Individual repository" individual-repository)))
+
 (defun org-attach-git-use-annex ()
   "Return non-nil if git annex can be used."
-  (let ((git-dir (vc-git-root (expand-file-name org-attach-id-dir))))
+  (let ((git-dir (vc-git-root
+                  (cond ((eq org-attach-git-dir 'default)
+                         (expand-file-name org-attach-id-dir))
+                        ((eq org-attach-git-dir 'individual-repository)
+                         (org-attach-dir))))))
     (and org-attach-git-annex-cutoff
          (or (file-exists-p (expand-file-name "annex" git-dir))
              (file-exists-p (expand-file-name ".git/annex" git-dir))))))
@@ -62,7 +78,11 @@ If \\='ask, prompt using `y-or-n-p'.  If t, always get.  If 
nil, never get."
 (defun org-attach-git-annex-get-maybe (path)
   "Call git annex get PATH (via shell) if using git annex.
 Signals an error if the file content is not available and it was not 
retrieved."
-  (let* ((default-directory (expand-file-name org-attach-id-dir))
+  (let* ((default-directory
+           (cond ((eq org-attach-git-dir 'default)
+                  (expand-file-name org-attach-id-dir))
+                 ((eq org-attach-git-dir 'individual-repository)
+                  (org-attach-dir))))
         (path-relative (file-relative-name path)))
     (when (and (org-attach-git-use-annex)
               (not
@@ -86,7 +106,10 @@ This checks for the existence of a \".git\" directory in 
that directory.
 
 Takes an unused optional argument for the sake of being compatible
 with hook `org-attach-after-change-hook'."
-  (let* ((dir (expand-file-name org-attach-id-dir))
+  (let* ((dir (cond ((eq org-attach-git-dir 'default)
+                     (expand-file-name org-attach-id-dir))
+                    ((eq org-attach-git-dir 'individual-repository)
+                     (org-attach-dir))))
         (git-dir (vc-git-root dir))
         (use-annex (org-attach-git-use-annex))
         (changes 0))
@@ -102,7 +125,7 @@ with hook `org-attach-after-change-hook'."
                        org-attach-git-annex-cutoff))
               (call-process "git" nil nil nil "annex" "add" new-or-modified)
             (call-process "git" nil nil nil "add" new-or-modified))
-           (cl-incf changes))
+         (cl-incf changes))
        (dolist (deleted
                 (split-string
                  (shell-command-to-string "git ls-files -z --deleted") "\0" t))
diff --git a/lisp/org/org-attach.el b/lisp/org/org-attach.el
index 46decacca0..75db69c9cc 100644
--- a/lisp/org/org-attach.el
+++ b/lisp/org/org-attach.el
@@ -40,8 +40,11 @@
 (require 'org-id)
 
 (declare-function dired-dwim-target-directory "dired-aux")
+(declare-function dired-get-marked-files "dired" (&optional localp arg filter 
distinguish-one-marked error))
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-type "org-element" (element))
+(declare-function org-inlinetask-goto-beginning "org-inlinetask" ())
+(declare-function org-inlinetask-in-task-p "org-inlinetask" ())
 
 (defgroup org-attach nil
   "Options concerning attachments in Org mode."
@@ -118,7 +121,7 @@ lns   create a symbol link.  Note that this is not supported
 (defcustom org-attach-use-inheritance 'selective
   "Attachment inheritance for the outline.
 
-Enabling inheritance for org-attach implies two things.  First,
+Enabling inheritance for `org-attach' implies two things.  First,
 that attachment links will look through all parent headings until
 it finds the linked attachment.  Second, that running org-attach
 inside a node without attachments will make org-attach operate on
@@ -243,6 +246,17 @@ Each entry in this list is a list of three elements:
                       (function :tag "Command")
                       (string :tag "Docstring"))))
 
+(defcustom org-attach-sync-delete-empty-dir 'query
+  "Determine what to do with an empty attachment directory on sync.
+When set to nil, don't touch the directory.  When set to `query',
+ask the user instead, else remove without asking."
+  :group 'org-attach
+  :package-version '(Org . "9.5")
+  :type '(choice
+         (const :tag "Never delete" nil)
+         (const :tag "Always delete" t)
+         (const :tag "Query the user" query)))
+
 ;;;###autoload
 (defun org-attach ()
   "The dispatcher for attachment commands.
@@ -256,38 +270,45 @@ Shows a list of commands and prompts for another key to 
execute a command."
       (unless marker
        (error "No item in current line")))
     (org-with-point-at marker
-      (org-back-to-heading-or-point-min t)
+      (if (and (featurep 'org-inlinetask)
+              (not (org-inlinetask-in-task-p)))
+         (org-with-limited-levels
+          (org-back-to-heading-or-point-min t))
+        (if (and (featurep 'org-inlinetask)
+                (org-inlinetask-in-task-p))
+            (org-inlinetask-goto-beginning)
+          (org-back-to-heading-or-point-min t)))
       (save-excursion
        (save-window-excursion
          (unless org-attach-expert
            (org-switch-to-buffer-other-window "*Org Attach*")
            (erase-buffer)
            (setq cursor-type nil
-             header-line-format "Use C-v, M-v, C-n or C-p to navigate.")
+                 header-line-format "Use C-v, M-v, C-n or C-p to navigate.")
            (insert
-               (concat "Attachment folder:\n"
-                      (or dir
-                          "Can't find an existing attachment-folder")
-                      (unless (and dir (file-directory-p dir))
-                        "\n(Not yet created)")
-                      "\n\n"
-                      (format "Select an Attachment Command:\n\n%s"
-                              (mapconcat
-                               (lambda (entry)
-                                 (pcase entry
-                                   (`((,key . ,_) ,_ ,docstring)
-                                    (format "%c       %s"
-                                            key
-                                            (replace-regexp-in-string 
"\n\\([\t ]*\\)"
-                                                                      "        
"
-                                                                      docstring
-                                                                      nil nil 
1)))
-                                   (_
-                                    (user-error
-                                     "Invalid `org-attach-commands' item: %S"
-                                     entry))))
-                               org-attach-commands
-                               "\n")))))
+             (concat "Attachment folder:\n"
+                    (or dir
+                        "Can't find an existing attachment-folder")
+                    (unless (and dir (file-directory-p dir))
+                      "\n(Not yet created)")
+                    "\n\n"
+                    (format "Select an Attachment Command:\n\n%s"
+                            (mapconcat
+                             (lambda (entry)
+                               (pcase entry
+                                 (`((,key . ,_) ,_ ,docstring)
+                                  (format "%c       %s"
+                                          key
+                                          (replace-regexp-in-string "\n\\([\t 
]*\\)"
+                                                                    "        "
+                                                                    docstring
+                                                                    nil nil 
1)))
+                                 (_
+                                  (user-error
+                                   "Invalid `org-attach-commands' item: %S"
+                                   entry))))
+                             org-attach-commands
+                             "\n")))))
          (org-fit-window-to-buffer (get-buffer-window "*Org Attach*"))
          (let ((msg (format "Select command: [%s]"
                             (concat (mapcar #'caar org-attach-commands)))))
@@ -365,7 +386,7 @@ If the attachment by some reason cannot be created an error 
will be raised."
     attach-dir))
 
 (defun org-attach-dir-from-id (id  &optional try-all)
-  "Returns a folder path based on `org-attach-id-dir' and ID.
+  "Return a folder path based on `org-attach-id-dir' and ID.
 If TRY-ALL is non-nil, try all id-to-path functions in
 `org-attach-id-to-path-function-list' and return the first path
 that exist in the filesystem, or the first one if none exist.
@@ -426,7 +447,7 @@ Return the directory."
     new))
 
 (defun org-attach-unset-directory ()
-  "Removes DIR node property.
+  "Remove DIR node property.
 If attachment folder is changed due to removal of DIR-property
 ask to move attachments to new location and ask to delete old
 attachment-folder.
@@ -591,14 +612,22 @@ with no prompts."
 
 (defun org-attach-sync ()
   "Synchronize the current outline node with its attachments.
-This can be used after files have been added externally."
+Useful after files have been added/removed externally.  Option
+`org-attach-sync-delete-empty-dir' controls the behavior for
+empty attachment directories."
   (interactive)
   (let ((attach-dir (org-attach-dir)))
-    (when attach-dir
+    (if (not attach-dir)
+        (org-attach-tag 'off)
       (run-hook-with-args 'org-attach-after-change-hook attach-dir)
       (let ((files (org-attach-file-list attach-dir)))
-       (org-attach-tag (not files))))
-    (unless attach-dir (org-attach-tag t))))
+       (org-attach-tag (not files)))
+      (when org-attach-sync-delete-empty-dir
+        (when (and (org-directory-empty-p attach-dir)
+                   (if (eq 'query org-attach-sync-delete-empty-dir)
+                       (yes-or-no-p "Attachment directory is empty.  Delete?")
+                     t))
+          (delete-directory attach-dir))))))
 
 (defun org-attach-file-list (dir)
   "Return a list of files in the attachment directory.
diff --git a/lisp/org/org-capture.el b/lisp/org/org-capture.el
index 7ae8fae3aa..1756b34fc5 100644
--- a/lisp/org/org-capture.el
+++ b/lisp/org/org-capture.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -69,6 +69,7 @@
 (declare-function org-table-goto-line "org-table" (N))
 
 (defvar dired-buffers)
+(defvar crm-separator)
 (defvar org-end-time-was-given)
 (defvar org-keyword-properties)
 (defvar org-remember-default-headline)
@@ -107,7 +108,7 @@
 
 (defun org-capture-upgrade-templates (templates)
   "Update the template list to the new format.
-TEMPLATES is a template list, as in `org-capture-templates'. The
+TEMPLATES is a template list, as in `org-capture-templates'.  The
 new format unifies all the date/week tree targets into one that
 also allows for an optional outline path to specify a target."
   (let ((modified-templates
@@ -246,6 +247,10 @@ properties are:
 
  :jump-to-captured   When set, jump to the captured entry when finished.
 
+ :refile-targets     When exiting capture mode via `org-capture-refile', the
+                     variable `org-refile-targets' will be temporarily bound
+                     to the value of this property.
+
  :empty-lines        Set this to the number of lines that should be inserted
                      before and after the new item.  Default 0, only common
                      other value is 1.
@@ -301,13 +306,15 @@ be replaced with content and expanded:
               current template.
   %(sexp)     Evaluate elisp `(sexp)' and replace it with the results.
               Only placeholders pre-existing within the template, or
-              introduced with %[pathname] are expanded this way.  Since this
-              happens after expanding non-interactive %-escapes, those can
-              be used to fill the expression.
-  %<...>      The result of format-time-string on the ... format specification.
-  %t          Time stamp, date only.  The time stamp is the current time,
-              except when called from agendas with `\\[org-agenda-capture]' or
-              with `org-capture-use-agenda-date' set.
+              introduced with %[pathname] are expanded this way.
+              Since this happens after expanding non-interactive
+              %-escapes, those can be used to fill the expression.
+  %<...>      The result of `format-time-string' on the ... format
+              specification.
+  %t          Time stamp, date only.  The time stamp is the current
+              time, except when called from agendas with
+              `\\[org-agenda-capture]' or with
+              `org-capture-use-agenda-date' set.
   %T          Time stamp as above, with date and time.
   %u, %U      Like the above, but inactive time stamps.
   %i          Initial content, copied from the active region.  If
@@ -317,12 +324,13 @@ be replaced with content and expanded:
   %a          Annotation, normally the link created with `org-store-link'.
   %A          Like %a, but prompt for the description part.
   %l          Like %a, but only insert the literal link.
+  %L          Like %l, but without brackets (the link content itself).
   %c          Current kill ring head.
   %x          Content of the X clipboard.
   %k          Title of currently clocked task.
   %K          Link to currently clocked task.
   %n          User name (taken from the variable `user-full-name').
-  %f          File visited by current buffer when org-capture was called.
+  %f          File visited by current buffer when `org-capture' was called.
   %F          Full path of the file or directory visited by current buffer.
   %:keyword   Specific information for certain link types, see below.
   %^g         Prompt for tags, with completion on tags in target file.
@@ -333,6 +341,8 @@ be replaced with content and expanded:
   %^C         Interactive selection of which kill or clip to use.
   %^L         Like %^C, but insert as link.
   %^{prop}p   Prompt the user for a value for property `prop'.
+              A default value can be specified like this:
+              %^{prop|default}p.
   %^{prompt}  Prompt the user for a string and replace this sequence with it.
               A default value and a completion table can be specified like 
this:
               %^{prompt|default|completion2|completion3|...}.
@@ -363,7 +373,7 @@ calendar                |  %:type %:date
 When you need to insert a literal percent sign in the template,
 you can escape ambiguous cases with a backward slash, e.g., \\%i."
   :group 'org-capture
-  :version "24.1"
+  :package-version '(Org . "9.5")
   :set (lambda (s v) (set s (org-capture-upgrade-templates v)))
   :type
   (let ((file-variants '(choice :tag "Filename       "
@@ -371,78 +381,78 @@ you can escape ambiguous cases with a backward slash, 
e.g., \\%i."
                                (function :tag "Function")
                                (variable :tag "Variable")
                                (sexp :tag "Form"))))
-  `(repeat
-    (choice :value ("" "" entry (file "~/org/notes.org") "")
-           (list :tag "Multikey description"
-                 (string :tag "Keys       ")
-                 (string :tag "Description"))
-           (list :tag "Template entry"
-                 (string :tag "Keys           ")
-                 (string :tag "Description    ")
-                 (choice :tag "Capture Type   " :value entry
-                         (const :tag "Org entry" entry)
-                         (const :tag "Plain list item" item)
-                         (const :tag "Checkbox item" checkitem)
-                         (const :tag "Plain text" plain)
-                         (const :tag "Table line" table-line))
-                 (choice :tag "Target location"
-                         (list :tag "File"
-                               (const :format "" file)
-                               ,file-variants)
-                         (list :tag "ID"
-                               (const :format "" id)
-                               (string :tag "  ID"))
-                         (list :tag "File & Headline"
-                               (const :format "" file+headline)
-                               ,file-variants
-                               (string :tag "  Headline"))
-                         (list :tag "File & Outline path"
-                               (const :format "" file+olp)
-                               ,file-variants
-                               (repeat :tag "Outline path" :inline t
-                                       (string :tag "Headline")))
-                         (list :tag "File & Regexp"
-                               (const :format "" file+regexp)
-                               ,file-variants
-                               (regexp :tag "  Regexp"))
-                         (list :tag "File [ & Outline path ] & Date tree"
-                               (const :format "" file+olp+datetree)
-                               ,file-variants
-                               (option (repeat :tag "Outline path" :inline t
-                                               (string :tag "Headline"))))
-                         (list :tag "File & function"
-                               (const :format "" file+function)
-                               ,file-variants
-                               (sexp :tag "  Function"))
-                         (list :tag "Current clocking task"
-                               (const :format "" clock))
-                         (list :tag "Function"
-                               (const :format "" function)
-                               (sexp :tag "  Function")))
-                 (choice :tag "Template       "
-                         (string)
-                         (list :tag "File"
-                               (const :format "" file)
-                               (file :tag "Template file"))
-                         (list :tag "Function"
-                               (const :format "" function)
-                               (function :tag "Template function")))
-                 (plist :inline t
-                        ;; Give the most common options as checkboxes
-                        :options (((const :format "%v " :prepend) (const t))
-                                  ((const :format "%v " :immediate-finish) 
(const t))
-                                  ((const :format "%v " :jump-to-captured) 
(const t))
-                                  ((const :format "%v " :empty-lines) (const 
1))
-                                  ((const :format "%v " :empty-lines-before) 
(const 1))
-                                  ((const :format "%v " :empty-lines-after) 
(const 1))
-                                  ((const :format "%v " :clock-in) (const t))
-                                  ((const :format "%v " :clock-keep) (const t))
-                                  ((const :format "%v " :clock-resume) (const 
t))
-                                  ((const :format "%v " :time-prompt) (const 
t))
-                                  ((const :format "%v " :tree-type) (const 
week))
-                                  ((const :format "%v " :unnarrowed) (const t))
-                                  ((const :format "%v " :table-line-pos) 
(string))
-                                  ((const :format "%v " :kill-buffer) (const 
t)))))))))
+    `(repeat
+      (choice :value ("" "" entry (file "~/org/notes.org") "")
+             (list :tag "Multikey description"
+                   (string :tag "Keys       ")
+                   (string :tag "Description"))
+             (list :tag "Template entry"
+                   (string :tag "Keys           ")
+                   (string :tag "Description    ")
+                   (choice :tag "Capture Type   " :value entry
+                           (const :tag "Org entry" entry)
+                           (const :tag "Plain list item" item)
+                           (const :tag "Checkbox item" checkitem)
+                           (const :tag "Plain text" plain)
+                           (const :tag "Table line" table-line))
+                   (choice :tag "Target location"
+                           (list :tag "File"
+                                 (const :format "" file)
+                                 ,file-variants)
+                           (list :tag "ID"
+                                 (const :format "" id)
+                                 (string :tag "  ID"))
+                           (list :tag "File & Headline"
+                                 (const :format "" file+headline)
+                                 ,file-variants
+                                 (string :tag "  Headline"))
+                           (list :tag "File & Outline path"
+                                 (const :format "" file+olp)
+                                 ,file-variants
+                                 (repeat :tag "Outline path" :inline t
+                                         (string :tag "Headline")))
+                           (list :tag "File & Regexp"
+                                 (const :format "" file+regexp)
+                                 ,file-variants
+                                 (regexp :tag "  Regexp"))
+                           (list :tag "File [ & Outline path ] & Date tree"
+                                 (const :format "" file+olp+datetree)
+                                 ,file-variants
+                                 (option (repeat :tag "Outline path" :inline t
+                                                 (string :tag "Headline"))))
+                           (list :tag "File & function"
+                                 (const :format "" file+function)
+                                 ,file-variants
+                                 (sexp :tag "  Function"))
+                           (list :tag "Current clocking task"
+                                 (const :format "" clock))
+                           (list :tag "Function"
+                                 (const :format "" function)
+                                 (sexp :tag "  Function")))
+                   (choice :tag "Template       "
+                           (string)
+                           (list :tag "File"
+                                 (const :format "" file)
+                                 (file :tag "Template file"))
+                           (list :tag "Function"
+                                 (const :format "" function)
+                                 (function :tag "Template function")))
+                   (plist :inline t
+                          ;; Give the most common options as checkboxes
+                          :options (((const :format "%v " :prepend) (const t))
+                                    ((const :format "%v " :immediate-finish) 
(const t))
+                                    ((const :format "%v " :jump-to-captured) 
(const t))
+                                    ((const :format "%v " :empty-lines) (const 
1))
+                                    ((const :format "%v " :empty-lines-before) 
(const 1))
+                                    ((const :format "%v " :empty-lines-after) 
(const 1))
+                                    ((const :format "%v " :clock-in) (const t))
+                                    ((const :format "%v " :clock-keep) (const 
t))
+                                    ((const :format "%v " :clock-resume) 
(const t))
+                                    ((const :format "%v " :time-prompt) (const 
t))
+                                    ((const :format "%v " :tree-type) (const 
week))
+                                    ((const :format "%v " :unnarrowed) (const 
t))
+                                    ((const :format "%v " :table-line-pos) 
(string))
+                                    ((const :format "%v " :kill-buffer) (const 
t)))))))))
 
 (defcustom org-capture-before-finalize-hook nil
   "Hook that is run right before a capture process is finalized.
@@ -467,8 +477,7 @@ The capture buffer is current and still narrowed."
   :type 'hook)
 
 (defcustom org-capture-bookmark t
-  "When non-nil, add a bookmark pointing at the last stored
-position when capturing."
+  "When non-nil, add bookmark pointing at the last stored position when 
capturing."
   :group 'org-capture
   :version "24.3"
   :type 'boolean)
@@ -488,19 +497,19 @@ is copied to this variable, which is local in the 
indirect buffer.")
 
 (defvar org-capture-clock-keep nil
   "Local variable to store the value of the :clock-keep parameter.
-This is needed in case org-capture-finalize is called interactively.")
+This is needed in case `org-capture-finalize' is called interactively.")
 
-(defun org-capture-put (&rest stuff)
-  "Add properties to the capture property list `org-capture-plist'."
-  (while stuff
+(defun org-capture-put (&rest elements)
+  "Add ELEMENTS to the capture property list `org-capture-plist'."
+  (while elements
     (setq org-capture-plist (plist-put org-capture-plist
-                                      (pop stuff) (pop stuff)))))
-(defun org-capture-get (prop &optional local)
-  "Get properties from the capture property list `org-capture-plist'.
+                                      (pop elements) (pop elements)))))
+(defun org-capture-get (property &optional local)
+  "Get PROPERTY from the capture property list `org-capture-plist'.
 When LOCAL is set, use the local variable `org-capture-current-plist',
 this is necessary after initialization of the capture process,
 to avoid conflicts with other active capture processes."
-  (plist-get (if local org-capture-current-plist org-capture-plist) prop))
+  (plist-get (if local org-capture-current-plist org-capture-plist) property))
 
 ;;; The minor mode
 
@@ -579,17 +588,17 @@ to avoid duplicates.)"
                       (string :tag "        Capture key")
                       (string :tag "Replace by template")
                       (repeat :tag "Available when"
-                             (choice
-                              (cons :tag "Condition"
-                                    (choice
-                                     (const :tag "In file" in-file)
-                                     (const :tag "Not in file" not-in-file)
-                                     (const :tag "In buffer" in-buffer)
-                                     (const :tag "Not in buffer" not-in-buffer)
-                                     (const :tag "In mode" in-mode)
-                                     (const :tag "Not in mode" not-in-mode))
-                                    (regexp))
-                              (function :tag "Custom function"))))))
+                              (choice
+                               (cons :tag "Condition"
+                                     (choice
+                                      (const :tag "In file" in-file)
+                                      (const :tag "Not in file" not-in-file)
+                                      (const :tag "In buffer" in-buffer)
+                                      (const :tag "Not in buffer" 
not-in-buffer)
+                                      (const :tag "In mode" in-mode)
+                                      (const :tag "Not in mode" not-in-mode))
+                                     (regexp))
+                               (function :tag "Custom function"))))))
 
 (defcustom org-capture-use-agenda-date nil
   "Non-nil means use the date at point when capturing from agendas.
@@ -882,7 +891,8 @@ for `entry'-type templates"))
         (pos (make-marker))
         (org-capture-is-refiling t)
         (kill-buffer (org-capture-get :kill-buffer 'local))
-        (jump-to-captured (org-capture-get :jump-to-captured 'local)))
+        (jump-to-captured (org-capture-get :jump-to-captured 'local))
+        (refile-targets (org-capture-get :refile-targets 'local)))
     ;; Since `org-capture-finalize' may alter buffer contents (e.g.,
     ;; empty lines) around entry, use a marker to refer to the
     ;; headline to be refiled.  Place the marker in the base buffer,
@@ -892,11 +902,12 @@ for `entry'-type templates"))
     ;; early.  We want to wait for the refiling to be over, so we
     ;; control when the latter function is called.
     (org-capture-put :kill-buffer nil :jump-to-captured nil)
-    (org-capture-finalize)
-    (save-window-excursion
-      (with-current-buffer base
-       (org-with-point-at pos
-         (call-interactively 'org-refile))))
+    (let ((org-refile-targets (or refile-targets org-refile-targets)))
+      (org-capture-finalize)
+      (save-window-excursion
+        (with-current-buffer base
+         (org-with-point-at pos
+           (call-interactively 'org-refile)))))
     (when kill-buffer
       (with-current-buffer base (save-buffer))
       (kill-buffer base))
@@ -916,7 +927,7 @@ for `entry'-type templates"))
   (interactive)
   (org-goto-marker-or-bmk org-capture-last-stored-marker
                          (plist-get org-bookmark-names-plist
-                                :last-capture))
+                                    :last-capture))
   (message "This is the last note stored by a capture process"))
 
 ;;; Supporting functions for handling the process
@@ -1025,28 +1036,23 @@ Store them in the capture property list."
               (time-to-days org-overriding-default-time))
              ((or (org-capture-get :time-prompt)
                   (equal current-prefix-arg 1))
-              ;; Prompt for date.
-              (let ((prompt-time (org-read-date
-                                  nil t nil "Date for tree entry:")))
+               ;; Prompt for date.  Bind `org-end-time-was-given' so
+               ;; that `org-read-date-analyze' handles the time range
+               ;; case and returns `prompt-time' with the start value.
+               (let* ((org-time-was-given nil)
+                      (org-end-time-was-given nil)
+                      (prompt-time (org-read-date
+                                   nil t nil "Date for tree entry:")))
                 (org-capture-put
                  :default-time
-                 (cond ((and (or (not (boundp 'org-time-was-given))
-                                 (not org-time-was-given))
-                             (not (= (time-to-days prompt-time) (org-today))))
-                        ;; Use 00:00 when no time is given for another
-                        ;; date than today?
-                        (apply #'encode-time 0 0
-                               org-extend-today-until
-                               (cl-cdddr (decode-time prompt-time))))
-                       ((string-match "\\([^ ]+\\)-[^ ]+[ ]+\\(.*\\)"
-                                      org-read-date-final-answer)
-                        ;; Replace any time range by its start.
-                        (apply #'encode-time
-                               (org-read-date-analyze
-                                (replace-match "\\1 \\2" nil nil
-                                               org-read-date-final-answer)
-                                prompt-time (decode-time prompt-time))))
-                       (t prompt-time)))
+                  (if (or org-time-was-given
+                          (= (time-to-days prompt-time) (org-today)))
+                      prompt-time
+                    ;; Use 00:00 when no time is given for another
+                    ;; date than today?
+                    (apply #'encode-time 0 0
+                           org-extend-today-until
+                           (cl-cdddr (decode-time prompt-time)))))
                 (time-to-days prompt-time)))
              (t
               ;; Current date, possibly corrected for late night
@@ -1115,7 +1121,7 @@ FILE is a generalized file location, as handled by
 
 (defun org-capture-place-template (&optional inhibit-wconf-store)
   "Insert the template at the target location, and display the buffer.
-When `inhibit-wconf-store', don't store the window configuration, as it
+When INHIBIT-WCONF-STORE is non-nil, don't store the window configuration, as 
it
 may have been stored before."
   (unless inhibit-wconf-store
     (org-capture-put :return-to-wconf (current-window-configuration)))
@@ -1410,21 +1416,21 @@ Of course, if exact position has been required, just 
put it there."
        (org-capture--position-cursor beg end)))))
 
 (defun org-capture-mark-kill-region (beg end)
-  "Mark the region that will have to be killed when aborting capture."
+  "Mark region between BEG and END to be killed on aborted capture."
   (let ((m1 (copy-marker beg))
        (m2 (copy-marker end t)))
     (org-capture-put :begin-marker m1)
     (org-capture-put :end-marker m2)))
 
-(defun org-capture-position-for-last-stored (where)
-  "Memorize the position that should later become the position of last 
capture."
+(defun org-capture-position-for-last-stored (position)
+  "Put POSITION on `org-capture-plist' for future use as `last capture`."
   (cond
-   ((integerp where)
+   ((integerp position)
     (org-capture-put :position-for-last-stored
-                    (move-marker (make-marker) where
+                    (move-marker (make-marker) position
                                  (or (buffer-base-buffer (current-buffer))
                                      (current-buffer)))))
-   ((eq where 'table-line)
+   ((eq position 'table-line)
     (org-capture-put :position-for-last-stored
                     (list 'table-line
                           (org-table-current-dline))))
@@ -1451,7 +1457,8 @@ Of course, if exact position has been required, just put 
it there."
        (move-marker org-capture-last-stored-marker (point))))))
 
 (defun org-capture-narrow (beg end)
-  "Narrow, unless configuration says not to narrow."
+  "Possibly narrow to region between BEG and END.
+If configuration contains non-nil :unnarrowed property, do not narrow."
   (unless (org-capture-get :unnarrowed)
     (narrow-to-region beg end)))
 
@@ -1464,8 +1471,9 @@ of the template."
     (replace-match "")))
 
 (defun org-capture-empty-lines-before (&optional n)
-  "Set the correct number of empty lines before the insertion point.
-Point will be after the empty lines, so insertion can directly be done."
+  "Insert N empty lines before the insertion point.
+Point will be after the empty lines, so insertion can directly be done.
+If N is nil, :empty-lines-before or :empty-lines are considered."
   (setq n (or n (org-capture-get :empty-lines-before)
              (org-capture-get :empty-lines) 0))
   (let ((pos (point)))
@@ -1475,7 +1483,8 @@ Point will be after the empty lines, so insertion can 
directly be done."
 
 (defun org-capture-empty-lines-after (&optional n)
   "Set the correct number of empty lines after the inserted string.
-Point will remain at the first line after the inserted text."
+Point will remain at the first line after the inserted text.
+If N is nil, :empty-lines-after or :empty-lines are considered."
   (setq n (or n (org-capture-get :empty-lines-after)
              (org-capture-get :empty-lines) 0))
   (org-back-over-empty-lines)
@@ -1487,7 +1496,7 @@ Point will remain at the first line after the inserted 
text."
 (defvar org-clock-marker) ; Defined in org.el
 
 (defun org-capture-set-plist (entry)
-  "Initialize the property list from the template definition."
+  "Initialize the property list for ENTRY from the template definition."
   (setq org-capture-plist (copy-sequence (nthcdr 5 entry)))
   (org-capture-put :key (car entry) :description (nth 1 entry)
                   :target (nth 3 entry))
@@ -1504,7 +1513,7 @@ Point will remain at the first line after the inserted 
text."
 
 (defun org-capture-goto-target (&optional template-key)
   "Go to the target location of a capture template.
-The user is queried for the template."
+If TEMPLATE-KEY is nil, the user is queried for the template."
   (interactive)
   (let ((entry (org-capture-select-template template-key)))
     (unless entry (error "No capture template selected"))
@@ -1514,7 +1523,7 @@ The user is queried for the template."
     (goto-char (org-capture-get :pos))))
 
 (defun org-capture-get-indirect-buffer (&optional buffer prefix)
-  "Make an indirect buffer for a capture process.
+  "Make an indirect BUFFER for a capture process.
 Use PREFIX as a prefix for the name of the indirect buffer."
   (setq buffer (or buffer (current-buffer)))
   (let ((n 1) (base (buffer-name buffer)) bname)
@@ -1556,8 +1565,10 @@ Lisp programs can force the template by setting KEYS to 
a string."
   "List various clipboards values.")
 
 (defun org-capture-fill-template (&optional template initial annotation)
-  "Fill a template and return the filled template as a string.
-The template may still contain \"%?\" for cursor positioning."
+  "Fill a TEMPLATE and return the filled template as a string.
+The template may still contain \"%?\" for cursor positioning.
+INITIAL content and/or ANNOTATION may be specified, but will be overridden
+by their respective `org-store-link-plist' properties if present."
   (let* ((template (or template (org-capture-get :template)))
         (buffer (org-capture-get :buffer))
         (file (buffer-file-name (or (buffer-base-buffer buffer) buffer)))
@@ -1595,6 +1606,9 @@ The template may still contain \"%?\" for cursor 
positioning."
         (v-l (if (and v-a (string-match l-re v-a))
                  (replace-match "[[\\1]]" nil nil v-a)
                v-a))
+        (v-L (if (and v-a (string-match l-re v-a))
+                 (replace-match "\\1" nil nil v-a)
+               v-a))
         (v-n user-full-name)
         (v-k (if (marker-buffer org-clock-marker)
                  (org-no-properties org-clock-heading)
@@ -1647,7 +1661,7 @@ The template may still contain \"%?\" for cursor 
positioning."
       ;; Mark %() embedded elisp for later evaluation.
       (org-capture-expand-embedded-elisp 'mark)
       ;; Expand non-interactive templates.
-      (let ((regexp 
"%\\(:[-A-Za-z]+\\|<\\([^>\n]+\\)>\\|[aAcfFikKlntTuUx]\\)"))
+      (let ((regexp 
"%\\(:[-A-Za-z]+\\|<\\([^>\n]+\\)>\\|[aAcfFikKlLntTuUx]\\)"))
        (save-excursion
          (while (re-search-forward regexp nil t)
            ;; `org-capture-escaped-%' may modify buffer and cripple
@@ -1684,6 +1698,7 @@ The template may still contain \"%?\" for cursor 
positioning."
                          (?k v-k)
                          (?K v-K)
                          (?l v-l)
+                         (?L v-L)
                          (?n v-n)
                          (?t v-t)
                          (?T v-T)
@@ -1731,12 +1746,11 @@ The template may still contain \"%?\" for cursor 
positioning."
                            (org-add-colon-after-tag-completion t)
                            (ins (mapconcat
                                  #'identity
-                                 (org-split-string
-                                  (completing-read
-                                   (if prompt (concat prompt ": ") "Tags: ")
-                                   'org-tags-completion-function nil nil nil
-                                   'org-tags-history)
-                                  "[^[:alnum:]_@#%]+")
+                                 (let ((crm-separator "[ \t]*:[ \t]*"))
+                                    (completing-read-multiple
+                                    (if prompt (concat prompt ": ") "Tags: ")
+                                    org-last-tags-completion-table nil nil nil
+                                    'org-tags-history))
                                  ":")))
                       (when (org-string-nw-p ins)
                         (unless (eq (char-before) ?:) (insert ":"))
@@ -1785,7 +1799,8 @@ The template may still contain \"%?\" for cursor 
positioning."
                                           (setq l (org-up-heading-safe)))
                                         (if l (point-marker)
                                           (point-min-marker)))))))
-                           (value (org-read-property-value prompt pom)))
+                           (value
+                            (org-read-property-value prompt pom default)))
                       (org-set-property prompt value)))
                    ((or "t" "T" "u" "U")
                     ;; These are the date/time related ones.
@@ -1800,10 +1815,13 @@ The template may still contain \"%?\" for cursor 
positioning."
                     ;; Load history list for current prompt.
                     (setq org-capture--prompt-history
                           (gethash prompt org-capture--prompt-history-table))
-                    (push (org-completing-read
-                           (concat (or prompt "Enter string")
-                                   (and default (format " [%s]" default))
-                                   ": ")
+                     (push (org-completing-read
+                            ;; `format-prompt' is new in Emacs 28.1.
+                            (if (fboundp 'format-prompt)
+                                (format-prompt (or prompt "Enter string") 
default)
+                              (concat (or prompt "Enter string")
+                                      (and default (format " [%s]" default))
+                                      ": "))
                            completions
                            nil nil nil 'org-capture--prompt-history default)
                           strings)
@@ -1840,7 +1858,7 @@ The template may still contain \"%?\" for cursor 
positioning."
 
 (defun org-capture-escaped-% ()
   "Non-nil if % was escaped.
-If yes, unescape it now.  Assume match-data contains the
+If yes, unescape it now.  Assume `match-data' contains the
 placeholder to check."
   (save-excursion
     (goto-char (match-beginning 0))
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index 1283970bc2..12a4c2b7b7 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -85,7 +85,7 @@ function `org-clock-into-drawer' instead."
          (string :tag "Into Drawer named...")))
 
 (defun org-clock-into-drawer ()
-  "Value of `org-clock-into-drawer'. but let properties overrule.
+  "Value of `org-clock-into-drawer', but let properties overrule.
 
 If the current entry has or inherits a CLOCK_INTO_DRAWER
 property, it will be used instead of the default value.
@@ -219,8 +219,7 @@ Emacs initialization file."
          (const :tag "Clock and history" t)
          (const :tag "No persistence" nil)))
 
-(defcustom org-clock-persist-file (convert-standard-filename
-                                  (concat user-emacs-directory 
"org-clock-save.el"))
+(defcustom org-clock-persist-file (locate-user-emacs-file "org-clock-save.el")
   "File to save clock data to."
   :group 'org-clock
   :type 'string)
@@ -438,12 +437,11 @@ specifications than `frame-title-format', which see."
 (defcustom org-clock-x11idle-program-name "x11idle"
   "Name of the program which prints X11 idle time in milliseconds.
 
-You can find x11idle.c in the contrib/scripts directory of the
-Org git distribution. Or, you can do:
+you can do \"~$ sudo apt-get install xprintidle\" if you are using
+a Debian-based distribution.
 
-    sudo apt-get install xprintidle
-
-if you are using Debian."
+Alternatively, can find x11idle.c in the org-contrib repository at
+https://git.sr.ht/~bzg/org-contrib";
   :group 'org-clock
   :version "24.4"
   :package-version '(Org . "8.0")
@@ -485,6 +483,17 @@ is added to the user configuration."
          (integer :tag "Clock out after Emacs is idle for X seconds")
          (const :tag "Never auto clock out" nil)))
 
+(defcustom org-clock-ask-before-exiting t
+  "If non-nil, ask if the user wants to clock out before exiting Emacs.
+This variable only has effect if set with \\[customize]."
+  :set (lambda (symbol value)
+         (if value
+             (add-hook 'kill-emacs-query-functions 
#'org-clock-kill-emacs-query)
+           (remove-hook 'kill-emacs-query-functions 
#'org-clock-kill-emacs-query))
+         (set symbol value))
+  :type 'boolean
+  :package-version '(Org . "9.5"))
+
 (defvar org-clock-in-prepare-hook nil
   "Hook run when preparing the clock.
 This hook is run before anything happens to the task that
@@ -503,9 +512,9 @@ to add an effort property.")
   "Has the clock been used during the current Emacs session?")
 
 (defvar org-clock-stored-history nil
-  "Clock history, populated by `org-clock-load'")
+  "Clock history, populated by `org-clock-load'.")
 (defvar org-clock-stored-resume-clock nil
-  "Clock to resume, saved by `org-clock-load'")
+  "Clock to resume, saved by `org-clock-load'.")
 
 ;;; The clock for measuring work time.
 
@@ -607,10 +616,6 @@ cannot be translated."
          ((stringp drawer) drawer)
          (t nil))))
 
-(defun org-clocking-buffer ()
-  "Return the clocking buffer if we are currently clocking a task or nil."
-  (marker-buffer org-clock-marker))
-
 (defun org-clocking-p ()
   "Return t when clocking a task."
   (not (equal (org-clocking-buffer) nil)))
@@ -677,19 +682,19 @@ pointing to it."
     (let (cat task heading prefix)
       (with-current-buffer (org-base-buffer (marker-buffer marker))
        (org-with-wide-buffer
-         (ignore-errors
-           (goto-char marker)
-           (setq cat (org-get-category)
-                 heading (org-get-heading 'notags)
-                 prefix (save-excursion
-                          (org-back-to-heading t)
-                          (looking-at org-outline-regexp)
-                          (match-string 0))
-                 task (substring
-                       (org-fontify-like-in-org-mode
-                        (concat prefix heading)
-                        org-odd-levels-only)
-                       (length prefix))))))
+        (ignore-errors
+          (goto-char marker)
+          (setq cat (org-get-category)
+                heading (org-get-heading 'notags)
+                prefix (save-excursion
+                         (org-back-to-heading t)
+                         (looking-at org-outline-regexp)
+                         (match-string 0))
+                task (substring
+                      (org-fontify-like-in-org-mode
+                       (concat prefix heading)
+                       org-odd-levels-only)
+                      (length prefix))))))
       (when (and cat task)
        (insert (format "[%c] %-12s  %s\n" i cat task))
        (cons i marker)))))
@@ -853,6 +858,10 @@ use libnotify if available, or fall back on a message."
            org-show-notification-timeout
            nil
            (lambda () (w32-notification-close id)))))
+        ((fboundp 'ns-do-applescript)
+         (ns-do-applescript
+          (format "display notification \"%s\" with title \"Org mode 
notification\""
+                  (replace-regexp-in-string "\"" "#" notification))))
        ((fboundp 'notifications-notify)
         (notifications-notify
          :title "Org mode message"
@@ -1162,13 +1171,12 @@ If `only-dangling-p' is non-nil, only ask to resolve 
dangling
                  (org-clock-resolve
                   clock
                   (or prompt-fn
-                      (function
-                       (lambda (clock)
-                         (format
-                          "Dangling clock started %d mins ago"
-                          (floor (org-time-convert-to-integer
-                                   (org-time-since (cdr clock)))
-                                  60)))))
+                      (lambda (clock)
+                        (format
+                         "Dangling clock started %d mins ago"
+                         (floor (org-time-convert-to-integer
+                                 (org-time-since (cdr clock)))
+                                60))))
                   (or last-valid
                       (cdr clock)))))))))))
 
@@ -1367,7 +1375,7 @@ the default behavior."
                        (end-of-line 0)
                        (org-in-item-p)))
             (beginning-of-line 1)
-            (indent-line-to (- (current-indentation) 2)))
+            (indent-line-to (max 0 (- (current-indentation) 2))))
           (insert org-clock-string " ")
           (setq org-clock-effort (org-entry-get (point) org-effort-property))
           (setq org-clock-total-time (org-clock-sum-current-item
@@ -1671,17 +1679,13 @@ to, overriding the existing value of 
`org-clock-out-switch-to-state'."
          (insert " => " (format "%2d:%02d" h m))
          (move-marker org-clock-marker nil)
          (move-marker org-clock-hd-marker nil)
-         ;; Possibly remove zero time clocks.  However, do not add
-         ;; a note associated to the CLOCK line in this case.
-         (cond ((and org-clock-out-remove-zero-time-clocks
-                     (= 0 h m))
-                (setq remove t)
-                (delete-region (line-beginning-position)
-                               (line-beginning-position 2)))
-               (org-log-note-clock-out
-                (org-add-log-setup
-                 'clock-out nil nil nil
-                 (concat "# Task: " (org-get-heading t) "\n\n"))))
+         ;; Possibly remove zero time clocks.
+          (when (and org-clock-out-remove-zero-time-clocks
+                    (= 0 h m))
+            (setq remove t)
+           (delete-region (line-beginning-position)
+                          (line-beginning-position 2)))
+          (org-clock-remove-empty-clock-drawer)
          (when org-clock-mode-line-timer
            (cancel-timer org-clock-mode-line-timer)
            (setq org-clock-mode-line-timer nil))
@@ -1712,11 +1716,14 @@ to, overriding the existing value of 
`org-clock-out-switch-to-state'."
                       "Clock stopped at %s after %s => LINE REMOVED"
                     "Clock stopped at %s after %s")
                   te (org-duration-from-minutes (+ (* 60 h) m)))
-         (run-hooks 'org-clock-out-hook)
-         (unless (org-clocking-p)
-           (setq org-clock-current-task nil)))))))
-
-(add-hook 'org-clock-out-hook #'org-clock-remove-empty-clock-drawer)
+          (unless (org-clocking-p)
+           (setq org-clock-current-task nil))
+          (run-hooks 'org-clock-out-hook)
+          ;; Add a note, but only if we didn't remove the clock line.
+          (when (and org-log-note-clock-out (not remove))
+            (org-add-log-setup
+            'clock-out nil nil nil
+            (concat "# Task: " (org-get-heading t) "\n\n"))))))))
 
 (defun org-clock-remove-empty-clock-drawer ()
   "Remove empty clock drawers in current subtree."
@@ -2696,7 +2703,18 @@ from the dynamic block definition."
             (format (concat "| %s %s | %s%s%s"
                             (format org-clock-file-time-cell-format
                                     (org-clock--translate "File time" lang))
-                            " | *%s*|\n")
+
+                            ;; The file-time rollup value goes in the first 
time
+                            ;; column (of which there is always at least 
one)...
+                            " | *%s*|"
+                            ;; ...and the remaining file time cols (if any) 
are blank.
+                            (make-string (max 0 (1- time-columns)) ?|)
+
+                            ;; Optionally show the percentage contribution of 
"this"
+                            ;; file time to the total time.
+                            (if (eq formula '%) " %s |" "")
+                            "\n")
+
                     (file-name-nondirectory file-name)
                     (if level?    "| " "") ;level column, maybe
                     (if timestamp "| " "") ;timestamp column, maybe
@@ -2704,7 +2722,12 @@ from the dynamic block definition."
                     (if properties         ;properties columns, maybe
                         (make-string (length properties) ?|)
                       "")
-                    (org-duration-from-minutes file-time)))) ;time
+                    (org-duration-from-minutes file-time) ;time
+
+                    (cond ((not (eq formula '%)) "")      ;time percentage, 
maybe
+                          ((or (not total-time) (= total-time 0)) "0.0")
+                          (t
+                           (format "%.1f" (* 100 (/ file-time (float 
total-time)))))))))
 
          ;; Get the list of node entries and iterate over it
          (when (> maxlevel 0)
@@ -2732,13 +2755,13 @@ from the dynamic block definition."
                 (if timestamp (concat ts "|") "")   ;timestamp, maybe
                 (if tags (concat (mapconcat #'identity tgs ", ") "|") "")   
;tags, maybe
                 (if properties         ;properties columns, maybe
-                    (concat (mapconcat (lambda (p) (or (cdr (assoc p props)) 
""))
-                                       properties
-                                       "|")
-                            "|")
+                  (concat (mapconcat (lambda (p) (or (cdr (assoc p props)) ""))
+                                     properties
+                                     "|")
+                          "|")
                   "")
                 (if indent             ;indentation
-                    (org-clocktable-indent-string level)
+                  (org-clocktable-indent-string level)
                   "")
                 (format-field headline)
                 ;; Empty fields for higher levels.
@@ -2746,7 +2769,7 @@ from the dynamic block definition."
                 (format-field (org-duration-from-minutes time))
                 (make-string (max 0 (- time-columns level)) ?|)
                 (if (eq formula '%)
-                    (format "%.1f |" (* 100 (/ time (float total-time))))
+                  (format "%.1f |" (* 100 (/ time (float total-time))))
                   "")
                 "\n")))))))
     (delete-char -1)
@@ -3101,6 +3124,17 @@ The details of what will be saved are regulated by the 
variable
               (when (org-invisible-p) (org-show-context))))))
        (_ nil)))))
 
+(defun org-clock-kill-emacs-query ()
+  "Query user when killing Emacs.
+This function is added to `kill-emacs-query-functions'."
+  (let ((buf (org-clocking-buffer)))
+    (when (and buf (yes-or-no-p "Clock out and save? "))
+      (with-current-buffer buf
+        (org-clock-out)
+        (save-buffer))))
+  ;; Unconditionally return t for `kill-emacs-query-functions'.
+  t)
+
 ;; Suggested bindings
 (org-defkey org-mode-map "\C-c\C-x\C-e" 'org-clock-modify-effort-estimate)
 
diff --git a/lisp/org/org-colview.el b/lisp/org/org-colview.el
index 2f03906440..9794382d8a 100644
--- a/lisp/org/org-colview.el
+++ b/lisp/org/org-colview.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -213,7 +213,7 @@ See `org-columns-summary-types' for details.")
              (lambda () (interactive)
                (org-columns-next-allowed-value nil i))))
 
-(easy-menu-define org-columns-menu org-columns-map "Org Column Menu"
+(easy-menu-define org-columns-menu org-columns-map "Org Column Menu."
   '("Column"
     ["Edit property" org-columns-edit-value t]
     ["Next allowed value" org-columns-next-allowed-value t]
@@ -836,12 +836,11 @@ Also sets `org-columns-top-level-marker' to the new 
position."
 (defun org-columns (&optional global columns-fmt-string)
   "Turn on column view on an Org mode file.
 
-Column view applies to the whole buffer if point is before the
-first headline.  Otherwise, it applies to the first ancestor
-setting \"COLUMNS\" property.  If there is none, it defaults to
-the current headline.  With a `\\[universal-argument]' prefix \
-argument, turn on column
-view for the whole buffer unconditionally.
+Column view applies to the whole buffer if point is before the first
+headline.  Otherwise, it applies to the first ancestor setting
+\"COLUMNS\" property.  If there is none, it defaults to the current
+headline.  With a `\\[universal-argument]' prefix \ argument, GLOBAL,
+turn on column view for the whole buffer unconditionally.
 
 When COLUMNS-FMT-STRING is non-nil, use it as the column format."
   (interactive "P")
@@ -867,9 +866,8 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column 
format."
        (let ((cache
               ;; Collect contents of columns ahead of time so as to
               ;; compute their maximum width.
-              (org-map-entries
-               (lambda () (cons (point) (org-columns--collect-values)))
-               nil nil (and org-columns-skip-archived-trees 'archive))))
+               (org-scan-tags
+               (lambda () (cons (point) (org-columns--collect-values))) t 
org--matcher-tags-todo-only)))
          (when cache
            (org-columns--set-widths cache)
            (org-columns--display-here-title)
@@ -879,7 +877,8 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column 
format."
            (unless (local-variable-p 'org-colview-initial-truncate-line-value)
              (setq-local org-colview-initial-truncate-line-value
                          truncate-lines))
-           (setq truncate-lines t)
+            (if (not global-visual-line-mode)
+                (setq truncate-lines t))
            (dolist (entry cache)
              (goto-char (car entry))
              (org-columns--display-here (cdr entry)))))))))
@@ -1165,7 +1164,11 @@ properties drawers."
         (last-level lmax)
         (property (car spec))
         (printf (nth 4 spec))
-        (operator (nth 3 spec))
+         ;; Special properties cannot be collected nor summarized, as
+         ;; they have their own way to be computed.  Therefore, ignore
+         ;; any operator attached to them.
+        (operator (and (not (member property org-special-properties))
+                        (nth 3 spec)))
         (collect (and operator (org-columns--collect operator)))
         (summarize (and operator (org-columns--summarize operator))))
     (org-with-wide-buffer
@@ -1269,7 +1272,7 @@ When PRINTF is non-nil, use it to format the result."
   "Summarize CHECK-BOXES with a check-box cookie."
   (format "[%d/%d]"
          (cl-count-if (lambda (b) (or (equal b "[X]")
-                                  (string-match-p "\\[\\([1-9]\\)/\\1\\]" b)))
+                                      (string-match-p "\\[\\([1-9]\\)/\\1\\]" 
b)))
                       check-boxes)
          (length check-boxes)))
 
@@ -1395,8 +1398,9 @@ other rows.  Each row is a list of fields, as strings, or
                                  (org-get-tags))))
             (push (cons (org-reduced-level (org-current-level)) (nreverse row))
                   table)))))
-     (or (and maxlevel (format "LEVEL<=%d" maxlevel))
-        (and match match))
+     (if match
+         (concat match (and maxlevel (format "+LEVEL<=%d" maxlevel)))
+       (and maxlevel (format "LEVEL<=%d" maxlevel)))
      (and local 'tree)
      'archive 'comment)
     (org-columns-quit)
@@ -1691,7 +1695,7 @@ This will add overlays to the date lines, to show the 
summary for each day."
                               (delq nil
                                     (mapcar
                                      (lambda (e) (org-string-nw-p
-                                             (nth 1 (assoc spec e))))
+                                                  (nth 1 (assoc spec e))))
                                      entries)))
                              (final (if values
                                         (funcall summarize values printf)
diff --git a/lisp/org/org-compat.el b/lisp/org/org-compat.el
index 7f97ac9c2a..d230ee2b11 100644
--- a/lisp/org/org-compat.el
+++ b/lisp/org/org-compat.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -72,6 +72,16 @@
 (defvar org-table1-hline-regexp)
 
 
+;;; Emacs < 28.1 compatibility
+
+(if (fboundp 'directory-empty-p)
+    (defalias 'org-directory-empty-p #'directory-empty-p)
+  (defun org-directory-empty-p (dir)
+    "Return t if DIR names an existing directory containing no other files."
+    (and (file-directory-p dir)
+         (null (directory-files dir nil directory-files-no-dot-files-regexp 
t)))))
+
+
 ;;; Emacs < 27.1 compatibility
 
 (unless (fboundp 'proper-list-p)
@@ -119,6 +129,32 @@ extension beyond end of line was not controllable."
   (when (fboundp 'set-face-extend)
     (mapc (lambda (f) (set-face-extend f extend-p)) faces)))
 
+(if (fboundp 'string-distance)
+    (defalias 'org-string-distance 'string-distance)
+  (defun org-string-distance (s1 s2)
+    "Return the edit (levenshtein) distance between strings S1 S2."
+    (let* ((l1 (length s1))
+          (l2 (length s2))
+          (dist (vconcat (mapcar (lambda (_) (make-vector (1+ l2) nil))
+                                 (number-sequence 1 (1+ l1)))))
+          (in (lambda (i j) (aref (aref dist i) j))))
+      (setf (aref (aref dist 0) 0) 0)
+      (dolist (j (number-sequence 1 l2))
+        (setf (aref (aref dist 0) j) j))
+      (dolist (i (number-sequence 1 l1))
+        (setf (aref (aref dist i) 0) i)
+        (dolist (j (number-sequence 1 l2))
+         (setf (aref (aref dist i) j)
+               (min
+                (1+ (funcall in (1- i) j))
+                (1+ (funcall in i (1- j)))
+                (+ (if (equal (aref s1 (1- i)) (aref s2 (1- j))) 0 1)
+                   (funcall in (1- i) (1- j)))))))
+      (funcall in l1 l2))))
+
+(define-obsolete-function-alias 'org-babel-edit-distance 'org-string-distance
+  "9.5")
+
 
 ;;; Emacs < 26.1 compatibility
 
@@ -212,38 +248,38 @@ Case is significant."
 ;;; Obsolete aliases (remove them after the next major release).
 
 ;;;; XEmacs compatibility, now removed.
-(define-obsolete-function-alias 'org-activate-mark 'activate-mark "Org 9.0")
-(define-obsolete-function-alias 'org-add-hook 'add-hook "Org 9.0")
-(define-obsolete-function-alias 'org-bound-and-true-p 'bound-and-true-p "Org 
9.0")
-(define-obsolete-function-alias 'org-decompose-region 'decompose-region "Org 
9.0")
-(define-obsolete-function-alias 'org-defvaralias 'defvaralias "Org 9.0")
-(define-obsolete-function-alias 'org-detach-overlay 'delete-overlay "Org 9.0")
-(define-obsolete-function-alias 'org-file-equal-p 'file-equal-p "Org 9.0")
-(define-obsolete-function-alias 'org-float-time 'float-time "Org 9.0")
-(define-obsolete-function-alias 'org-indent-line-to 'indent-line-to "Org 9.0")
-(define-obsolete-function-alias 'org-indent-to-column 'indent-to-column "Org 
9.0")
-(define-obsolete-function-alias 'org-looking-at-p 'looking-at-p "Org 9.0")
-(define-obsolete-function-alias 'org-looking-back 'looking-back "Org 9.0")
-(define-obsolete-function-alias 'org-match-string-no-properties 
'match-string-no-properties "Org 9.0")
-(define-obsolete-function-alias 'org-propertize 'propertize "Org 9.0")
-(define-obsolete-function-alias 'org-select-frame-set-input-focus 
'select-frame-set-input-focus "Org 9.0")
-(define-obsolete-function-alias 'org-file-remote-p 'file-remote-p "Org 9.2")
+(define-obsolete-function-alias 'org-activate-mark 'activate-mark "9.0")
+(define-obsolete-function-alias 'org-add-hook 'add-hook "9.0")
+(define-obsolete-function-alias 'org-bound-and-true-p 'bound-and-true-p "9.0")
+(define-obsolete-function-alias 'org-decompose-region 'decompose-region "9.0")
+(define-obsolete-function-alias 'org-defvaralias 'defvaralias "9.0")
+(define-obsolete-function-alias 'org-detach-overlay 'delete-overlay "9.0")
+(define-obsolete-function-alias 'org-file-equal-p 'file-equal-p "9.0")
+(define-obsolete-function-alias 'org-float-time 'float-time "9.0")
+(define-obsolete-function-alias 'org-indent-line-to 'indent-line-to "9.0")
+(define-obsolete-function-alias 'org-indent-to-column 'indent-to-column "9.0")
+(define-obsolete-function-alias 'org-looking-at-p 'looking-at-p "9.0")
+(define-obsolete-function-alias 'org-looking-back 'looking-back "9.0")
+(define-obsolete-function-alias 'org-match-string-no-properties 
'match-string-no-properties "9.0")
+(define-obsolete-function-alias 'org-propertize 'propertize "9.0")
+(define-obsolete-function-alias 'org-select-frame-set-input-focus 
'select-frame-set-input-focus "9.0")
+(define-obsolete-function-alias 'org-file-remote-p 'file-remote-p "9.2")
 
 (defmacro org-re (s)
   "Replace posix classes in regular expression S."
   (declare (debug (form))
-           (obsolete "you can safely remove it." "Org 9.0"))
+           (obsolete "you can safely remove it." "9.0"))
   s)
 
 ;;;; Functions from cl-lib that Org used to have its own implementation of.
-(define-obsolete-function-alias 'org-count 'cl-count "Org 9.0")
-(define-obsolete-function-alias 'org-every 'cl-every "Org 9.0")
-(define-obsolete-function-alias 'org-find-if 'cl-find-if "Org 9.0")
-(define-obsolete-function-alias 'org-reduce 'cl-reduce "Org 9.0")
-(define-obsolete-function-alias 'org-remove-if 'cl-remove-if "Org 9.0")
-(define-obsolete-function-alias 'org-remove-if-not 'cl-remove-if-not "Org 9.0")
-(define-obsolete-function-alias 'org-some 'cl-some "Org 9.0")
-(define-obsolete-function-alias 'org-floor* 'cl-floor "Org 9.0")
+(define-obsolete-function-alias 'org-count 'cl-count "9.0")
+(define-obsolete-function-alias 'org-every 'cl-every "9.0")
+(define-obsolete-function-alias 'org-find-if 'cl-find-if "9.0")
+(define-obsolete-function-alias 'org-reduce 'cl-reduce "9.0")
+(define-obsolete-function-alias 'org-remove-if 'cl-remove-if "9.0")
+(define-obsolete-function-alias 'org-remove-if-not 'cl-remove-if-not "9.0")
+(define-obsolete-function-alias 'org-some 'cl-some "9.0")
+(define-obsolete-function-alias 'org-floor* 'cl-floor "9.0")
 
 (defun org-sublist (list start end)
   "Return a section of LIST, from START to END.
@@ -251,89 +287,91 @@ Counting starts at 1."
   (cl-subseq list (1- start) end))
 (make-obsolete 'org-sublist
                "use cl-subseq (note the 0-based counting)."
-               "Org 9.0")
+               "9.0")
 
 
 ;;;; Functions available since Emacs 24.3
-(define-obsolete-function-alias 'org-buffer-narrowed-p 'buffer-narrowed-p "Org 
9.0")
-(define-obsolete-function-alias 'org-called-interactively-p 
'called-interactively-p "Org 9.0")
-(define-obsolete-function-alias 'org-char-to-string 'char-to-string "Org 9.0")
-(define-obsolete-function-alias 'org-delete-directory 'delete-directory "Org 
9.0")
-(define-obsolete-function-alias 'org-format-seconds 'format-seconds "Org 9.0")
-(define-obsolete-function-alias 'org-link-escape-browser 'url-encode-url "Org 
9.0")
-(define-obsolete-function-alias 'org-no-warnings 'with-no-warnings "Org 9.0")
-(define-obsolete-function-alias 'org-number-sequence 'number-sequence "Org 
9.0")
-(define-obsolete-function-alias 'org-pop-to-buffer-same-window 
'pop-to-buffer-same-window "Org 9.0")
-(define-obsolete-function-alias 'org-string-match-p 'string-match-p "Org 9.0")
+(define-obsolete-function-alias 'org-buffer-narrowed-p 'buffer-narrowed-p 
"9.0")
+(define-obsolete-function-alias 'org-called-interactively-p 
'called-interactively-p "9.0")
+(define-obsolete-function-alias 'org-char-to-string 'char-to-string "9.0")
+(define-obsolete-function-alias 'org-delete-directory 'delete-directory "9.0")
+(define-obsolete-function-alias 'org-format-seconds 'format-seconds "9.0")
+(define-obsolete-function-alias 'org-link-escape-browser 'url-encode-url "9.0")
+(define-obsolete-function-alias 'org-no-warnings 'with-no-warnings "9.0")
+(define-obsolete-function-alias 'org-number-sequence 'number-sequence "9.0")
+(define-obsolete-function-alias 'org-pop-to-buffer-same-window 
'pop-to-buffer-same-window "9.0")
+(define-obsolete-function-alias 'org-string-match-p 'string-match-p "9.0")
 
 ;;;; Functions and variables from previous releases now obsolete.
 (define-obsolete-function-alias 'org-element-remove-indentation
-  'org-remove-indentation "Org 9.0")
+  'org-remove-indentation "9.0")
 (define-obsolete-variable-alias 'org-latex-create-formula-image-program
-  'org-preview-latex-default-process "Org 9.0")
+  'org-preview-latex-default-process "9.0")
 (define-obsolete-variable-alias 'org-latex-preview-ltxpng-directory
-  'org-preview-latex-image-directory "Org 9.0")
-(define-obsolete-function-alias 'org-table-p 'org-at-table-p "Org 9.0")
-(define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "Org 9.0")
-(define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "Org 8.3")
+  'org-preview-latex-image-directory "9.0")
+(define-obsolete-function-alias 'org-table-p 'org-at-table-p "9.0")
+(define-obsolete-function-alias 'org-on-heading-p 'org-at-heading-p "9.0")
+(define-obsolete-function-alias 'org-at-regexp-p 'org-in-regexp "8.3")
 (define-obsolete-function-alias 'org-image-file-name-regexp
-  'image-file-name-regexp "Org 9.0")
+  'image-file-name-regexp "9.0")
 (define-obsolete-function-alias 'org-completing-read-no-i
-  'completing-read "Org 9.0")
+  'completing-read "9.0")
 (define-obsolete-function-alias 'org-icompleting-read
-  'completing-read "Org 9.0")
-(define-obsolete-function-alias 'org-iread-file-name 'read-file-name "Org 9.0")
+  'completing-read "9.0")
+(define-obsolete-function-alias 'org-iread-file-name 'read-file-name "9.0")
 (define-obsolete-function-alias 'org-days-to-time
-  'org-time-stamp-to-now "Org 8.2")
+  'org-time-stamp-to-now "8.2")
 (define-obsolete-variable-alias 'org-agenda-ignore-drawer-properties
-  'org-agenda-ignore-properties "Org 9.0")
+  'org-agenda-ignore-properties "9.0")
 (define-obsolete-function-alias 'org-preview-latex-fragment
-  'org-toggle-latex-fragment "Org 8.3")
+  'org-toggle-latex-fragment "8.3")
 (define-obsolete-function-alias 'org-export-get-genealogy
-  'org-element-lineage "Org 9.0")
+  'org-element-lineage "9.0")
 (define-obsolete-variable-alias 'org-latex-with-hyperref
-  'org-latex-hyperref-template "Org 9.0")
-(define-obsolete-variable-alias 'hfy-optimisations 'hfy-optimizations "Org 
9.0")
+  'org-latex-hyperref-template "9.0")
+(define-obsolete-variable-alias 'hfy-optimisations 'hfy-optimizations "9.0")
 (define-obsolete-variable-alias 'org-export-htmlized-org-css-url
-  'org-org-htmlized-css-url "Org 8.2")
-(define-obsolete-function-alias 'org-list-parse-list 'org-list-to-lisp "Org 
9.0")
+  'org-org-htmlized-css-url "8.2")
+(define-obsolete-function-alias 'org-list-parse-list 'org-list-to-lisp "9.0")
 (define-obsolete-function-alias 'org-agenda-todayp
-  'org-agenda-today-p "Org 9.0")
+  'org-agenda-today-p "9.0")
 (define-obsolete-function-alias 'org-babel-examplize-region
-  'org-babel-examplify-region "Org 9.0")
+  'org-babel-examplify-region "9.0")
 (define-obsolete-variable-alias 'org-babel-capitalize-example-region-markers
-  'org-babel-uppercase-example-markers "Org 9.1")
+  'org-babel-uppercase-example-markers "9.1")
 
-(define-obsolete-function-alias 'org-babel-trim 'org-trim "Org 9.0")
+(define-obsolete-function-alias 'org-babel-trim 'org-trim "9.0")
 (define-obsolete-variable-alias 'org-html-style 'org-html-head "24.4")
 (define-obsolete-function-alias 'org-insert-columns-dblock
-  'org-columns-insert-dblock "Org 9.0")
+  'org-columns-insert-dblock "9.0")
 (define-obsolete-variable-alias 'org-export-babel-evaluate
-  'org-export-use-babel "Org 9.1")
+  'org-export-use-babel "9.1")
 (define-obsolete-function-alias 'org-activate-bracket-links
-  'org-activate-links "Org 9.0")
-(define-obsolete-function-alias 'org-activate-plain-links 'ignore "Org 9.0")
-(define-obsolete-function-alias 'org-activate-angle-links 'ignore "Org 9.0")
-(define-obsolete-function-alias 'org-remove-double-quotes 'org-strip-quotes 
"Org 9.0")
+  'org-activate-links "9.0")
+(define-obsolete-function-alias 'org-activate-plain-links 'ignore "9.0")
+(define-obsolete-function-alias 'org-activate-angle-links 'ignore "9.0")
+(define-obsolete-function-alias 'org-remove-double-quotes 'org-strip-quotes 
"9.0")
 (define-obsolete-function-alias 'org-get-indentation
-  'current-indentation "Org 9.2")
-(define-obsolete-function-alias 'org-capture-member 'org-capture-get "Org 9.2")
+  'current-indentation "9.2")
+(define-obsolete-function-alias 'org-capture-member 'org-capture-get "9.2")
 (define-obsolete-function-alias 'org-remove-from-invisibility-spec
-  'remove-from-invisibility-spec "Org 9.2")
+  'remove-from-invisibility-spec "9.2")
 
 (define-obsolete-variable-alias 'org-effort-durations 'org-duration-units
-  "Org 9.2")
+  "9.2")
 
 (define-obsolete-function-alias 'org-toggle-latex-fragment 'org-latex-preview
-  "Org 9.3")
+  "9.3")
 
 (define-obsolete-function-alias 'org-remove-latex-fragment-image-overlays
-  'org-clear-latex-preview "Org 9.3")
+  'org-clear-latex-preview "9.3")
 
 (define-obsolete-variable-alias 'org-attach-directory
-  'org-attach-id-dir "Org 9.3")
-(make-obsolete 'org-attach-store-link "No longer used" "Org 9.4")
-(make-obsolete 'org-attach-expand-link "No longer used" "Org 9.4")
+  'org-attach-id-dir "9.3")
+(make-obsolete 'org-attach-store-link "No longer used" "9.4")
+(make-obsolete 'org-attach-expand-link "No longer used" "9.4")
+
+(define-obsolete-function-alias 'org-file-url-p 'org-url-p "9.5")
 
 (defun org-in-fixed-width-region-p ()
   "Non-nil if point in a fixed-width region."
@@ -341,7 +379,7 @@ Counting starts at 1."
     (eq 'fixed-width (org-element-type (org-element-at-point)))))
 (make-obsolete 'org-in-fixed-width-region-p
                "use `org-element' library"
-               "Org 9.0")
+               "9.0")
 
 (defun org-compatible-face (inherits specs)
   "Make a compatible face specification.
@@ -352,7 +390,7 @@ is, use SPECS to define the face."
   (if (facep inherits)
       (list (list t :inherit inherits))
     specs))
-(make-obsolete 'org-compatible-face "you can remove it." "Org 9.0")
+(make-obsolete 'org-compatible-face "you can remove it." "9.0")
 
 (defun org-add-link-type (type &optional follow export)
   "Add a new TYPE link.
@@ -383,7 +421,7 @@ See `org-link-parameters' for documentation on the other 
parameters."
   (org-link-set-parameters type :follow follow :export export)
   (message "Created %s link." type))
 
-(make-obsolete 'org-add-link-type "use `org-link-set-parameters' instead." 
"Org 9.0")
+(make-obsolete 'org-add-link-type "use `org-link-set-parameters' instead." 
"9.0")
 
 ;;;; Functions unused in Org core.
 (defun org-table-recognize-table.el ()
@@ -407,12 +445,12 @@ See `org-link-parameters' for documentation on the other 
parameters."
 ;; Not used since commit 6d1e3082, Feb 2010.
 (make-obsolete 'org-table-recognize-table.el
                "please notify Org mailing list if you use this function."
-               "Org 9.0")
+               "9.0")
 
 (defmacro org-preserve-lc (&rest body)
   (declare (debug (body))
           (obsolete "please notify Org mailing list if you use this function."
-                    "Org 9.2"))
+                    "9.2"))
   (org-with-gensyms (line col)
     `(let ((,line (org-current-line))
           (,col (current-column)))
@@ -424,12 +462,12 @@ See `org-link-parameters' for documentation on the other 
parameters."
 (defun org-version-check (version &rest _)
   "Non-nil if VERSION is lower (older) than `emacs-version'."
   (declare (obsolete "use `version<' or `fboundp' instead."
-                    "Org 9.2"))
+                    "9.2"))
   (version< version emacs-version))
 
 (defun org-remove-angle-brackets (s)
   (org-unbracket-string "<" ">" s))
-(make-obsolete 'org-remove-angle-brackets 'org-unbracket-string "Org 9.0")
+(make-obsolete 'org-remove-angle-brackets 'org-unbracket-string "9.0")
 
 (defcustom org-publish-sitemap-file-entry-format "%t"
   "Format string for site-map file entry.
@@ -443,7 +481,7 @@ You could use brackets to delimit on what part the link 
will be.
 (make-obsolete-variable
  'org-publish-sitemap-file-entry-format
  "set `:sitemap-format-entry' in `org-publish-project-alist' instead."
- "Org 9.1")
+ "9.1")
 
 (defvar org-agenda-skip-regexp)
 (defun org-agenda-skip-entry-when-regexp-matches ()
@@ -452,7 +490,7 @@ If yes, it returns the end position of this entry, causing 
agenda commands
 to skip the entry but continuing the search in the subtree.  This is a
 function that can be put into `org-agenda-skip-function' for the duration
 of a command."
-  (declare (obsolete "use `org-agenda-skip-if' instead." "Org 9.1"))
+  (declare (obsolete "use `org-agenda-skip-if' instead." "9.1"))
   (let ((end (save-excursion (org-end-of-subtree t)))
        skip)
     (save-excursion
@@ -464,7 +502,7 @@ of a command."
 If yes, it returns the end position of this tree, causing agenda commands
 to skip this subtree.  This is a function that can be put into
 `org-agenda-skip-function' for the duration of a command."
-  (declare (obsolete "use `org-agenda-skip-if' instead." "Org 9.1"))
+  (declare (obsolete "use `org-agenda-skip-if' instead." "9.1"))
   (let ((end (save-excursion (org-end-of-subtree t)))
        skip)
     (save-excursion
@@ -478,7 +516,7 @@ causing agenda commands to skip the entry but continuing 
the search in
 the subtree.  This is a function that can be put into
 `org-agenda-skip-function' for the duration of a command.  An important
 use of this function is for the stuck project list."
-  (declare (obsolete "use `org-agenda-skip-if' instead." "Org 9.1"))
+  (declare (obsolete "use `org-agenda-skip-if' instead." "9.1"))
   (let ((end (save-excursion (org-end-of-subtree t)))
        (entry-end (save-excursion (outline-next-heading) (1- (point))))
        skip)
@@ -487,126 +525,126 @@ use of this function is for the stuck project list."
     (and skip entry-end)))
 
 (define-obsolete-function-alias 'org-minutes-to-clocksum-string
-  'org-duration-from-minutes "Org 9.1")
+  'org-duration-from-minutes "9.1")
 
 (define-obsolete-function-alias 'org-hh:mm-string-to-minutes
-  'org-duration-to-minutes "Org 9.1")
+  'org-duration-to-minutes "9.1")
 
 (define-obsolete-function-alias 'org-duration-string-to-minutes
-  'org-duration-to-minutes "Org 9.1")
+  'org-duration-to-minutes "9.1")
 
 (make-obsolete-variable 'org-time-clocksum-format
-  "set `org-duration-format' instead." "Org 9.1")
+                        "set `org-duration-format' instead." "9.1")
 
 (make-obsolete-variable 'org-time-clocksum-use-fractional
-  "set `org-duration-format' instead." "Org 9.1")
+                        "set `org-duration-format' instead." "9.1")
 
 (make-obsolete-variable 'org-time-clocksum-fractional-format
-  "set `org-duration-format' instead." "Org 9.1")
+                        "set `org-duration-format' instead." "9.1")
 
 (make-obsolete-variable 'org-time-clocksum-use-effort-durations
-  "set `org-duration-units' instead." "Org 9.1")
+                        "set `org-duration-units' instead." "9.1")
 
 (define-obsolete-function-alias 'org-babel-number-p
-  'org-babel--string-to-number "Org 9.0")
+  'org-babel--string-to-number "9.0")
 
 (define-obsolete-variable-alias 'org-usenet-links-prefer-google
-  'org-gnus-prefer-web-links "Org 9.1")
+  'org-gnus-prefer-web-links "9.1")
 
 (define-obsolete-variable-alias 'org-texinfo-def-table-markup
-  'org-texinfo-table-default-markup "Org 9.1")
+  'org-texinfo-table-default-markup "9.1")
 
 (define-obsolete-variable-alias 'org-agenda-overriding-columns-format
-  'org-overriding-columns-format "Org 9.2.2")
+  'org-overriding-columns-format "9.2.2")
 
 (define-obsolete-variable-alias 'org-doi-server-url
-  'org-link-doi-server-url "Org 9.3")
+  'org-link-doi-server-url "9.3")
 
 (define-obsolete-variable-alias 'org-email-link-description-format
-  'org-link-email-description-format "Org 9.3")
+  'org-link-email-description-format "9.3")
 
 (define-obsolete-variable-alias 'org-make-link-description-function
-  'org-link-make-description-function "Org 9.3")
+  'org-link-make-description-function "9.3")
 
 (define-obsolete-variable-alias 'org-from-is-user-regexp
-  'org-link-from-user-regexp "Org 9.3")
+  'org-link-from-user-regexp "9.3")
 
 (define-obsolete-variable-alias 'org-descriptive-links
-  'org-link-descriptive "Org 9.3")
+  'org-link-descriptive "9.3")
 
 (define-obsolete-variable-alias 'org-context-in-file-links
-  'org-link-context-for-files "Org 9.3")
+  'org-link-context-for-files "9.3")
 
 (define-obsolete-variable-alias 'org-keep-stored-link-after-insertion
-  'org-link-keep-stored-after-insertion "Org 9.3")
+  'org-link-keep-stored-after-insertion "9.3")
 
 (define-obsolete-variable-alias 'org-display-internal-link-with-indirect-buffer
-  'org-link-use-indirect-buffer-for-internals "Org 9.3")
+  'org-link-use-indirect-buffer-for-internals "9.3")
 
 (define-obsolete-variable-alias 'org-confirm-shell-link-function
-  'org-link-shell-confirm-function "Org 9.3")
+  'org-link-shell-confirm-function "9.3")
 
 (define-obsolete-variable-alias 'org-confirm-shell-link-not-regexp
-  'org-link-shell-skip-confirm-regexp "Org 9.3")
+  'org-link-shell-skip-confirm-regexp "9.3")
 
 (define-obsolete-variable-alias 'org-confirm-elisp-link-function
-  'org-link-elisp-confirm-function "Org 9.3")
+  'org-link-elisp-confirm-function "9.3")
 
 (define-obsolete-variable-alias 'org-confirm-elisp-link-not-regexp
-  'org-link-elisp-skip-confirm-regexp "Org 9.3")
+  'org-link-elisp-skip-confirm-regexp "9.3")
 
 (define-obsolete-function-alias 'org-file-complete-link
-  'org-link-complete-file "Org 9.3")
+  'org-link-complete-file "9.3")
 
 (define-obsolete-function-alias 'org-email-link-description
-  'org-link-email-description "Org 9.3")
+  'org-link-email-description "9.3")
 
 (define-obsolete-function-alias 'org-make-link-string
-  'org-link-make-string "Org 9.3")
+  'org-link-make-string "9.3")
 
 (define-obsolete-function-alias 'org-store-link-props
-  'org-link-store-props "Org 9.3")
+  'org-link-store-props "9.3")
 
 (define-obsolete-function-alias 'org-add-link-props
-  'org-link-add-props "Org 9.3")
+  'org-link-add-props "9.3")
 
 (define-obsolete-function-alias 'org-make-org-heading-search-string
-  'org-link-heading-search-string "Org 9.3")
+  'org-link-heading-search-string "9.3")
 
 (define-obsolete-function-alias 'org-make-link-regexps
-  'org-link-make-regexps "Org 9.3")
+  'org-link-make-regexps "9.3")
 
 (define-obsolete-function-alias 'org-property-global-value
-  'org-property-global-or-keyword-value "Org 9.3")
+  'org-property-global-or-keyword-value "9.3")
 
-(make-obsolete-variable 'org-file-properties 'org-keyword-properties "Org 9.3")
+(make-obsolete-variable 'org-file-properties 'org-keyword-properties "9.3")
 
 (define-obsolete-variable-alias 'org-angle-link-re
-  'org-link-angle-re "Org 9.3")
+  'org-link-angle-re "9.3")
 
 (define-obsolete-variable-alias 'org-plain-link-re
-  'org-link-plain-re "Org 9.3")
+  'org-link-plain-re "9.3")
 
 (define-obsolete-variable-alias 'org-bracket-link-regexp
-  'org-link-bracket-re "Org 9.3")
+  'org-link-bracket-re "9.3")
 
 (define-obsolete-variable-alias 'org-bracket-link-analytic-regexp
-  'org-link-bracket-re "Org 9.3")
+  'org-link-bracket-re "9.3")
 
 (define-obsolete-variable-alias 'org-any-link-re
-  'org-link-any-re "Org 9.3")
+  'org-link-any-re "9.3")
 
 (define-obsolete-function-alias 'org-open-link-from-string
-  'org-link-open-from-string "Org 9.3")
+  'org-link-open-from-string "9.3")
 
 (define-obsolete-function-alias 'org-add-angle-brackets
-  'org-link-add-angle-brackets "Org 9.3")
+  'org-link-add-angle-brackets "9.3")
 
 ;; The function was made obsolete by commit 65399674d5 of 2013-02-22.
 ;; This make-obsolete call was added 2016-09-01.
 (make-obsolete 'org-capture-import-remember-templates
               "use the `org-capture-templates' variable instead."
-              "Org 9.0")
+              "9.0")
 
 (defun org-show-block-all ()
   "Unfold all blocks in the current buffer."
@@ -615,34 +653,34 @@ use of this function is for the stuck project list."
 
 (make-obsolete 'org-show-block-all
               "use `org-show-all' instead."
-              "Org 9.2")
+              "9.2")
 
-(define-obsolete-function-alias 'org-get-tags-at 'org-get-tags "Org 9.2")
+(define-obsolete-function-alias 'org-get-tags-at 'org-get-tags "9.2")
 
 (defun org-get-local-tags ()
   "Get a list of tags defined in the current headline."
-  (declare (obsolete "use `org-get-tags' instead." "Org 9.2"))
+  (declare (obsolete "use `org-get-tags' instead." "9.2"))
   (org-get-tags nil 'local))
 
 (defun org-get-local-tags-at (&optional pos)
   "Get a list of tags defined in the current headline."
-  (declare (obsolete "use `org-get-tags' instead." "Org 9.2"))
+  (declare (obsolete "use `org-get-tags' instead." "9.2"))
   (org-get-tags pos 'local))
 
 (defun org-get-tags-string ()
   "Get the TAGS string in the current headline."
-  (declare (obsolete "use `org-make-tag-string' instead." "Org 9.2"))
+  (declare (obsolete "use `org-make-tag-string' instead." "9.2"))
   (org-make-tag-string (org-get-tags nil t)))
 
-(define-obsolete-function-alias 'org-set-tags-to 'org-set-tags "Org 9.2")
+(define-obsolete-function-alias 'org-set-tags-to 'org-set-tags "9.2")
 
 (defun org-align-all-tags ()
   "Align the tags in all headings."
-  (declare (obsolete "use `org-align-tags' instead." "Org 9.2"))
+  (declare (obsolete "use `org-align-tags' instead." "9.2"))
   (org-align-tags t))
 
 (define-obsolete-function-alias
-  'org-at-property-block-p 'org-at-property-drawer-p "Org 9.4")
+  'org-at-property-block-p 'org-at-property-drawer-p "9.4")
 
 (defun org-flag-drawer (flag &optional element beg end)
   "When FLAG is non-nil, hide the drawer we are at.
@@ -653,7 +691,7 @@ When optional argument ELEMENT is a parsed drawer, as 
returned by
 
 When buffer positions BEG and END are provided, hide or show that
 region as a drawer without further ado."
-  (declare (obsolete "use `org-hide-drawer-toggle' instead." "Org 9.4"))
+  (declare (obsolete "use `org-hide-drawer-toggle' instead." "9.4"))
   (if (and beg end) (org-flag-region beg end flag 'outline)
     (let ((drawer
           (or element
@@ -678,14 +716,14 @@ region as a drawer without further ado."
   "Toggle visibility of block at point.
 Unlike to `org-hide-block-toggle', this function does not throw
 an error.  Return a non-nil value when toggling is successful."
-  (declare (obsolete "use `org-hide-block-toggle' instead." "Org 9.4"))
+  (declare (obsolete "use `org-hide-block-toggle' instead." "9.4"))
   (interactive)
   (org-hide-block-toggle nil t))
 
 (defun org-hide-block-toggle-all ()
   "Toggle the visibility of all blocks in the current buffer."
   (declare (obsolete "please notify Org mailing list if you use this function."
-                    "Org 9.4"))
+                    "9.4"))
   (let ((start (point-min))
         (end (point-max)))
     (save-excursion
@@ -703,17 +741,17 @@ an error.  Return a non-nil value when toggling is 
successful."
 Calls `org-table-next-row' or `newline-and-indent', depending on
 context.  See the individual commands for more information."
   (declare (obsolete "use `org-return' with INDENT set to t instead."
-                    "Org 9.4"))
+                    "9.4"))
   (interactive)
   (org-return t))
 
 (defmacro org-with-silent-modifications (&rest body)
-  (declare (obsolete "use `with-silent-modifications' instead." "Org 9.2")
+  (declare (obsolete "use `with-silent-modifications' instead." "9.2")
           (debug (body)))
   `(with-silent-modifications ,@body))
 
 (define-obsolete-function-alias 'org-babel-strip-quotes
-  'org-strip-quotes "Org 9.2")
+  'org-strip-quotes "9.2")
 
 (define-obsolete-variable-alias 'org-sort-agenda-notime-is-late
   'org-agenda-sort-notime-is-late "9.4")
@@ -730,7 +768,11 @@ context.  See the individual commands for more 
information."
 (make-obsolete-variable
  'org-maybe-keyword-time-regexp
  "use `org-planning-line-re', followed by `org-ts-regexp-both' instead."
- "Org 9.4")
+ "9.4")
+
+(define-obsolete-function-alias 'org-copy 'org-refile-copy "9.4")
+
+(define-obsolete-function-alias 'org-get-last-sibling 
'org-get-previous-sibling "9.4")
 
 ;;;; Obsolete link types
 
@@ -1023,8 +1065,7 @@ ELEMENT is the element at point."
 (defun org-mode-flyspell-verify ()
   "Function used for `flyspell-generic-check-word-predicate'."
   (if (org-at-heading-p)
-      ;; At a headline or an inlinetask, check title only.  This is
-      ;; faster than relying on `org-element-at-point'.
+      ;; At a headline or an inlinetask, check title only.
       (and (save-excursion (beginning-of-line)
                           (and (let ((case-fold-search t))
                                  (not (looking-at-p "\\*+ END[ \t]*$")))
@@ -1033,7 +1074,9 @@ ELEMENT is the element at point."
           (match-beginning 4)
           (>= (point) (match-beginning 4))
           (or (not (match-beginning 5))
-              (< (point) (match-beginning 5))))
+              (< (point) (match-beginning 5)))
+           ;; Ignore checks in code, verbatim and others.
+           (org--flyspell-object-check-p (org-element-at-point)))
     (let* ((element (org-element-at-point))
           (post-affiliated (org-element-property :post-affiliated element)))
       (cond
@@ -1102,14 +1145,7 @@ ELEMENT is the element at point."
        (org-show-context 'bookmark-jump)))
 
 ;; Make `bookmark-jump' shows the jump location if it was hidden.
-(eval-after-load 'bookmark
-  '(if (boundp 'bookmark-after-jump-hook)
-       ;; We can use the hook
-       (add-hook 'bookmark-after-jump-hook 'org-bookmark-jump-unhide)
-     ;; Hook not available, use advice
-     (defadvice bookmark-jump (after org-make-visible activate)
-       "Make the position visible."
-       (org-bookmark-jump-unhide))))
+(add-hook 'bookmark-after-jump-hook 'org-bookmark-jump-unhide)
 
 ;;;; Calendar
 
@@ -1206,6 +1242,11 @@ key."
 (eval-after-load 'session
   '(add-to-list 'session-globals-exclude 'org-mark-ring))
 
+;;;; Speed commands
+
+(make-obsolete-variable 'org-speed-commands-user
+                        "configure `org-speed-commands' instead." "9.5")
+
 (provide 'org-compat)
 
 ;; Local variables:
diff --git a/lisp/org/org-crypt.el b/lisp/org/org-crypt.el
index 103baeb49e..48f76b79fd 100644
--- a/lisp/org/org-crypt.el
+++ b/lisp/org/org-crypt.el
@@ -185,10 +185,10 @@ See `org-crypt-disable-auto-save'."
      ((eq org-crypt-disable-auto-save 'encrypt)
       (message "org-decrypt: Enabling re-encryption on auto-save.")
       (add-hook 'auto-save-hook
-                   (lambda ()
-                     (message "org-crypt: Re-encrypting all decrypted entries 
due to auto-save.")
-                     (org-encrypt-entries))
-                   nil t))
+               (lambda ()
+                 (message "org-crypt: Re-encrypting all decrypted entries due 
to auto-save.")
+                 (org-encrypt-entries))
+               nil t))
      (t nil))))
 
 (defun org-crypt-key-for-heading ()
diff --git a/lisp/org/org-ctags.el b/lisp/org/org-ctags.el
index dc2b3be632..7876c6ef75 100644
--- a/lisp/org/org-ctags.el
+++ b/lisp/org/org-ctags.el
@@ -3,10 +3,8 @@
 ;; Copyright (C) 2007-2021 Free Software Foundation, Inc.
 
 ;; Author: Paul Sexton <eeeickythump@gmail.com>
-
-
 ;; Keywords: org, wp
-;;
+
 ;; This file is part of GNU Emacs.
 ;;
 ;; GNU Emacs is free software: you can redistribute it and/or modify
@@ -22,6 +20,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Commentary:
+
 ;;
 ;; Synopsis
 ;; ========
diff --git a/lisp/org/org-datetree.el b/lisp/org/org-datetree.el
index 62bd46e2e9..74442b038a 100644
--- a/lisp/org/org-datetree.el
+++ b/lisp/org/org-datetree.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -72,8 +72,8 @@ will be built under the headline at point."
 (defun org-datetree--find-create-group
     (d time-grouping &optional keep-restriction)
   "Find or create an entry for date D.
-If time-period is day, group entries by day. If time-period is
-month, then group entries by month."
+If time-period is day, group entries by day.
+If time-period is month, then group entries by month."
   (setq-local org-datetree-base-level 1)
   (save-restriction
     (if (eq keep-restriction 'subtree-at-point)
diff --git a/lisp/org/org-duration.el b/lisp/org/org-duration.el
index 29fae2dbf0..e627d0936a 100644
--- a/lisp/org/org-duration.el
+++ b/lisp/org/org-duration.el
@@ -97,7 +97,11 @@ sure to call the following command:
   :group 'org-agenda
   :version "26.1"
   :package-version '(Org . "9.1")
-  :set (lambda (var val) (set-default var val) (org-duration-set-regexps))
+  :set (lambda (var val)
+         (set-default var val)
+         ;; Avoid recursive load at startup.
+        (when (featurep 'org-duration)
+           (org-duration-set-regexps)))
   :initialize 'custom-initialize-changed
   :type '(choice
          (const :tag "H:MM" h:mm)
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 31f5f78eae..f8334ccbc6 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -117,6 +117,19 @@
 ;; `org-element-update-syntax' builds proper syntax regexps according
 ;; to current setup.
 
+(defconst org-element-citation-key-re
+  (rx "@" (group (one-or-more (any word "-.:?!`'/*@+|(){}<>&_^$#%~"))))
+  "Regexp matching a citation key.
+Key is located in match group 1.")
+
+(defconst org-element-citation-prefix-re
+  (rx "[cite"
+      (opt "/" (group (one-or-more (any "/_-" alnum)))) ;style
+      ":"
+      (zero-or-more (any "\t\n ")))
+  "Regexp matching a citation prefix.
+Style, if any, is located in match group 1.")
+
 (defvar org-element-paragraph-separate nil
   "Regexp to separate paragraphs in an Org buffer.
 In the case of lines starting with \"#\" and \":\", this regexp
@@ -182,15 +195,17 @@ specially in `org-element--object-lex'.")
                                      (nth 2 org-emphasis-regexp-components)))
                      ;; Plain links.
                      (concat "\\<" link-types ":")
-                     ;; Objects starting with "[": regular link,
+                     ;; Objects starting with "[": citations,
                      ;; footnote reference, statistics cookie,
-                     ;; timestamp (inactive).
-                     (concat "\\[\\(?:"
-                             "fn:" "\\|"
-                             "\\[" "\\|"
-                             "[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}" "\\|"
-                             "[0-9]*\\(?:%\\|/[0-9]*\\)\\]"
-                             "\\)")
+                     ;; timestamp (inactive) and regular link.
+                     (format "\\[\\(?:%s\\)"
+                             (mapconcat
+                              #'identity
+                              (list "cite[:/]"
+                                    "fn:"
+                                    "\\(?:[0-9]\\|\\(?:%\\|/[0-9]*\\)\\]\\)"
+                                    "\\[")
+                              "\\|"))
                      ;; Objects starting with "@": export snippets.
                      "@@"
                      ;; Objects starting with "{": macro.
@@ -234,15 +249,15 @@ specially in `org-element--object-lex'.")
   "List of recursive element types aka Greater Elements.")
 
 (defconst org-element-all-objects
-  '(bold code entity export-snippet footnote-reference inline-babel-call
-        inline-src-block italic line-break latex-fragment link macro
-        radio-target statistics-cookie strike-through subscript superscript
-        table-cell target timestamp underline verbatim)
+  '(bold citation citation-reference code entity export-snippet
+        footnote-reference inline-babel-call inline-src-block italic line-break
+        latex-fragment link macro radio-target statistics-cookie strike-through
+        subscript superscript table-cell target timestamp underline verbatim)
   "Complete list of object types.")
 
 (defconst org-element-recursive-objects
-  '(bold footnote-reference italic link subscript radio-target strike-through
-        superscript table-cell underline)
+  '(bold citation footnote-reference italic link subscript radio-target
+        strike-through superscript table-cell underline)
   "List of recursive object types.")
 
 (defconst org-element-object-containers
@@ -331,9 +346,12 @@ Don't modify it, set `org-element-affiliated-keywords' 
instead.")
 (defconst org-element-object-restrictions
   (let* ((minimal-set '(bold code entity italic latex-fragment strike-through
                             subscript superscript underline verbatim))
-        (standard-set (remq 'table-cell org-element-all-objects))
+        (standard-set
+         (remq 'citation-reference (remq 'table-cell org-element-all-objects)))
         (standard-set-no-line-break (remq 'line-break standard-set)))
     `((bold ,@standard-set)
+      (citation citation-reference)
+      (citation-reference ,@minimal-set)
       (footnote-reference ,@standard-set)
       (headline ,@standard-set-no-line-break)
       (inlinetask ,@standard-set-no-line-break)
@@ -354,8 +372,8 @@ Don't modify it, set `org-element-affiliated-keywords' 
instead.")
       ;; Ignore inline babel call and inline source block as formulas
       ;; are possible.  Also ignore line breaks and statistics
       ;; cookies.
-      (table-cell export-snippet footnote-reference link macro radio-target
-                 target timestamp ,@minimal-set)
+      (table-cell citation export-snippet footnote-reference link macro
+                  radio-target target timestamp ,@minimal-set)
       (table-row table-cell)
       (underline ,@standard-set)
       (verse-block ,@standard-set)))
@@ -370,9 +388,11 @@ This alist also applies to secondary string.  For example, 
an
 still has an entry since one of its properties (`:title') does.")
 
 (defconst org-element-secondary-value-alist
-  '((headline :title)
+  '((citation :prefix :suffix)
+    (headline :title)
     (inlinetask :title)
-    (item :tag))
+    (item :tag)
+    (citation-reference :prefix :suffix))
   "Alist between element types and locations of secondary values.")
 
 (defconst org-element--pair-round-table
@@ -737,7 +757,9 @@ Return a list whose CAR is `drawer' and CDR is a plist 
containing
 
 Assume point is at beginning of drawer."
   (let ((case-fold-search t))
-    (if (not (save-excursion (re-search-forward "^[ \t]*:END:[ \t]*$" limit 
t)))
+    (if (not (save-excursion
+               (goto-char (min limit (line-end-position)))
+               (re-search-forward "^[ \t]*:END:[ \t]*$" limit t)))
        ;; Incomplete drawer: parse it as a paragraph.
        (org-element-paragraph-parser limit affiliated)
       (save-excursion
@@ -999,7 +1021,10 @@ Assume point is at beginning of the headline."
           (commentedp
            (and (let (case-fold-search) (looking-at org-comment-string))
                 (goto-char (match-end 0))))
-          (title-start (point))
+          (title-start (prog1 (point)
+                          (unless (or todo priority commentedp)
+                            ;; Headline like "* :tag:"
+                            (skip-chars-backward " \t"))))
           (tags (when (re-search-forward
                        "[ \t]+\\(:[[:alnum:]_@#%:]+:\\)[ \t]*$"
                        (line-end-position)
@@ -2751,6 +2776,129 @@ CONTENTS is the contents of the object."
   (format "*%s*" contents))
 
 
+;;;; Citation
+
+(defun org-element-citation-parser ()
+  "Parse citation object at point, if any.
+
+When at a citation object, return a list whose car is `citation'
+and cdr is a plist with `:style', `:prefix', `:suffix', `:begin',
+`:end', `:contents-begin', `:contents-end', and `:post-blank'
+keywords.  Otherwise, return nil.
+
+Assume point is at the beginning of the citation."
+  (when (looking-at org-element-citation-prefix-re)
+    (let* ((begin (point))
+          (style (and (match-end 1)
+                      (match-string-no-properties 1)))
+          ;; Ignore blanks between cite type and prefix or key.
+          (start (match-end 0))
+          (closing (with-syntax-table org-element--pair-square-table
+                     (ignore-errors (scan-lists begin 1 0)))))
+      (save-excursion
+       (when (and closing
+                  (re-search-forward org-element-citation-key-re closing t))
+         ;; Find prefix, if any.
+         (let ((first-key-end (match-end 0))
+               (types (org-element-restriction 'citation-reference))
+                (cite
+                (list 'citation
+                      (list :style style
+                            :begin begin
+                            :post-blank (progn
+                                          (goto-char closing)
+                                          (skip-chars-forward " \t"))
+                            :end (point)))))
+           ;; `:contents-begin' depends on the presence of
+           ;; a non-empty common prefix.
+           (goto-char first-key-end)
+           (if (not (search-backward ";" start t))
+               (org-element-put-property cite :contents-begin start)
+             (when (< start (point))
+               (org-element-put-property
+                 cite :prefix
+                 (org-element--parse-objects start (point) nil types cite)))
+             (forward-char)
+             (org-element-put-property cite :contents-begin (point)))
+           ;; `:contents-end' depends on the presence of a non-empty
+           ;; common suffix.
+           (goto-char (1- closing))
+           (skip-chars-backward " \r\t\n")
+           (let ((end (point)))
+             (if (or (not (search-backward ";" first-key-end t))
+                     (re-search-forward org-element-citation-key-re end t))
+                 (org-element-put-property cite :contents-end end)
+                (forward-char)
+               (when (< (point) end)
+                 (org-element-put-property
+                   cite :suffix
+                   (org-element--parse-objects (point) end nil types cite)))
+               (org-element-put-property cite :contents-end (point))))
+           cite))))))
+
+(defun org-element-citation-interpreter (citation contents)
+  "Interpret CITATION object as Org syntax.
+CONTENTS is the contents of the object, as a string."
+  (let ((prefix (org-element-property :prefix citation))
+        (suffix (org-element-property :suffix citation))
+        (style (org-element-property :style citation)))
+    (concat "[cite"
+            (and style (concat "/" style))
+            ":"
+            (and prefix (concat (org-element-interpret-data prefix) ";"))
+            (if suffix
+                (concat contents (org-element-interpret-data suffix))
+              ;; Remove spurious semicolon.
+              (substring contents nil -1))
+            "]")))
+
+
+;;;; Citation Reference
+
+(defun org-element-citation-reference-parser ()
+  "Parse citation reference object at point, if any.
+
+When at a reference, return a list whose car is
+`citation-reference', and cdr is a plist with `:key',
+`:prefix', `:suffix', `:begin', `:end', and `:post-blank' keywords.
+
+Assume point is at the beginning of the reference."
+  (save-excursion
+    (let ((begin (point)))
+      (when (re-search-forward org-element-citation-key-re nil t)
+        (let* ((key (match-string-no-properties 1))
+              (key-start (match-beginning 0))
+              (key-end (match-end 0))
+              (separator (search-forward ";" nil t))
+               (end (or separator (point-max)))
+               (suffix-end (if separator (1- end) end))
+               (types (org-element-restriction 'citation-reference))
+              (reference
+               (list 'citation-reference
+                     (list :key key
+                           :begin begin
+                           :end end
+                           :post-blank 0))))
+         (when (< begin key-start)
+           (org-element-put-property
+            reference :prefix
+             (org-element--parse-objects begin key-start nil types reference)))
+         (when (< key-end suffix-end)
+           (org-element-put-property
+            reference :suffix
+             (org-element--parse-objects key-end suffix-end nil types 
reference)))
+         reference)))))
+
+(defun org-element-citation-reference-interpreter (citation-reference _)
+  "Interpret CITATION-REFERENCE object as Org syntax."
+  (concat (org-element-interpret-data
+           (org-element-property :prefix citation-reference))
+         "@" (org-element-property :key citation-reference)
+         (org-element-interpret-data
+           (org-element-property :suffix citation-reference))
+          ";"))
+
+
 ;;;; Code
 
 (defun org-element-code-parser ()
@@ -3951,14 +4099,36 @@ element it has to parse."
                  ;; There is no strict definition of a table.el
                  ;; table.  Try to prevent false positive while being
                  ;; quick.
-                 (let ((rule-regexp "[ \t]*\\+\\(-+\\+\\)+[ \t]*$")
+                 (let ((rule-regexp
+                        (rx (zero-or-more (any " \t"))
+                            "+"
+                            (one-or-more (one-or-more "-") "+")
+                            (zero-or-more (any " \t"))
+                            eol))
+                       (non-table.el-line
+                        (rx bol
+                            (zero-or-more (any " \t"))
+                            (or eol (not (any "+| \t")))))
                        (next (line-beginning-position 2)))
-                   (and (looking-at rule-regexp)
-                        (save-excursion
-                          (forward-line)
-                          (re-search-forward "^[ \t]*\\($\\|[^|]\\)" limit t)
-                          (and (> (line-beginning-position) next)
-                               (org-match-line rule-regexp))))))
+                   ;; Start with a full rule.
+                   (and
+                    (looking-at rule-regexp)
+                    (< next limit)     ;no room for a table.el table
+                    (save-excursion
+                      (end-of-line)
+                      (cond
+                       ;; Must end with a full rule.
+                       ((not (re-search-forward non-table.el-line limit 'move))
+                        (if (bolp) (forward-line -1) (beginning-of-line))
+                        (looking-at rule-regexp))
+                       ;; Ignore pseudo-tables with a single
+                       ;; rule.
+                       ((= next (line-beginning-position))
+                        nil)
+                       ;; Must end with a full rule.
+                       (t
+                        (forward-line -1)
+                        (looking-at rule-regexp)))))))
              (org-element-table-parser limit affiliated))
             ;; List.
             ((looking-at (org-item-re))
@@ -4322,7 +4492,7 @@ element or object.  Meaningful values are `first-section',
 TYPE is the type of the current element or object.
 
 If PARENT? is non-nil, assume the next element or object will be
-located inside the current one.  "
+located inside the current one."
   (if parent?
       (pcase type
        (`headline 'section)
@@ -4413,7 +4583,11 @@ Elements are accumulated into ACC."
 RESTRICTION is a list of object types, as symbols, that should be
 looked after.  This function assumes that the buffer is narrowed
 to an appropriate container (e.g., a paragraph)."
-  (if (memq 'table-cell restriction) (org-element-table-cell-parser)
+  (cond
+   ((memq 'table-cell restriction) (org-element-table-cell-parser))
+   ((memq 'citation-reference restriction)
+    (org-element-citation-reference-parser))
+   (t
     (let* ((start (point))
           (limit
            ;; Object regexp sometimes needs to have a peek at
@@ -4501,6 +4675,9 @@ to an appropriate container (e.g., a paragraph)."
                         ((and ?f
                               (guard (memq 'footnote-reference restriction)))
                          (org-element-footnote-reference-parser))
+                        ((and ?c
+                              (guard (memq 'citation restriction)))
+                         (org-element-citation-parser))
                         ((and (or ?% ?/)
                               (guard (memq 'statistics-cookie restriction)))
                          (org-element-statistics-cookie-parser))
@@ -4515,8 +4692,8 @@ to an appropriate container (e.g., a paragraph)."
            (or (eobp) (forward-char))))
        (cond (found)
              (limit (forward-char -1)
-                    (org-element-link-parser)) ;radio link
-             (t nil))))))
+                    (org-element-link-parser)) ;radio link
+             (t nil)))))))
 
 (defun org-element--parse-objects (beg end acc restriction &optional parent)
   "Parse objects between BEG and END and return recursive structure.
@@ -4640,7 +4817,7 @@ to interpret.  Return Org syntax as a string."
                                   (eq (org-element-property :pre-blank parent)
                                       0)))))
                          ""))))))
-               (if (memq type '(org-data plain-text nil)) results
+               (if (memq type '(org-data nil)) results
                  ;; Build white spaces.  If no `:post-blank' property
                  ;; is specified, assume its value is 0.
                  (let ((blank (or (org-element-property :post-blank data) 0)))
@@ -4655,19 +4832,18 @@ to interpret.  Return Org syntax as a string."
   "Return ELEMENT's affiliated keywords as Org syntax.
 If there is no affiliated keyword, return the empty string."
   (let ((keyword-to-org
-        (function
-         (lambda (key value)
-           (let (dual)
-             (when (member key org-element-dual-keywords)
-               (setq dual (cdr value) value (car value)))
-             (concat "#+" (downcase key)
-                     (and dual
-                          (format "[%s]" (org-element-interpret-data dual)))
-                     ": "
-                     (if (member key org-element-parsed-keywords)
-                         (org-element-interpret-data value)
-                       value)
-                     "\n"))))))
+        (lambda (key value)
+          (let (dual)
+            (when (member key org-element-dual-keywords)
+              (setq dual (cdr value) value (car value)))
+            (concat "#+" (downcase key)
+                    (and dual
+                         (format "[%s]" (org-element-interpret-data dual)))
+                    ": "
+                    (if (member key org-element-parsed-keywords)
+                        (org-element-interpret-data value)
+                      value)
+                    "\n")))))
     (mapconcat
      (lambda (prop)
        (let ((value (org-element-property prop element))
diff --git a/lisp/org/org-entities.el b/lisp/org/org-entities.el
index eb098993b7..9c5f626ab7 100644
--- a/lisp/org/org-entities.el
+++ b/lisp/org/org-entities.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>,
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>,
 ;;         Ulf Stegemann <ulf at zeitform dot de>
 ;; Keywords: outlines, calendar, wp
 ;; Homepage: https://orgmode.org
@@ -114,6 +114,8 @@ packages to be loaded, add these packages to 
`org-latex-packages-alist'."
      ("igrave" "\\`{i}" nil "&igrave;" "i" "ì" "ì")
      ("Iacute" "\\'{I}" nil "&Iacute;" "I" "Í" "Í")
      ("iacute" "\\'{i}" nil "&iacute;" "i" "í" "í")
+     ("Idot" "\\.{I}" nil "&idot;" "I" "İ" "İ")
+     ("inodot" "\\i" nil "&inodot;" "i" "ı" "ı")
      ("Icirc" "\\^{I}" nil "&Icirc;" "I" "Î" "Î")
      ("icirc" "\\^{i}" nil "&icirc;" "i" "î" "î")
      ("Iuml" "\\\"{I}" nil "&Iuml;" "I" "Ï" "Ï")
diff --git a/lisp/org/org-faces.el b/lisp/org/org-faces.el
index c56873b54c..b151045a95 100644
--- a/lisp/org/org-faces.el
+++ b/lisp/org/org-faces.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -38,13 +38,28 @@
   :group 'org-faces)
 
 (defface org-hide
-  '((((background light)) (:foreground "white"))
+  '((default :inherit fixed-pitch)
+    (((background light)) (:foreground "white"))
     (((background dark)) (:foreground "black")))
   "Face used to hide leading stars in headlines.
 The foreground color of this face should be equal to the background
 color of the frame."
   :group 'org-faces)
 
+(defface org-dispatcher-highlight
+  '((default :weight bold)
+    (((class color) (min-colors 88) (background dark))
+     :background "gray20" :foreground "gold1")
+    (((class color) (min-colors 88) (background light))
+     :background "SlateGray1" :foreground "DarkBlue")
+    (((class color) (min-colors 16) (background dark))
+     :foreground "yellow")
+    (((class color) (min-colors 16) (background light))
+     :foreground "blue")
+    (t :inverse-video t))
+  "Face for highlighted keys in the dispatcher."
+  :group 'org-faces)
+
 (defface org-level-1 '((t :inherit outline-1))
   "Face used for level 1 headlines."
   :group 'org-faces)
@@ -153,6 +168,14 @@ set the properties in the `org-column' face.  For example, 
set
   "Face for headline with the ARCHIVE tag."
   :group 'org-faces)
 
+(defface org-cite '((t :inherit link))
+  "Face for citations."
+  :group 'org-faces)
+
+(defface org-cite-key '((t :inherit link))
+  "Face for citation keys."
+  :group 'org-faces)
+
 (defface org-link '((t :inherit link))
   "Face for links."
   :group 'org-faces)
@@ -179,7 +202,8 @@ set the properties in the `org-column' face.  For example, 
set
   :group 'org-faces)
 
 (defface org-date
-  '((((class color) (background light)) (:foreground "Purple" :underline t))
+  '((default :inherit fixed-pitch)
+    (((class color) (background light)) (:foreground "Purple" :underline t))
     (((class color) (background dark)) (:foreground "Cyan" :underline t))
     (t (:underline t)))
   "Face for date/time stamps."
@@ -355,7 +379,8 @@ changes."
                   (sexp :tag "Face")))))
 
 (defface org-table        ;Copied from `font-lock-function-name-face'
-  '((((class color) (min-colors 88) (background light)) (:foreground "Blue1"))
+  '((default :inherit fixed-pitch)
+    (((class color) (min-colors 88) (background light)) (:foreground "Blue1"))
     (((class color) (min-colors 88) (background dark)) (:foreground 
"LightSkyBlue"))
     (((class color) (min-colors 16) (background light)) (:foreground "Blue"))
     (((class color) (min-colors 16) (background dark)) (:foreground 
"LightSkyBlue"))
@@ -371,7 +396,8 @@ changes."
   :group 'org-faces)
 
 (defface org-formula
-  '((((class color) (min-colors 88) (background light)) (:foreground 
"Firebrick"))
+  '((default :inherit fixed-pitch)
+    (((class color) (min-colors 88) (background light)) (:foreground 
"Firebrick"))
     (((class color) (min-colors 88) (background dark)) (:foreground 
"chocolate1"))
     (((class color) (min-colors 8)  (background light)) (:foreground "red"))
     (((class color) (min-colors 8)  (background dark)) (:foreground "red"))
@@ -379,12 +405,12 @@ changes."
   "Face for formulas."
   :group 'org-faces)
 
-(defface org-code '((t :inherit shadow))
+(defface org-code '((t :inherit (fixed-pitch shadow)))
   "Face for fixed-width text like code snippets."
   :group 'org-faces
   :version "22.1")
 
-(defface org-meta-line '((t :inherit font-lock-comment-face))
+(defface org-meta-line '((t :inherit (fixed-pitch font-lock-comment-face)))
   "Face for meta lines starting with \"#+\"."
   :group 'org-faces
   :version "22.1")
@@ -400,15 +426,18 @@ changes."
   '((((class color) (background light)) (:foreground "midnight blue"))
     (((class color) (background dark)) (:foreground "pale turquoise"))
     (t nil))
-  "Face for document date, author and email; i.e. that which
-follows a #+DATE:, #+AUTHOR: or #+EMAIL: keyword."
+  "Face for document information such as the author and date.
+This applies to the text that follows a #+SUBTITLE:, #+DATE:,
+#+AUTHOR: or #+EMAIL: keyword."
   :group 'org-faces)
 
 (defface org-document-info-keyword '((t :inherit shadow))
-  "Face for #+TITLE:, #+AUTHOR:, #+EMAIL: and #+DATE: keywords."
+  "Face for document information keywords.
+This face applies to the #+TITLE:, #+SUBTITLE:, #+AUTHOR:,
+#+EMAIL: and #+DATE: keywords."
   :group 'org-faces)
 
-(defface org-block `((t :inherit shadow
+(defface org-block `((t :inherit (fixed-pitch shadow)
                        ,@(and (>= emacs-major-version 27) '(:extend t))))
   "Face used for text inside various blocks.
 
@@ -430,7 +459,7 @@ verse and quote blocks are fontified using the `org-verse' 
and
   "Face used for the line delimiting the end of source blocks."
   :group 'org-faces)
 
-(defface org-verbatim '((t (:inherit shadow)))
+(defface org-verbatim '((t (:inherit (fixed-pitch shadow))))
   "Face for fixed-with text like code snippets."
   :group 'org-faces
   :version "22.1")
@@ -478,6 +507,16 @@ content of these blocks will still be treated as Org 
syntax."
   "Face used in agenda for captions and dates."
   :group 'org-faces)
 
+(defface org-agenda-structure-secondary '((t (:inherit org-agenda-structure)))
+  "Face used for secondary information in agenda block headers."
+  :group 'org-faces)
+
+(defface org-agenda-structure-filter '((t (:inherit (org-warning 
org-agenda-structure))))
+  "Face used for the current type of task filter in the agenda.
+It inherits from `org-agenda-structure' so it can adapt to
+it (e.g. if that is assigned a diffent font height or family)."
+  :group 'org-faces)
+
 (defface org-agenda-date '((t (:inherit org-agenda-structure)))
   "Face used in agenda for normal days."
   :group 'org-faces)
@@ -487,6 +526,10 @@ content of these blocks will still be treated as Org 
syntax."
   "Face used in agenda for today."
   :group 'org-faces)
 
+(defface org-agenda-date-weekend-today '((t (:inherit org-agenda-date-today)))
+  "Face used in agenda for today during weekends."
+  :group 'org-faces)
+
 (defface org-agenda-clocking '((t (:inherit secondary-selection)))
   "Face marking the current clock item in the agenda."
   :group 'org-faces)
@@ -529,6 +572,11 @@ which days belong to the weekend."
   "Face for items scheduled previously, and not yet done."
   :group 'org-faces)
 
+(defface org-imminent-deadline '((t :inherit org-warning))
+  "Face for current deadlines in the agenda.
+See also `org-agenda-deadline-faces'."
+  :group 'org-faces)
+
 (defface org-upcoming-deadline
   '((((class color) (min-colors 88) (background light)) (:foreground 
"Firebrick"))
     (((class color) (min-colors 88) (background dark)) (:foreground 
"chocolate1"))
@@ -544,7 +592,7 @@ See also `org-agenda-deadline-faces'."
 See also `org-agenda-deadline-faces'.")
 
 (defcustom org-agenda-deadline-faces
-  '((1.0 . org-warning)
+  '((1.0 . org-imminent-deadline)
     (0.5 . org-upcoming-deadline)
     (0.0 . org-upcoming-distant-deadline))
   "Faces for showing deadlines in the agenda.
diff --git a/lisp/org/org-feed.el b/lisp/org/org-feed.el
index 5dbd887ef5..5df3b69766 100644
--- a/lisp/org/org-feed.el
+++ b/lisp/org/org-feed.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
diff --git a/lisp/org/org-footnote.el b/lisp/org/org-footnote.el
index 3d42421e0d..fcc7579bad 100644
--- a/lisp/org/org-footnote.el
+++ b/lisp/org/org-footnote.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -37,6 +37,7 @@
 (declare-function org-at-comment-p "org" ())
 (declare-function org-at-heading-p "org" (&optional ignored))
 (declare-function org-back-over-empty-lines "org" ())
+(declare-function org-end-of-meta-data "org" (&optional full))
 (declare-function org-edit-footnote-reference "org-src" ())
 (declare-function org-element-at-point "org-element" ())
 (declare-function org-element-class "org-element" (datum &optional parent))
@@ -280,13 +281,21 @@ otherwise."
            (save-excursion (goto-char (org-element-property :end context))
                            (skip-chars-backward " \r\t\n")
                            (if (eq (org-element-class context) 'object) (point)
-                             (1+ (line-beginning-position 2))))))
+                             (line-beginning-position 2)))))
+       ;; At the beginning of a footnote definition, right after the
+       ;; label, is OK.
+       ((eq type 'footnote-definition) (looking-at (rx space)))
        ;; Other elements are invalid.
        ((eq (org-element-class context) 'element) nil)
        ;; Just before object is fine.
        ((= (point) (org-element-property :begin context)))
        ;; Within recursive object too, but not in a link.
        ((eq type 'link) nil)
+       ((eq type 'table-cell)
+        ;; :contents-begin is not reliable on empty cells, so special
+        ;; case it.
+        (<= (save-excursion (skip-chars-backward " \t") (point))
+            (org-element-property :contents-end context)))
        ((let ((cbeg (org-element-property :contents-begin context))
              (cend (org-element-property :contents-end context)))
          (and cbeg (>= (point) cbeg) (<= (point) cend))))))))
@@ -704,7 +713,7 @@ function doesn't move point."
           (concat "^\\*+[ \t]+" (regexp-quote org-footnote-section) "[ \t]*$")
           nil t))
        (goto-char (match-end 0))
-       (forward-line)
+        (org-end-of-meta-data t)
        (unless (bolp) (insert "\n")))
        (t (org-footnote--clear-footnote-section)))
       (when (zerop (org-back-over-empty-lines)) (insert "\n"))
diff --git a/lisp/org/org-goto.el b/lisp/org/org-goto.el
index 163aa580ef..0a3470f545 100644
--- a/lisp/org/org-goto.el
+++ b/lisp/org/org-goto.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -219,9 +219,9 @@ position or nil."
            (error (make-indirect-buffer (current-buffer) "*org-goto*" t))))
         (let (temp-buffer-show-function temp-buffer-show-hook)
           (with-output-to-temp-buffer "*Org Help*"
-          (princ (format help (if org-goto-auto-isearch
-                                  "  Just type for auto-isearch."
-                                "  n/p/f/b/u to navigate, q to quit.")))))
+            (princ (format help (if org-goto-auto-isearch
+                                    "  Just type for auto-isearch."
+                                  "  n/p/f/b/u to navigate, q to quit.")))))
         (org-fit-window-to-buffer (get-buffer-window "*Org Help*"))
         (org-overview)
         (setq buffer-read-only t)
@@ -250,7 +250,7 @@ want.
 
 This command works around this by showing a copy of the current
 buffer in an indirect buffer, in overview mode.  You can dive
-into the tree in that copy, use org-occur and incremental search
+into the tree in that copy, use `org-occur' and incremental search
 to find a location.  When pressing RET or `Q', the command
 returns to the original buffer in which the visibility is still
 unchanged.  After RET it will also jump to the location selected
diff --git a/lisp/org/org-habit.el b/lisp/org/org-habit.el
index 231c08be0a..a355d8e5fa 100644
--- a/lisp/org/org-habit.el
+++ b/lisp/org/org-habit.el
@@ -90,7 +90,7 @@ It will be green even if it was done after the deadline."
   :type 'boolean)
 
 (defcustom org-habit-scheduled-past-days nil
-"Value to use instead of `org-scheduled-past-days', for habits only.
+  "Value to use instead of `org-scheduled-past-days', for habits only.
 
 If nil, `org-scheduled-past-days' is used.
 
diff --git a/lisp/org/org-id.el b/lisp/org/org-id.el
index b3b98c614a..bd7e73905f 100644
--- a/lisp/org/org-id.el
+++ b/lisp/org/org-id.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -128,6 +128,15 @@ nil   Never use an ID to make a link, instead link using a 
text search for
   :group 'org-id
   :type 'string)
 
+(defcustom org-id-ts-format "%Y%m%dT%H%M%S.%6N"
+  "Timestamp format for IDs generated using `ts' `org-id-method'.
+The format should be suitable to pass as an argument to `format-time-string'.
+
+Defaults to ISO8601 timestamps without separators and without
+timezone, local time and precision down to 1e-6 seconds."
+  :type 'string
+  :package-version '(Org . "9.5"))
+
 (defcustom org-id-method 'uuid
   "The method that should be used to create new IDs.
 
@@ -144,13 +153,12 @@ uuid       Create random (version 4) UUIDs.  If the 
program defined in
            `org-id-uuid-program' is available it is used to create the ID.
            Otherwise an internal functions is used.
 
-ts         Create ID's based on ISO8601 timestamps (without separators
-           and without timezone, local time).  Precision down to seconds."
+ts         Create ID's based on timestamps as specified in `org-id-ts-format'."
   :group 'org-id
   :type '(choice
          (const :tag "Org's internal method" org)
          (const :tag "external: uuidgen" uuid)
-         (const :tag "ISO8601 timestamp" ts)))
+         (const :tag "Timestamp with format `org-id-ts-format'" ts)))
 
 (defcustom org-id-prefix nil
   "The prefix for IDs.
@@ -188,15 +196,14 @@ the link."
   :group 'org-id
   :type 'boolean)
 
-(defcustom org-id-locations-file (convert-standard-filename
-                                 (concat user-emacs-directory 
".org-id-locations"))
+(defcustom org-id-locations-file (locate-user-emacs-file ".org-id-locations")
   "The file for remembering in which file an ID was defined.
 This variable is only relevant when `org-id-track-globally' is set."
   :group 'org-id
   :type 'file)
 
 (defcustom org-id-locations-file-relative nil
-  "Determines if org-id-locations should be stored as relative links.
+  "Determine if `org-id-locations' should be stored as relative links.
 Non-nil means that links to locations are stored as links
 relative to the location of where `org-id-locations-file' is
 stored.
@@ -297,7 +304,7 @@ If necessary, the ID is created."
          (if (caar org-refile-targets) 'file t))
         (org-refile-target-verify-function nil)
         (spos (org-refile-get-location "Entry"))
-        (pom (and spos (move-marker (make-marker) (nth 3 spos)
+        (pom (and spos (move-marker (make-marker) (or (nth 3 spos) 1)
                                     (get-file-buffer (nth 1 spos))))))
     (prog1 (org-id-get pom 'create)
       (move-marker pom nil))))
@@ -374,17 +381,15 @@ So a typical ID could look like \"Org:4nd91V40HI\"."
        (setq unique (org-id-uuid))))
      ((eq org-id-method 'org)
       (let* ((etime (org-reverse-string (org-id-time-to-b36)))
-            (postfix (if org-id-include-domain
-                         (progn
-                           (require 'message)
-                           (concat "@" (message-make-fqdn))))))
+            (postfix (when org-id-include-domain
+                       (require 'message)
+                       (concat "@" (message-make-fqdn)))))
        (setq unique (concat etime postfix))))
      ((eq org-id-method 'ts)
-      (let ((ts (format-time-string "%Y%m%dT%H%M%S.%6N"))
-           (postfix (if org-id-include-domain
-                        (progn
-                          (require 'message)
-                          (concat "@" (message-make-fqdn))))))
+      (let ((ts (format-time-string org-id-ts-format))
+           (postfix (when org-id-include-domain
+                      (require 'message)
+                      (concat "@" (message-make-fqdn)))))
        (setq unique (concat ts postfix))))
      (t (error "Invalid `org-id-method'")))
     (concat prefix unique)))
@@ -413,15 +418,15 @@ So a typical ID could look like \"Org:4nd91V40HI\"."
            (substring rnd 18 20)
            (substring rnd 20 32))))
 
-(defun org-id-int-to-b36-one-digit (i)
-  "Turn an integer between 0 and 61 into a single character 0..9, A..Z, a..z."
+(defun org-id-int-to-b36-one-digit (integer)
+  "Convert INTEGER between 0 and 61 into a single character 0..9, A..Z, a..z."
   (cond
-   ((< i 10) (+ ?0 i))
-   ((< i 36) (+ ?a i -10))
+   ((< integer 10) (+ ?0 integer))
+   ((< integer 36) (+ ?a integer -10))
    (t (error "Larger that 35"))))
 
 (defun org-id-b36-to-int-one-digit (i)
-  "Turn a character 0..9, A..Z, a..z into a number 0..61.
+  "Convert character 0..9, A..Z, a..z into a number 0..61.
 The input I may be a character, or a single-letter string."
   (and (stringp i) (setq i (string-to-char i)))
   (cond
@@ -429,9 +434,11 @@ The input I may be a character, or a single-letter string."
    ((and (>= i ?a) (<= i ?z)) (+ (- i ?a) 10))
    (t (error "Invalid b36 letter"))))
 
-(defun org-id-int-to-b36 (i &optional length)
-  "Convert an integer to a base-36 number represented as a string."
-  (let ((s ""))
+(defun org-id-int-to-b36 (integer &optional length)
+  "Convert an INTEGER to a base-36 number represented as a string.
+The returned string is padded with leading zeros to LENGTH if necessary."
+  (let ((s "")
+        (i integer))
     (while (> i 0)
       (setq s (concat (char-to-string
                       (org-id-int-to-b36-one-digit (mod i 36))) s)
@@ -441,11 +448,11 @@ The input I may be a character, or a single-letter 
string."
        (setq s (concat (make-string (- length (length s)) ?0) s)))
     s))
 
-(defun org-id-b36-to-int (s)
-  "Convert a base-36 string into the corresponding integer."
+(defun org-id-b36-to-int (string)
+  "Convert a base-36 STRING into the corresponding integer."
   (let ((r 0))
     (mapc (lambda (i) (setq r (+ (* r 36) (org-id-b36-to-int-one-digit i))))
-         s)
+         string)
     r))
 
 (defun org-id-time-to-b36 (&optional time)
@@ -483,7 +490,8 @@ and TIME is a Lisp time value (HI LO USEC)."
 Store the relation between files and corresponding IDs.
 This will scan all agenda files, all associated archives, and all
 files currently mentioned in `org-id-locations'.
-When FILES is given, scan also these files."
+When FILES is given, scan also these files.
+If SILENT is non-nil, messages are suppressed."
   (interactive)
   (unless org-id-track-globally
     (error "Please turn on `org-id-track-globally' if you want to track IDs"))
@@ -512,28 +520,31 @@ When FILES is given, scan also these files."
          (seen-ids nil)
          (ndup 0)
          (i 0))
-    (dolist (file files)
-      (when (file-exists-p file)
-        (unless silent
-          (cl-incf i)
-          (message "Finding ID locations (%d/%d files): %s" i nfiles file))
-        (with-current-buffer (find-file-noselect file t)
-          (let ((ids nil)
-                (case-fold-search t))
-            (org-with-point-at 1
-              (while (re-search-forward id-regexp nil t)
-                (when (org-at-property-p)
-                  (push (org-entry-get (point) "ID") ids)))
-              (when ids
-                (push (cons (abbreviate-file-name file) ids)
-                      org-id-locations)
-                (dolist (id ids)
-                  (cond
-                   ((not (member id seen-ids)) (push id seen-ids))
-                   (silent nil)
-                   (t
-                    (message "Duplicate ID %S" id)
-                    (cl-incf ndup))))))))))
+    (with-temp-buffer
+      (delay-mode-hooks
+       (org-mode)
+       (dolist (file files)
+         (when (file-exists-p file)
+            (unless silent
+              (cl-incf i)
+              (message "Finding ID locations (%d/%d files): %s" i nfiles file))
+           (insert-file-contents file nil nil nil 'replace)
+            (let ((ids nil)
+                 (case-fold-search t))
+              (org-with-point-at 1
+               (while (re-search-forward id-regexp nil t)
+                 (when (org-at-property-p)
+                    (push (org-entry-get (point) "ID") ids)))
+               (when ids
+                 (push (cons (abbreviate-file-name file) ids)
+                       org-id-locations)
+                 (dolist (id ids)
+                    (cond
+                     ((not (member id seen-ids)) (push id seen-ids))
+                     (silent nil)
+                     (t
+                      (message "Duplicate ID %S" id)
+                      (cl-incf ndup)))))))))))
     (setq org-id-files (mapcar #'car org-id-locations))
     (org-id-locations-save)
     ;; Now convert to a hash table.
@@ -580,7 +591,7 @@ When FILES is given, scan also these files."
                        (setf (car item) (expand-file-name (car item) loc))))
                    org-id-locations)))
        (error
-        (message "Could not read org-id-values from %s.  Setting it to nil."
+        (message "Could not read `org-id-values' from %s, setting it to nil"
                  org-id-locations-file))))
     (setq org-id-files (mapcar 'car org-id-locations))
     (setq org-id-locations (org-id-alist-to-hash org-id-locations))))
@@ -589,7 +600,7 @@ When FILES is given, scan also these files."
   "Add the ID with location FILE to the database of ID locations."
   ;; Only if global tracking is on, and when the buffer has a file
   (unless file
-    (error "bug: org-id-get expects a file-visiting buffer"))
+    (error "`org-id-get' expects a file-visiting buffer"))
   (let ((afile (abbreviate-file-name file)))
     (when (and org-id-track-globally id)
       (unless org-id-locations (org-id-locations-load))
@@ -601,7 +612,8 @@ When FILES is given, scan also these files."
   (add-hook 'kill-emacs-hook 'org-id-locations-save))
 
 (defun org-id-hash-to-alist (hash)
-  "Turn an org-id hash into an alist, so that it can be written to a file."
+  "Turn an org-id HASH into an alist.
+This is to be able to write it to a file."
   (let (res x)
     (maphash
      (lambda (k v)
@@ -612,7 +624,7 @@ When FILES is given, scan also these files."
     res))
 
 (defun org-id-alist-to-hash (list)
-  "Turn an org-id location list into a hash table."
+  "Turn an org-id location LIST into a hash table."
   (let ((res (make-hash-table
              :test 'equal
              :size (apply '+ (mapcar 'length list))))
@@ -625,7 +637,7 @@ When FILES is given, scan also these files."
     res))
 
 (defun org-id-paste-tracker (txt &optional buffer-or-file)
-  "Update any IDs in TXT and assign BUFFER-OR-FILE to them."
+  "Update any ids in TXT and assign BUFFER-OR-FILE to them."
   (when org-id-track-globally
     (save-match-data
       (setq buffer-or-file (or buffer-or-file (current-buffer)))
@@ -644,7 +656,7 @@ When FILES is given, scan also these files."
 
 ;;;###autoload
 (defun org-id-find-id-file (id)
-  "Query the id database for the file in which this ID is located."
+  "Query the id database for the file in which ID is located."
   (unless org-id-locations (org-id-locations-load))
   (or (and org-id-locations
           (hash-table-p org-id-locations)
@@ -655,20 +667,27 @@ When FILES is given, scan also these files."
 
 (defun org-id-find-id-in-file (id file &optional markerp)
   "Return the position of the entry ID in FILE.
+
 If that files does not exist, or if it does not contain this ID,
 return nil.
+
 The position is returned as a cons cell (file-name . position).  With
 optional argument MARKERP, return the position as a new marker."
-  (let (org-agenda-new-buffers buf pos)
-    (cond
-     ((not file) nil)
-     ((not (file-exists-p file)) nil)
-     (t (with-current-buffer (setq buf (org-get-agenda-file-buffer file))
-         (setq pos (org-find-entry-with-id id))
-         (when pos
-           (if markerp
-               (move-marker (make-marker) pos buf)
-             (cons file pos))))))))
+  (cond
+   ((not file) nil)
+   ((not (file-exists-p file)) nil)
+   (t
+    (let* ((visiting (find-buffer-visiting file))
+          (buffer (or visiting (find-file-noselect file))))
+      (unwind-protect
+         (with-current-buffer buffer
+           (let ((pos (org-find-entry-with-id id)))
+             (cond
+              ((null pos) nil)
+              (markerp (move-marker (make-marker) pos buffer))
+              (t (cons file pos)))))
+       ;; Remove opened buffer in the process.
+       (unless (or visiting markerp) (kill-buffer buffer)))))))
 
 ;; id link type
 
@@ -677,21 +696,27 @@ optional argument MARKERP, return the position as a new 
marker."
 
 ;;;###autoload
 (defun org-id-store-link ()
-  "Store a link to the current entry, using its ID."
+  "Store a link to the current entry, using its ID.
+
+If before first heading store first title-keyword as description
+or filename if no title."
   (interactive)
   (when (and (buffer-file-name (buffer-base-buffer)) (derived-mode-p 
'org-mode))
     (let* ((link (concat "id:" (org-id-get-create)))
           (case-fold-search nil)
           (desc (save-excursion
                   (org-back-to-heading-or-point-min t)
-                  (or (and (org-before-first-heading-p)
-                           (file-name-nondirectory
-                            (buffer-file-name (buffer-base-buffer))))
-                      (and (looking-at org-complex-heading-regexp)
-                           (if (match-end 4)
-                               (match-string 4)
-                             (match-string 0)))
-                      link))))
+                   (cond ((org-before-first-heading-p)
+                          (let ((keywords (org-collect-keywords '("TITLE"))))
+                            (if keywords
+                                (cadr (assoc "TITLE" keywords))
+                              (file-name-nondirectory
+                              (buffer-file-name (buffer-base-buffer))))))
+                        ((looking-at org-complex-heading-regexp)
+                         (if (match-end 4)
+                             (match-string 4)
+                           (match-string 0)))
+                         (t link)))))
       (org-link-store-props :link link :description desc :type "id")
       link)))
 
diff --git a/lisp/org/org-indent.el b/lisp/org/org-indent.el
index 3475cadc42..e0cb69780e 100644
--- a/lisp/org/org-indent.el
+++ b/lisp/org/org-indent.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -126,31 +126,32 @@ useful to make it ever so slightly different."
        (make-vector org-indent--deepest-level nil))
   (setq org-indent--text-line-prefixes
        (make-vector org-indent--deepest-level nil))
-  (dotimes (n org-indent--deepest-level)
-    (let ((indentation (if (<= n 1) 0
-                        (* (1- org-indent-indentation-per-level)
-                           (1- n)))))
-      ;; Headlines line prefixes.
-      (let ((heading-prefix (make-string indentation ?*)))
-       (aset org-indent--heading-line-prefixes
+  (when (> org-indent-indentation-per-level 0)
+    (dotimes (n org-indent--deepest-level)
+      (let ((indentation (if (<= n 1) 0
+                          (* (1- org-indent-indentation-per-level)
+                             (1- n)))))
+        ;; Headlines line prefixes.
+        (let ((heading-prefix (make-string indentation ?*)))
+         (aset org-indent--heading-line-prefixes
+               n
+               (org-add-props heading-prefix nil 'face 'org-indent))
+         ;; Inline tasks line prefixes
+         (aset org-indent--inlinetask-line-prefixes
+               n
+               (cond ((<= n 1) "")
+                     ((bound-and-true-p org-inlinetask-show-first-star)
+                      (concat org-indent-inlinetask-first-star
+                              (substring heading-prefix 1)))
+                     (t (org-add-props heading-prefix nil 'face 
'org-indent)))))
+        ;; Text line prefixes.
+        (aset org-indent--text-line-prefixes
              n
-             (org-add-props heading-prefix nil 'face 'org-indent))
-       ;; Inline tasks line prefixes
-       (aset org-indent--inlinetask-line-prefixes
-             n
-             (cond ((<= n 1) "")
-                   ((bound-and-true-p org-inlinetask-show-first-star)
-                    (concat org-indent-inlinetask-first-star
-                            (substring heading-prefix 1)))
-                   (t (org-add-props heading-prefix nil 'face 'org-indent)))))
-      ;; Text line prefixes.
-      (aset org-indent--text-line-prefixes
-           n
-           (org-add-props
-               (concat (make-string (+ n indentation) ?\s)
-                       (and (> n 0)
-                            (char-to-string org-indent-boundary-char)))
-               nil 'face 'org-indent)))))
+             (org-add-props
+                 (concat (make-string (+ n indentation) ?\s)
+                         (and (> n 0)
+                              (char-to-string org-indent-boundary-char)))
+                 nil 'face 'org-indent))))))
 
 (defsubst org-indent-remove-properties (beg end)
   "Remove indentations between BEG and END."
diff --git a/lisp/org/org-inlinetask.el b/lisp/org/org-inlinetask.el
index 48402b092b..3379a2e460 100644
--- a/lisp/org/org-inlinetask.el
+++ b/lisp/org/org-inlinetask.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 
@@ -131,7 +131,7 @@ If there is a region wrap it inside the inline task."
   ;; before this one.
   (when (and (org-inlinetask-in-task-p)
             (not (and (org-inlinetask-at-task-p) (bolp))))
-    (error "Cannot nest inline tasks"))
+    (user-error "Cannot nest inline tasks"))
   (or (bolp) (newline))
   (let* ((indent (if org-odd-levels-only
                     (1- (* 2 org-inlinetask-min-level))
@@ -189,7 +189,7 @@ The number of levels is controlled by 
`org-inlinetask-min-level'."
 
 (defun org-inlinetask-goto-end ()
   "Go to the end of the inline task at point.
-    Return point."
+Return point."
   (save-match-data
     (beginning-of-line)
     (let ((case-fold-search t)
@@ -225,7 +225,7 @@ If the task has an end part, promote it.  Also, prevents 
level from
 going below `org-inlinetask-min-level'."
   (interactive)
   (if (not (org-inlinetask-in-task-p))
-      (error "Not in an inline task")
+      (user-error "Not in an inline task")
     (save-excursion
       (let* ((lvl (org-inlinetask-get-task-level))
             (next-lvl (org-get-valid-level lvl -1))
@@ -233,15 +233,18 @@ going below `org-inlinetask-min-level'."
             (down-task (concat (make-string next-lvl ?*)))
             beg)
        (if (< next-lvl org-inlinetask-min-level)
-           (error "Cannot promote an inline task at minimum level")
+           (user-error "Cannot promote an inline task at minimum level")
          (org-inlinetask-goto-beginning)
          (setq beg (point))
          (replace-match down-task nil t nil 1)
          (org-inlinetask-goto-end)
-         (if (eobp) (beginning-of-line) (forward-line -1))
+         (if (and (eobp) (looking-back "END\\s-*" (point-at-bol)))
+              (beginning-of-line)
+            (forward-line -1))
          (unless (= (point) beg)
+            (looking-at (org-inlinetask-outline-regexp))
            (replace-match down-task nil t nil 1)
-           (when org-adapt-indentation
+           (when (eq org-adapt-indentation t)
              (goto-char beg)
              (org-fixup-indentation diff))))))))
 
@@ -250,7 +253,7 @@ going below `org-inlinetask-min-level'."
 If the task has an end part, also demote it."
   (interactive)
   (if (not (org-inlinetask-in-task-p))
-      (error "Not in an inline task")
+      (user-error "Not in an inline task")
     (save-excursion
       (let* ((lvl (org-inlinetask-get-task-level))
             (next-lvl (org-get-valid-level lvl 1))
@@ -261,10 +264,13 @@ If the task has an end part, also demote it."
        (setq beg (point))
        (replace-match down-task nil t nil 1)
        (org-inlinetask-goto-end)
-       (if (eobp) (beginning-of-line) (forward-line -1))
+        (if (and (eobp) (looking-back "END\\s-*" (point-at-bol)))
+            (beginning-of-line)
+          (forward-line -1))
        (unless (= (point) beg)
+          (looking-at (org-inlinetask-outline-regexp))
          (replace-match down-task nil t nil 1)
-         (when org-adapt-indentation
+         (when (eq org-adapt-indentation t)
            (goto-char beg)
            (org-fixup-indentation diff)))))))
 
diff --git a/lisp/org/org-keys.el b/lisp/org/org-keys.el
index f0fdb79ea4..a10db7e666 100644
--- a/lisp/org/org-keys.el
+++ b/lisp/org/org-keys.el
@@ -31,6 +31,8 @@
 
 (defvar org-outline-regexp)
 
+(require 'oc)
+
 (declare-function org-add-note "org" ())
 (declare-function org-agenda "org" (&optional arg org-keys restriction))
 (declare-function org-agenda-file-to-front "org" (&optional to-end))
@@ -56,7 +58,6 @@
 (declare-function org-clone-subtree-with-time-shift "org" (n &optional shift))
 (declare-function org-columns "org" (&optional global columns-fmt-string))
 (declare-function org-comment-dwim "org" (arg))
-(declare-function org-refile-copy "org" ())
 (declare-function org-copy-special "org" ())
 (declare-function org-copy-visible "org" (beg end))
 (declare-function org-ctrl-c-ctrl-c "org" (&optional arg))
@@ -143,6 +144,8 @@
 (declare-function org-promote-subtree "org" ())
 (declare-function org-redisplay-inline-images "org" ())
 (declare-function org-refile "org" (&optional arg1 default-buffer rfloc msg))
+(declare-function org-refile-copy "org" ())
+(declare-function org-refile-reverse "org-refile" (&optional arg 
default-buffer rfloc msg))
 (declare-function org-reftex-citation "org" ())
 (declare-function org-reload "org" (&optional arg1))
 (declare-function org-remove-file "org" (&optional file))
@@ -174,7 +177,6 @@
 (declare-function org-show-subtree "org" ())
 (declare-function org-sort "org" (&optional with-case))
 (declare-function org-sparse-tree "org" (&optional arg type))
-(declare-function org-table-blank-field "org" ())
 (declare-function org-table-copy-down "org" (n))
 (declare-function org-table-create-or-convert-from-region "org" (arg))
 (declare-function org-table-create-with-table\.el "org-table" ())
@@ -277,8 +279,7 @@ before org.el is loaded."
   :type '(choice
          (const :tag "A double click follows the link" double)
          (const :tag "Unconditionally follow the link with mouse-1" t)
-         (integer :tag "mouse-1 click does not follow the link if longer than 
N ms" 450))
-  :safe t)
+         (integer :tag "mouse-1 click does not follow the link if longer than 
N ms" 450)))
 
 (defcustom org-tab-follows-link nil
   "Non-nil means on links TAB will follow the link.
@@ -298,7 +299,7 @@ implementation is bad."
 In tables, the special behavior of RET has precedence."
   :group 'org-link-follow
   :type 'boolean
-  :safe t)
+  :safe #'booleanp)
 
 
 ;;; Functions
@@ -337,7 +338,6 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
   (org-defkey org-mouse-map [follow-link] 'mouse-face))
 
 (when org-tab-follows-link
-  (org-defkey org-mouse-map (kbd "<tab>") #'org-open-at-point)
   (org-defkey org-mouse-map (kbd "TAB") #'org-open-at-point))
 
 
@@ -443,18 +443,13 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
 (org-defkey org-mode-map (kbd "C-c C-x") (make-sparse-keymap))
 
 ;;;; TAB key with modifiers
-(org-defkey org-mode-map (kbd "C-i") #'org-cycle)
-(org-defkey org-mode-map (kbd "<tab>") #'org-cycle)
-(org-defkey org-mode-map (kbd "C-c C-<tab>") #'org-force-cycle-archived)
+(org-defkey org-mode-map (kbd "TAB") #'org-cycle)
+(org-defkey org-mode-map (kbd "C-c C-TAB") #'org-force-cycle-archived)
 ;; Override text-mode binding to expose `complete-symbol' for
 ;; pcomplete functionality.
-(org-defkey org-mode-map (kbd "M-<tab>") nil)
 (org-defkey org-mode-map (kbd "M-TAB") nil)
-(org-defkey org-mode-map (kbd "ESC <tab>") nil)
 (org-defkey org-mode-map (kbd "ESC TAB") nil)
 
-(org-defkey org-mode-map (kbd "<S-iso-leftab>") #'org-shifttab)
-(org-defkey org-mode-map (kbd "S-<tab>") #'org-shifttab)
 (org-defkey org-mode-map (kbd "S-TAB") #'org-shifttab)
 (define-key org-mode-map (kbd "<backtab>") #'org-shifttab)
 
@@ -463,12 +458,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
 (org-defkey org-mode-map (kbd "S-RET") #'org-table-copy-down)
 (org-defkey org-mode-map (kbd "M-S-<return>") #'org-insert-todo-heading)
 (org-defkey org-mode-map (kbd "M-S-RET") #'org-insert-todo-heading)
-(org-defkey org-mode-map (kbd "ESC S-<return>") #'org-insert-todo-heading)
-(org-defkey org-mode-map (kbd "ESC S-RET") #'org-insert-todo-heading)
-(org-defkey org-mode-map (kbd "M-<return>") #'org-meta-return)
 (org-defkey org-mode-map (kbd "M-RET") #'org-meta-return)
-(org-defkey org-mode-map (kbd "ESC <return>") #'org-meta-return)
-(org-defkey org-mode-map (kbd "ESC RET") #'org-meta-return)
 
 ;;;; Cursor keys with modifiers
 (org-defkey org-mode-map (kbd "M-<left>") #'org-metaleft)
@@ -582,6 +572,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
 (org-defkey org-mode-map (kbd "C-c ;") #'org-toggle-comment)
 (org-defkey org-mode-map (kbd "C-c C-w") #'org-refile)
 (org-defkey org-mode-map (kbd "C-c M-w") #'org-refile-copy)
+(org-defkey org-mode-map (kbd "C-c C-M-w") #'org-refile-reverse)
 (org-defkey org-mode-map (kbd "C-c /") #'org-sparse-tree) ;minor-mode reserved
 (org-defkey org-mode-map (kbd "C-c \\") #'org-match-sparse-tree) ;minor-mode r.
 (org-defkey org-mode-map (kbd "C-c RET") #'org-ctrl-c-ret)
@@ -620,7 +611,6 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
 (org-defkey org-mode-map (kbd "RET") #'org-return)
 (org-defkey org-mode-map (kbd "C-j") #'org-return-and-maybe-indent)
 (org-defkey org-mode-map (kbd "C-c ?") #'org-table-field-info)
-(org-defkey org-mode-map (kbd "C-c SPC") #'org-table-blank-field)
 (org-defkey org-mode-map (kbd "C-c +") #'org-table-sum)
 (org-defkey org-mode-map (kbd "C-c =") #'org-table-eval-formula)
 (org-defkey org-mode-map (kbd "C-c '") #'org-edit-special)
@@ -676,6 +666,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command 
names."
 (org-defkey org-mode-map (kbd "C-c C-x !") #'org-reload)
 (org-defkey org-mode-map (kbd "C-c C-x g") #'org-feed-update-all)
 (org-defkey org-mode-map (kbd "C-c C-x G") #'org-feed-goto-inbox)
+(org-defkey org-mode-map (kbd "C-c C-x @") #'org-cite-insert)
 (org-defkey org-mode-map (kbd "C-c C-x [") #'org-reftex-citation)
 (org-defkey org-mode-map (kbd "C-c C-x I") #'org-info-find-node)
 
@@ -698,28 +689,6 @@ star at the beginning of the headline, you can do this:
          (const :tag "At beginning of headline stars" t)
          (function)))
 
-(defcustom org-speed-commands-user nil
-  "Alist of additional speed commands.
-This list will be checked before `org-speed-commands-default'
-when the variable `org-use-speed-commands' is non-nil
-and when the cursor is at the beginning of a headline.
-The car of each entry is a string with a single letter, which must
-be assigned to `self-insert-command' in the global map.
-The cdr is either a command to be called interactively, a function
-to be called, or a form to be evaluated.
-An entry that is just a list with a single string will be interpreted
-as a descriptive headline that will be added when listing the speed
-commands in the Help buffer using the `?' speed command."
-  :group 'org-structure
-  :type '(repeat :value ("k" . ignore)
-                (choice :value ("k" . ignore)
-                        (list :tag "Descriptive Headline" (string :tag 
"Headline"))
-                        (cons :tag "Letter and Command"
-                              (string :tag "Command letter")
-                              (choice
-                               (function)
-                               (sexp))))))
-
 (defcustom org-speed-command-hook
   '(org-speed-command-activate org-babel-speed-command-activate)
   "Hook for activating speed commands at strategic locations.
@@ -739,7 +708,7 @@ hook.  The default setting is `org-speed-command-activate'."
   :version "24.1"
   :type 'hook)
 
-(defconst org-speed-commands-default
+(defcustom org-speed-commands
   '(("Outline Navigation")
     ("n" . (org-speed-move-safe 'org-next-visible-heading))
     ("p" . (org-speed-move-safe 'org-previous-visible-heading))
@@ -749,7 +718,7 @@ hook.  The default setting is `org-speed-command-activate'."
     ("B" . org-previous-block)
     ("u" . (org-speed-move-safe 'outline-up-heading))
     ("j" . org-goto)
-    ("g" . (org-refile t))
+    ("g" . (org-refile '(4)))
     ("Outline Visibility")
     ("c" . org-cycle)
     ("C" . org-shifttab)
@@ -764,8 +733,7 @@ hook.  The default setting is `org-speed-command-activate'."
     ("l" . org-metaleft)
     ("R" . org-shiftmetaright)
     ("L" . org-shiftmetaleft)
-    ("i" . (progn (forward-char 1) (call-interactively
-                                   'org-insert-heading-respect-content)))
+    ("i" . (progn (forward-char 1) (call-interactively 
'org-insert-heading-respect-content)))
     ("^" . org-sort)
     ("w" . org-refile)
     ("a" . org-archive-subtree-default-with-confirmation)
@@ -784,8 +752,7 @@ hook.  The default setting is `org-speed-command-activate'."
     (":" . org-set-tags-command)
     ("e" . org-set-effort)
     ("E" . org-inc-effort)
-    ("W" . (lambda(m) (interactive "sMinutes before warning: ")
-            (org-entry-put (point) "APPT_WARNTIME" m)))
+    ("W" . (lambda (m) (interactive "sMinutes before warning: ") 
(org-entry-put (point) "APPT_WARNTIME" m)))
     ("Agenda Views etc")
     ("v" . org-agenda)
     ("/" . org-sparse-tree)
@@ -794,7 +761,28 @@ hook.  The default setting is 
`org-speed-command-activate'."
     ("?" . org-speed-command-help)
     ("<" . (org-agenda-set-restriction-lock 'subtree))
     (">" . (org-agenda-remove-restriction-lock)))
-  "The default speed commands.")
+  "Alist of speed commands.
+
+The car of each entry is a string with a single letter, which
+must be assigned to `self-insert-command' in the global map.
+
+The cdr is either a command to be called interactively, a
+function to be called, or a form to be evaluated.
+
+An entry that is just a list with a single string will be
+interpreted as a descriptive headline that will be added when
+listing the speed commands in the Help buffer using the `?' speed
+command."
+  :group 'org-structure
+  :package-version '(Org . "9.5")
+  :type '(repeat :value ("k" . ignore)
+                (choice :value ("k" . ignore)
+                        (list :tag "Descriptive Headline" (string :tag 
"Headline"))
+                        (cons :tag "Letter and Command"
+                              (string :tag "Command letter")
+                              (choice
+                               (function)
+                               (sexp))))))
 
 (defun org-print-speed-command (e)
   (if (> (length (car e)) 1)
@@ -816,12 +804,18 @@ hook.  The default setting is 
`org-speed-command-activate'."
   (interactive)
   (unless org-use-speed-commands
     (user-error "Speed commands are not activated, customize 
`org-use-speed-commands'"))
+  ;; FIXME: remove this warning for 9.6
+  (when (boundp 'org-speed-commands-user)
+    (message "`org-speed-command-user' is obsolete, please use 
`org-speed-commands'")
+    (sit-for 3))
   (with-output-to-temp-buffer "*Help*"
-    (princ "User-defined Speed commands\n===========================\n")
-    (mapc #'org-print-speed-command org-speed-commands-user)
-    (princ "\n")
-    (princ "Built-in Speed commands\n=======================\n")
-    (mapc #'org-print-speed-command org-speed-commands-default))
+    (princ "Speed commands\n==============\n")
+    (mapc #'org-print-speed-command
+          ;; FIXME: don't check `org-speed-commands-user' past 9.6
+          (if (boundp 'org-speed-commands-user)
+              (append org-speed-commands
+                      org-speed-commands-user)
+            org-speed-commands)))
   (with-current-buffer "*Help*"
     (setq truncate-lines t)))
 
@@ -837,13 +831,16 @@ If not, return to the original position and throw an 
error."
 
 (defun org-speed-command-activate (keys)
   "Hook for activating single-letter speed commands.
-`org-speed-commands-default' specifies a minimal command set.
-Use `org-speed-commands-user' for further customization."
+See `org-speed-commands' for configuring them."
   (when (or (and (bolp) (looking-at org-outline-regexp))
            (and (functionp org-use-speed-commands)
                 (funcall org-use-speed-commands)))
-    (cdr (assoc keys (append org-speed-commands-user
-                            org-speed-commands-default)))))
+    (cdr (assoc keys
+                ;; FIXME: don't check `org-speed-commands-user' past 9.6
+                (if (boundp 'org-speed-commands-user)
+                    (append org-speed-commands
+                            org-speed-commands-user)
+                  org-speed-commands)))))
 
 
 ;;; Babel speed keys
diff --git a/lisp/org/org-lint.el b/lisp/org/org-lint.el
index 2e080cc138..da5e6ae799 100644
--- a/lisp/org/org-lint.el
+++ b/lisp/org/org-lint.el
@@ -350,7 +350,7 @@ called with one argument, the key used for comparison."
    (lambda (datum name)
      (goto-char (org-element-property :begin datum))
      (re-search-forward
-      (format "^[ \t]*#\\+[A-Za-z]+: +%s *$" (regexp-quote name)))
+      (format "^[ \t]*#\\+[A-Za-z]+:[ \t]*%s[ \t]*$" (regexp-quote name)))
      (match-beginning 0))
    (lambda (key) (format "Duplicate NAME \"%s\"" key))))
 
@@ -593,7 +593,7 @@ in description"
        (let ((file (org-unbracket-string
                        "\"" "\""
                      (org-element-property :value k))))
-         (and (not (org-file-url-p file))
+         (and (not (org-url-p file))
               (not (file-remote-p file))
               (not (file-exists-p file))
               (list (org-element-property :begin k)
@@ -671,7 +671,7 @@ Use \"export %s\" instead"
        (when (string= (org-element-property :key k) "OPTIONS")
          (let ((value (org-element-property :value k))
                (start 0))
-           (while (string-match "\\(.+?\\):\\((.*?)\\|\\S-*\\)[ \t]*"
+           (while (string-match "\\(.+?\\):\\((.*?)\\|\\S-+\\)?[ \t]*"
                                 value
                                 start)
              (setf start (match-end 0))
@@ -679,19 +679,50 @@ Use \"export %s\" instead"
                (unless (member item allowed)
                  (push (list (org-element-property :post-affiliated k)
                              (format "Unknown OPTIONS item \"%s\"" item))
-                       reports))))))))
+                       reports))
+                (unless (match-string 2 value)
+                  (push (list (org-element-property :post-affiliated k)
+                              (format "Missing value for option item %S" item))
+                        reports))))))))
     reports))
 
 (defun org-lint-invalid-macro-argument-and-template (ast)
-  (let ((extract-placeholders
-        (lambda (template)
-          (let ((start 0)
-                args)
-            (while (string-match "\\$\\([1-9][0-9]*\\)" template start)
-              (setf start (match-end 0))
-              (push (string-to-number (match-string 1 template)) args))
-            (sort (org-uniquify args) #'<))))
-       reports)
+  (let* ((reports nil)
+         (extract-placeholders
+         (lambda (template)
+           (let ((start 0)
+                 args)
+             (while (string-match "\\$\\([1-9][0-9]*\\)" template start)
+               (setf start (match-end 0))
+               (push (string-to-number (match-string 1 template)) args))
+             (sort (org-uniquify args) #'<))))
+         (check-arity
+          (lambda (arity macro)
+            (let* ((name (org-element-property :key macro))
+                   (pos (org-element-property :begin macro))
+                   (args (org-element-property :args macro))
+                   (l (length args)))
+              (cond
+               ((< l (1- (car arity)))
+                (push (list pos (format "Missing arguments in macro %S" name))
+                      reports))
+               ((< l (car arity))
+                (push (list pos (format "Missing argument in macro %S" name))
+                      reports))
+               ((> l (1+ (cdr arity)))
+                (push (let ((spurious-args (nthcdr (cdr arity) args)))
+                        (list pos
+                              (format "Spurious arguments in macro %S: %s"
+                                      name
+                                      (mapconcat #'org-trim spurious-args ", 
"))))
+                      reports))
+               ((> l (cdr arity))
+                (push (list pos
+                            (format "Spurious argument in macro %S: %s"
+                                    name
+                                    (org-last args)))
+                      reports))
+               (t nil))))))
     ;; Check arguments for macro templates.
     (org-element-map ast 'keyword
       (lambda (k)
@@ -727,25 +758,29 @@ Use \"export %s\" instead"
        (lambda (macro)
          (let* ((name (org-element-property :key macro))
                 (template (cdr (assoc-string name templates t))))
-           (if (not template)
-               (push (list (org-element-property :begin macro)
-                           (format "Undefined macro \"%s\"" name))
-                     reports)
-             (let ((arg-numbers (funcall extract-placeholders template)))
-               (when arg-numbers
-                 (let ((spurious-args
-                        (nthcdr (apply #'max arg-numbers)
-                                (org-element-property :args macro))))
-                   (when spurious-args
-                     (push
-                      (list (org-element-property :begin macro)
-                            (format "Unused argument%s in macro \"%s\": %s"
-                                    (if (> (length spurious-args) 1) "s" "")
-                                    name
-                                    (mapconcat (lambda (a) (format "\"%s\"" a))
-                                               spurious-args
-                                               ", ")))
-                      reports))))))))))
+            (pcase template
+              (`nil
+               (push (list (org-element-property :begin macro)
+                          (format "Undefined macro %S" name))
+                    reports))
+              ((guard (string= name "keyword"))
+               (funcall check-arity '(1 . 1) macro))
+              ((guard (string= name "modification-time"))
+               (funcall check-arity '(1 . 2) macro))
+              ((guard (string= name "n"))
+               (funcall check-arity '(0 . 2) macro))
+              ((guard (string= name "property"))
+               (funcall check-arity '(1 . 2) macro))
+              ((guard (string= name "time"))
+               (funcall check-arity '(1 . 1) macro))
+              ((pred functionp))        ;ignore (eval ...) templates
+              (_
+               (let* ((arg-numbers (funcall extract-placeholders template))
+                      (arity (if (null arg-numbers)
+                                 '(0 . 0)
+                               (let ((m (apply #'max arg-numbers)))
+                                 (cons m m)))))
+                 (funcall check-arity arity macro))))))))
     reports))
 
 (defun org-lint-undefined-footnote-reference (ast)
@@ -1191,7 +1226,6 @@ CHECKERS is the list of checkers used."
       (setf org-lint--source-buffer source)
       (setf org-lint--local-checkers checkers)
       (org-lint--refresh-reports)
-      (tabulated-list-print)
       (add-hook 'tabulated-list-revert-hook #'org-lint--refresh-reports nil t))
     (pop-to-buffer buffer)))
 
@@ -1217,7 +1251,7 @@ CHECKERS is the list of checkers used."
   (let ((c (org-lint--current-checker)))
     (setf tabulated-list-entries
          (cl-remove-if (lambda (e) (equal c (org-lint--current-checker e)))
-                        tabulated-list-entries))
+                       tabulated-list-entries))
     (tabulated-list-print)))
 
 (defun org-lint--ignore-checker ()
@@ -1271,7 +1305,7 @@ ARG can also be a list of checker names, as symbols, to 
run."
                     (throw 'exit c)))))))
           ((pred consp)
            (cl-remove-if-not (lambda (c) (memq (org-lint-checker-name c) arg))
-                              org-lint--checkers))
+                             org-lint--checkers))
           (_ (user-error "Invalid argument `%S' for `org-lint'" arg)))))
     (if (not (called-interactively-p 'any))
        (org-lint--generate-reports (current-buffer) checkers)
diff --git a/lisp/org/org-list.el b/lisp/org/org-list.el
index ddb47dd190..2bd9dc4d9e 100644
--- a/lisp/org/org-list.el
+++ b/lisp/org/org-list.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;        Bastien Guerry <bzg@gnu.org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
@@ -601,25 +601,23 @@ Assume point is at an item."
           (beg-cell (cons (point) (current-indentation)))
            itm-lst itm-lst-2 end-lst end-lst-2 struct
           (assoc-at-point
-           (function
-            ;; Return association at point.
-            (lambda (ind)
-              (looking-at org-list-full-item-re)
-              (let ((bullet (match-string-no-properties 1)))
-                (list (point)
-                      ind
-                      bullet
-                      (match-string-no-properties 2) ; counter
-                      (match-string-no-properties 3) ; checkbox
-                      ;; Description tag.
-                      (and (string-match-p "[-+*]" bullet)
-                           (match-string-no-properties 4)))))))
+           ;; Return association at point.
+           (lambda (ind)
+             (looking-at org-list-full-item-re)
+             (let ((bullet (match-string-no-properties 1)))
+               (list (point)
+                     ind
+                     bullet
+                     (match-string-no-properties 2) ; counter
+                     (match-string-no-properties 3) ; checkbox
+                     ;; Description tag.
+                     (and (string-match-p "[-+*]" bullet)
+                          (match-string-no-properties 4))))))
           (end-before-blank
-           (function
-            ;; Ensure list ends at the first blank line.
-            (lambda ()
-              (skip-chars-backward " \r\t\n")
-              (min (1+ (point-at-eol)) lim-down)))))
+           ;; Ensure list ends at the first blank line.
+           (lambda ()
+             (skip-chars-backward " \r\t\n")
+             (min (1+ (point-at-eol)) lim-down))))
       ;; 1. Read list from starting item to its beginning, and save
       ;;    top item position and indentation in BEG-CELL.  Also store
       ;;    ending position of items in END-LST.
@@ -1004,23 +1002,22 @@ alist of ancestors, as returned by 
`org-list-parents-alist'.
 Return value is a list of integers.  Counters have an impact on
 that value."
   (let ((get-relative-number
-        (function
-         (lambda (item struct prevs)
-           ;; Return relative sequence number of ITEM in the sub-list
-           ;; it belongs.  STRUCT is the list structure.  PREVS is
-           ;; the alist of previous items.
-           (let ((seq 0) (pos item) counter)
-             (while (and (not (setq counter (org-list-get-counter pos struct)))
-                         (setq pos (org-list-get-prev-item pos struct prevs)))
-               (cl-incf seq))
-             (if (not counter) (1+ seq)
-               (cond
-                ((string-match "[A-Za-z]" counter)
-                 (+ (- (string-to-char (upcase (match-string 0 counter))) 64)
-                    seq))
-                ((string-match "[0-9]+" counter)
-                 (+ (string-to-number (match-string 0 counter)) seq))
-                (t (1+ seq)))))))))
+        (lambda (item struct prevs)
+          ;; Return relative sequence number of ITEM in the sub-list
+          ;; it belongs.  STRUCT is the list structure.  PREVS is
+          ;; the alist of previous items.
+          (let ((seq 0) (pos item) counter)
+            (while (and (not (setq counter (org-list-get-counter pos struct)))
+                        (setq pos (org-list-get-prev-item pos struct prevs)))
+              (cl-incf seq))
+            (if (not counter) (1+ seq)
+              (cond
+               ((string-match "[A-Za-z]" counter)
+                (+ (- (string-to-char (upcase (match-string 0 counter))) 64)
+                   seq))
+               ((string-match "[0-9]+" counter)
+                (+ (string-to-number (match-string 0 counter)) seq))
+               (t (1+ seq))))))))
     ;; Cons each parent relative number into return value (OUT).
     (let ((out (list (funcall get-relative-number item struct prevs)))
          (parent item))
@@ -1182,14 +1179,13 @@ some heuristics to guess the result."
           (cdr (assq 'plain-list-item org-blank-before-new-entry)))
          usr-blank
          (count-blanks
-          (function
-           (lambda ()
-             ;; Count blank lines above beginning of line.
-             (save-excursion
-               (count-lines (goto-char (point-at-bol))
-                            (progn (skip-chars-backward " \r\t\n")
-                                   (forward-line)
-                                   (point))))))))
+          (lambda ()
+            ;; Count blank lines above beginning of line.
+            (save-excursion
+              (count-lines (goto-char (point-at-bol))
+                           (progn (skip-chars-backward " \r\t\n")
+                                  (forward-line)
+                                  (point)))))))
       (cond
        ;; Trivial cases where there should be none.
        ((not insert-blank-p) 0)
@@ -1652,65 +1648,64 @@ PREVS is the alist of previous items, as returned by
 This function modifies STRUCT."
   (let ((case-fold-search nil)
        (fix-bul
-        (function
-         ;; Set bullet of ITEM in STRUCT, depending on the type of
-         ;; first item of the list, the previous bullet and counter
-         ;; if any.
-         (lambda (item)
-           (let* ((prev (org-list-get-prev-item item struct prevs))
-                  (prev-bul (and prev (org-list-get-bullet prev struct)))
-                  (counter (org-list-get-counter item struct))
-                  (bullet (org-list-get-bullet item struct))
-                  (alphap (and (not prev)
-                               (org-list-use-alpha-bul-p item struct prevs))))
-             (org-list-set-bullet
-              item struct
-              (org-list-bullet-string
-               (cond
-                ;; Alpha counter in alpha list: use counter.
-                ((and prev counter
-                      (string-match "[a-zA-Z]" counter)
-                      (string-match "[a-zA-Z]" prev-bul))
-                 ;; Use cond to be sure `string-match' is used in
-                 ;; both cases.
-                 (let ((real-count
-                        (cond
-                         ((string-match "[a-z]" prev-bul) (downcase counter))
-                         ((string-match "[A-Z]" prev-bul) (upcase counter)))))
-                   (replace-match real-count nil nil prev-bul)))
-                ;; Num counter in a num list: use counter.
-                ((and prev counter
-                      (string-match "[0-9]+" counter)
-                      (string-match "[0-9]+" prev-bul))
-                 (replace-match counter nil nil prev-bul))
-                ;; No counter: increase, if needed, previous bullet.
-                (prev
-                 (org-list-inc-bullet-maybe (org-list-get-bullet prev struct)))
-                ;; Alpha counter at first item: use counter.
-                ((and counter (org-list-use-alpha-bul-p item struct prevs)
-                      (string-match "[A-Za-z]" counter)
-                      (string-match "[A-Za-z]" bullet))
-                 (let ((real-count
-                        (cond
-                         ((string-match "[a-z]" bullet) (downcase counter))
-                         ((string-match "[A-Z]" bullet) (upcase counter)))))
-                   (replace-match real-count nil nil bullet)))
-                ;; Num counter at first item: use counter.
-                ((and counter
-                      (string-match "[0-9]+" counter)
-                      (string-match "[0-9]+" bullet))
-                 (replace-match counter nil nil bullet))
-                ;; First bullet is alpha uppercase: use "A".
-                ((and alphap (string-match "[A-Z]" bullet))
-                 (replace-match "A" nil nil bullet))
-                ;; First bullet is alpha lowercase: use "a".
-                ((and alphap (string-match "[a-z]" bullet))
-                 (replace-match "a" nil nil bullet))
-                ;; First bullet is num: use "1".
-                ((string-match "\\([0-9]+\\|[A-Za-z]\\)" bullet)
-                 (replace-match "1" nil nil bullet))
-                ;; Not an ordered list: keep bullet.
-                (t bullet)))))))))
+        ;; Set bullet of ITEM in STRUCT, depending on the type of
+        ;; first item of the list, the previous bullet and counter
+        ;; if any.
+        (lambda (item)
+          (let* ((prev (org-list-get-prev-item item struct prevs))
+                 (prev-bul (and prev (org-list-get-bullet prev struct)))
+                 (counter (org-list-get-counter item struct))
+                 (bullet (org-list-get-bullet item struct))
+                 (alphap (and (not prev)
+                              (org-list-use-alpha-bul-p item struct prevs))))
+            (org-list-set-bullet
+             item struct
+             (org-list-bullet-string
+              (cond
+               ;; Alpha counter in alpha list: use counter.
+               ((and prev counter
+                     (string-match "[a-zA-Z]" counter)
+                     (string-match "[a-zA-Z]" prev-bul))
+                ;; Use cond to be sure `string-match' is used in
+                ;; both cases.
+                (let ((real-count
+                       (cond
+                        ((string-match "[a-z]" prev-bul) (downcase counter))
+                        ((string-match "[A-Z]" prev-bul) (upcase counter)))))
+                  (replace-match real-count nil nil prev-bul)))
+               ;; Num counter in a num list: use counter.
+               ((and prev counter
+                     (string-match "[0-9]+" counter)
+                     (string-match "[0-9]+" prev-bul))
+                (replace-match counter nil nil prev-bul))
+               ;; No counter: increase, if needed, previous bullet.
+               (prev
+                (org-list-inc-bullet-maybe (org-list-get-bullet prev struct)))
+               ;; Alpha counter at first item: use counter.
+               ((and counter (org-list-use-alpha-bul-p item struct prevs)
+                     (string-match "[A-Za-z]" counter)
+                     (string-match "[A-Za-z]" bullet))
+                (let ((real-count
+                       (cond
+                        ((string-match "[a-z]" bullet) (downcase counter))
+                        ((string-match "[A-Z]" bullet) (upcase counter)))))
+                  (replace-match real-count nil nil bullet)))
+               ;; Num counter at first item: use counter.
+               ((and counter
+                     (string-match "[0-9]+" counter)
+                     (string-match "[0-9]+" bullet))
+                (replace-match counter nil nil bullet))
+               ;; First bullet is alpha uppercase: use "A".
+               ((and alphap (string-match "[A-Z]" bullet))
+                (replace-match "A" nil nil bullet))
+               ;; First bullet is alpha lowercase: use "a".
+               ((and alphap (string-match "[a-z]" bullet))
+                (replace-match "a" nil nil bullet))
+               ;; First bullet is num: use "1".
+               ((string-match "\\([0-9]+\\|[A-Za-z]\\)" bullet)
+                (replace-match "1" nil nil bullet))
+               ;; Not an ordered list: keep bullet.
+               (t bullet))))))))
     (mapc fix-bul (mapcar #'car struct))))
 
 (defun org-list-struct-fix-ind (struct parents &optional bullet-size)
@@ -1756,21 +1751,20 @@ all others cases, the return value will be nil.
 This function modifies STRUCT."
   (let ((all-items (mapcar #'car struct))
        (set-parent-box
-        (function
-         (lambda (item)
-           (let* ((box-list
-                   (mapcar (lambda (child)
-                             (org-list-get-checkbox child struct))
-                           (org-list-get-children item struct parents))))
-             (org-list-set-checkbox
-              item struct
-              (cond
-               ((and (member "[ ]" box-list) (member "[X]" box-list)) "[-]")
-               ((member "[-]" box-list) "[-]")
-               ((member "[X]" box-list) "[X]")
-               ((member "[ ]" box-list) "[ ]")
-               ;; Parent has no boxed child: leave box as-is.
-               (t (org-list-get-checkbox item struct))))))))
+        (lambda (item)
+          (let* ((box-list
+                  (mapcar (lambda (child)
+                            (org-list-get-checkbox child struct))
+                          (org-list-get-children item struct parents))))
+            (org-list-set-checkbox
+             item struct
+             (cond
+              ((and (member "[ ]" box-list) (member "[X]" box-list)) "[-]")
+              ((member "[-]" box-list) "[-]")
+              ((member "[X]" box-list) "[X]")
+              ((member "[ ]" box-list) "[ ]")
+              ;; Parent has no boxed child: leave box as-is.
+              (t (org-list-get-checkbox item struct)))))))
        parent-list)
     ;; 1. List all parents with a checkbox.
     (mapc
@@ -1841,56 +1835,54 @@ Initial position of cursor is restored after the 
changes."
                             (org-inlinetask-outline-regexp)))
         (item-re (org-item-re))
         (shift-body-ind
-         (function
-          ;; Shift the indentation between END and BEG by DELTA.
-          ;; Start from the line before END.
-          (lambda (end beg delta)
-            (goto-char end)
-            (skip-chars-backward " \r\t\n")
-            (beginning-of-line)
-            (while (or (> (point) beg)
-                       (and (= (point) beg)
-                            (not (looking-at item-re))))
-              (cond
-               ;; Skip inline tasks.
-               ((and inlinetask-re (looking-at inlinetask-re))
-                (org-inlinetask-goto-beginning))
-               ;; Shift only non-empty lines.
-               ((looking-at-p "^[ \t]*\\S-")
-                (indent-line-to (+ (current-indentation) delta))))
-              (forward-line -1)))))
-         (modify-item
-          (function
-          ;; Replace ITEM first line elements with new elements from
-          ;; STRUCT, if appropriate.
-          (lambda (item)
-            (goto-char item)
-            (let* ((new-ind (org-list-get-ind item struct))
-                   (old-ind (current-indentation))
-                   (new-bul (org-list-bullet-string
-                             (org-list-get-bullet item struct)))
-                   (old-bul (org-list-get-bullet item old-struct))
-                   (new-box (org-list-get-checkbox item struct)))
-              (looking-at org-list-full-item-re)
-              ;; a.  Replace bullet
-              (unless (equal old-bul new-bul)
-                (replace-match new-bul nil nil nil 1))
-              ;; b.  Replace checkbox.
-              (cond
-               ((equal (match-string 3) new-box))
-               ((and (match-string 3) new-box)
-                (replace-match new-box nil nil nil 3))
-               ((match-string 3)
-                (looking-at ".*?\\([ \t]*\\[[ X-]\\]\\)")
-                (replace-match "" nil nil nil 1))
-               (t (let ((counterp (match-end 2)))
-                    (goto-char (if counterp (1+ counterp) (match-end 1)))
-                    (insert (concat new-box (unless counterp " "))))))
-              ;; c.  Indent item to appropriate column.
-              (unless (= new-ind old-ind)
-                (delete-region (goto-char (point-at-bol))
-                               (progn (skip-chars-forward " \t") (point)))
-                (indent-to new-ind)))))))
+         ;; Shift the indentation between END and BEG by DELTA.
+         ;; Start from the line before END.
+         (lambda (end beg delta)
+           (goto-char end)
+           (skip-chars-backward " \r\t\n")
+           (beginning-of-line)
+           (while (or (> (point) beg)
+                      (and (= (point) beg)
+                           (not (looking-at item-re))))
+             (cond
+              ;; Skip inline tasks.
+              ((and inlinetask-re (looking-at inlinetask-re))
+               (org-inlinetask-goto-beginning))
+              ;; Shift only non-empty lines.
+              ((looking-at-p "^[ \t]*\\S-")
+               (indent-line-to (+ (current-indentation) delta))))
+             (forward-line -1))))
+        (modify-item
+         ;; Replace ITEM first line elements with new elements from
+         ;; STRUCT, if appropriate.
+         (lambda (item)
+           (goto-char item)
+           (let* ((new-ind (org-list-get-ind item struct))
+                  (old-ind (current-indentation))
+                  (new-bul (org-list-bullet-string
+                            (org-list-get-bullet item struct)))
+                  (old-bul (org-list-get-bullet item old-struct))
+                  (new-box (org-list-get-checkbox item struct)))
+             (looking-at org-list-full-item-re)
+             ;; a.  Replace bullet
+             (unless (equal old-bul new-bul)
+               (replace-match new-bul nil nil nil 1))
+             ;; b.  Replace checkbox.
+             (cond
+              ((equal (match-string 3) new-box))
+              ((and (match-string 3) new-box)
+               (replace-match new-box nil nil nil 3))
+              ((match-string 3)
+               (looking-at ".*?\\([ \t]*\\[[ X-]\\]\\)")
+               (replace-match "" nil nil nil 1))
+              (t (let ((counterp (match-end 2)))
+                   (goto-char (if counterp (1+ counterp) (match-end 1)))
+                   (insert (concat new-box (unless counterp " "))))))
+             ;; c.  Indent item to appropriate column.
+             (unless (= new-ind old-ind)
+               (delete-region (goto-char (point-at-bol))
+                              (progn (skip-chars-forward " \t") (point)))
+               (indent-to new-ind))))))
     ;; 1. First get list of items and position endings.  We maintain
     ;;    two alists: ITM-SHIFT, determining indentation shift needed
     ;;    at item, and END-LIST, a pseudo-alist where key is ending
@@ -2484,10 +2476,10 @@ With optional prefix argument ALL, do this for the 
whole buffer."
    (let* ((cookie-re "\\(\\(\\[[0-9]*%\\]\\)\\|\\(\\[[0-9]*/[0-9]*\\]\\)\\)")
          (box-re "^[ \t]*\\([-+*]\\|\\([0-9]+\\|[A-Za-z]\\)[.)]\\)[ \t]+\
 \\(?:\\[@\\(?:start:\\)?\\([0-9]+\\|[A-Za-z]\\)\\][ \t]*\\)?\\(\\[[- X]\\]\\)")
+          (cookie-data (or (org-entry-get nil "COOKIE_DATA") ""))
          (recursivep
           (or (not org-checkbox-hierarchical-statistics)
-              (string-match "\\<recursive\\>"
-                            (or (org-entry-get nil "COOKIE_DATA") ""))))
+              (string-match-p "\\<recursive\\>" cookie-data)))
          (within-inlinetask (and (not all)
                                  (featurep 'org-inlinetask)
                                  (org-inlinetask-in-task-p)))
@@ -2533,7 +2525,8 @@ With optional prefix argument ALL, do this for the whole 
buffer."
      (while (re-search-forward cookie-re end t)
        (let ((context (save-excursion (backward-char)
                                      (save-match-data (org-element-context)))))
-        (when (eq (org-element-type context) 'statistics-cookie)
+        (when (and (eq (org-element-type context) 'statistics-cookie)
+                    (not (string-match-p "\\<todo\\>" cookie-data)))
           (push
            (append
             (list (match-beginning 1) (match-end 1) (match-end 2))
diff --git a/lisp/org/org-macro.el b/lisp/org/org-macro.el
index f914a33d61..c38a07b69a 100644
--- a/lisp/org/org-macro.el
+++ b/lisp/org/org-macro.el
@@ -30,7 +30,7 @@
 ;; `org-macro-initialize-templates', which recursively calls
 ;; `org-macro--collect-macros' in order to read setup files.
 
-;; Argument in macros are separated with commas. Proper escaping rules
+;; Argument in macros are separated with commas.  Proper escaping rules
 ;; are implemented in `org-macro-escape-arguments' and arguments can
 ;; be extracted from a string with `org-macro-extract-arguments'.
 
@@ -61,7 +61,6 @@
 (declare-function org-element-type "org-element" (element))
 (declare-function org-entry-get "org" (pom property &optional inherit 
literal-nil))
 (declare-function org-file-contents "org" (file &optional noerror nocache))
-(declare-function org-file-url-p "org" (file))
 (declare-function org-in-commented-heading-p "org" (&optional no-inheritance))
 (declare-function org-link-search "ol" (s &optional avoid-pos stealth))
 (declare-function org-mode "org" ())
@@ -84,42 +83,67 @@ directly, use instead:
 
 ;;; Functions
 
-(defun org-macro--set-template (name value templates)
+(defun org-macro--makeargs (template)
+  "Compute the formal arglist to use for TEMPLATE."
+  (let ((max 0) (i 0))
+    (while (string-match "\\$\\([0-9]+\\)" template i)
+      (setq i (match-end 0))
+      (setq max (max max (string-to-number (match-string 1 template)))))
+    (let ((args '(&rest _)))
+      (if (< max 1) args ;Avoid `&optional &rest', refused by Emacs-26!
+        (while (> max 0)
+          (push (intern (format "$%d" max)) args)
+          (setq max (1- max)))
+        (cons '&optional args)))))
+
+(defun org-macro--set-templates (templates)
   "Set template for the macro NAME.
 VALUE is the template of the macro.  The new value override the
-previous one, unless VALUE is nil.  TEMPLATES is the list of
-templates.  Return the updated list."
-  (let ((old-definition (assoc name templates)))
-    (cond ((and value old-definition) (setcdr old-definition value))
-         (old-definition)
-         (t (push (cons name (or value "")) templates))))
-  templates)
+previous one, unless VALUE is nil.  Return the updated list."
+  (let ((new-templates nil))
+    (pcase-dolist (`(,name . ,value) templates)
+      (let ((old-definition (assoc name new-templates)))
+        (when (and (stringp value) (string-match-p "\\`(eval\\>" value))
+          ;; Pre-process the evaluation form for faster macro expansion.
+          (let* ((args (org-macro--makeargs value))
+                 (body
+                  (condition-case nil
+                      ;; `value' is of the form "(eval ...)" but we
+                      ;; don't want this to mean to pass the result to
+                      ;; `eval' (which would cause double evaluation),
+                      ;; so we strip the `eval' away with `cadr'.
+                     (cadr (read value))
+                   (error
+                     (user-error "Invalid definition for macro %S" name)))))
+           (setq value (eval (macroexpand-all `(lambda ,args ,body)) t))))
+        (cond ((and value old-definition) (setcdr old-definition value))
+             (old-definition)
+             (t (push (cons name (or value "")) new-templates)))))
+    new-templates))
 
 (defun org-macro--collect-macros ()
   "Collect macro definitions in current buffer and setup files.
 Return an alist containing all macro templates found."
-  (let ((templates nil))
+  (let ((templates
+         `(("author" . ,(org-macro--find-keyword-value "AUTHOR" t))
+          ("email" . ,(org-macro--find-keyword-value "EMAIL"))
+          ("title" . ,(org-macro--find-keyword-value "TITLE" t))
+          ("date" . ,(org-macro--find-date)))))
     (pcase (org-collect-keywords '("MACRO"))
       (`(("MACRO" . ,values))
        (dolist (value values)
         (when (string-match "^\\(\\S-+\\)[ \t]*" value)
           (let ((name (match-string 1 value))
                 (definition (substring value (match-end 0))))
-            (setq templates
-                  (org-macro--set-template name definition templates)))))))
-    (let ((macros `(("author" . ,(org-macro--find-keyword-value "AUTHOR"))
-                   ("email" . ,(org-macro--find-keyword-value "EMAIL"))
-                   ("title" . ,(org-macro--find-keyword-value "TITLE" t))
-                   ("date" . ,(org-macro--find-date)))))
-      (pcase-dolist (`(,name . ,value) macros)
-       (setq templates (org-macro--set-template name value templates))))
+             (push (cons name definition) templates))))))
     templates))
 
-(defun org-macro-initialize-templates ()
+(defun org-macro-initialize-templates (&optional default)
   "Collect macro templates defined in current buffer.
 
-Templates are stored in buffer-local variable
-`org-macro-templates'.
+DEFAULT is a list of globally available templates.
+
+Templates are stored in buffer-local variable `org-macro-templates'.
 
 In addition to buffer-defined macros, the function installs the
 following ones: \"n\", \"author\", \"email\", \"keyword\",
@@ -129,8 +153,9 @@ a file, \"input-file\" and \"modification-time\"."
   (org-macro--counter-initialize)      ;for "n" macro
   (setq org-macro-templates
        (nconc
-        ;; Install user-defined macros.
-        (org-macro--collect-macros)
+        ;; Install user-defined macros.  Local macros have higher
+         ;; precedence than global ones.
+         (org-macro--set-templates (append default 
(org-macro--collect-macros)))
         ;; Install file-specific macros.
         (let ((visited-file (buffer-file-name (buffer-base-buffer))))
           (and visited-file
@@ -138,21 +163,23 @@ a file, \"input-file\" and \"modification-time\"."
                (list
                 `("input-file" . ,(file-name-nondirectory visited-file))
                 `("modification-time" .
-                  ,(format "(eval
-\(format-time-string $1
-                     (or (and (org-string-nw-p $2)
-                              (org-macro--vc-modified-time %s))
-                     '%s)))"
-                           (prin1-to-string visited-file)
-                           (prin1-to-string
-                            (file-attribute-modification-time
-                             (file-attributes visited-file))))))))
+                  ,(let ((modtime (file-attribute-modification-time
+                                   (file-attributes visited-file))))
+                     (lambda (arg1 &optional arg2 &rest _)
+                       (format-time-string
+                         arg1
+                         (or (and (org-string-nw-p arg2)
+                                  (org-macro--vc-modified-time visited-file))
+                             modtime))))))))
         ;; Install generic macros.
-        (list
-         '("n" . "(eval (org-macro--counter-increment $1 $2))")
-         '("keyword" . "(eval (org-macro--find-keyword-value $1))")
-         '("time" . "(eval (format-time-string $1))")
-         '("property" . "(eval (org-macro--get-property $1 $2))")))))
+        '(("keyword" . (lambda (arg1 &rest _)
+                          (org-macro--find-keyword-value arg1 t)))
+          ("n" . (lambda (&optional arg1 arg2 &rest _)
+                    (org-macro--counter-increment arg1 arg2)))
+           ("property" . (lambda (arg1 &optional arg2 &rest _)
+                           (org-macro--get-property arg1 arg2)))
+          ("time" . (lambda (arg1 &rest _)
+                       (format-time-string arg1)))))))
 
 (defun org-macro-expand (macro templates)
   "Return expanded MACRO, as a string.
@@ -164,21 +191,17 @@ default value.  Return nil if no template was found."
         ;; Macro names are case-insensitive.
         (cdr (assoc-string (org-element-property :key macro) templates t))))
     (when template
-      (let* ((eval? (string-match-p "\\`(eval\\>" template))
-            (value
-             (replace-regexp-in-string
-              "\\$[0-9]+"
-              (lambda (m)
-                (let ((arg (or (nth (1- (string-to-number (substring m 1)))
-                                    (org-element-property :args macro))
-                               ;; No argument: remove place-holder.
-                               "")))
-                  ;; `eval' implies arguments are strings.
-                  (if eval? (format "%S" arg) arg)))
-              template nil 'literal)))
-        (when eval?
-          (setq value (eval (condition-case nil (read value)
-                             (error (debug))))))
+      (let* ((value
+             (if (functionp template)
+                 (apply template (org-element-property :args macro))
+               (replace-regexp-in-string
+                "\\$[0-9]+"
+                (lambda (m)
+                  (or (nth (1- (string-to-number (substring m 1)))
+                           (org-element-property :args macro))
+                      ;; No argument: remove place-holder.
+                      ""))
+                template nil 'literal))))
         ;; Force return value to be a string.
         (format "%s" (or value ""))))))
 
@@ -380,7 +403,7 @@ value, i.e. do not increment.
 If the string represents an integer, set the counter to this number.
 
 Any other non-empty string resets the counter to 1."
-  (let ((name-trimmed (org-trim name))
+  (let ((name-trimmed (if (stringp name) (org-trim name) ""))
         (action-trimmed (when (org-string-nw-p action)
                           (org-trim action))))
     (puthash name-trimmed
diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el
index 58d3fd3992..0779c3a82c 100644
--- a/lisp/org/org-macs.el
+++ b/lisp/org/org-macs.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -39,6 +39,7 @@
 (declare-function org-string-collate-lessp "org-compat" (s1 s2 &optional 
locale ignore-case))
 
 (defvar org-ts-regexp0)
+(defvar ffap-url-regexp)
 
 
 ;;; Macros
@@ -172,7 +173,7 @@ because otherwise all these markers will point to nowhere."
        ,@body)))
 
 (defmacro org-eval-in-environment (environment form)
-  (declare (debug (form form)) (indent 1))
+  (declare (debug (form form)) (indent 1) (obsolete cl-progv "2021"))
   `(eval (list 'let ,environment ',form)))
 
 ;;;###autoload
@@ -208,7 +209,7 @@ because otherwise all these markers will point to nowhere."
 
 (defmacro org-no-popups (&rest body)
   "Suppress popup windows and evaluate BODY."
-  `(let (pop-up-frames display-buffer-alist)
+  `(let (pop-up-frames pop-up-windows)
      ,@body))
 
 
@@ -325,17 +326,19 @@ it for output."
 
 ;;; Indentation
 
-(defun org-do-remove-indentation (&optional n)
+(defun org-do-remove-indentation (&optional n skip-fl)
   "Remove the maximum common indentation from the buffer.
 When optional argument N is a positive integer, remove exactly
-that much characters from indentation, if possible.  Return nil
-if it fails."
+that much characters from indentation, if possible.  When
+optional argument SKIP-FL is non-nil, skip the first
+line.  Return nil if it fails."
   (catch :exit
     (goto-char (point-min))
     ;; Find maximum common indentation, if not specified.
     (let ((n (or n
                 (let ((min-ind (point-max)))
                   (save-excursion
+                     (when skip-fl (forward-line))
                     (while (re-search-forward "^[ \t]*\\S-" nil t)
                       (let ((ind (current-indentation)))
                         (if (zerop ind) (throw :exit nil)
@@ -343,6 +346,7 @@ if it fails."
                   min-ind))))
       (if (zerop n) (throw :exit nil)
        ;; Remove exactly N indentation, but give up if not possible.
+        (when skip-fl (forward-line))
        (while (not (eobp))
          (let ((ind (progn (skip-chars-forward " \t") (current-column))))
            (cond ((eolp) (delete-region (line-beginning-position) (point)))
@@ -366,15 +370,17 @@ error when the user input is empty."
          (allow-empty? nil)
          (t (user-error "Empty input is not valid")))))
 
+(declare-function org-time-stamp-inactive "org" (&optional arg))
+
 (defun org-completing-read (&rest args)
   "Completing-read with SPACE being a normal character."
   (let ((enable-recursive-minibuffers t)
        (minibuffer-local-completion-map
         (copy-keymap minibuffer-local-completion-map)))
-    (define-key minibuffer-local-completion-map " " 'self-insert-command)
-    (define-key minibuffer-local-completion-map "?" 'self-insert-command)
+    (define-key minibuffer-local-completion-map " " #'self-insert-command)
+    (define-key minibuffer-local-completion-map "?" #'self-insert-command)
     (define-key minibuffer-local-completion-map (kbd "C-c !")
-      'org-time-stamp-inactive)
+      #'org-time-stamp-inactive)
     (apply #'completing-read args)))
 
 (defun org--mks-read-key (allowed-keys prompt navigation-keys)
@@ -470,8 +476,8 @@ is selected, only the bare key is returned."
                (goto-char (point-min))
                (org-fit-window-to-buffer)
                (message "") ; With this line the prompt appears in
-                            ; the minibuffer. Else keystrokes may
-                            ; appear, which is spurious.
+                                        ; the minibuffer. Else keystrokes may
+                                        ; appear, which is spurious.
                (let ((pressed (org--mks-read-key
                                allowed-keys prompt
                                (not (pos-visible-in-window-p (1- 
(point-max)))))))
@@ -535,6 +541,11 @@ that may remove elements by altering the list structure."
     (setq list (delete (pop elts) list)))
   list)
 
+(defun org-plist-delete-all (plist props)
+  "Delete all elements in PROPS from PLIST."
+  (dolist (e props plist)
+    (setq plist (org-plist-delete plist e))))
+
 (defun org-plist-delete (plist property)
   "Delete PROPERTY from PLIST.
 This is in contrast to merely setting it to 0."
@@ -627,6 +638,30 @@ program is needed for, so that the error message can be 
more informative."
   (let ((message-log-max nil))
     (apply #'message args)))
 
+(defmacro org-dlet (binders &rest body)
+  "Like `let*' but using dynamic scoping."
+  (declare (indent 1) (debug let))
+  (let ((vars (mapcar (lambda (binder)
+                        (if (consp binder) (car binder) binder))
+                      binders)))
+    `(progn
+       (with-no-warnings
+         ,@(mapcar (lambda (var) `(defvar ,var)) vars))
+       (let* ,binders ,@body))))
+
+(defmacro org-pushnew-to-end (val var)
+  "Like `cl-pushnew' but pushes to the end of the list.
+Uses `equal' for comparisons.
+
+Beware: this performs O(N) memory allocations, so if you use it in a loop, you
+get an unnecessary O(N²) space complexity, so you're usually better off using
+`cl-pushnew' (with a final `reverse' if you care about the order of elements)."
+  (declare (debug (form gv-place)))
+  (let ((v (make-symbol "v")))
+    `(let ((,v ,val))
+       (unless (member ,v ,var)
+         (setf ,var (append ,var (list ,v)))))))
+
 (defun org-eval (form)
   "Eval FORM and return result."
   (condition-case error
@@ -781,6 +816,10 @@ return nil."
           (list context (match-beginning group) (match-end group))
         t)))
 
+(defun org-url-p (s)
+  "Non-nil if string S is a URL."
+  (require 'ffap)
+  (and ffap-url-regexp (string-match-p ffap-url-regexp s)))
 
 
 ;;; String manipulation
@@ -975,7 +1014,7 @@ IF WIDTH is nil and LINES is non-nil, the string is forced 
into at most that
 many lines, whatever width that takes.
 The return value is a list of lines, without newlines at the end."
   (let* ((words (split-string string))
-        (maxword (apply 'max (mapcar 'org-string-width words)))
+        (maxword (apply #'max (mapcar #'org-string-width words)))
         w ll)
     (cond (width
           (org--do-wrap words (max maxword width)))
@@ -1072,10 +1111,11 @@ that will be added to PLIST.  Returns the string that 
was modified."
   string)
 
 (defun org-make-parameter-alist (flat)
+  ;; FIXME: "flat" is called a "plist"!
   "Return alist based on FLAT.
 FLAT is a list with alternating symbol names and values.  The
 returned alist is a list of lists with the symbol name in car and
-the value in cdr."
+the value in cadr."
   (when flat
     (cons (list (car flat) (cadr flat))
          (org-make-parameter-alist (cddr flat)))))
@@ -1122,13 +1162,13 @@ move it back by one char before doing this check."
     (org-invisible-p)))
 
 (defun org-find-visible ()
-  "Return closest visible buffer position, or `point-max'"
+  "Return closest visible buffer position, or `point-max'."
   (if (org-invisible-p)
       (next-single-char-property-change (point) 'invisible)
     (point)))
 
 (defun org-find-invisible ()
-  "Return closest invisible buffer position, or `point-max'"
+  "Return closest invisible buffer position, or `point-max'."
   (if (org-invisible-p)
       (point)
     (next-single-char-property-change (point) 'invisible)))
@@ -1221,10 +1261,11 @@ Return 0. if S is not recognized as a valid value."
        ((string= s "<tomorrow>") (+ 86400.0 today))
        ((string= s "<yesterday>") (- today 86400.0))
        ((string-match "\\`<\\([-+][0-9]+\\)\\([hdwmy]\\)>\\'" s)
-       (+ today
+       (+ (if (string= (match-string 2 s) "h") (float-time) today)
           (* (string-to-number (match-string 1 s))
              (cdr (assoc (match-string 2 s)
-                         '(("d" . 86400.0)   ("w" . 604800.0)
+                         '(("h" . 3600.0)
+                           ("d" . 86400.0)   ("w" . 604800.0)
                            ("m" . 2678400.0) ("y" . 31557600.0)))))))
        ((string-match org-ts-regexp0 s) (org-2ft s))
        (t 0.)))))
@@ -1238,13 +1279,13 @@ window."
        (scrldn (if additional-keys `(?\d ?\M-v) ?\M-v)))
     (pcase key
       (?\C-n (if (not (pos-visible-in-window-p (point-max)))
-             (ignore-errors (scroll-up 1))
-           (message "End of buffer")
-           (sit-for 1)))
+                (ignore-errors (scroll-up 1))
+              (message "End of buffer")
+              (sit-for 1)))
       (?\C-p (if (not (pos-visible-in-window-p (point-min)))
-             (ignore-errors (scroll-down 1))
-           (message "Beginning of buffer")
-           (sit-for 1)))
+                (ignore-errors (scroll-down 1))
+              (message "Beginning of buffer")
+              (sit-for 1)))
       ;; SPC or
       ((guard (memq key scrlup))
        (if (not (pos-visible-in-window-p (point-max)))
diff --git a/lisp/org/org-mobile.el b/lisp/org/org-mobile.el
index a64e0a274a..e51258af05 100644
--- a/lisp/org/org-mobile.el
+++ b/lisp/org/org-mobile.el
@@ -1,7 +1,7 @@
 ;;; org-mobile.el --- Code for Asymmetric Sync With a Mobile Device -*- 
lexical-binding: t; -*-
 ;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
diff --git a/lisp/org/org-mouse.el b/lisp/org/org-mouse.el
index 57281dd68c..a35a19bca6 100644
--- a/lisp/org/org-mouse.el
+++ b/lisp/org/org-mouse.el
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
 ;; Author: Piotr Zielinski <piotr dot zielinski at gmail dot com>
-;; Maintainer: Carsten Dominik <carsten at orgmode dot org>
+;; Maintainer: Carsten Dominik <carsten.dominik@gmail.com>
 
 ;; This file is part of GNU Emacs.
 
@@ -161,7 +161,7 @@ it is intended to operate on.  If nil, then the action has 
been invoked
 indirectly, for example, through the agenda buffer.")
 
 (defgroup org-mouse nil
-  "Mouse support for org-mode."
+  "Mouse support for `org-mode'."
   :tag "Org Mouse"
   :group 'org)
 
@@ -220,7 +220,7 @@ this function is called.  Otherwise, the current major mode 
menu is used."
          (if (fboundp 'mouse-menu-major-mode-map)
              (popup-menu (mouse-menu-major-mode-map) event prefix)
            (with-no-warnings ; don't warn about fallback, obsolete since 23.1
-            (mouse-major-mode-menu event prefix)))))
+             (mouse-major-mode-menu event prefix)))))
     (setq this-command 'mouse-save-then-kill)
     (mouse-save-then-kill event)))
 
@@ -291,18 +291,18 @@ string to (format ITEMFORMAT keyword).  If it is neither 
a string
 nor a function, elements of KEYWORDS are used directly."
   (mapcar
    (lambda (keyword)
-      (vector (cond
-              ((functionp itemformat) (funcall itemformat keyword))
-              ((stringp itemformat) (format itemformat keyword))
-              (t keyword))
-             (list 'funcall function keyword)
-             :style (cond
-                     ((null selected) t)
-                     ((functionp selected) 'toggle)
-                     (t 'radio))
-             :selected (if (functionp selected)
-                           (and (funcall selected keyword) t)
-                         (equal selected keyword))))
+     (vector (cond
+             ((functionp itemformat) (funcall itemformat keyword))
+             ((stringp itemformat) (format itemformat keyword))
+             (t keyword))
+            (list 'funcall function keyword)
+            :style (cond
+                    ((null selected) t)
+                    ((functionp selected) 'toggle)
+                    (t 'radio))
+            :selected (if (functionp selected)
+                          (and (funcall selected keyword) t)
+                        (equal selected keyword))))
    keywords))
 
 (defun org-mouse-remove-match-and-spaces ()
@@ -424,11 +424,11 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
      (org-mouse-keyword-menu
       (sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
       (lambda (tag)
-        (org-mouse-set-tags
-         (sort (if (member tag tags)
-                   (delete tag tags)
-                 (cons tag tags))
-               #'string-lessp)))
+       (org-mouse-set-tags
+        (sort (if (member tag tags)
+                  (delete tag tags)
+                (cons tag tags))
+              #'string-lessp)))
       (lambda (tag) (member tag tags))
       ))
    '("--"
@@ -499,7 +499,7 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
      ("Check Tags"
       ,@(org-mouse-keyword-menu
         (sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
-        #'(lambda (tag) (org-tags-sparse-tree nil tag)))
+         (lambda (tag) (org-tags-sparse-tree nil tag)))
       "--"
       ["Custom Tag ..." org-tags-sparse-tree t])
      ["Check Phrase ..." org-occur]
@@ -509,26 +509,26 @@ SCHEDULED: or DEADLINE: or ANYTHINGLIKETHIS:"
      ("Display Tags"
       ,@(org-mouse-keyword-menu
         (sort (mapcar #'car (org-get-buffer-tags)) #'string-lessp)
-        #'(lambda (tag) (org-tags-view nil tag)))
+         (lambda (tag) (org-tags-view nil tag)))
       "--"
       ["Custom Tag ..." org-tags-view t])
      ["Display Calendar" org-goto-calendar t]
      "--"
      ,@(org-mouse-keyword-menu
        (mapcar #'car org-agenda-custom-commands)
-       #'(lambda (key)
-           (org-agenda nil (string-to-char key)))
+        (lambda (key)
+         (org-agenda nil (string-to-char key)))
        nil
-       #'(lambda (key)
-           (let ((entry (assoc key org-agenda-custom-commands)))
-             (org-mouse-clip-text
-              (cond
-               ((stringp (nth 1 entry)) (nth 1 entry))
-               ((stringp (nth 2 entry))
-                (concat (org-mouse-agenda-type (nth 1 entry))
-                        (nth 2 entry)))
-               (t "Agenda Command `%s'"))
-              30))))
+        (lambda (key)
+          (let ((entry (assoc key org-agenda-custom-commands)))
+            (org-mouse-clip-text
+             (cond
+              ((stringp (nth 1 entry)) (nth 1 entry))
+              ((stringp (nth 2 entry))
+               (concat (org-mouse-agenda-type (nth 1 entry))
+                       (nth 2 entry)))
+              (t "Agenda Command `%s'"))
+             30))))
      "--"
      ["Delete Blank Lines" delete-blank-lines
       :visible (org-mouse-empty-line)]
@@ -793,8 +793,8 @@ This means, between the beginning of line and the point."
           ("Tags and Priorities"
            ,@(org-mouse-keyword-menu
               (org-mouse-priority-list)
-              #'(lambda (keyword)
-                  (org-mouse-set-priority (string-to-char keyword)))
+               (lambda (keyword)
+                 (org-mouse-set-priority (string-to-char keyword)))
               priority "Priority %s")
            "--"
            ,@(org-mouse-tag-menu))
@@ -854,55 +854,55 @@ This means, between the beginning of line and the point."
     (mouse-drag-region event)))
 
 (add-hook 'org-mode-hook
-         #'(lambda ()
-             (setq org-mouse-context-menu-function #'org-mouse-context-menu)
-
-             (when (memq 'context-menu org-mouse-features)
-               (org-defkey org-mouse-map [mouse-3] nil)
-               (org-defkey org-mode-map [mouse-3] 
#'org-mouse-show-context-menu))
-             (org-defkey org-mode-map [down-mouse-1] #'org-mouse-down-mouse)
-             (when (memq 'context-menu org-mouse-features)
-               (org-defkey org-mouse-map [C-drag-mouse-1] 
#'org-mouse-move-tree)
-               (org-defkey org-mouse-map [C-down-mouse-1] 
#'org-mouse-move-tree-start))
-             (when (memq 'yank-link org-mouse-features)
-               (org-defkey org-mode-map [S-mouse-2] #'org-mouse-yank-link)
-               (org-defkey org-mode-map [drag-mouse-3] #'org-mouse-yank-link))
-             (when (memq 'move-tree org-mouse-features)
-               (org-defkey org-mouse-map [drag-mouse-3] #'org-mouse-move-tree)
-               (org-defkey org-mouse-map [down-mouse-3] 
#'org-mouse-move-tree-start))
-
-             (when (memq 'activate-stars org-mouse-features)
-               (font-lock-add-keywords
-                nil
-                `((,org-outline-regexp
-                   0 `(face org-link mouse-face highlight keymap 
,org-mouse-map)
-                   'prepend))
-                t))
-
-             (when (memq 'activate-bullets org-mouse-features)
-               (font-lock-add-keywords
-                nil
-                `(("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +"
-                   (1 `(face org-link keymap ,org-mouse-map mouse-face 
highlight)
-                      'prepend)))
-                t))
-
-             (when (memq 'activate-checkboxes org-mouse-features)
-               (font-lock-add-keywords
-                nil
-                `(("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +\\(\\[[ X]\\]\\)"
-                   (2 `(face bold keymap ,org-mouse-map mouse-face highlight) 
t)))
-                t))
-
-             (defadvice org-open-at-point (around org-mouse-open-at-point 
activate)
-               (let ((context (org-context)))
-                 (cond
-                  ((assq :headline-stars context) (org-cycle))
-                  ((assq :checkbox context) (org-toggle-checkbox))
-                  ((assq :item-bullet context)
-                   (let ((org-cycle-include-plain-lists t)) (org-cycle)))
-                  ((org-footnote-at-reference-p) nil)
-                  (t ad-do-it))))))
+          (lambda ()
+            (setq org-mouse-context-menu-function #'org-mouse-context-menu)
+
+            (when (memq 'context-menu org-mouse-features)
+              (org-defkey org-mouse-map [mouse-3] nil)
+              (org-defkey org-mode-map [mouse-3] 
#'org-mouse-show-context-menu))
+            (org-defkey org-mode-map [down-mouse-1] #'org-mouse-down-mouse)
+            (when (memq 'context-menu org-mouse-features)
+              (org-defkey org-mouse-map [C-drag-mouse-1] #'org-mouse-move-tree)
+              (org-defkey org-mouse-map [C-down-mouse-1] 
#'org-mouse-move-tree-start))
+            (when (memq 'yank-link org-mouse-features)
+              (org-defkey org-mode-map [S-mouse-2] #'org-mouse-yank-link)
+              (org-defkey org-mode-map [drag-mouse-3] #'org-mouse-yank-link))
+            (when (memq 'move-tree org-mouse-features)
+              (org-defkey org-mouse-map [drag-mouse-3] #'org-mouse-move-tree)
+              (org-defkey org-mouse-map [down-mouse-3] 
#'org-mouse-move-tree-start))
+
+            (when (memq 'activate-stars org-mouse-features)
+              (font-lock-add-keywords
+               nil
+               `((,org-outline-regexp
+                  0 `(face org-link mouse-face highlight keymap ,org-mouse-map)
+                  'prepend))
+               t))
+
+            (when (memq 'activate-bullets org-mouse-features)
+              (font-lock-add-keywords
+               nil
+               `(("^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) +"
+                  (1 `(face org-link keymap ,org-mouse-map mouse-face 
highlight)
+                     'prepend)))
+               t))
+
+            (when (memq 'activate-checkboxes org-mouse-features)
+              (font-lock-add-keywords
+               nil
+               `(("^[ \t]*\\(?:[-+*]\\|[0-9]+[.)]\\)[ 
\t]+\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\(\\[[- X]\\]\\)"
+                  (1 `(face nil keymap ,org-mouse-map mouse-face highlight) 
prepend)))
+               t))
+
+            (defadvice org-open-at-point (around org-mouse-open-at-point 
activate)
+              (let ((context (org-context)))
+                (cond
+                 ((assq :headline-stars context) (org-cycle))
+                 ((assq :checkbox context) (org-toggle-checkbox))
+                 ((assq :item-bullet context)
+                  (let ((org-cycle-include-plain-lists t)) (org-cycle)))
+                 ((org-footnote-at-reference-p) nil)
+                 (t ad-do-it))))))
 
 (defun org-mouse-move-tree-start (_event)
   (interactive "e")
diff --git a/lisp/org/org-num.el b/lisp/org/org-num.el
index ebddaa32b4..f00e6c463b 100644
--- a/lisp/org/org-num.el
+++ b/lisp/org/org-num.el
@@ -29,8 +29,8 @@
 ;; to toggle it.
 ;;
 ;; You can select what is numbered according to level, tags, COMMENT
-;; keyword, or UNNUMBERED property. You can also skip footnotes
-;; sections. See `org-num-max-level', `org-num-skip-tags',
+;; keyword, or UNNUMBERED property.  You can also skip footnotes
+;; sections.  See `org-num-max-level', `org-num-skip-tags',
 ;; `org-num-skip-commented', `org-num-skip-unnumbered', and
 ;; `org-num-skip-footnotes' for details.
 ;;
@@ -63,6 +63,7 @@
 
 (require 'cl-lib)
 (require 'org-macs)
+(require 'org) ;Otherwise `org-num--comment-re' burps on `org-comment-string'
 
 (defvar org-comment-string)
 (defvar org-complex-heading-regexp)
@@ -90,7 +91,7 @@ output."
                  (face :tag "Use face"))
   :safe (lambda (val) (or (null val) (facep val))))
 
-(defcustom org-num-format-function 'org-num-default-format
+(defcustom org-num-format-function #'org-num-default-format
   "Function used to display numbering.
 It is called with one argument, a list of numbers, and should
 return a string, or nil.  When nil, no numbering is displayed.
@@ -98,8 +99,7 @@ Any `face' text property on the returned string overrides
 `org-num-face'."
   :group 'org-appearance
   :package-version '(Org . "9.3")
-  :type 'function
-  :safe nil)
+  :type 'function)
 
 (defcustom org-num-max-level nil
   "Level below which headlines are not numbered.
diff --git a/lisp/org/org-pcomplete.el b/lisp/org/org-pcomplete.el
index d8a4937b95..b31dc333fd 100644
--- a/lisp/org/org-pcomplete.el
+++ b/lisp/org/org-pcomplete.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;         John Wiegley <johnw at gnu dot org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
@@ -21,8 +21,7 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
+
 ;;; Code:
 
 ;;;; Require other packages
@@ -186,7 +185,7 @@ When completing for #+STARTUP, for example, this function 
returns
        (cons (reverse args) (reverse begins))))))
 
 (defun org-pcomplete-initial ()
-  "Calls the right completion function for first argument completions."
+  "Call the right completion function for first argument completions."
   (ignore
    (funcall (or (pcomplete-find-completion-function
                 (car (org-thing-at-point)))
diff --git a/lisp/org/org-plot.el b/lisp/org/org-plot.el
index 4ac15b379d..4f14c7d4c3 100644
--- a/lisp/org/org-plot.el
+++ b/lisp/org/org-plot.el
@@ -51,19 +51,28 @@
   "Parse an OPTIONS line and set values in the property list P.
 Returns the resulting property list."
   (when options
-    (let ((op '(("type"    . :plot-type)
-               ("script"  . :script)
-               ("line"    . :line)
-               ("set"     . :set)
-               ("title"   . :title)
-               ("ind"     . :ind)
-               ("deps"    . :deps)
-               ("with"    . :with)
-               ("file"    . :file)
-               ("labels"  . :labels)
-               ("map"     . :map)
-               ("timeind" . :timeind)
-               ("timefmt" . :timefmt)))
+    (let ((op '(("type"      . :plot-type)
+               ("script"    . :script)
+               ("line"      . :line)
+               ("set"       . :set)
+               ("title"     . :title)
+               ("ind"       . :ind)
+               ("deps"      . :deps)
+               ("with"      . :with)
+               ("file"      . :file)
+               ("labels"    . :labels)
+               ("map"       . :map)
+               ("timeind"   . :timeind)
+               ("timefmt"   . :timefmt)
+               ("min"       . :ymin)
+               ("ymin"      . :ymin)
+               ("max"       . :ymax)
+               ("ymax"      . :ymax)
+               ("xmin"      . :xmin)
+               ("xmax"      . :xmax)
+               ("ticks"     . :ticks)
+               ("trans"     . :transpose)
+               ("transpose" . :transpose)))
          (multiples '("set" "line"))
          (regexp ":\\([\"][^\"]+?[\"]\\|[(][^)]+?[)]\\|[^ \t\n\r;,.]*\\)")
          (start 0))
@@ -180,94 +189,440 @@ and dependent variables."
          (setf back-edge "") (setf front-edge ""))))
     row-vals))
 
-(defun org-plot/gnuplot-script (data-file num-cols params &optional preface)
-  "Write a gnuplot script to DATA-FILE respecting the options set in PARAMS.
+(defun org--plot/values-stats (nums &optional hard-min hard-max)
+  "Rudimentary statistics about NUMS, useful for guessing axis ticks.
+If HARD-MIN or HARD-MAX are set, they will be used instead of the min/max
+of the NUMS."
+  (let* ((minimum (or hard-min (apply #'min nums)))
+        (maximum (or hard-max (apply #'max nums)))
+        (range (- maximum minimum))
+        (rangeOrder (if (= range 0) 0
+                      (ceiling (- 1 (log range 10)))))
+        (range-factor (expt 10 rangeOrder))
+        (nice-min (if (= range 0) (car nums)
+                    (/ (float (floor (* minimum range-factor))) range-factor)))
+        (nice-max (if (= range 0) (car nums)
+                    (/ (float (ceiling (* maximum range-factor))) 
range-factor))))
+    `(:min ,minimum :max ,maximum :range ,range
+           :range-factor ,range-factor
+           :nice-min ,nice-min :nice-max ,nice-max :nice-range ,(- nice-max 
nice-min))))
+
+(defun org--plot/sensible-tick-num (table &optional hard-min hard-max)
+  "From a the values in a TABLE of data, guess an appropriate number of ticks.
+If HARD-MIN and HARD-MAX can be used to fix the ends of the axis."
+  (let* ((row-data
+         (mapcar (lambda (row) (org--plot/values-stats
+                                (mapcar #'string-to-number (cdr row))
+                                hard-min
+                                hard-max)) table))
+        (row-normalised-ranges (mapcar (lambda (r-data)
+                                         (let ((val (round (*
+                                                            (plist-get r-data 
:range-factor)
+                                                            (plist-get r-data 
:nice-range)))))
+                                           (if (= (% val 10) 0) (/ val 10) 
val)))
+                                       row-data))
+        (range-prime-decomposition (mapcar #'org--plot/prime-factors 
row-normalised-ranges))
+        (weighted-factors (sort (apply #'org--plot/merge-alists #'+ 0
+                                       (mapcar (lambda (factors) 
(org--plot/item-frequencies factors t))
+                                               range-prime-decomposition))
+                                (lambda (a b) (> (cdr a) (cdr b))))))
+    (apply #'* (org--plot/nice-frequency-pick weighted-factors))))
+
+(defun org--plot/nice-frequency-pick (frequencies)
+  "From a list of FREQUENCIES, try to sensibly pick a sample of the most 
frequent."
+  ;; TODO this mosly works decently, but could do with some tweaking to work 
more consistently.
+  (cl-case (length frequencies)
+    (1 (list (car (nth 0 frequencies))))
+    (2 (if (<= 3 (/ (cdr (nth 0 frequencies))
+                   (cdr (nth 1 frequencies))))
+          (make-list 2
+                     (car (nth 0 frequencies)))
+        (list (car (nth 0 frequencies))
+              (car (nth 1 frequencies)))))
+    (t
+     (let* ((total-count (apply #'+ (mapcar #'cdr frequencies)))
+           (n-freq (mapcar (lambda (freq) `(,(car freq) . ,(/ (float (cdr 
freq)) total-count))) frequencies))
+           (f-pick (list (car (car n-freq))))
+           (1-2-ratio (/ (cdr (nth 0 n-freq))
+                         (cdr (nth 1 n-freq))))
+           (2-3-ratio (/ (cdr (nth 1 n-freq))
+                         (cdr (nth 2 n-freq))))
+           (1-3-ratio (* 1-2-ratio 2-3-ratio))
+           (1-val (car (nth 0 n-freq)))
+           (2-val (car (nth 1 n-freq)))
+           (3-val (car (nth 2 n-freq))))
+       (when (> 1-2-ratio 4) (push 1-val f-pick))
+       (when (and (< 1-2-ratio 2-val)
+                 (< (* (apply #'* f-pick) 2-val) 30))
+        (push 2-val f-pick))
+       (when (and (< 1-3-ratio 3-val)
+                 (< (* (apply #'* f-pick) 3-val) 30))
+        (push 3-val f-pick))
+       f-pick))))
+
+(defun org--plot/merge-alists (function default alist1 alist2 &rest alists)
+  "Using FUNCTION, combine the elements of ALIST1, ALIST2 and any other ALISTS.
+When an element is only present in one alist, DEFAULT is used as the second
+argument for the FUNCTION."
+  (when (> (length alists) 0)
+    (setq alist2 (apply #'org--plot/merge-alists function default alist2 
alists)))
+  (cl-flet ((keys (alist) (mapcar #'car alist))
+           (lookup (key alist) (or (cdr (assoc key alist)) default)))
+    (cl-loop with keys = (cl-union (keys alist1) (keys alist2) :test 'equal)
+            for k in keys collect
+            (cons k (funcall function (lookup k alist1) (lookup k alist2))))))
+
+(defun org--plot/item-frequencies (values &optional normalise)
+  "Return an alist indicating the frequency of values in VALUES list.
+When NORMALISE is non-nil, the count is divided by the number of values."
+  (let ((normaliser (if normalise (float (length values)) 1)))
+    (cl-loop for (n . m) in (seq-group-by #'identity values)
+            collect (cons n (/ (length m) normaliser)))))
+
+(defun org--plot/prime-factors (value)
+  "Return the prime decomposition of VALUE, e.g. for 12, '(3 2 2)."
+  (let ((factors '(1)) (i 1))
+    (while (/= 1 value)
+      (setq i (1+ i))
+      (when (eq 0 (% value i))
+       (push i factors)
+       (setq value (/ value i))
+       (setq i (1- i))
+       ))
+    (cl-subseq factors 0 -1)))
+
+(defcustom org-plot/gnuplot-script-preamble ""
+  "String of function to be inserted before the gnuplot plot command is run.
+
+Note that this is in addition to, not instead of other content generated in
+`org-plot/gnuplot-script'.  If a function, it is called with the plot type as
+the argument, and must return a string to be used."
+  :group 'org-plot
+  :type '(choice string function))
+
+(defcustom org-plot/preset-plot-types
+  '((2d :plot-cmd "plot"
+       :check-ind-type t
+       :plot-func
+       (lambda (_table data-file num-cols params plot-str)
+         (let* ((type (plist-get params :plot-type))
+                (with (if (eq type 'grid) 'pm3d (plist-get params :with)))
+                (ind (plist-get params :ind))
+                (deps (if (plist-member params :deps) (plist-get params 
:deps)))
+                (text-ind (or (plist-get params :textind)
+                               (eq (plist-get params :with) 'histograms)))
+                (col-labels (plist-get params :labels))
+                res)
+           (dotimes (col num-cols res)
+             (unless (and (eq type '2d)
+                          (or (and ind (equal (1+ col) ind))
+                              (and deps (not (member (1+ col) deps)))))
+               (setf res
+                     (cons
+                      (format plot-str data-file
+                              (or (and ind (> ind 0)
+                                       (not text-ind)
+                                       (format "%d:" ind)) "")
+                              (1+ col)
+                              (if text-ind (format ":xticlabel(%d)" ind) "")
+                              with
+                              (or (nth col col-labels)
+                                  (format "%d" (1+ col))))
+                      res)))))))
+    (3d :plot-cmd "splot"
+       :plot-pre (lambda (_table _data-file _num-cols params _plot-str)
+                   (if (plist-get params :map) "set map"))
+       :plot-func
+       (lambda (_table data-file _num-cols params _plot-str)
+         (let* ((type (plist-get params :plot-type))
+                (with (if (eq type 'grid) 'pm3d (plist-get params :with))))
+           (list (format "'%s' matrix with %s title ''"
+                         data-file with)))))
+    (grid :plot-cmd "splot"
+         :plot-pre (lambda (_table _data-file _num-cols params _plot-str)
+                     (if (plist-get params :map) "set pm3d map" "set map"))
+         :data-dump (lambda (table data-file params _num-cols)
+                      (let ((y-labels (org-plot/gnuplot-to-grid-data
+                                       table data-file params)))
+                        (when y-labels (plist-put params :ylabels y-labels))))
+         :plot-func
+         (lambda (table data-file _num-cols params _plot-str)
+           (let* ((type (plist-get params :plot-type))
+                  (with (if (eq type 'grid) 'pm3d (plist-get params :with))))
+             (list (format "'%s' with %s title ''"
+                           data-file with)))))
+    (radar :plot-func
+          (lambda (table _data-file _num-cols params plot-str)
+            (list (org--plot/radar table params)))))
+  "List of plists describing the available plot types.
+The car is the type name, and the property :plot-func must be
+set.  The value of :plot-func is a lambda which yields plot-lines
+\(a list of strings) as the cdr.
+
+All lambda functions have the parameters of
+`org-plot/gnuplot-script' and PLOT-STR passed to them.  i.e. they
+are called with the following signature: (TABLE DATA-FILE
+NUM-COLS PARAMS PLOT-STR)
+
+Potentially useful parameters in PARAMS include:
+ :set :line :map :title :file :ind :timeind :timefmt :textind
+ :deps :labels :xlabels :ylabels :xmin :xmax :ymin :ymax :ticks
+
+In addition to :plot-func, the following optional properties may
+be set.
+
+- :plot-cmd - A gnuplot command appended to each plot-line.
+  Accepts string or nil.  Default value: nil.
+
+- :check-ind-type - Whether the types of ind values should be checked.
+  Accepts boolean.
+
+- :plot-str - the formula string passed to :plot-func as PLOT-STR
+  Accepts string.  Default value: \"'%s' using %s%d%s with %s title '%s'\"
+
+- :data-dump - Function to dump the table to a datafile for ease of
+  use.
+
+  Accepts lambda function.  Default lambda body:
+  (org-plot/gnuplot-to-data table data-file params)
+
+- :plot-pre - Gnuplot code to be inserted early into the script, just
+  after term and output have been set.
+
+   Accepts string, nil, or lambda function which returns string
+   or nil.  Defaults to nil."
+  :group 'org-plot
+  :type 'alist)
+
+(defvar org--plot/radar-template
+  "### spider plot/chart with gnuplot
+# also known as: radar chart, web chart, star chart, cobweb chart,
+#                radar plot,  web plot,  star plot,  cobweb plot,  etc. ...
+set datafile separator ' '
+set size square
+unset tics
+set angles degree
+set key bmargin center horizontal
+unset border
+
+# Load data and setup
+load \"%s\"
+
+# General settings
+DataColCount = words($Data[1])-1
+AxesCount = |$Data|-HeaderLines-1
+AngleOffset = 90
+Max = 1
+d=0.1*Max
+Direction = -1   # counterclockwise=1, clockwise = -1
+
+# Tic settings
+TicCount = %s
+TicOffset = 0.1
+TicValue(axis,i) = real(i)*(word($Settings[axis],3)-word($Settings[axis],2)) \\
+         / word($Settings[axis],4)+word($Settings[axis],2)
+TicLabelPosX(axis,i) = PosX(axis,i/TicCount) + PosY(axis, TicOffset)
+TicLabelPosY(axis,i) = PosY(axis,i/TicCount) - PosX(axis, TicOffset)
+TicLen = 0.03
+TicdX(axis,i) = 0.5*TicLen*cos(alpha(axis)-90)
+TicdY(axis,i) = 0.5*TicLen*sin(alpha(axis)-90)
+
+# Label
+LabOffset = 0.10
+LabX(axis) = PosX(axis+1,Max+2*d) + PosY(axis, LabOffset)
+LabY(axis) = PosY($0+1,Max+2*d)
+
+# Functions
+alpha(axis) = (axis-1)*Direction*360.0/AxesCount+AngleOffset
+PosX(axis,R) = R*cos(alpha(axis))
+PosY(axis,R) = R*sin(alpha(axis))
+Scale(axis,value) = 
real(value-word($Settings[axis],2))/(word($Settings[axis],3)-word($Settings[axis],2))
+
+# Spider settings
+set style arrow 1 dt 1 lw 1.0 @fgal head filled size 0.06,25     # style for 
axes
+set style arrow 2 dt 2 lw 0.5 @fgal nohead   # style for weblines
+set style arrow 3 dt 1 lw 1 @fgal nohead     # style for axis tics
+set samples AxesCount
+set isosamples TicCount
+set urange[1:AxesCount]
+set vrange[1:TicCount]
+set style fill transparent solid 0.2
+
+set xrange[-Max-4*d:Max+4*d]
+set yrange[-Max-4*d:Max+4*d]
+plot \\
+    '+' u (0):(0):(PosX($0,Max+d)):(PosY($0,Max+d)) w vec as 1 not, \\
+    $Data u (LabX($0)): \\
+       (LabY($0)):1 every ::HeaderLines w labels center enhanced @fgt not, \\
+    for [i=1:DataColCount] $Data u (PosX($0+1,Scale($0+1,column(i+1)))): \\
+       (PosY($0+1,Scale($0+1,column(i+1)))) every ::HeaderLines w filledcurves 
lt i title word($Data[1],i+1), \\
+%s
+#    '++' u (PosX($1,$2/TicCount)-TicdX($1,$2/TicCount)): \\
+#        (PosY($1,$2/TicCount)-TicdY($1,$2/TicCount)): \\
+#        (2*TicdX($1,$2/TicCount)):(2*TicdY($1,$2/TicCount)) \\
+#        w vec as 3 not, \\
+### end of code
+")
+
+(defvar org--plot/radar-ticks
+  "    '++' u (PosX($1,$2/TicCount)):(PosY($1,$2/TicCount)): \\
+       (PosX($1+1,$2/TicCount)-PosX($1,$2/TicCount)):  \\
+       (PosY($1+1,$2/TicCount)-PosY($1,$2/TicCount)) w vec as 2 not, \\
+    '++' u (TicLabelPosX(%s,$2)):(TicLabelPosY(%s,$2)): \\
+       (sprintf('%%g',TicValue(%s,$2))) w labels font ',8' @fgat not")
+
+(defvar org--plot/radar-setup-template
+  "# Data
+$Data <<HEREHAVESOMEDATA
+%s
+HEREHAVESOMEDATA
+HeaderLines = 1
+
+# Settings for scale and offset adjustments
+# axis min max tics axisLabelXoff axisLabelYoff
+$Settings <<EOD
+%s
+EOD
+")
+
+(defun org--plot/radar (table params)
+  "Create gnuplot code for a radar plot of TABLE with PARAMS."
+  (let* ((data
+         (concat "\"" (mapconcat #'identity (plist-get params :labels) "\" 
\"") "\""
+                 "\n"
+                 (mapconcat (lambda (row)
+                              (format
+                               "\"%s\" %s"
+                               (car row)
+                               (mapconcat #'identity (cdr row) " ")))
+                            (append table (list (car table)))
+                            "\n")))
+        (ticks (or (plist-get params :ticks)
+                   (org--plot/sensible-tick-num table
+                                                (plist-get params :ymin)
+                                                (plist-get params :ymax))))
+        (settings
+         (mapconcat (lambda (row)
+                      (let ((data (org--plot/values-stats
+                                   (mapcar #'string-to-number (cdr row)))))
+                        (format
+                         "\"%s\" %s %s %s"
+                         (car row)
+                         (or (plist-get params :ymin)
+                             (plist-get data :nice-min))
+                         (or (plist-get params :ymax)
+                             (plist-get data :nice-max))
+                         (if (eq ticks 0) 2 ticks)
+                         )))
+                    (append table (list (car table)))
+                    "\n"))
+        (setup-file (make-temp-file "org-plot-setup")))
+    (let ((coding-system-for-write 'utf-8))
+      (write-region (format org--plot/radar-setup-template data settings) nil 
setup-file nil :silent))
+    (format org--plot/radar-template
+           setup-file
+           (if (eq ticks 0) 2 ticks)
+           (if (eq ticks 0) ""
+             (apply #'format org--plot/radar-ticks
+                    (make-list 3 (if (and (plist-get params :ymin)
+                                          (plist-get params :ymax))
+                                     ;; FIXME multi-drawing of tick labels 
with "1"
+                                     "1" "$1")))))))
+
+(defcustom org-plot/gnuplot-term-extra ""
+  "String or function which provides the extra term options.
+E.g. a value of \"size 1050,650\" would cause
+\"set term ... size 1050,650\" to be used.
+If a function, it is called with the plot type as the argument."
+  :group 'org-plot
+  :type '(choice string function))
+
+(defun org-plot/gnuplot-script (table data-file num-cols params &optional 
preface)
+  "Write a gnuplot script for TABLE to DATA-FILE respecting options in PARAMS.
 NUM-COLS controls the number of columns plotted in a 2-d plot.
 Optional argument PREFACE returns only option parameters in a
 manner suitable for prepending to a user-specified script."
-  (let* ((type (plist-get params :plot-type))
-        (with (if (eq type 'grid) 'pm3d (plist-get params :with)))
-        (sets (plist-get params :set))
-        (lines (plist-get params :line))
-        (map (plist-get params :map))
-        (title (plist-get params :title))
-        (file (plist-get params :file))
-        (ind (plist-get params :ind))
-        (time-ind (plist-get params :timeind))
-        (timefmt (plist-get params :timefmt))
-        (text-ind (plist-get params :textind))
-        (deps (if (plist-member params :deps) (plist-get params :deps)))
-        (col-labels (plist-get params :labels))
-        (x-labels (plist-get params :xlabels))
-        (y-labels (plist-get params :ylabels))
-        (plot-str "'%s' using %s%d%s with %s title '%s'")
-        (plot-cmd (pcase type
-                    (`2d "plot")
-                    (`3d "splot")
-                    (`grid "splot")))
-        (script "reset")
-        ;; ats = add-to-script
-        (ats (lambda (line) (setf script (concat script "\n" line))))
-        plot-lines)
-    (when file                         ; output file
-      (funcall ats (format "set term %s" (file-name-extension file)))
-      (funcall ats (format "set output '%s'" file)))
-    (pcase type                                ; type
-      (`2d ())
-      (`3d (when map (funcall ats "set map")))
-      (`grid (funcall ats (if map "set pm3d map" "set pm3d"))))
-    (when title (funcall ats (format "set title '%s'" title))) ; title
-    (mapc ats lines)                                          ; line
-    (dolist (el sets) (funcall ats (format "set %s" el)))      ; set
-    ;; Unless specified otherwise, values are TAB separated.
-    (unless (string-match-p "^set datafile separator" script)
-      (funcall ats "set datafile separator \"\\t\""))
-    (when x-labels                     ; x labels (xtics)
-      (funcall ats
-              (format "set xtics (%s)"
-                      (mapconcat (lambda (pair)
-                                   (format "\"%s\" %d" (cdr pair) (car pair)))
-                                 x-labels ", "))))
-    (when y-labels                     ; y labels (ytics)
-      (funcall ats
-              (format "set ytics (%s)"
-                      (mapconcat (lambda (pair)
-                                   (format "\"%s\" %d" (cdr pair) (car pair)))
-                                 y-labels ", "))))
-    (when time-ind                     ; timestamp index
-      (funcall ats "set xdata time")
-      (funcall ats (concat "set timefmt \""
-                          (or timefmt  ; timefmt passed to gnuplot
-                              "%Y-%m-%d-%H:%M:%S") "\"")))
-    (unless preface
-      (pcase type                      ; plot command
-       (`2d (dotimes (col num-cols)
-              (unless (and (eq type '2d)
-                           (or (and ind (equal (1+ col) ind))
-                               (and deps (not (member (1+ col) deps)))))
-                (setf plot-lines
-                      (cons
-                       (format plot-str data-file
-                               (or (and ind (> ind 0)
-                                        (not text-ind)
-                                        (format "%d:" ind)) "")
-                               (1+ col)
-                               (if text-ind (format ":xticlabel(%d)" ind) "")
-                               with
-                               (or (nth col col-labels)
-                                   (format "%d" (1+ col))))
-                       plot-lines)))))
-       (`3d
-        (setq plot-lines (list (format "'%s' matrix with %s title ''"
-                                       data-file with))))
-       (`grid
-        (setq plot-lines (list (format "'%s' with %s title ''"
-                                       data-file with)))))
+  (let* ((type-name (plist-get params :plot-type))
+        (type (cdr (assoc type-name org-plot/preset-plot-types))))
+    (unless type
+      (user-error "Org-plot type `%s' is undefined" type-name))
+    (let* ((sets (plist-get params :set))
+          (lines (plist-get params :line))
+          (title (plist-get params :title))
+          (file (plist-get params :file))
+          (time-ind (plist-get params :timeind))
+          (timefmt (plist-get params :timefmt))
+          (x-labels (plist-get params :xlabels))
+          (y-labels (plist-get params :ylabels))
+          (plot-str (or (plist-get type :plot-str)
+                        "'%s' using %s%d%s with %s title '%s'"))
+          (plot-cmd (plist-get type :plot-cmd))
+          (plot-pre (plist-get type :plot-pre))
+          (script "reset")
+          ;; ats = add-to-script
+          (ats (lambda (line) (when line (setf script (concat script "\n" 
line)))))
+          plot-lines)
+
+
+      ;; handle output file, background, and size
+      (funcall ats (format "set term %s %s"
+                          (if file (file-name-extension file) "GNUTERM")
+                          (if (stringp org-plot/gnuplot-term-extra)
+                              org-plot/gnuplot-term-extra
+                            (funcall org-plot/gnuplot-term-extra type))))
+      (when file ; output file
+       (funcall ats (format "set output '%s'" (expand-file-name file))))
+
+      (when plot-pre
+       (funcall ats (funcall plot-pre table data-file num-cols params 
plot-str)))
+
       (funcall ats
-              (concat plot-cmd " " (mapconcat #'identity
-                                              (reverse plot-lines)
-                                              ",\\\n    "))))
-    script))
+              (if (stringp org-plot/gnuplot-script-preamble)
+                  org-plot/gnuplot-script-preamble
+                (funcall org-plot/gnuplot-script-preamble type)))
+
+      (when title (funcall ats (format "set title '%s'" title))) ; title
+      (mapc ats lines)                                        ; line
+      (dolist (el sets) (funcall ats (format "set %s" el)))      ; set
+      ;; Unless specified otherwise, values are TAB separated.
+      (unless (string-match-p "^set datafile separator" script)
+       (funcall ats "set datafile separator \"\\t\""))
+      (when x-labels                   ; x labels (xtics)
+       (funcall ats
+                (format "set xtics (%s)"
+                        (mapconcat (lambda (pair)
+                                     (format "\"%s\" %d" (cdr pair) (car 
pair)))
+                                   x-labels ", "))))
+      (when y-labels                   ; y labels (ytics)
+       (funcall ats
+                (format "set ytics (%s)"
+                        (mapconcat (lambda (pair)
+                                     (format "\"%s\" %d" (cdr pair) (car 
pair)))
+                                   y-labels ", "))))
+      (when time-ind                   ; timestamp index
+       (funcall ats "set xdata time")
+       (funcall ats (concat "set timefmt \""
+                            (or timefmt        ; timefmt passed to gnuplot
+                                "%Y-%m-%d-%H:%M:%S") "\"")))
+      (unless preface
+       (let ((type-func (plist-get type :plot-func)))
+         (when type-func
+           (setq plot-lines
+                 (funcall type-func table data-file num-cols params 
plot-str))))
+       (funcall ats
+                (concat plot-cmd
+                        (when plot-cmd " ")
+                        (mapconcat #'identity
+                                   (reverse plot-lines)
+                                   ",\\\n    "))))
+      script)))
+
+(defun org-plot/redisplay-img-in-buffer (img-file)
+  "Find any overlays for IMG-FILE in the current Org buffer, and refresh them."
+  (dolist (img-overlay org-inline-image-overlays)
+    (when (string= img-file (plist-get (cdr (overlay-get img-overlay 
'display)) :file))
+      (when (file-exists-p img-file)
+        (image-refresh (overlay-get img-overlay 'display))))))
 
 ;;-----------------------------------------------------------------------------
 ;; facade functions
@@ -283,15 +638,40 @@ line directly before or after the table."
     (when (get-buffer "*gnuplot*") ; reset *gnuplot* if it already running
       (with-current-buffer "*gnuplot*"
        (goto-char (point-max))))
-    (org-plot/goto-nearest-table)
-    ;; Set default options.
-    (dolist (pair org-plot/gnuplot-default-options)
-      (unless (plist-member params (car pair))
-       (setf params (plist-put params (car pair) (cdr pair)))))
+    (save-excursion
+      (org-plot/goto-nearest-table)
+      ;; Set default options.
+      (dolist (pair org-plot/gnuplot-default-options)
+        (unless (plist-member params (car pair))
+          (setf params (plist-put params (car pair) (cdr pair)))))
+      ;; Collect options.
+      (while (and (equal 0 (forward-line -1))
+                  (looking-at "[[:space:]]*#\\+"))
+        (setf params (org-plot/collect-options params))))
     ;; collect table and table information
     (let* ((data-file (make-temp-file "org-plot"))
-          (table (org-table-collapse-header (org-table-to-lisp)))
-          (num-cols (length (car table))))
+           (table (let ((tbl (save-excursion
+                               (org-plot/goto-nearest-table)
+                               (org-table-to-lisp))))
+                   (when (pcase (plist-get params :transpose)
+                           (`y   t)
+                           (`yes t)
+                           (`t   t))
+                     (if (not (memq 'hline tbl))
+                         (setq tbl (apply #'cl-mapcar #'list tbl))
+                       ;; When present, remove hlines as they can't 
(currentily) be easily transposed.
+                       (setq tbl (apply #'cl-mapcar #'list
+                                        (remove 'hline tbl)))
+                       (push 'hline (cdr tbl))))
+                   tbl))
+          (num-cols (length (if (eq (nth 0 table) 'hline) (nth 1 table)
+                              (nth 0 table))))
+          (type (assoc (plist-get params :plot-type)
+                       org-plot/preset-plot-types)))
+
+      (unless type
+       (user-error "Org-plot type `%s' is undefined" (plist-get params 
:plot-type)))
+
       (run-with-idle-timer 0.1 nil #'delete-file data-file)
       (when (eq (cadr table) 'hline)
        (setf params
@@ -301,15 +681,12 @@ line directly before or after the table."
       (save-excursion (while (and (equal 0 (forward-line -1))
                                  (looking-at "[[:space:]]*#\\+"))
                        (setf params (org-plot/collect-options params))))
-      ;; Dump table to datafile (very different for grid).
-      (pcase (plist-get params :plot-type)
-       (`2d   (org-plot/gnuplot-to-data table data-file params))
-       (`3d   (org-plot/gnuplot-to-data table data-file params))
-       (`grid (let ((y-labels (org-plot/gnuplot-to-grid-data
-                               table data-file params)))
-                (when y-labels (plist-put params :ylabels y-labels)))))
+      ;; Dump table to datafile
+      (if-let ((dump-func (plist-get type :data-dump)))
+         (funcall dump-func table data-file num-cols params)
+       (org-plot/gnuplot-to-data table data-file params))
       ;; Check type of ind column (timestamp? text?)
-      (when (eq `2d (plist-get params :plot-type))
+      (when (plist-get params :check-ind-type)
        (let* ((ind (1- (plist-get params :ind)))
               (ind-column (mapcar (lambda (row) (nth ind row)) table)))
          (cond ((< ind 0) nil) ; ind is implicit
@@ -326,18 +703,23 @@ line directly before or after the table."
       (with-temp-buffer
        (if (plist-get params :script)  ; user script
            (progn (insert
-                    (org-plot/gnuplot-script data-file num-cols params t))
-                   (insert "\n")
-                   (insert-file-contents (plist-get params :script))
-                   (goto-char (point-min))
-                   (while (re-search-forward "\\$datafile" nil t)
-                     (replace-match data-file nil nil)))
-         (insert (org-plot/gnuplot-script data-file num-cols params)))
+                   (org-plot/gnuplot-script table data-file num-cols params t))
+                  (insert "\n")
+                  (insert-file-contents (plist-get params :script))
+                  (goto-char (point-min))
+                  (while (re-search-forward "\\$datafile" nil t)
+                    (replace-match data-file nil nil)))
+         (insert (org-plot/gnuplot-script table data-file num-cols params)))
        ;; Graph table.
        (gnuplot-mode)
-       (gnuplot-send-buffer-to-gnuplot))
+        (condition-case nil
+            (gnuplot-send-buffer-to-gnuplot)
+          (buffer-read-only nil)))
       ;; Cleanup.
-      (bury-buffer (get-buffer "*gnuplot*")))))
+      (bury-buffer (get-buffer "*gnuplot*"))
+      ;; Refresh any displayed images
+      (when (plist-get params :file)
+        (org-plot/redisplay-img-in-buffer (expand-file-name (plist-get params 
:file)))))))
 
 (provide 'org-plot)
 
diff --git a/lisp/org/org-protocol.el b/lisp/org/org-protocol.el
index 726c1ca2ba..ca3249dda5 100644
--- a/lisp/org/org-protocol.el
+++ b/lisp/org/org-protocol.el
@@ -49,7 +49,7 @@
 ;;   4.) Try this from the command line (adjust the URL as needed):
 ;;
 ;;       $ emacsclient \
-;;         
org-protocol://store-link?url=http:%2F%2Flocalhost%2Findex.html&title=The%20title
+;;         
"org-protocol://store-link?url=http:%2F%2Flocalhost%2Findex.html&title=The%20title"
 ;;
 ;;   5.) Optionally add custom sub-protocols and handlers:
 ;;
@@ -94,6 +94,15 @@
 ;; You may use the same bookmark URL for all those standard handlers and just
 ;; adjust the sub-protocol used:
 ;;
+;;     javascript:location.href='org-protocol://sub-protocol?'+
+;;           new URLSearchParams({
+;;                 url: location.href,
+;;                 title: document.title,
+;;                 body: window.getSelection()})
+;;
+;; Alternatively use the following expression that encodes space as \"%20\"
+;; instead of \"+\", so it is compatible with Org versions from 9.0 to 9.4:
+;;
 ;;     location.href='org-protocol://sub-protocol?url='+
 ;;           encodeURIComponent(location.href)+'&title='+
 ;;           encodeURIComponent(document.title)+'&body='+
@@ -103,6 +112,11 @@
 ;; char that, if present, triggers the use of a special template.
 ;; Example:
 ;;
+;;     location.href='org-protocol://capture?'+
+;;           new URLSearchParams({template:'x', /* ... */})
+;;
+;; or
+;;
 ;;     location.href='org-protocol://capture?template=x'+ ...
 ;;
 ;;  uses template ?x.
@@ -176,13 +190,13 @@ Possible properties are:
 
   :online-suffix     - the suffix to strip from the published URLs
   :working-suffix    - the replacement for online-suffix
-  :base-url          - the base URL, e.g. http://www.example.com/project/
+  :base-url          - the base URL, e.g. https://www.example.com/project/
                        Last slash required.
-  :working-directory - the local working directory.  This is, what base-url 
will
-                       be replaced with.
-  :redirects         - A list of cons cells, each of which maps a regular
-                       expression to match to a path relative to
-                       :working-directory.
+  :working-directory - the local working directory.  This is what
+                       base-url will be replaced with.
+  :redirects         - A list of cons cells, each of which maps a
+                       regular expression to match to a path relative
+                       to `:working-directory'.
 
 Example:
 
@@ -216,8 +230,9 @@ Example:
    does not include any suffix properties, allowing local source
    file to be opened as found by OpenGrok.
 
-Consider using the interactive functions `org-protocol-create' and
-`org-protocol-create-for-org' to help you filling this variable with valid 
contents."
+Consider using the interactive functions `org-protocol-create'
+and `org-protocol-create-for-org' to help you filling this
+variable with valid contents."
   :group 'org-protocol
   :type 'alist)
 
@@ -426,7 +441,12 @@ Parameters: url, title (optional), body (optional)
 Old-style links such as org-protocol://store-link://URL/TITLE are
 also recognized.
 
-The location for a browser's bookmark has to look like this:
+The location for a browser's bookmark may look like this:
+
+  javascript:location.href = \\='org-protocol://store-link?\\=' +
+       new URLSearchParams({url:location.href, title:document.title});
+
+or to keep compatibility with Org versions from 9.0 to 9.4 it may be:
 
   javascript:location.href = \\
       \\='org-protocol://store-link?url=\\=' + \\
@@ -435,7 +455,9 @@ The location for a browser's bookmark has to look like this:
 
 Don't use `escape()'!  Use `encodeURIComponent()' instead.  The
 title of the page could contain slashes and the location
-definitely will.
+definitely will.  Org 9.4 and earlier could not decode \"+\"
+to space, that is why less readable latter expression may be necessary
+for backward compatibility.
 
 The sub-protocol used to reach this function is set in
 `org-protocol-protocol-alist'.
@@ -463,8 +485,16 @@ The sub-protocol used to reach this function is set in
 This function detects an URL, title and optional text, separated
 by `/'.  The location for a browser's bookmark looks like this:
 
+  javascript:location.href = \\='org-protocol://capture?\\=' +
+        new URLSearchParams({
+              url: location.href,
+              title: document.title,
+              body: window.getSelection()})
+
+or to keep compatibility with Org versions from 9.0 to 9.4:
+
   javascript:location.href = \\='org-protocol://capture?url=\\='+ \\
-        encodeURIComponent(location.href) + \\='&title=\\=' \\
+        encodeURIComponent(location.href) + \\='&title=\\=' + \\
         encodeURIComponent(document.title) + \\='&body=\\=' + \\
         encodeURIComponent(window.getSelection())
 
@@ -518,10 +548,11 @@ Now template ?b will be used."
 (defun org-protocol-convert-query-to-plist (query)
   "Convert QUERY key=value pairs in the URL to a property list."
   (when query
-    (apply 'append (mapcar (lambda (x)
-                            (let ((c (split-string x "=")))
-                              (list (intern (concat ":" (car c))) (cadr c))))
-                          (split-string query "&")))))
+    (let ((plus-decoded (replace-regexp-in-string "\\+" " " query t t)))
+      (apply 'append (mapcar (lambda (x)
+                              (let ((c (split-string x "=")))
+                                (list (intern (concat ":" (car c))) (cadr c))))
+                            (split-string plus-decoded "&"))))))
 
 (defun org-protocol-open-source (fname)
   "Process an org-protocol://open-source?url= style URL with FNAME.
@@ -531,6 +562,12 @@ in `org-protocol-project-alist'.
 
 The location for a browser's bookmark should look like this:
 
+  javascript:location.href = \\='org-protocol://open-source?\\=' +
+        new URLSearchParams({url: location.href})
+
+or if you prefer to keep compatibility with older Org versions (9.0 to 9.4),
+consider the following expression:
+
   javascript:location.href = \\='org-protocol://open-source?url=\\=' + \\
         encodeURIComponent(location.href)"
   ;; As we enter this function for a match on our protocol, the return value
@@ -553,7 +590,7 @@ The location for a browser's bookmark should look like this:
                   (f1 (substring f 0 (string-match "\\([\\?#].*\\)?$" f)))
                    (start-pos (+ (string-match wsearch f1) (length base-url)))
                    (end-pos (if strip-suffix
-                             (string-match (regexp-quote strip-suffix) f1)
+                               (string-match (regexp-quote strip-suffix) f1)
                              (length f1)))
                   ;; We have to compare redirects without suffix below:
                   (f2 (concat wdir (substring f1 start-pos end-pos)))
@@ -631,7 +668,7 @@ CLIENT is ignored."
                        (greedy (plist-get (cdr prolist) :greedy))
                        (split (split-string fname proto))
                        (result (if greedy restoffiles (cadr split)))
-                      (new-style (string-match "/*?" (match-string 1 fname))))
+                      (new-style (not (= ?: (aref (match-string 1 fname) 0)))))
                   (when (plist-get (cdr prolist) :kill-client)
                    (message "Greedy org-protocol handler.  Killing client.")
                    (server-edit))
diff --git a/lisp/org/org-refile.el b/lisp/org/org-refile.el
index 8b42f817c1..73eaad6bf5 100644
--- a/lisp/org/org-refile.el
+++ b/lisp/org/org-refile.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;;
 ;; This file is part of GNU Emacs.
@@ -214,7 +214,7 @@ converted to a headline before refiling."
                   org-org-menu
                   '("Edit Structure") i))
       '(["Refile Subtree" org-refile (org-in-subtree-not-table-p)]
-       ["Refile and copy Subtree" org-copy (org-in-subtree-not-table-p)]))
+       ["Refile and copy Subtree" org-refile-copy 
(org-in-subtree-not-table-p)]))
 
 (defun org-refile-marker (pos)
   "Get a new refile marker, but only if caching is in use."
@@ -310,11 +310,13 @@ converted to a headline before refiling."
                 (setq f (buffer-file-name (buffer-base-buffer f))))
               (setq f (and f (expand-file-name f)))
               (when (eq org-refile-use-outline-path 'file)
-                (push (list (file-name-nondirectory f) f nil nil) tgs))
+                (push (list (and f (file-name-nondirectory f)) f nil nil) tgs))
               (when (eq org-refile-use-outline-path 'buffer-name)
                 (push (list (buffer-name (buffer-base-buffer)) f nil nil) tgs))
               (when (eq org-refile-use-outline-path 'full-file-path)
-                (push (list (file-truename (buffer-file-name 
(buffer-base-buffer))) f nil nil) tgs))
+                (push (list (and (buffer-file-name (buffer-base-buffer))
+                                  (file-truename (buffer-file-name 
(buffer-base-buffer))))
+                             f nil nil) tgs))
               (org-with-wide-buffer
                (goto-char (point-min))
                (setq org-outline-path-cache nil)
@@ -337,9 +339,10 @@ converted to a headline before refiling."
                                #'identity
                                (append
                                 (pcase org-refile-use-outline-path
-                                  (`file (list (file-name-nondirectory
-                                                (buffer-file-name
-                                                 (buffer-base-buffer)))))
+                                  (`file (list
+                                           (and (buffer-file-name 
(buffer-base-buffer))
+                                                (file-name-nondirectory
+                                                 (buffer-file-name 
(buffer-base-buffer))))))
                                   (`full-file-path
                                    (list (buffer-file-name
                                           (buffer-base-buffer))))
@@ -373,8 +376,6 @@ the *old* location.")
 (defvar org-refile-keep nil
   "Non-nil means `org-refile' will copy instead of refile.")
 
-(define-obsolete-function-alias 'org-copy 'org-refile-copy "Org 9.4")
-
 ;;;###autoload
 (defun org-refile-copy ()
   "Like `org-refile', but preserve the refiled subtree."
@@ -382,8 +383,19 @@ the *old* location.")
   (let ((org-refile-keep t))
     (org-refile nil nil nil "Copy")))
 
+;;;###autoload
+(defun org-refile-reverse (&optional arg default-buffer rfloc msg)
+  "Refile while temporarily toggling `org-reverse-note-order'.
+So if `org-refile' would append the entry as the last entry under
+the target heading, `org-refile-reverse' will prepend it as the
+first entry, and vice-versa."
+  (interactive "P")
+  (let ((org-reverse-note-order (not (org-notes-order-reversed-p))))
+    (org-refile arg default-buffer rfloc msg)))
+
 (defvar org-capture-last-stored-marker)
 
+
 ;;;###autoload
 (defun org-refile (&optional arg default-buffer rfloc msg)
   "Move the entry or entries at point to another heading.
@@ -426,7 +438,7 @@ needed when passing RFLOC
 headline to refile under
 
 MSG is a string to replace \"Refile\" in the default prompt with
-another verb.  E.g. `org-copy' sets this parameter to \"Copy\".
+another verb.  E.g. `org-refile-copy' sets this parameter to \"Copy\".
 
 See also `org-refile-use-outline-path'.
 
@@ -628,29 +640,29 @@ this function appends the default value from
               org-refile-target-table))
         (completion-ignore-case t)
         cdef
-        (prompt (concat prompt
-                        (or (and (car org-refile-history)
-                                 (concat " (default " (car org-refile-history) 
")"))
-                            (and (assoc cbnex tbl) (setq cdef cbnex)
-                                 (concat " (default " cbnex ")"))) ": "))
+         (prompt (let ((default (or (car org-refile-history)
+                                    (and (assoc cbnex tbl) (setq cdef cbnex)
+                                         cbnex))))
+                   ;; `format-prompt' is new in Emacs 28.1.
+                   (if (fboundp 'format-prompt)
+                       (format-prompt prompt default)
+                     (concat prompt " (default " default ": "))))
         pa answ parent-target child parent old-hist)
     (setq old-hist org-refile-history)
     (setq answ (funcall cfunc prompt tbl nil (not new-nodes)
                        nil 'org-refile-history
-                       (or cdef (concat (car org-refile-history) extra))))
+                       (or cdef (car org-refile-history))))
     (if (setq pa (org-refile--get-location answ tbl))
-       (let* ((last-refile-loc (car org-refile-history))
-              (last-refile-loc-path (concat last-refile-loc extra)))
+       (let ((last-refile-loc (car org-refile-history)))
          (org-refile-check-position pa)
          (when (or (not org-refile-history)
                    (not (eq old-hist org-refile-history))
-                   (not (equal (car pa) last-refile-loc-path)))
+                   (not (equal (car pa) last-refile-loc)))
            (setq org-refile-history
                  (cons (car pa) (if (assoc last-refile-loc tbl)
                                     org-refile-history
                                   (cdr org-refile-history))))
-           (when (or (equal last-refile-loc-path (nth 1 org-refile-history))
-                     (equal last-refile-loc (nth 1 org-refile-history)))
+           (when (equal last-refile-loc (nth 1 org-refile-history))
              (pop org-refile-history)))
          pa)
       (if (string-match "\\`\\(.*\\)/\\([^/]+\\)\\'" answ)
diff --git a/lisp/org/org-src.el b/lisp/org/org-src.el
index cabedecb68..8d02cf4345 100644
--- a/lisp/org/org-src.el
+++ b/lisp/org/org-src.el
@@ -2,7 +2,7 @@
 ;;
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;        Bastien Guerry <bzg@gnu.org>
 ;;         Dan Davison <davison at stats dot ox dot ac dot uk>
 ;; Keywords: outlines, hypermedia, calendar, wp
@@ -38,6 +38,7 @@
 (require 'org-keys)
 
 (declare-function org-mode "org" ())
+(declare-function org--get-expected-indentation "org" (element contentsp))
 (declare-function org-element-at-point "org-element" ())
 (declare-function org-element-class "org-element" (datum &optional parent))
 (declare-function org-element-context "org-element" (&optional element))
@@ -299,6 +300,9 @@ is 0.")
   "File name associated to Org source buffer, or nil.")
 (put 'org-src-source-file-name 'permanent-local t)
 
+(defvar-local org-src--preserve-blank-line nil)
+(put 'org-src--preserve-blank-line 'permanent-local t)
+
 (defun org-src--construct-edit-buffer-name (org-buffer-name lang)
   "Construct the buffer name for a source editing buffer."
   (concat "*Org Src " org-buffer-name "[ " lang " ]*"))
@@ -324,11 +328,11 @@ a cons cell (LINE . COLUMN) or symbol `end'.  See also
   (if (>= pos end) 'end
     (org-with-wide-buffer
      (goto-char (max beg pos))
-     (cons (count-lines beg (line-beginning-position))
+     (cons (count-lines (save-excursion (goto-char beg) 
(line-beginning-position))
+                        (line-beginning-position))
           ;; Column is relative to the end of line to avoid problems of
           ;; comma escaping or colons appended in front of the line.
-          (- (current-column)
-             (progn (end-of-line) (current-column)))))))
+          (- (point) (min end (line-end-position)))))))
 
 (defun org-src--goto-coordinates (coord beg end)
   "Move to coordinates COORD relatively to BEG and END.
@@ -341,9 +345,9 @@ which see.  BEG and END are buffer positions."
      (org-with-wide-buffer
       (goto-char beg)
       (forward-line (car coord))
-      (end-of-line)
-      (org-move-to-column (max (+ (current-column) (cdr coord)) 0))
-      (point)))))
+      (max (point)
+           (+ (min end (line-end-position))
+              (cdr coord)))))))
 
 (defun org-src--contents-area (datum)
   "Return contents boundaries of DATUM.
@@ -433,8 +437,8 @@ spaces after it as being outside."
                (line-end-position)
              (point))))))
 
-(defun org-src--contents-for-write-back ()
-  "Return buffer contents in a format appropriate for write back.
+(defun org-src--contents-for-write-back (write-back-buf)
+  "Populate WRITE-BACK-BUF with contents in the appropriate format.
 Assume point is in the corresponding edit buffer."
   (let ((indentation-offset
         (if org-src--preserve-indentation 0
@@ -443,28 +447,39 @@ Assume point is in the corresponding edit buffer."
                  org-src--content-indentation
                0))))
        (use-tabs? (and (> org-src--tab-width 0) t))
+        (preserve-fl (eq org-src--source-type 'latex-fragment))
        (source-tab-width org-src--tab-width)
-       (contents (org-with-wide-buffer (buffer-string)))
-       (write-back org-src--allow-write-back))
-    (with-temp-buffer
+       (contents (org-with-wide-buffer
+                   (let ((eol (line-end-position)))
+                     (list (buffer-substring (point-min) eol)
+                           (buffer-substring eol (point-max))))))
+       (write-back org-src--allow-write-back)
+        (preserve-blank-line org-src--preserve-blank-line)
+        marker)
+    (with-current-buffer write-back-buf
       ;; Reproduce indentation parameters from source buffer.
       (setq indent-tabs-mode use-tabs?)
       (when (> source-tab-width 0) (setq tab-width source-tab-width))
       ;; Apply WRITE-BACK function on edit buffer contents.
-      (insert (org-no-properties contents))
+      (insert (org-no-properties (car contents)))
+      (setq marker (point-marker))
+      (insert (org-no-properties (car (cdr contents))))
       (goto-char (point-min))
       (when (functionp write-back) (save-excursion (funcall write-back)))
-      ;; Add INDENTATION-OFFSET to every non-empty line in buffer,
+      ;; Add INDENTATION-OFFSET to every line in buffer,
       ;; unless indentation is meant to be preserved.
       (when (> indentation-offset 0)
-       (while (not (eobp))
+       (when preserve-fl (forward-line))
+        (while (not (eobp))
          (skip-chars-forward " \t")
-         (unless (eolp)                ;ignore blank lines
+          (when (or (not (eolp))                               ; not a blank 
line
+                    (and (eq (point) (marker-position marker)) ; current line
+                         preserve-blank-line))
            (let ((i (current-column)))
              (delete-region (line-beginning-position) (point))
              (indent-to (+ i indentation-offset))))
          (forward-line)))
-      (buffer-string))))
+      (set-marker marker nil))))
 
 (defun org-src--edit-element
     (datum name &optional initialize write-back contents remote)
@@ -507,8 +522,19 @@ Leave point in edit buffer."
             (source-tab-width (if indent-tabs-mode tab-width 0))
             (type (org-element-type datum))
             (block-ind (org-with-point-at (org-element-property :begin datum)
-                         (current-indentation)))
+                          (cond
+                           ((save-excursion (skip-chars-backward " \t") (bolp))
+                           (current-indentation))
+                           ((org-element-property :parent datum)
+                            (org--get-expected-indentation
+                             (org-element-property :parent datum) nil))
+                           (t (current-indentation)))))
             (content-ind org-edit-src-content-indentation)
+             (blank-line (save-excursion (beginning-of-line)
+                                         (looking-at-p "^[[:space:]]*$")))
+             (empty-line (and blank-line (looking-at-p "^$")))
+             (preserve-blank-line (or (and blank-line (not empty-line))
+                                      (and empty-line (= (+ block-ind 
content-ind) 0))))
             (preserve-ind
              (and (memq type '(example-block src-block))
                   (or (org-element-property :preserve-indent datum)
@@ -532,7 +558,8 @@ Leave point in edit buffer."
        (insert contents)
        (remove-text-properties (point-min) (point-max)
                                '(display nil invisible nil intangible nil))
-       (unless preserve-ind (org-do-remove-indentation))
+       (let ((lf (eq type 'latex-fragment)))
+          (unless preserve-ind (org-do-remove-indentation (and lf block-ind) 
lf)))
        (set-buffer-modified-p nil)
        (setq buffer-file-name nil)
        ;; Initialize buffer.
@@ -557,6 +584,7 @@ Leave point in edit buffer."
        (setq org-src--overlay overlay)
        (setq org-src--allow-write-back write-back)
        (setq org-src-source-file-name source-file-name)
+        (setq org-src--preserve-blank-line preserve-blank-line)
        ;; Start minor mode.
        (org-src-mode)
        ;; Clear undo information so we cannot undo back to the
@@ -587,7 +615,7 @@ Leave point in edit buffer."
 
 (defun org-src-font-lock-fontify-block (lang start end)
   "Fontify code block.
-This function is called by emacs automatic fontification, as long
+This function is called by Emacs' automatic fontification, as long
 as `org-src-fontify-natively' is non-nil."
   (let ((lang-mode (org-src-get-lang-mode lang)))
     (when (fboundp lang-mode)
@@ -1190,20 +1218,27 @@ Throw an error if there is no such buffer."
   (interactive)
   (unless (org-src-edit-buffer-p) (user-error "Not in a sub-editing buffer"))
   (set-buffer-modified-p nil)
-  (let ((edited-code (org-src--contents-for-write-back))
+  (let ((write-back-buf (generate-new-buffer "*org-src-write-back*"))
        (beg org-src--beg-marker)
        (end org-src--end-marker)
        (overlay org-src--overlay))
+    (org-src--contents-for-write-back write-back-buf)
     (with-current-buffer (org-src-source-buffer)
       (undo-boundary)
       (goto-char beg)
       ;; Temporarily disable read-only features of OVERLAY in order to
       ;; insert new contents.
       (delete-overlay overlay)
-      (delete-region beg end)
       (let ((expecting-bol (bolp)))
-       (insert edited-code)
+       (if (version< emacs-version "27.1")
+           (progn (delete-region beg end)
+                  (insert (with-current-buffer write-back-buf 
(buffer-string))))
+         (save-restriction
+           (narrow-to-region beg end)
+           (replace-buffer-contents write-back-buf 0.1 nil)
+           (goto-char (point-max))))
        (when (and expecting-bol (not (bolp))) (insert "\n")))
+      (kill-buffer write-back-buf)
       (save-buffer)
       (move-overlay overlay beg (point))))
   ;; `write-contents-functions' requires the function to return
@@ -1213,30 +1248,45 @@ Throw an error if there is no such buffer."
 (defun org-edit-src-exit ()
   "Kill current sub-editing buffer and return to source buffer."
   (interactive)
-  (unless (org-src-edit-buffer-p) (error "Not in a sub-editing buffer"))
+  (unless (org-src-edit-buffer-p)
+    (error "Not in a sub-editing buffer"))
   (let* ((beg org-src--beg-marker)
         (end org-src--end-marker)
         (write-back org-src--allow-write-back)
         (remote org-src--remote)
         (coordinates (and (not remote)
                           (org-src--coordinates (point) 1 (point-max))))
-        (code (and write-back (org-src--contents-for-write-back))))
+        (write-back-buf
+          (and write-back (generate-new-buffer "*org-src-write-back*"))))
+    (when write-back (org-src--contents-for-write-back write-back-buf))
     (set-buffer-modified-p nil)
     ;; Switch to source buffer.  Kill sub-editing buffer.
     (let ((edit-buffer (current-buffer))
          (source-buffer (marker-buffer beg)))
-      (unless source-buffer (error "Source buffer disappeared.  Aborting"))
+      (unless source-buffer
+        (when write-back-buf (kill-buffer write-back-buf))
+        (error "Source buffer disappeared.  Aborting"))
       (org-src-switch-to-buffer source-buffer 'exit)
       (kill-buffer edit-buffer))
     ;; Insert modified code.  Ensure it ends with a newline character.
     (org-with-wide-buffer
-     (when (and write-back (not (equal (buffer-substring beg end) code)))
+     (when (and write-back
+                (not (equal (buffer-substring beg end)
+                           (with-current-buffer write-back-buf
+                              (buffer-string)))))
        (undo-boundary)
        (goto-char beg)
-       (delete-region beg end)
        (let ((expecting-bol (bolp)))
-        (insert code)
+        (if (version< emacs-version "27.1")
+            (progn (delete-region beg end)
+                   (insert (with-current-buffer write-back-buf
+                              (buffer-string))))
+          (save-restriction
+            (narrow-to-region beg end)
+            (replace-buffer-contents write-back-buf 0.1 nil)
+            (goto-char (point-max))))
         (when (and expecting-bol (not (bolp))) (insert "\n")))))
+    (when write-back-buf (kill-buffer write-back-buf))
     ;; If we are to return to source buffer, put point at an
     ;; appropriate location.  In particular, if block is hidden, move
     ;; to the beginning of the block opening line.
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index 0e93fb271f..89c57fb06c 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
@@ -66,6 +66,7 @@
 (declare-function org-export-install-filters "ox" (info))
 (declare-function org-export-table-has-special-column-p "ox" (table))
 (declare-function org-export-table-row-is-special-p "ox" (table-row info))
+(declare-function org-forward-paragraph "org" (&optional arg))
 (declare-function org-id-find "org-id" (id &optional markerp))
 (declare-function org-indent-line "org" ())
 (declare-function org-load-modules-maybe "org" (&optional force))
@@ -331,7 +332,7 @@ relies on the variables to be present in the list."
 The default value is `hours', and will output the results as a
 number of hours.  Other allowed values are `seconds', `minutes' and
 `days', and the output will be a fraction of seconds, minutes or
-days. `hh:mm' selects to use hours and minutes, ignoring seconds.
+days.  `hh:mm' selects to use hours and minutes, ignoring seconds.
 The `U' flag in a table formula will select this specific format for
 a single formula."
   :group 'org-table-calculation
@@ -461,36 +462,41 @@ This may be useful when columns have been shrunk."
     (when pos (goto-char pos))
     (goto-char (line-beginning-position))
     (let ((end (line-end-position)) str)
+      (backward-char)
       (while (progn (forward-char 1) (< (point) end))
        (let ((ov (car (overlays-at (point)))))
          (if (not ov)
              (push (char-to-string (char-after)) str)
            (push (overlay-get ov 'display) str)
            (goto-char (1- (overlay-end ov))))))
-      (format "|%s" (mapconcat #'identity (reverse str) "")))))
+      (format "%s" (mapconcat #'identity (reverse str) "")))))
 
 (defvar-local org-table-header-overlay nil)
 (defun org-table-header-set-header ()
   "Display the header of the table at point."
-  (when (overlayp org-table-header-overlay)
-    (delete-overlay org-table-header-overlay))
-  (let* ((ws (window-start))
-        (beg (save-excursion
-               (goto-char (org-table-begin))
-               (while (or (org-at-table-hline-p)
-                          (looking-at-p ".*|\\s-+<[rcl]?\\([0-9]+\\)?>"))
-                 (move-beginning-of-line 2))
-               (point)))
-        (end (save-excursion (goto-char beg) (point-at-eol))))
-    (if (pos-visible-in-window-p beg)
-       (when (overlayp org-table-header-overlay)
-         (delete-overlay org-table-header-overlay))
-      (setq org-table-header-overlay
-           (make-overlay ws (+ ws (- end beg))))
-      (org-overlay-display
-       org-table-header-overlay
-       (org-table-row-get-visible-string beg)
-       'org-table-header))))
+  (let ((gcol temporary-goal-column))
+    (unwind-protect
+        (progn
+          (when (overlayp org-table-header-overlay)
+            (delete-overlay org-table-header-overlay))
+          (let* ((ws (window-start))
+                 (beg (save-excursion
+                        (goto-char (org-table-begin))
+                        (while (or (org-at-table-hline-p)
+                                   (looking-at-p 
".*|\\s-+<[rcl]?\\([0-9]+\\)?>"))
+                          (move-beginning-of-line 2))
+                        (line-beginning-position)))
+                 (end (save-excursion (goto-char beg) (point-at-eol))))
+            (if (pos-visible-in-window-p beg)
+                (when (overlayp org-table-header-overlay)
+                  (delete-overlay org-table-header-overlay))
+              (setq org-table-header-overlay
+                    (make-overlay ws (+ ws (- end beg))))
+              (org-overlay-display
+               org-table-header-overlay
+               (org-table-row-get-visible-string beg)
+               'org-table-header))))
+      (setq temporary-goal-column gcol))))
 
 ;;;###autoload
 (define-minor-mode org-table-header-line-mode
@@ -679,8 +685,6 @@ Will be filled automatically during use.")
     ("_" . "Names for values in row below this one.")
     ("^" . "Names for values in row above this one.")))
 
-(defvar org-tbl-calc-modes nil)
-
 (defvar org-pos nil)
 
 
@@ -724,18 +728,6 @@ Field is restored even in case of abnormal exit."
         (org-table-goto-column ,column)
         (set-marker ,line nil)))))
 
-(defsubst org-table--set-calc-mode (var &optional value)
-  (if (stringp var)
-      (setq var (assoc var '(("D" calc-angle-mode deg)
-                            ("R" calc-angle-mode rad)
-                            ("F" calc-prefer-frac t)
-                            ("S" calc-symbolic-mode t)))
-           value (nth 2 var) var (nth 1 var)))
-  (if (memq var org-tbl-calc-modes)
-      (setcar (cdr (memq var org-tbl-calc-modes)) value)
-    (cons var (cons value org-tbl-calc-modes)))
-  org-tbl-calc-modes)
-
 
 ;;; Predicates
 
@@ -870,52 +862,52 @@ nil      When nil, the command tries to be smart and 
figure out the
   (let* ((beg (min beg0 end0))
         (end (max beg0 end0))
         re)
-    (if (> (count-lines beg end) org-table-convert-region-max-lines)
-       (user-error "Region is longer than `org-table-convert-region-max-lines' 
(%s) lines; not converting"
-                   org-table-convert-region-max-lines)
-      (when (equal separator '(64))
-       (setq separator (read-regexp "Regexp for field separator")))
-      (goto-char beg)
-      (beginning-of-line 1)
-      (setq beg (point-marker))
-      (goto-char end)
-      (if (bolp) (backward-char 1) (end-of-line 1))
-      (setq end (point-marker))
-      ;; Get the right field separator
-      (unless separator
-       (goto-char beg)
-       (setq separator
-             (cond
-              ((not (re-search-forward "^[^\n\t]+$" end t)) '(16))
-              ((not (re-search-forward "^[^\n,]+$" end t)) '(4))
-              (t 1))))
+    (when (> (count-lines beg end) org-table-convert-region-max-lines)
+      (user-error "Region is longer than `org-table-convert-region-max-lines' 
(%s) lines; not converting"
+                 org-table-convert-region-max-lines))
+    (when (equal separator '(64))
+      (setq separator (read-regexp "Regexp for field separator")))
+    (goto-char beg)
+    (beginning-of-line 1)
+    (setq beg (point-marker))
+    (goto-char end)
+    (if (bolp) (backward-char 1) (end-of-line 1))
+    (setq end (point-marker))
+    ;; Get the right field separator
+    (unless separator
       (goto-char beg)
-      (if (equal separator '(4))
-         (while (< (point) end)
-           ;; parse the csv stuff
+      (setq separator
            (cond
-            ((looking-at "^") (insert "| "))
-            ((looking-at "[ \t]*$") (replace-match " |") (beginning-of-line 2))
-            ((looking-at "[ \t]*\"\\([^\"\n]*\\)\"")
-             (replace-match "\\1")
-             (if (looking-at "\"") (insert "\"")))
-            ((looking-at "[^,\n]+") (goto-char (match-end 0)))
-            ((looking-at "[ \t]*,") (replace-match " | "))
-            (t (beginning-of-line 2))))
-       (setq re (cond
-                 ((equal separator '(4)) "^\\|\"?[ \t]*,[ \t]*\"?")
-                 ((equal separator '(16)) "^\\|\t")
-                 ((integerp separator)
-                  (if (< separator 1)
-                      (user-error "Number of spaces in separator must be >= 1")
-                    (format "^ *\\| *\t *\\| \\{%d,\\}" separator)))
-                 ((stringp separator)
-                  (format "^ *\\|%s" separator))
-                 (t (error "This should not happen"))))
-       (while (re-search-forward re end t)
-         (replace-match "| " t t)))
-      (goto-char beg)
-      (org-table-align))))
+            ((not (re-search-forward "^[^\n\t]+$" end t)) '(16))
+            ((not (re-search-forward "^[^\n,]+$" end t)) '(4))
+            (t 1))))
+    (goto-char beg)
+    (if (equal separator '(4))
+       (while (< (point) end)
+         ;; parse the csv stuff
+         (cond
+          ((looking-at "^") (insert "| "))
+          ((looking-at "[ \t]*$") (replace-match " |") (beginning-of-line 2))
+          ((looking-at "[ \t]*\"\\([^\"\n]*\\)\"")
+           (replace-match "\\1")
+           (if (looking-at "\"") (insert "\"")))
+          ((looking-at "[^,\n]+") (goto-char (match-end 0)))
+          ((looking-at "[ \t]*,") (replace-match " | "))
+          (t (beginning-of-line 2))))
+      (setq re (cond
+               ((equal separator '(4)) "^\\|\"?[ \t]*,[ \t]*\"?")
+               ((equal separator '(16)) "^\\|\t")
+               ((integerp separator)
+                (if (< separator 1)
+                    (user-error "Number of spaces in separator must be >= 1")
+                  (format "^ *\\| *\t *\\| \\{%d,\\}" separator)))
+               ((stringp separator)
+                (format "^ *\\|%s" separator))
+               (t (error "This should not happen"))))
+      (while (re-search-forward re end t)
+       (replace-match "| " t t)))
+    (goto-char beg)
+    (org-table-align)))
 
 ;;;###autoload
 (defun org-table-import (file separator)
@@ -938,7 +930,8 @@ lines.  It can have the following values:
 - regexp  When a regular expression, use it to match the separator."
   (interactive "f\nP")
   (when (and (called-interactively-p 'any)
-            (not (string-match-p (rx "." (or "txt" "tsv" "csv") eos) file)))
+            (not (string-match-p (rx "." (or "txt" "tsv" "csv") eos) file))
+             (not (yes-or-no-p "The file's extension is not .txt, .tsv or 
.csv.  Import? ")))
     (user-error "Cannot import such file"))
   (unless (bolp) (insert "\n"))
   (let ((beg (point))
@@ -1936,8 +1929,9 @@ of lists of fields."
        (forward-line))
       (set-marker end nil))
     (when cut (org-table-align))
-    (message (substitute-command-keys "Cells in the region copied, use \
-\\[org-table-paste-rectangle] to paste them in a table."))
+    (when (called-interactively-p 'any)
+      (message (substitute-command-keys "Cells in the region copied, use \
+\\[org-table-paste-rectangle] to paste them in a table.")))
     (setq org-table-clip (nreverse region))))
 
 ;;;###autoload
@@ -2168,7 +2162,7 @@ LOCATION instead."
            (goto-char (match-beginning 3))
            (delete-region (match-beginning 3) (match-end 0)))
        (org-indent-line)
-       (insert (or (match-string 2) "#+TBLFM:")))
+       (insert "#+TBLFM:"))
       (insert " "
              (mapconcat (lambda (x) (concat (car x) "=" (cdr x)))
                         (sort alist #'org-table-formula-less-p)
@@ -2436,51 +2430,45 @@ location of point."
                        equation
                      (org-table-get-formula equation (equal arg '(4)))))
           (n0 (org-table-current-column))
-          (org-tbl-calc-modes (copy-sequence org-calc-default-modes))
+          (calc-modes (copy-sequence org-calc-default-modes))
           (numbers nil)           ; was a variable, now fixed default
           (keep-empty nil)
-          n form form0 formrpl formrg bw fmt x ev orig c lispp literal
+          form form0 formrpl formrg bw fmt ev orig lispp literal
           duration duration-output-format)
       ;; Parse the format string.  Since we have a lot of modes, this is
       ;; a lot of work.  However, I think calc still uses most of the time.
-      (if (string-match ";" formula)
-         (let ((tmp (org-split-string formula ";")))
-           (setq formula (car tmp)
-                 fmt (concat (cdr (assoc "%" org-table-local-parameters))
-                             (nth 1 tmp)))
+      (if (string-match "\\(.*\\);\\(.*\\)" formula)
+         (progn
+           (setq fmt (concat (cdr (assoc "%" org-table-local-parameters))
+                             (match-string-no-properties 2 formula)))
+           (setq formula (match-string-no-properties 1 formula))
            (while (string-match "\\([pnfse]\\)\\(-?[0-9]+\\)" fmt)
-             (setq c (string-to-char (match-string 1 fmt))
-                   n (string-to-number (match-string 2 fmt)))
-             (if (= c ?p)
-                 (setq org-tbl-calc-modes
-                       (org-table--set-calc-mode 'calc-internal-prec n))
-               (setq org-tbl-calc-modes
-                     (org-table--set-calc-mode
-                      'calc-float-format
-                      (list (cdr (assoc c '((?n . float) (?f . fix)
-                                            (?s . sci) (?e . eng))))
-                            n))))
+             (let ((c (string-to-char (match-string 1 fmt)))
+                   (n (string-to-number (match-string 2 fmt))))
+               (cl-case c
+                 (?p (setf (cl-getf calc-modes 'calc-internal-prec) n))
+                 (?n (setf (cl-getf calc-modes 'calc-float-format) (list 
'float n)))
+                 (?f (setf (cl-getf calc-modes 'calc-float-format) (list 'fix 
n)))
+                 (?s (setf (cl-getf calc-modes 'calc-float-format) (list 'sci 
n)))
+                 (?e (setf (cl-getf calc-modes 'calc-float-format) (list 'eng 
n)))))
+             ;; Remove matched flags from the mode string.
              (setq fmt (replace-match "" t t fmt)))
-           (if (string-match "[tTU]" fmt)
-               (let ((ff (match-string 0 fmt)))
-                 (setq duration t numbers t
-                       duration-output-format
-                       (cond ((equal ff "T") nil)
-                             ((equal ff "t") org-table-duration-custom-format)
-                             ((equal ff "U") 'hh:mm))
-                       fmt (replace-match "" t t fmt))))
-           (if (string-match "N" fmt)
-               (setq numbers t
-                     fmt (replace-match "" t t fmt)))
-           (if (string-match "L" fmt)
-               (setq literal t
-                     fmt (replace-match "" t t fmt)))
-           (if (string-match "E" fmt)
-               (setq keep-empty t
-                     fmt (replace-match "" t t fmt)))
-           (while (string-match "[DRFS]" fmt)
-             (setq org-tbl-calc-modes
-                   (org-table--set-calc-mode (match-string 0 fmt)))
+           (while (string-match "\\([tTUNLEDRFSu]\\)" fmt)
+             (let ((c (string-to-char (match-string 1 fmt))))
+               (cl-case c
+                 (?t (setq duration t numbers t
+                            duration-output-format 
org-table-duration-custom-format))
+                 (?T (setq duration t numbers t duration-output-format nil))
+                 (?U (setq duration t numbers t duration-output-format 'hh:mm))
+                 (?N (setq numbers t))
+                 (?L (setq literal t))
+                 (?E (setq keep-empty t))
+                 (?D (setf (cl-getf calc-modes 'calc-angle-mode) 'deg))
+                 (?R (setf (cl-getf calc-modes 'calc-angle-mode) 'rad))
+                 (?F (setf (cl-getf calc-modes 'calc-prefer-frac) t))
+                 (?S (setf (cl-getf calc-modes 'calc-symbolic-mode) t))
+                 (?u (setf (cl-getf calc-modes 'calc-simplify-mode) 'units))))
+             ;; Remove matched flags from the mode string.
              (setq fmt (replace-match "" t t fmt)))
            (unless (string-match "\\S-" fmt)
              (setq fmt nil))))
@@ -2582,17 +2570,17 @@ location of point."
        (setq form0 form)
        ;; Insert the references to fields in same row
        (while (string-match "\\$\\(\\([-+]\\)?[0-9]+\\)" form)
-         (setq n (+ (string-to-number (match-string 1 form))
-                    (if (match-end 2) n0 0))
-               x (nth (1- (if (= n 0) n0 (max n 1))) fields)
-               formrpl (save-match-data
-                         (org-table-make-reference
-                          x keep-empty numbers lispp)))
-         (when (or (not x)
-                   (save-match-data
-                     (string-match (regexp-quote formula) formrpl)))
-           (user-error "Invalid field specifier \"%s\""
-                       (match-string 0 form)))
+         (let* ((n (+ (string-to-number (match-string 1 form))
+                      (if (match-end 2) n0 0)))
+                (x (nth (1- (if (= n 0) n0 (max n 1))) fields)))
+           (setq formrpl (save-match-data
+                           (org-table-make-reference
+                            x keep-empty numbers lispp)))
+           (when (or (not x)
+                     (save-match-data
+                       (string-match (regexp-quote formula) formrpl)))
+             (user-error "Invalid field specifier \"%s\""
+                         (match-string 0 form))))
          (setq form (replace-match formrpl t t form)))
 
        (if lispp
@@ -2624,7 +2612,7 @@ location of point."
 
          (setq ev (if (and duration (string-match 
"^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" form))
                       form
-                    (calc-eval (cons form org-tbl-calc-modes)
+                    (calc-eval (cons form calc-modes)
                                (when (and (not keep-empty) numbers) 'num)))
                ev (if duration (org-table-time-seconds-to-string
                                 (if (string-match 
"^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" ev)
@@ -3280,7 +3268,7 @@ Parameters get priority."
     (org-defkey map "\C-c}"    'org-table-fedit-toggle-coordinates)
     map))
 
-(easy-menu-define org-table-fedit-menu org-table-fedit-map "Org Edit Formulas 
Menu"
+(easy-menu-define org-table-fedit-menu org-table-fedit-map "Org Edit Formulas 
Menu."
   '("Edit-Formulas"
     ["Finish and Install" org-table-fedit-finish t]
     ["Finish, Install, and Apply" (org-table-fedit-finish t) :keys "C-u C-c 
C-c"]
@@ -4674,19 +4662,24 @@ blank, and the content is appended to the field above."
   (if (org-region-active-p)
       ;; There is a region: fill as a paragraph.
       (let ((start (region-beginning)))
-       (org-table-cut-region (region-beginning) (region-end))
-       (when (> (length (car org-table-clip)) 1)
-         (user-error "Region must be limited to single column"))
-       (let ((nlines (cond ((not arg) (length org-table-clip))
-                           ((< arg 1) (+ (length org-table-clip) arg))
-                           (t arg))))
-         (setq org-table-clip
-               (mapcar #'list
-                       (org-wrap (mapconcat #'car org-table-clip " ")
-                                 nil
-                                 nlines))))
-       (goto-char start)
-       (org-table-paste-rectangle))
+        (save-restriction
+          (narrow-to-region
+           (save-excursion (goto-char start) (move-beginning-of-line 1))
+           (save-excursion (org-forward-paragraph) (point)))
+          (org-table-cut-region (region-beginning) (region-end))
+         (when (> (length (car org-table-clip)) 1)
+           (user-error "Region must be limited to single column"))
+         (let ((nlines (cond ((not arg) (length org-table-clip))
+                             ((< arg 1) (+ (length org-table-clip) arg))
+                             (t arg))))
+           (setq org-table-clip
+                 (mapcar #'list
+                         (org-wrap (mapconcat #'car org-table-clip " ")
+                                   nil
+                                   nlines))))
+         (goto-char start)
+         (org-table-paste-rectangle))
+        (org-table-align))
     ;; No region, split the current field at point.
     (unless (org-get-alist-option org-M-RET-may-split-line 'table)
       (skip-chars-forward "^\r\n|"))
@@ -5084,7 +5077,7 @@ When LOCAL is non-nil, show references for the table at 
point."
 (put 'orgtbl-mode :included t)
 (put 'orgtbl-mode :menu-tag "Org Table Mode")
 
-(easy-menu-define orgtbl-mode-menu orgtbl-mode-map "OrgTbl menu"
+(easy-menu-define orgtbl-mode-menu orgtbl-mode-map "OrgTbl menu."
   '("OrgTbl"
     ["Create or convert" org-table-create-or-convert-from-region
      :active (not (org-at-table-p)) :keys "C-c |" ]
@@ -5334,7 +5327,7 @@ With prefix arg, also recompute table."
 (defun orgtbl-create-or-convert-from-region (_arg)
   "Create table or convert region to table, if no conflicting binding.
 This installs the table binding `C-c |', but only if there is no
-conflicting binding to this key outside orgtbl-mode."
+conflicting binding to this key outside `orgtbl-mode'."
   (interactive "P")
   (let* (orgtbl-mode (cmd (key-binding "\C-c|")))
     (if cmd
@@ -5573,7 +5566,7 @@ First element has index 0, or I0 if given."
 
 ;;;###autoload
 (defun orgtbl-to-generic (table params)
-  "Convert the orgtbl-mode TABLE to some other format.
+  "Convert the `orgtbl-mode' TABLE to some other format.
 
 This generic routine can be used for many standard cases.
 
@@ -5960,12 +5953,12 @@ information."
 
 ;;;###autoload
 (defun orgtbl-to-tsv (table params)
-  "Convert the orgtbl-mode table to TAB separated material."
+  "Convert the `orgtbl-mode' TABLE to TAB separated material."
   (orgtbl-to-generic table (org-combine-plists '(:sep "\t") params)))
 
 ;;;###autoload
 (defun orgtbl-to-csv (table params)
-  "Convert the orgtbl-mode table to CSV material.
+  "Convert the `orgtbl-mode' TABLE to CSV material.
 This does take care of the proper quoting of fields with comma or quotes."
   (orgtbl-to-generic table
                     (org-combine-plists '(:sep "," :fmt org-quote-csv-field)
@@ -5973,7 +5966,7 @@ This does take care of the proper quoting of fields with 
comma or quotes."
 
 ;;;###autoload
 (defun orgtbl-to-latex (table params)
-  "Convert the orgtbl-mode TABLE to LaTeX.
+  "Convert the `orgtbl-mode' TABLE to LaTeX.
 
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
@@ -6006,7 +5999,7 @@ supported.  It is also possible to use the following ones:
 
 ;;;###autoload
 (defun orgtbl-to-html (table params)
-  "Convert the orgtbl-mode TABLE to HTML.
+  "Convert the `orgtbl-mode' TABLE to HTML.
 
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
@@ -6037,7 +6030,7 @@ supported.  It is also possible to use the following one:
 
 ;;;###autoload
 (defun orgtbl-to-texinfo (table params)
-  "Convert the orgtbl-mode TABLE to Texinfo.
+  "Convert the `orgtbl-mode' TABLE to Texinfo.
 
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
@@ -6068,7 +6061,7 @@ supported.  It is also possible to use the following one:
 
 ;;;###autoload
 (defun orgtbl-to-orgtbl (table params)
-  "Convert the orgtbl-mode TABLE into another orgtbl-mode table.
+  "Convert the `orgtbl-mode' TABLE into another orgtbl-mode table.
 
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
@@ -6083,7 +6076,7 @@ be set to provide ORGTBL directives for the generated 
table."
   (orgtbl-to-generic table (org-combine-plists params (list :backend 'org))))
 
 (defun orgtbl-to-table.el (table params)
-  "Convert the orgtbl-mode TABLE into a table.el table.
+  "Convert the `orgtbl-mode' TABLE into a table.el table.
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
 PARAMS is a property list of parameters that can influence the
@@ -6097,7 +6090,7 @@ supported."
      (replace-regexp-in-string "|-" "+-" (buffer-substring 1 (buffer-size))))))
 
 (defun orgtbl-to-unicode (table params)
-  "Convert the orgtbl-mode TABLE into a table with unicode characters.
+  "Convert the `orgtbl-mode' TABLE into a table with unicode characters.
 
 TABLE is a list, each entry either the symbol `hline' for
 a horizontal separator line, or a list of fields for that line.
@@ -6109,7 +6102,7 @@ supported.  It is also possible to use the following ones:
 
   When non-nil, use \"ascii-art-to-unicode\" package to translate
   the table.  You can download it here:
-  http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el.
+  https://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el.
 
 :narrow
 
@@ -6214,7 +6207,7 @@ which will prompt for the width."
 
 (defun orgtbl-uc-draw-grid (value min max &optional width)
   "Draw a bar in a table using block unicode characters.
-It is a variant of orgtbl-ascii-draw with Unicode block
+It is a variant of `orgtbl-ascii-draw' with Unicode block
 characters, for a smooth display.  Bars appear as grids (to the
 extent the font allows)."
   ;; https://en.wikipedia.org/wiki/Block_Elements
@@ -6224,7 +6217,7 @@ extent the font allows)."
 
 (defun orgtbl-uc-draw-cont (value min max &optional width)
   "Draw a bar in a table using block unicode characters.
-It is a variant of orgtbl-ascii-draw with Unicode block
+It is a variant of `orgtbl-ascii-draw' with Unicode block
 characters, for a smooth display.  Bars are solid (to the extent
 the font allows)."
   (orgtbl-ascii-draw value min max width
diff --git a/lisp/org/org-timer.el b/lisp/org/org-timer.el
index e2116be701..bfcea443c3 100644
--- a/lisp/org/org-timer.el
+++ b/lisp/org/org-timer.el
@@ -2,7 +2,7 @@
 
 ;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 ;;
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index 8871ef798d..6427f30072 100644
--- a/lisp/org/org-version.el
+++ b/lisp/org/org-version.el
@@ -5,13 +5,13 @@
 (defun org-release ()
   "The release version of Org.
 Inserted by installing Org mode or when a release is made."
-   (let ((org-release "9.4.4"))
+   (let ((org-release "9.5"))
      org-release))
 ;;;###autoload
 (defun org-git-version ()
   "The Git version of Org mode.
 Inserted by installing Org or when a release is made."
-   (let ((org-git-version "release_9.4.4"))
+   (let ((org-git-version "release_9.5-68-g77e2ec"))
      org-git-version))
 
 (provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index d03676e3fb..83b3d79cb1 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -3,12 +3,13 @@
 ;; Carstens outline-mode for keeping track of everything.
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 ;;
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;; Maintainer: Bastien Guerry <bzg@gnu.org>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
+;; Package-Requires: ((emacs "25.1"))
 
-;; Version: 9.4.4
+;; Version: 9.5
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -93,6 +94,8 @@
 (require 'org-compat)
 (require 'org-keys)
 (require 'ol)
+(require 'oc)
+(require 'oc-basic)
 (require 'org-table)
 
 ;; `org-outline-regexp' ought to be a defconst but is let-bound in
@@ -144,7 +147,6 @@ Stars are put in group 1 and the trimmed body in group 2.")
 (declare-function org-clock-timestamps-down "org-clock" (&optional n))
 (declare-function org-clock-timestamps-up "org-clock" (&optional n))
 (declare-function org-clock-update-time-maybe "org-clock" ())
-(declare-function org-clocking-buffer "org-clock" ())
 (declare-function org-clocktable-shift "org-clock" (dir n))
 (declare-function org-columns-quit "org-colview" ())
 (declare-function org-columns-insert-dblock "org-colview" ())
@@ -157,13 +159,18 @@ Stars are put in group 1 and the trimmed body in group 
2.")
 (declare-function org-element-context "org-element" (&optional element))
 (declare-function org-element-copy "org-element" (datum))
 (declare-function org-element-create "org-element" (type &optional props &rest 
children))
+(declare-function org-element-extract-element "org-element" (element))
+(declare-function org-element-insert-before "org-element" (element location))
 (declare-function org-element-interpret-data "org-element" (data))
 (declare-function org-element-lineage "org-element" (blob &optional types 
with-self))
 (declare-function org-element-link-parser "org-element" ())
+(declare-function org-element-map "org-element" (data types fun &optional info 
first-match no-recursion with-affiliated))
 (declare-function org-element-nested-p "org-element" (elem-a elem-b))
 (declare-function org-element-parse-buffer "org-element" (&optional 
granularity visible-only))
+(declare-function org-element-parse-secondary-string "org-element" (string 
restriction &optional parent))
 (declare-function org-element-property "org-element" (property element))
 (declare-function org-element-put-property "org-element" (element property 
value))
+(declare-function org-element-restriction "org-element" (element))
 (declare-function org-element-swap-A-B "org-element" (elem-a elem-b))
 (declare-function org-element-timestamp-parser "org-element" ())
 (declare-function org-element-type "org-element" (element))
@@ -191,7 +198,6 @@ Stars are put in group 1 and the trimmed body in group 2.")
 (declare-function org-toggle-archive-tag "org-archive" (&optional find-done))
 (declare-function org-update-radio-target-regexp "ol" ())
 
-(defvar ffap-url-regexp)
 (defvar org-element-paragraph-separate)
 (defvar org-indent-indentation-per-level)
 (defvar org-radio-target-regexp)
@@ -202,6 +208,8 @@ Stars are put in group 1 and the trimmed body in group 2.")
 ;; load languages based on value of `org-babel-load-languages'
 (defvar org-babel-load-languages)
 
+(defvar crm-separator)  ; dynamically scoped param
+
 ;;;###autoload
 (defun org-babel-do-load-languages (sym value)
   "Load the languages defined in `org-babel-load-languages'."
@@ -230,7 +238,11 @@ byte-compiled before it is loaded."
             tangled-file
             (file-attribute-modification-time
              (file-attributes (file-truename file))))
-      (org-babel-tangle-file file tangled-file "emacs-lisp\\|elisp"))
+      (org-babel-tangle-file file
+                             tangled-file
+                             (rx string-start
+                                 (or "emacs-lisp" "elisp")
+                                 string-end)))
     (if compile
        (progn
          (byte-compile-file tangled-file)
@@ -263,32 +275,25 @@ requirement."
                 (const :tag "Awk" awk)
                 (const :tag "C" C)
                 (const :tag "R" R)
-                (const :tag "Asymptote" asymptote)
-                (const :tag "Calc" calc)
+                 (const :tag "Calc" calc)
                 (const :tag "Clojure" clojure)
                 (const :tag "CSS" css)
                 (const :tag "Ditaa" ditaa)
                 (const :tag "Dot" dot)
-                (const :tag "Ebnf2ps" ebnf2ps)
-                (const :tag "Emacs Lisp" emacs-lisp)
+                 (const :tag "Emacs Lisp" emacs-lisp)
                 (const :tag "Forth" forth)
                 (const :tag "Fortran" fortran)
                 (const :tag "Gnuplot" gnuplot)
                 (const :tag "Haskell" haskell)
-                (const :tag "hledger" hledger)
-                (const :tag "IO" io)
-                (const :tag "J" J)
-                (const :tag "Java" java)
+                 (const :tag "Java" java)
                 (const :tag "Javascript" js)
                 (const :tag "LaTeX" latex)
-                (const :tag "Ledger" ledger)
-                (const :tag "Lilypond" lilypond)
+                 (const :tag "Lilypond" lilypond)
                 (const :tag "Lisp" lisp)
                 (const :tag "Makefile" makefile)
                 (const :tag "Maxima" maxima)
                 (const :tag "Matlab" matlab)
-                (const :tag "Mscgen" mscgen)
-                (const :tag "Ocaml" ocaml)
+                 (const :tag "Ocaml" ocaml)
                 (const :tag "Octave" octave)
                 (const :tag "Org" org)
                 (const :tag "Perl" perl)
@@ -301,11 +306,9 @@ requirement."
                 (const :tag "Scheme" scheme)
                 (const :tag "Screen" screen)
                 (const :tag "Shell Script" shell)
-                (const :tag "Shen" shen)
-                (const :tag "Sql" sql)
+                 (const :tag "Sql" sql)
                 (const :tag "Sqlite" sqlite)
-                (const :tag "Stan" stan)
-                (const :tag "Vala" vala))
+                (const :tag "Stan" stan))
                :value-type (boolean :tag "Activate" :value t)))
 
 ;;;; Customization variables
@@ -654,6 +657,10 @@ defined in org-duration.el.")
   :group 'org
   :type 'hook)
 
+(make-obsolete-variable
+ 'org-load-hook
+ "use `with-eval-after-load' instead." "9.5")
+
 (defcustom org-log-buffer-setup-hook nil
   "Hook that is run after an Org log buffer is created."
   :group 'org
@@ -680,15 +687,16 @@ defined in org-duration.el.")
     (org-load-modules-maybe 'force)
     (org-element-cache-reset 'all)))
 
-(defcustom org-modules '(ol-w3m ol-bbdb ol-bibtex ol-docview ol-gnus ol-info 
ol-irc ol-mhe ol-rmail ol-eww)
+(defcustom org-modules '(ol-doi ol-w3m ol-bbdb ol-bibtex ol-docview ol-gnus 
ol-info ol-irc ol-mhe ol-rmail ol-eww)
   "Modules that should always be loaded together with org.el.
 
-If a description starts with <C>, the file is not part of Emacs
-and loading it will require that you have downloaded and properly
-installed the Org mode distribution.
+If a description starts with <C>, the file is not part of Emacs and Org mode,
+so loading it will require that you have properly installed org-contrib
+package from NonGNU Emacs Lisp Package Archive
+http://elpa.nongnu.org/nongnu/org-contrib.html
 
 You can also use this system to load external packages (i.e. neither Org
-core modules, nor modules from the CONTRIB directory).  Just add symbols
+core modules, nor org-contrib modules).  Just add symbols
 to the end of the list.  If the package is called org-xyz.el, then you need
 to add the symbol `xyz', and the package must have a call to:
 
@@ -697,8 +705,7 @@ to add the symbol `xyz', and the package must have a call 
to:
 For export specific modules, see also `org-export-backends'."
   :group 'org
   :set 'org-set-modules
-  :version "26.1"
-  :package-version '(Org . "9.2")
+  :package-version '(Org . "9.5")
   :type
   '(set :greedy t
        (const :tag "   bbdb:              Links to BBDB entries" ol-bbdb)
@@ -706,6 +713,7 @@ For export specific modules, see also 
`org-export-backends'."
        (const :tag "   crypt:             Encryption of subtrees" org-crypt)
        (const :tag "   ctags:             Access to Emacs tags with links" 
org-ctags)
        (const :tag "   docview:           Links to Docview buffers" ol-docview)
+        (const :tag "   doi:               Links to DOI references" ol-doi)
        (const :tag "   eww:               Store link to URL of Eww" ol-eww)
        (const :tag "   gnus:              Links to GNUS folders/messages" 
ol-gnus)
        (const :tag "   habit:             Track your consistency with habits" 
org-habit)
@@ -762,9 +770,10 @@ For export specific modules, see also 
`org-export-backends'."
 (defcustom org-export-backends '(ascii html icalendar latex odt)
   "List of export back-ends that should be always available.
 
-If a description starts with <C>, the file is not part of Emacs
-and loading it will require that you have downloaded and properly
-installed the Org mode distribution.
+If a description starts with <C>, the file is not part of Emacs and Org mode,
+so loading it will require that you have properly installed org-contrib
+package from NonGNU Emacs Lisp Package Archive
+http://elpa.nongnu.org/nongnu/org-contrib.html
 
 Unlike to `org-modules', libraries in this list will not be
 loaded along with Org, but only once the export framework is
@@ -940,6 +949,7 @@ the following lines anywhere in the buffer:
    #+STARTUP: fold              (or `overview', this is equivalent)
    #+STARTUP: nofold            (or `showall', this is equivalent)
    #+STARTUP: content
+   #+STARTUP: show<n>levels (<n> = 2..5)
    #+STARTUP: showeverything
 
 Set `org-agenda-inhibit-startup' to a non-nil value if you want
@@ -950,6 +960,10 @@ time."
   :type '(choice
          (const :tag "nofold: show all" nil)
          (const :tag "fold: overview" t)
+         (const :tag "fold: show two levels" show2levels)
+         (const :tag "fold: show three levels" show3levels)
+         (const :tag "fold: show four levels" show4evels)
+         (const :tag "fold: show five levels" show5levels)
          (const :tag "content: all headlines" content)
          (const :tag "show everything, even drawers" showeverything)))
 
@@ -1194,6 +1208,8 @@ Allowed visibility spans are
   ancestors      show current headline and its direct ancestors; if
                  point is not on headline, also show entry
 
+  ancestors-full show current subtree and its direct ancestors
+
   lineage        show current headline, its direct ancestors and all
                  their children; if point is not on headline, also show
                  entry and first child
@@ -1235,6 +1251,7 @@ more context."
                           (const minimal)
                           (const local)
                           (const ancestors)
+                           (const ancestors-full)
                           (const lineage)
                           (const tree)
                           (const canonical))))))
@@ -1575,14 +1592,13 @@ lines to the buffer:
   :group 'org-appearance
   :type 'boolean)
 
-(defcustom org-adapt-indentation t
+(defcustom org-adapt-indentation nil
   "Non-nil means adapt indentation to outline node level.
 
-When this variable is set to t, Org assumes that you write
-outlines by indenting text in each node to align with the
-headline (after the stars).
+When set to t, Org assumes that you write outlines by indenting
+text in each node to align with the headline, after the stars.
 
-When this variable is set to 'headline-data, only adapt the
+When this variable is set to `headline-data', Org only adapts the
 indentation of the data lines right below the headline, such as
 planning/clock lines and property/logbook drawers.
 
@@ -1608,9 +1624,9 @@ time in Emacs."
   :type '(choice
          (const :tag "Adapt indentation for all lines" t)
          (const :tag "Adapt indentation for headline data lines"
-                'headline-data)
+                headline-data)
          (const :tag "Do not adapt indentation at all" nil))
-  :safe #'booleanp)
+  :safe (lambda (x) (memq x '(t nil headline-data))))
 
 (defvaralias 'org-special-ctrl-a 'org-special-ctrl-a/e)
 
@@ -2437,8 +2453,20 @@ set a priority."
 
 (defcustom org-priority-highest ?A
   "The highest priority of TODO items.
+
 A character like ?A, ?B, etc., or a numeric value like 1, 2, etc.
-Must be smaller than `org-priority-lowest'."
+
+The default is the character ?A, which is 65 as a numeric value.
+
+If you set `org-priority-highest' to a numeric value inferior to
+65, Org assumes you want to use digits for the priority cookie.
+If you set it to >=65, Org assumes you want to use alphabetical
+characters.
+
+In both cases, the value of `org-priority-highest' must be
+smaller than `org-priority-lowest': for example, if \"A\" is the
+highest priority, it is smaller than the lowest \"C\" priority:
+65 < 67."
   :group 'org-priorities
   :type '(choice
          (character :tag "Character")
@@ -2447,8 +2475,20 @@ Must be smaller than `org-priority-lowest'."
 (defvaralias 'org-lowest-priority 'org-priority-lowest)
 (defcustom org-priority-lowest ?C
   "The lowest priority of TODO items.
-A character like ?A, ?B, etc., or a numeric value like 1, 2, etc.
-Must be higher than `org-priority-highest'."
+
+A character like ?C, ?B, etc., or a numeric value like 9, 8, etc.
+
+The default is the character ?C, which is 67 as a numeric value.
+
+If you set `org-priority-lowest' to a numeric value inferior to
+65, Org assumes you want to use digits for the priority cookie.
+If you set it to >=65, Org assumes you want to use alphabetical
+characters.
+
+In both cases, the value of `org-priority-lowest' must be greater
+than `org-priority-highest': for example, if \"C\" is the lowest
+priority, it is greater than the highest \"A\" priority: 67 >
+65."
   :group 'org-priorities
   :type '(choice
          (character :tag "Character")
@@ -3113,7 +3153,7 @@ it in the document property drawer.  For example:
 :CATEGORY: ELisp
 :END:
 
-Other ways to define it is as an emacs file variable, for example
+Other ways to define it is as an Emacs file variable, for example
 
 #   -*- mode: org; org-category: \"ELisp\"
 
@@ -3285,7 +3325,7 @@ All available processes and theirs documents can be found 
in
      :image-output-type "png"
      :image-size-adjust (1.0 . 1.0)
      :latex-compiler ("latex -interaction nonstopmode -output-directory %o %f")
-     :image-converter ("dvipng -D %D -T tight -o %O %f"))
+     :image-converter ("dvipng -D %D -T tight -bg Transparent -o %O %f"))
     (dvisvgm
      :programs ("latex" "dvisvgm")
      :description "dvi > svg"
@@ -3428,13 +3468,11 @@ header, or they will be appended."
   '(("AUTO" "inputenc"  t ("pdflatex"))
     ("T1"   "fontenc"   t ("pdflatex"))
     (""     "graphicx"  t)
-    (""     "grffile"   t)
     (""     "longtable" nil)
     (""     "wrapfig"   nil)
     (""     "rotating"  nil)
     ("normalem" "ulem"  t)
     (""     "amsmath"   t)
-    (""     "textcomp"  t)
     (""     "amssymb"   t)
     (""     "capt-of"   nil)
     (""     "hyperref"  nil))
@@ -3448,15 +3486,14 @@ Org mode to function properly:
 
 - inputenc, fontenc:  for basic font and character selection
 - graphicx: for including images
-- grffile: allow periods and spaces in graphics file names
 - longtable: For multipage tables
 - wrapfig: for figure placement
 - rotating: for sideways figures and tables
 - ulem: for underline and strike-through
 - amsmath: for subscript and superscript and math environments
-- textcomp, amssymb: for various symbols used
-  for interpreting the entities in `org-entities'.  You can skip
-  some of these packages if you don't use any of their symbols.
+- amssymb: for various symbols used for interpreting the entities
+  in `org-entities'.  You can skip some of this package if you don't
+  use any of the symbols.
 - capt-of: for captions outside of floats
 - hyperref: for cross references
 
@@ -3570,10 +3607,11 @@ lines to the buffer:
 For example, a value \\='(title) for this list makes the document's title
 appear in the buffer without the initial \"#+TITLE:\" part."
   :group 'org-appearance
-  :version "24.1"
+  :package-version '(Org . "9.5")
   :type '(set (const :tag "#+AUTHOR" author)
              (const :tag "#+DATE" date)
              (const :tag "#+EMAIL" email)
+             (const :tag "#+SUBTITLE" subtitle)
              (const :tag "#+TITLE" title)))
 
 (defcustom org-custom-properties nil
@@ -3593,7 +3631,7 @@ When this is non-nil, the headline after the keyword is 
set to the
   :group 'org-appearance
   :package-version '(Org . "9.4")
   :type 'boolean
-  :safe t)
+  :safe #'booleanp)
 
 (defcustom org-fontify-done-headline t
   "Non-nil means change the face of a headline if it is marked DONE.
@@ -3822,10 +3860,11 @@ This is needed for font-lock setup.")
   "Marker recording the last clock-in, but the headline position.")
 (defvar org-clock-heading ""
   "The heading of the current clock entry.")
-(defun org-clock-is-active ()
+(defun org-clocking-buffer ()
   "Return the buffer where the clock is currently running.
 Return nil if no clock is running."
   (marker-buffer org-clock-marker))
+(defalias 'org-clock-is-active #'org-clocking-buffer)
 
 (defun org-check-running-clock ()
   "Check if the current buffer contains the running clock.
@@ -4106,7 +4145,7 @@ groups carry important information:
 (defconst org-stamp-time-of-day-regexp
   (concat
    "<\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\} +\\sw+ +\\)"
-   "\\([012][0-9]:[0-5][0-9]\\(-\\([012][0-9]:[0-5][0-9]\\)\\)?[^\n\r>]*?\\)>"
+   "\\([012][0-9]:[0-5][0-9]\\)\\(-\\([012][0-9]:[0-5][0-9]\\)\\)?[^\n\r>]*?>"
    "\\(--?"
    "<\\1\\([012][0-9]:[0-5][0-9]\\)>\\)?")
   "Regular expression to match a timestamp time or time range.
@@ -4122,6 +4161,10 @@ After a match, the following groups carry important 
information:
     ("overview" org-startup-folded t)
     ("nofold" org-startup-folded nil)
     ("showall" org-startup-folded nil)
+    ("show2levels" org-startup-folded show2levels)
+    ("show3levels" org-startup-folded show3levels)
+    ("show4levels" org-startup-folded show4levels)
+    ("show5levels" org-startup-folded show5levels)
     ("showeverything" org-startup-folded showeverything)
     ("content" org-startup-folded content)
     ("indent" org-startup-indented t)
@@ -4498,7 +4541,7 @@ directory."
                 (when (and (org-string-nw-p value)
                            (not buffer-read-only)) ;FIXME: bug in Gnus?
                   (let* ((uri (org-strip-quotes value))
-                         (uri-is-url (org-file-url-p uri))
+                         (uri-is-url (org-url-p uri))
                          (uri (if uri-is-url
                                   uri
                                 (expand-file-name uri))))
@@ -4628,11 +4671,6 @@ This is the cache of file URLs read using 
`org-file-contents'.")
   "Reset the cache of files downloaded by `org-file-contents'."
   (clrhash org--file-cache))
 
-(defun org-file-url-p (file)
-  "Non-nil if FILE is a URL."
-  (require 'ffap)
-  (string-match-p ffap-url-regexp file))
-
 (defun org-file-contents (file &optional noerror nocache)
   "Return the contents of FILE, as a string.
 
@@ -4647,7 +4685,7 @@ from file or URL, and return nil.
 
 If NOCACHE is non-nil, do a fresh fetch of FILE even if cached version
 is available.  This option applies only if FILE is a URL."
-  (let* ((is-url (org-file-url-p file))
+  (let* ((is-url (org-url-p file))
          (cache (and is-url
                      (not nocache)
                      (gethash file org--file-cache))))
@@ -4793,6 +4831,7 @@ The following commands are available:
   (org-load-modules-maybe)
   (org-install-agenda-files-menu)
   (when org-link-descriptive (add-to-invisibility-spec '(org-link)))
+  (make-local-variable 'org-link-descriptive)
   (add-to-invisibility-spec '(org-hide-block . t))
   (setq-local outline-regexp org-outline-regexp)
   (setq-local outline-level 'org-outline-level)
@@ -4903,6 +4942,18 @@ The following commands are available:
      (when org-startup-numerated (require 'org-num) (org-num-mode 1))
      (when org-startup-indented (require 'org-indent) (org-indent-mode 1))))
 
+  ;; Add a custom keymap for `visual-line-mode' so that activating
+  ;; this minor mode does not override Org's keybindings.
+  ;; FIXME: Probably `visual-line-mode' should take care of this.
+  (let ((oldmap (cdr (assoc 'visual-line-mode minor-mode-map-alist)))
+        (newmap (make-sparse-keymap)))
+    (set-keymap-parent newmap oldmap)
+    (define-key newmap [remap move-beginning-of-line] nil)
+    (define-key newmap [remap move-end-of-line] nil)
+    (define-key newmap [remap kill-line] nil)
+    (make-local-variable 'minor-mode-overriding-map-alist)
+    (push `(visual-line-mode . ,newmap) minor-mode-overriding-map-alist))
+
   ;; Activate `org-table-header-line-mode'
   (when org-table-header-line-p
     (org-table-header-line-mode 1))
@@ -4926,7 +4977,8 @@ The following commands are available:
                   ("9.1" . "26.1")
                   ("9.2" . "27.1")
                   ("9.3" . "27.1")
-                  ("9.4" . "27.2")))
+                  ("9.4" . "27.2")
+                  ("9.5" . "28.1")))
 
 (defvar org-mode-transpose-word-syntax-table
   (let ((st (make-syntax-table text-mode-syntax-table)))
@@ -5059,9 +5111,10 @@ stacked delimiters is N.  Escaping delimiters is not 
possible."
              (when (and org-hide-emphasis-markers
                         (not (org-at-comment-p)))
                (add-text-properties (match-end 4) (match-beginning 5)
-                                    '(invisible org-link))
+                                    '(invisible t))
                (add-text-properties (match-beginning 3) (match-end 3)
-                                    '(invisible org-link)))
+                                    '(invisible t)))
+              (goto-char (match-end 0))
              (throw :exit t))))))))
 
 (defun org-emphasize (&optional char)
@@ -5143,30 +5196,31 @@ This includes angle, plain, and bracket links."
                 (link (org-element-property :raw-link link-object))
                 (type (org-element-property :type link-object))
                 (path (org-element-property :path link-object))
+                 (face-property (pcase (org-link-get-parameter type :face)
+                                 ((and (pred functionp) face) (funcall face 
path))
+                                 ((and (pred facep) face) face)
+                                 ((and (pred consp) face) face) ;anonymous
+                                 (_ 'org-link)))
                 (properties            ;for link's visible part
-                 (list
-                  'face (pcase (org-link-get-parameter type :face)
-                          ((and (pred functionp) face) (funcall face path))
-                          ((and (pred facep) face) face)
-                          ((and (pred consp) face) face) ;anonymous
-                          (_ 'org-link))
-                  'mouse-face (or (org-link-get-parameter type :mouse-face)
-                                  'highlight)
-                  'keymap (or (org-link-get-parameter type :keymap)
-                              org-mouse-map)
-                  'help-echo (pcase (org-link-get-parameter type :help-echo)
-                               ((and (pred stringp) echo) echo)
-                               ((and (pred functionp) echo) echo)
-                               (_ (concat "LINK: " link)))
-                  'htmlize-link (pcase (org-link-get-parameter type
-                                                               :htmlize-link)
-                                  ((and (pred functionp) f) (funcall f))
-                                  (_ `(:uri ,link)))
-                  'font-lock-multiline t)))
+                 (list 'mouse-face (or (org-link-get-parameter type 
:mouse-face)
+                                       'highlight)
+                       'keymap (or (org-link-get-parameter type :keymap)
+                                   org-mouse-map)
+                       'help-echo (pcase (org-link-get-parameter type 
:help-echo)
+                                    ((and (pred stringp) echo) echo)
+                                    ((and (pred functionp) echo) echo)
+                                    (_ (concat "LINK: " link)))
+                       'htmlize-link (pcase (org-link-get-parameter type
+                                                                    
:htmlize-link)
+                                       ((and (pred functionp) f) (funcall f))
+                                       (_ `(:uri ,link)))
+                       'font-lock-multiline t)))
            (org-remove-flyspell-overlays-in start end)
            (org-rear-nonsticky-at end)
            (if (not (eq 'bracket style))
-               (add-text-properties start end properties)
+               (progn
+                  (add-face-text-property start end face-property)
+                 (add-text-properties start end properties))
              ;; Handle invisible parts in bracket links.
              (remove-text-properties start end '(invisible nil))
              (let ((hidden
@@ -5175,6 +5229,7 @@ This includes angle, plain, and bracket links."
                                    'org-link))
                             properties)))
                (add-text-properties start visible-start hidden)
+                (add-face-text-property start end face-property)
                (add-text-properties visible-start visible-end properties)
                (add-text-properties visible-end end hidden)
                (org-rear-nonsticky-at visible-start)
@@ -5272,7 +5327,8 @@ by a #."
            (org-remove-flyspell-overlays-in nl-before-endline end-of-endline)
            (cond
             ((and lang (not (string= lang "")) org-src-fontify-natively)
-             (org-src-font-lock-fontify-block lang block-start block-end)
+             (save-match-data
+                (org-src-font-lock-fontify-block lang block-start block-end))
              (add-text-properties bol-after-beginline block-end '(src-block 
t)))
             (quoting
              (add-text-properties
@@ -5303,7 +5359,7 @@ by a #."
                 (min (point-max) end-of-endline))
               '(face org-block-end-line)))
            t))
-        ((member dc1 '("+title:" "+author:" "+email:" "+date:"))
+        ((member dc1 '("+title:" "+subtitle:" "+author:" "+email:" "+date:"))
          (org-remove-flyspell-overlays-in
           (match-beginning 0)
           (if (equal "+title:" dc1) (match-end 2) (match-end 0)))
@@ -5376,22 +5432,26 @@ by a #."
          t)))))
 
 (defun org-fontify-extend-region (beg end _old-len)
-  (let ((begin-re "\\(\\\\\\[\\|\\(#\\+begin_\\|\\\\begin{\\)\\S-+\\)")
+  (let ((end (if (progn (goto-char end) (looking-at-p "^[*#]"))
+                 (1+ end) end))
+        (begin-re "\\(\\\\\\[\\|\\(#\\+begin_\\|\\\\begin{\\)\\S-+\\)")
        (end-re "\\(\\\\\\]\\|\\(#\\+end_\\|\\\\end{\\)\\S-+\\)")
-       (extend (lambda (r1 r2 dir)
-                 (let ((re (replace-regexp-in-string "\\(begin\\|end\\)" r1
-                            (replace-regexp-in-string "[][]" r2
-                             (match-string-no-properties 0)))))
-                   (re-search-forward (regexp-quote re) nil t dir)))))
+       (extend
+         (lambda (r1 r2 dir)
+          (let ((re (replace-regexp-in-string
+                      "\\(begin\\|end\\)" r1
+                     (replace-regexp-in-string
+                       "[][]" r2
+                      (match-string-no-properties 0)))))
+            (re-search-forward (regexp-quote re) nil t dir)))))
+    (goto-char beg)
+    (back-to-indentation)
     (save-match-data
-      (save-excursion
-       (goto-char beg)
-       (back-to-indentation)
-       (cond ((looking-at end-re)
-              (cons (or (funcall extend "begin" "[" -1) beg) end))
-             ((looking-at begin-re)
-              (cons beg (or (funcall extend "end" "]" 1) end)))
-             (t (cons beg end)))))))
+      (cond ((looking-at end-re)
+            (cons (or (funcall extend "begin" "[" -1) beg) end))
+           ((looking-at begin-re)
+            (cons beg (or (funcall extend "end" "]" 1) end)))
+           (t (cons beg end))))))
 
 (defun org-activate-footnote-links (limit)
   "Add text properties for footnotes."
@@ -5488,6 +5548,8 @@ highlighting was done, nil otherwise."
        (while (and (< (point) limit)
                    (re-search-forward org-latex-and-related-regexp nil t))
          (cond
+           ((>= (match-beginning 0) limit)
+           (throw 'found nil))
           ((cl-some (lambda (f)
                       (memq f '(org-code org-verbatim underline
                                          org-special-keyword)))
@@ -5600,111 +5662,116 @@ needs to be inserted at a specific position in the 
font-lock sequence.")
 
 (defun org-set-font-lock-defaults ()
   "Set font lock defaults for the current buffer."
-  (let* ((em org-fontify-emphasized-text)
-        (lk org-highlight-links)
-        (org-font-lock-extra-keywords
-         (list
-          ;; Call the hook
-          '(org-font-lock-hook)
-          ;; Headlines
-          `(,(if org-fontify-whole-heading-line
-                 "^\\(\\**\\)\\(\\* \\)\\(.*\n?\\)"
-               "^\\(\\**\\)\\(\\* \\)\\(.*\\)")
-            (1 (org-get-level-face 1))
-            (2 (org-get-level-face 2))
-            (3 (org-get-level-face 3)))
-          ;; Table lines
-          '("^[ \t]*\\(\\(|\\|\\+-[-+]\\).*\\S-\\)"
-            (1 'org-table t))
-          ;; Table internals
-          '("^[ \t]*|\\(?:.*?|\\)? *\\(:?=[^|\n]*\\)" (1 'org-formula t))
-          '("^[ \t]*| *\\([#*]\\) *|" (1 'org-formula t))
-          '("^[ \t]*|\\( *\\([$!_^/]\\) *|.*\\)|" (1 'org-formula t))
-          '("| *\\(<[lrc]?[0-9]*>\\)" (1 'org-formula t))
-          ;; Properties
-          (list org-property-re
-                '(1 'org-special-keyword t)
-                '(3 'org-property-value t))
-          ;; Drawers
-          '(org-fontify-drawers)
-          ;; Link related fontification.
-          '(org-activate-links)
-          (when (memq 'tag lk) '(org-activate-tags (1 'org-tag prepend)))
-          (when (memq 'radio lk) '(org-activate-target-links (1 'org-link t)))
-          (when (memq 'date lk) '(org-activate-dates (0 'org-date t)))
-          (when (memq 'footnote lk) '(org-activate-footnote-links))
-           ;; Targets.
-           (list org-radio-target-regexp '(0 'org-target t))
-          (list org-target-regexp '(0 'org-target t))
-          ;; Diary sexps.
-          '("^&?%%(.*\\|<%%([^>\n]*?>" (0 'org-sexp-date t))
-          ;; Macro
-          '(org-fontify-macros)
-          ;; TODO keyword
-          (list (format org-heading-keyword-regexp-format
-                        org-todo-regexp)
-                '(2 (org-get-todo-face 2) t))
-          ;; TODO
-          (when org-fontify-todo-headline
-            (list (format org-heading-keyword-regexp-format
-                          (concat
-                           "\\(?:"
-                           (mapconcat 'regexp-quote org-not-done-keywords 
"\\|")
-                           "\\)"))
-                  '(2 'org-headline-todo t)))
-          ;; DONE
-          (when org-fontify-done-headline
-            (list (format org-heading-keyword-regexp-format
-                          (concat
-                           "\\(?:"
-                           (mapconcat 'regexp-quote org-done-keywords "\\|")
-                           "\\)"))
-                  '(2 'org-headline-done t)))
-          ;; Priorities
-          '(org-font-lock-add-priority-faces)
-          ;; Tags
-          '(org-font-lock-add-tag-faces)
-          ;; Tags groups
-          (when (and org-group-tags org-tag-groups-alist)
-            (list (concat org-outline-regexp-bol ".+\\(:"
-                          (regexp-opt (mapcar 'car org-tag-groups-alist))
-                          ":\\).*$")
-                  '(1 'org-tag-group prepend)))
-          ;; Special keywords
-          (list (concat "\\<" org-deadline-string) '(0 'org-special-keyword t))
-          (list (concat "\\<" org-scheduled-string) '(0 'org-special-keyword 
t))
-          (list (concat "\\<" org-closed-string) '(0 'org-special-keyword t))
-          (list (concat "\\<" org-clock-string) '(0 'org-special-keyword t))
-          ;; Emphasis
-          (when em '(org-do-emphasis-faces))
-          ;; Checkboxes
-          '("^[ \t]*\\(?:[-+*]\\|[0-9]+[.)]\\)[ 
\t]+\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\(\\[[- X]\\]\\)"
-            1 'org-checkbox prepend)
-          (when (cdr (assq 'checkbox org-list-automatic-rules))
-            '("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]"
-              (0 (org-get-checkbox-statistics-face) t)))
-          ;; Description list items
-          '("^[ \t]*[-+*][ \t]+\\(.*?[ \t]+::\\)\\([ \t]+\\|$\\)"
-            1 'org-list-dt prepend)
-          ;; ARCHIVEd headings
-          (list (concat
-                 org-outline-regexp-bol
-                 "\\(.*:" org-archive-tag ":.*\\)")
-                '(1 'org-archived prepend))
-          ;; Specials
-          '(org-do-latex-and-related)
-          '(org-fontify-entities)
-          '(org-raise-scripts)
-          ;; Code
-          '(org-activate-code (1 'org-code t))
-          ;; COMMENT
-          (list (format
-                 "^\\*+\\(?: +%s\\)?\\(?: +\\[#[A-Z0-9]\\]\\)? 
+\\(?9:%s\\)\\(?: \\|$\\)"
-                 org-todo-regexp
-                 org-comment-string)
-                '(9 'org-special-keyword t))
-          ;; Blocks and meta lines
-          '(org-fontify-meta-lines-and-blocks))))
+  (let ((org-font-lock-extra-keywords
+        (list
+         ;; Call the hook
+         '(org-font-lock-hook)
+         ;; Headlines
+         `(,(if org-fontify-whole-heading-line
+                "^\\(\\**\\)\\(\\* \\)\\(.*\n?\\)"
+              "^\\(\\**\\)\\(\\* \\)\\(.*\\)")
+           (1 (org-get-level-face 1))
+           (2 (org-get-level-face 2))
+           (3 (org-get-level-face 3)))
+         ;; Table lines
+         '("^[ \t]*\\(\\(|\\|\\+-[-+]\\).*\\S-\\)"
+           (1 'org-table t))
+         ;; Table internals
+         '("^[ \t]*|\\(?:.*?|\\)? *\\(:?=[^|\n]*\\)" (1 'org-formula t))
+         '("^[ \t]*| *\\([#*]\\) *|" (1 'org-formula t))
+         '("^[ \t]*|\\( *\\([$!_^/]\\) *|.*\\)|" (1 'org-formula t))
+         '("| *\\(<[lrc]?[0-9]*>\\)" (1 'org-formula t))
+         ;; Properties
+         (list org-property-re
+               '(1 'org-special-keyword t)
+               '(3 'org-property-value t))
+         ;; Drawers
+         '(org-fontify-drawers)
+         ;; Link related fontification.
+         '(org-activate-links)
+         (when (memq 'tag org-highlight-links) '(org-activate-tags (1 'org-tag 
prepend)))
+         (when (memq 'radio org-highlight-links) '(org-activate-target-links 
(1 'org-link t)))
+         (when (memq 'date org-highlight-links) '(org-activate-dates (0 
'org-date t)))
+         (when (memq 'footnote org-highlight-links) 
'(org-activate-footnote-links))
+          ;; Targets.
+          (list org-radio-target-regexp '(0 'org-target t))
+         (list org-target-regexp '(0 'org-target t))
+         ;; Diary sexps.
+         '("^&?%%(.*\\|<%%([^>\n]*?>" (0 'org-sexp-date t))
+         ;; Macro
+         '(org-fontify-macros)
+         ;; TODO keyword
+         (list (format org-heading-keyword-regexp-format
+                       org-todo-regexp)
+               '(2 (org-get-todo-face 2) prepend))
+         ;; TODO
+         (when org-fontify-todo-headline
+           (list (format org-heading-keyword-regexp-format
+                         (concat
+                          "\\(?:"
+                          (mapconcat 'regexp-quote org-not-done-keywords "\\|")
+                          "\\)"))
+                 '(2 'org-headline-todo prepend)))
+         ;; DONE
+         (when org-fontify-done-headline
+           (list (format org-heading-keyword-regexp-format
+                         (concat
+                          "\\(?:"
+                          (mapconcat 'regexp-quote org-done-keywords "\\|")
+                          "\\)"))
+                 '(2 'org-headline-done prepend)))
+         ;; Priorities
+         '(org-font-lock-add-priority-faces)
+         ;; Tags
+         '(org-font-lock-add-tag-faces)
+         ;; Tags groups
+         (when (and org-group-tags org-tag-groups-alist)
+           (list (concat org-outline-regexp-bol ".+\\(:"
+                         (regexp-opt (mapcar 'car org-tag-groups-alist))
+                         ":\\).*$")
+                 '(1 'org-tag-group prepend)))
+         ;; Special keywords
+         (list (concat "\\<" org-deadline-string) '(0 'org-special-keyword t))
+         (list (concat "\\<" org-scheduled-string) '(0 'org-special-keyword t))
+         (list (concat "\\<" org-closed-string) '(0 'org-special-keyword t))
+         (list (concat "\\<" org-clock-string) '(0 'org-special-keyword t))
+         ;; Emphasis
+         (when org-fontify-emphasized-text '(org-do-emphasis-faces))
+         ;; Checkboxes
+         '("^[ \t]*\\(?:[-+*]\\|[0-9]+[.)]\\)[ 
\t]+\\(?:\\[@\\(?:start:\\)?[0-9]+\\][ \t]*\\)?\\(\\[[- X]\\]\\)"
+           1 'org-checkbox prepend)
+         (when (cdr (assq 'checkbox org-list-automatic-rules))
+           '("\\[\\([0-9]*%\\)\\]\\|\\[\\([0-9]*\\)/\\([0-9]*\\)\\]"
+             (0 (org-get-checkbox-statistics-face) prepend)))
+         ;; Description list items
+          '("\\(?:^[ \t]*[-+]\\|^[ \t]+[*]\\)[ \t]+\\(.*?[ \t]+::\\)\\([ 
\t]+\\|$\\)"
+           1 'org-list-dt prepend)
+          ;; Inline export snippets
+          '("\\(@@\\)\\([a-z-]+:\\).*?\\(@@\\)"
+            (1 'font-lock-comment-face t)
+            (2 'org-tag t)
+            (3 'font-lock-comment-face t))
+         ;; ARCHIVEd headings
+         (list (concat
+                org-outline-regexp-bol
+                "\\(.*:" org-archive-tag ":.*\\)")
+               '(1 'org-archived prepend))
+         ;; Specials
+         '(org-do-latex-and-related)
+         '(org-fontify-entities)
+         '(org-raise-scripts)
+         ;; Code
+         '(org-activate-code (1 'org-code t))
+         ;; COMMENT
+         (list (format
+                "^\\*+\\(?: +%s\\)?\\(?: +\\[#[A-Z0-9]\\]\\)? 
+\\(?9:%s\\)\\(?: \\|$\\)"
+                org-todo-regexp
+                org-comment-string)
+               '(9 'org-special-keyword t))
+         ;; Blocks and meta lines
+         '(org-fontify-meta-lines-and-blocks)
+          ;; Citations
+          '(org-cite-activate))))
     (setq org-font-lock-extra-keywords (delq nil org-font-lock-extra-keywords))
     (run-hooks 'org-font-lock-set-keywords-hook)
     ;; Now set the full font-lock-keywords
@@ -5842,19 +5909,26 @@ If TAG is a number, get the corresponding match group."
 
 (defun org-font-lock-add-priority-faces (limit)
   "Add the special priority faces."
-  (while (re-search-forward org-priority-regexp limit t)
-    (add-text-properties
-     (match-beginning 1) (1+ (match-end 2))
-     (list 'face (org-get-priority-face (string-to-char (match-string 2)))
-          'font-lock-fontified t))))
+  (while (re-search-forward (concat "^\\*+" org-priority-regexp) limit t)
+    (let ((beg (match-beginning 1))
+         (end (1+ (match-end 2))))
+      (add-face-text-property
+       beg end
+       (org-get-priority-face (string-to-char (match-string 2))))
+      (add-text-properties
+       beg end
+       (list 'font-lock-fontified t)))))
 
 (defun org-font-lock-add-tag-faces (limit)
   "Add the special tag faces."
   (when (and org-tag-faces org-tags-special-faces-re)
     (while (re-search-forward org-tags-special-faces-re limit t)
+      (add-face-text-property
+       (match-beginning 1)
+       (match-end 1)
+       (org-get-tag-face 1))
       (add-text-properties (match-beginning 1) (match-end 1)
-                          (list 'face (org-get-tag-face 1)
-                                'font-lock-fontified t))
+                          (list 'font-lock-fontified t))
       (backward-char 1))))
 
 (defun org-unfontify-region (beg end &optional _maybe_loudly)
@@ -5928,8 +6002,9 @@ and subscripts."
   "Remove outline overlays that do not contain non-white stuff."
   (dolist (o (overlays-at pos))
     (and (eq 'outline (overlay-get o 'invisible))
-        (not (string-match-p "\\S-" (buffer-substring (overlay-start o)
-                                                    (overlay-end o))))
+        (not (string-match-p
+               "\\S-" (buffer-substring (overlay-start o)
+                                       (overlay-end o))))
         (delete-overlay o))))
 
 (defun org-show-empty-lines-in-parent ()
@@ -6138,9 +6213,38 @@ Return a non-nil value when toggling is successful."
 
 (defun org-hide-drawer-all ()
   "Fold all drawers in the current buffer."
+  (let ((begin (point-min))
+       (end (point-max)))
+    (org--hide-drawers begin end)))
+
+(defun org-cycle-hide-drawers (state)
+  "Re-hide all drawers after a visibility state change.
+STATE should be one of the symbols listed in the docstring of
+`org-cycle-hook'."
+  (when (derived-mode-p 'org-mode)
+    (cond ((not (memq state '(overview folded contents)))
+          (let* ((global? (eq state 'all))
+                 (beg (if global? (point-min) (line-beginning-position)))
+                 (end (cond (global? (point-max))
+                            ((eq state 'children) (org-entry-end-position))
+                            (t (save-excursion (org-end-of-subtree t t))))))
+            (org--hide-drawers beg end)))
+         ((memq state '(overview contents))
+          ;; Hide drawers before first heading.
+          (let ((beg (point-min))
+                (end (save-excursion
+                       (goto-char (point-min))
+                       (if (org-before-first-heading-p)
+                           (org-entry-end-position)
+                         (point-min)))))
+            (when (< beg end)
+              (org--hide-drawers beg end)))))))
+
+(defun org--hide-drawers (begin end)
+  "Hide all drawers between BEGIN and END."
   (save-excursion
-    (goto-char (point-min))
-    (while (re-search-forward org-drawer-regexp nil t)
+    (goto-char begin)
+    (while (re-search-forward org-drawer-regexp end t)
       (let* ((pair (get-char-property-and-overlay (line-beginning-position)
                                                  'invisible))
             (o (cdr-safe pair)))
@@ -6157,32 +6261,6 @@ Return a non-nil value when toggling is successful."
                 ;; `org-drawer-regexp'.
                 (goto-char (org-element-property :end drawer)))))))))))
 
-(defun org-cycle-hide-drawers (state)
-  "Re-hide all drawers after a visibility state change.
-STATE should be one of the symbols listed in the docstring of
-`org-cycle-hook'."
-  (when (and (derived-mode-p 'org-mode)
-            (not (memq state '(overview folded contents))))
-    (let* ((global? (eq state 'all))
-          (beg (if global? (point-min) (line-beginning-position)))
-          (end (cond (global? (point-max))
-                     ((eq state 'children) (org-entry-end-position))
-                     (t (save-excursion (org-end-of-subtree t t))))))
-      (save-excursion
-       (goto-char beg)
-       (while (re-search-forward org-drawer-regexp end t)
-         (pcase (get-char-property-and-overlay (point) 'invisible)
-           ;; Do not fold already folded drawers.
-           (`(outline . ,o) (goto-char (overlay-end o)))
-           (_
-            (let ((drawer (org-element-at-point)))
-              (when (memq (org-element-type drawer) '(drawer property-drawer))
-                (org-hide-drawer-toggle t nil drawer)
-                ;; Make sure to skip drawer entirely or we might flag
-                ;; it another time when matching its ending line with
-                ;; `org-drawer-regexp'.
-                (goto-char (org-element-property :end drawer)))))))))))
-
 ;;;; Visibility cycling
 
 (defvar-local org-cycle-global-status nil)
@@ -6475,7 +6553,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
          (org-list-set-item-visibility (point-at-bol) struct 'children)
        (org-show-entry)
        (org-with-limited-levels (org-show-children))
-       (org-show-set-visibility 'canonical)
+       (org-show-set-visibility 'tree)
        ;; Fold every list in subtree to top-level items.
        (when (eq org-cycle-include-plain-lists 'integrate)
          (save-excursion
@@ -6541,6 +6619,14 @@ With a numeric prefix, show all headlines up to that 
level."
     (org-overview))
    ((eq org-startup-folded 'content)
     (org-content))
+   ((eq org-startup-folded 'show2levels)
+    (org-content 2))
+   ((eq org-startup-folded 'show3levels)
+    (org-content 3))
+   ((eq org-startup-folded 'show4levels)
+    (org-content 4))
+   ((eq org-startup-folded 'show5levels)
+    (org-content 5))
    ((or (eq org-startup-folded 'showeverything)
        (eq org-startup-folded nil))
     (org-show-all)))
@@ -6640,8 +6726,8 @@ This function is the default value of the hook 
`org-cycle-hook'."
   ;; First, find a reasonable region to look at:
   ;; Start two siblings above, end three below
   (let* ((beg (save-excursion
-               (and (org-get-last-sibling)
-                    (org-get-last-sibling))
+               (and (org-get-previous-sibling)
+                    (org-get-previous-sibling))
                (point)))
         (end (save-excursion
                (and (org-get-next-sibling)
@@ -6723,9 +6809,9 @@ be shown."
 
 (defun org-show-set-visibility (detail)
   "Set visibility around point according to DETAIL.
-DETAIL is either nil, `minimal', `local', `ancestors', `lineage',
-`tree', `canonical' or t.  See `org-show-context-detail' for more
-information."
+DETAIL is either nil, `minimal', `local', `ancestors',
+`ancestors-full', `lineage', `tree', `canonical' or t.  See
+`org-show-context-detail' for more information."
   ;; Show current heading and possibly its entry, following headline
   ;; or all children.
   (if (and (org-at-heading-p) (not (eq detail 'local)))
@@ -6740,14 +6826,16 @@ information."
       (org-with-limited-levels
        (cl-case detail
         ((tree canonical t) (org-show-children))
-        ((nil minimal ancestors))
+        ((nil minimal ancestors ancestors-full))
         (t (save-excursion
              (outline-next-heading)
              (org-flag-heading nil)))))))
+  ;; Show whole subtree.
+  (when (eq detail 'ancestors-full) (org-show-subtree))
   ;; Show all siblings.
   (when (eq detail 'lineage) (org-show-siblings))
   ;; Show ancestors, possibly with their children.
-  (when (memq detail '(ancestors lineage tree canonical t))
+  (when (memq detail '(ancestors ancestors-full lineage tree canonical t))
     (save-excursion
       (while (org-up-heading-safe)
        (org-flag-heading nil)
@@ -6945,6 +7033,14 @@ unconditionally."
         (when (equal arg '(16)) (org-up-heading-safe))
         (org-end-of-subtree)))
       (unless (bolp) (insert "\n"))
+      (when (and blank? (save-excursion
+                          (backward-char)
+                          (org-before-first-heading-p)))
+        (insert "\n")
+        (backward-char))
+      (when (and (not level) (not (eobp)) (not (bobp)))
+        (when (org-at-heading-p) (insert "\n"))
+        (backward-char))
       (unless (and blank? (org-previous-line-empty-p))
        (org-N-empty-lines-before-current (if blank? 1 0)))
       (insert stars " ")
@@ -7391,7 +7487,9 @@ Assume point is at a heading or an inlinetask beginning."
           (col (+ (current-indentation) diff)))
        (when (wholenump col)
         (while (< (point) end-marker)
-          (indent-line-to col)
+           (if (natnump diff)
+              (insert (make-string diff 32))
+             (delete-char (abs diff)))
           (forward-line)))))
    (catch 'no-shift
      (when (or (zerop diff) (not (eq org-adapt-indentation t)))
@@ -7521,7 +7619,7 @@ case."
   (setq arg (prefix-numeric-value arg))
   (org-preserve-local-variables
    (let ((movfunc (if (> arg 0) 'org-get-next-sibling
-                   'org-get-last-sibling))
+                   'org-get-previous-sibling))
         (ins-point (make-marker))
         (cnt (abs arg))
         (col (current-column))
@@ -7784,7 +7882,8 @@ called immediately, to move the markers with the entries."
   "Check if MARKER is between BEG and END.
 If yes, remember the marker and the distance to BEG."
   (when (and (marker-buffer marker)
-            (equal (marker-buffer marker) (current-buffer))
+            (or (equal (marker-buffer marker) (current-buffer))
+                 (equal (marker-buffer marker) (buffer-base-buffer 
(current-buffer))))
             (>= marker beg) (< marker end))
     (push (cons marker (- marker beg)) org-markers-to-move)))
 
@@ -7875,7 +7974,7 @@ with the original repeater."
                "")))                   ;No time shift
         (doshift
          (and (org-string-nw-p shift)
-              (or (string-match "\\`[ \t]*\\([+-]?[0-9]+\\)\\([dwmy]\\)[ 
\t]*\\'"
+              (or (string-match "\\`[ \t]*\\([+-]?[0-9]+\\)\\([hdwmy]\\)[ 
\t]*\\'"
                                 shift)
                   (user-error "Invalid shift specification %s" shift)))))
     (goto-char end-of-tree)
@@ -7885,6 +7984,7 @@ with the original repeater."
           (shift-n (and doshift (string-to-number (match-string 1 shift))))
           (shift-what (pcase (and doshift (match-string 2 shift))
                         (`nil nil)
+                        ("h" 'hour)
                         ("d" 'day)
                         ("w" (setq shift-n (* 7 shift-n)) 'day)
                         ("m" 'month)
@@ -8074,14 +8174,37 @@ Optional argument WITH-CASE means sort 
case-sensitively."
    with-case))
 
 (defun org-sort-remove-invisible (s)
-  "Remove invisible part of links and emphasis markers from string S."
-  (remove-text-properties 0 (length s) org-rm-props s)
-  (replace-regexp-in-string
-   org-verbatim-re (lambda (m) (format "%s " (match-string 4 m)))
-   (replace-regexp-in-string
-    org-emph-re (lambda (m) (format " %s " (match-string 4 m)))
-    (org-link-display-format s)
-    t t) t t))
+  "Remove emphasis markers and any invisible property from string S.
+Assume S may contain only objects."
+  ;; org-element-interpret-data clears any text property, including
+  ;; invisible part.
+  (org-element-interpret-data
+   (let ((tree (org-element-parse-secondary-string
+                s (org-element-restriction 'paragraph))))
+     (org-element-map tree '(bold code italic link strike-through underline 
verbatim)
+       (lambda (o)
+         (pcase (org-element-type o)
+           ;; Terminal object.  Replace it with its value.
+           ((or `code `verbatim)
+            (let ((new (org-element-property :value o)))
+              (org-element-insert-before new o)
+              (org-element-put-property
+               new :post-blank (org-element-property :post-blank o))))
+           ;; Non-terminal objects.  Splice contents.
+           (type
+            (let ((contents
+                   (or (org-element-contents o)
+                       (and (eq type 'link)
+                            (list (org-element-property :raw-link o)))))
+                  (c nil))
+              (while contents
+                (setq c (pop contents))
+                (org-element-insert-before c o))
+              (org-element-put-property
+               c :post-blank (org-element-property :post-blank o)))))
+         (org-element-extract-element o)))
+     ;; Return modified tree.
+     tree)))
 
 (defvar org-after-sorting-entries-or-items-hook nil
   "Hook that is run after a bunch of entries or items have been sorted.
@@ -8222,7 +8345,7 @@ function is being called interactively."
             ;; The clock marker is lost when using `sort-subr'; mark
             ;; the clock with temporary `:org-clock-marker-backup'
             ;; text property.
-            (when (and (eq (org-clock-is-active) (current-buffer))
+            (when (and (eq (org-clocking-buffer) (current-buffer))
                        (<= start (marker-position org-clock-marker))
                        (>= end (marker-position org-clock-marker)))
               (with-silent-modifications
@@ -8735,7 +8858,16 @@ If the file does not exist, throw an error."
 
       (save-window-excursion
        (message "Running %s...done" cmd)
-       (start-process-shell-command cmd nil cmd)
+        ;; Handlers such as "gio open" and kde-open5 start viewer in background
+        ;; and exit immediately.  Use pipe connection type instead of pty to
+        ;; avoid killing children processes with SIGHUP when temporary terminal
+        ;; session is finished.
+        ;;
+        ;; TODO: Once minimum Emacs version is 25.1 or above, consider using
+        ;; the `make-process' invocation from 5db61eb0f929 to get more helpful
+        ;; error messages.
+        (let ((process-connection-type nil))
+         (start-process-shell-command cmd nil cmd))
        (and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait))))
      ((or (stringp cmd)
          (eq cmd 'emacs))
@@ -8832,9 +8964,10 @@ a link."
            ;; closest one.
            (org-element-lineage
             (org-element-context)
-            '(clock comment comment-block footnote-definition
-                    footnote-reference headline inline-src-block inlinetask
-                    keyword link node-property planning src-block timestamp)
+            '(citation citation-reference clock comment comment-block
+                        footnote-definition footnote-reference headline
+                        inline-src-block inlinetask keyword link node-property
+                        planning src-block timestamp)
             t))
           (type (org-element-type context))
           (value (org-element-property :value context)))
@@ -8845,7 +8978,7 @@ a link."
        ((memq type '(comment comment-block node-property keyword))
        (call-interactively #'org-open-at-point-global))
        ;; On a headline or an inlinetask, but not on a timestamp,
-       ;; a link, a footnote reference.
+       ;; a link, a footnote reference or a citation.
        ((memq type '(headline inlinetask))
        (org-match-line org-complex-heading-regexp)
        (let ((tags-beg (match-beginning 5))
@@ -8908,6 +9041,7 @@ a link."
        ((eq type 'inline-src-block) (org-babel-open-src-block-result))
        ((eq type 'timestamp) (org-follow-timestamp-link))
        ((eq type 'link) (org-link-open context arg))
+       ((memq type '(citation citation-reference)) (org-cite-follow context 
arg))
        (t (user-error "No link found")))))
   (run-hook-with-args 'org-follow-link-hook))
 
@@ -9042,26 +9176,29 @@ or to another Org file, automatically push the old 
position onto the ring."
 
 (defvar org-agenda-buffer-tmp-name)
 (defvar org-agenda-start-on-weekday)
+(defvar org-agenda-buffer-name)
 (defun org-follow-timestamp-link ()
   "Open an agenda view for the time-stamp date/range at point."
-  (cond
-   ((org-at-date-range-p t)
-    (let ((org-agenda-start-on-weekday)
-         (t1 (match-string 1))
-         (t2 (match-string 2)) tt1 tt2)
-      (setq tt1 (time-to-days (org-time-string-to-time t1))
-           tt2 (time-to-days (org-time-string-to-time t2)))
+  ;; Avoid changing the global value.
+  (let ((org-agenda-buffer-name org-agenda-buffer-name))
+    (cond
+     ((org-at-date-range-p t)
+      (let ((org-agenda-start-on-weekday)
+           (t1 (match-string 1))
+           (t2 (match-string 2)) tt1 tt2)
+       (setq tt1 (time-to-days (org-time-string-to-time t1))
+             tt2 (time-to-days (org-time-string-to-time t2)))
+       (let ((org-agenda-buffer-tmp-name
+              (format "*Org Agenda(a:%s)"
+                      (concat (substring t1 0 10) "--" (substring t2 0 10)))))
+         (org-agenda-list nil tt1 (1+ (- tt2 tt1))))))
+     ((org-at-timestamp-p 'lax)
       (let ((org-agenda-buffer-tmp-name
-            (format "*Org Agenda(a:%s)"
-                    (concat (substring t1 0 10) "--" (substring t2 0 10)))))
-       (org-agenda-list nil tt1 (1+ (- tt2 tt1))))))
-   ((org-at-timestamp-p 'lax)
-    (let ((org-agenda-buffer-tmp-name
-          (format "*Org Agenda(a:%s)" (substring (match-string 1) 0 10))))
-      (org-agenda-list nil (time-to-days (org-time-string-to-time
-                                         (substring (match-string 1) 0 10)))
-                      1)))
-   (t (error "This should not happen"))))
+            (format "*Org Agenda(a:%s)" (substring (match-string 1) 0 10))))
+       (org-agenda-list nil (time-to-days (org-time-string-to-time
+                                           (substring (match-string 1) 0 10)))
+                        1)))
+     (t (error "This should not happen")))))
 
 
 ;;; Following file links
@@ -9427,7 +9564,7 @@ If an element cannot be made unique, an error is raised."
                                (mapcar (apply-partially #'concat (substring  
key 0 1))
                                        (split-string (substring key 1) "" 
t)))))))
        (if (or (not potential-key) (assoc potential-key menu-keys))
-           (user-error "Could not make unique key for %s." key)
+            (user-error "Could not make unique key for `%s'" key)
          (push (cons potential-key key) menu-keys))))
     (mapcar #'car
            (cl-sort menu-keys #'<
@@ -9958,7 +10095,8 @@ all statistics cookies in the buffer."
   (if all
       (progn
        (org-update-checkbox-count 'all)
-       (org-map-entries 'org-update-parent-todo-statistics))
+       (org-map-region 'org-update-parent-todo-statistics
+                        (point-min) (point-max)))
     (if (not (org-at-heading-p))
        (org-update-checkbox-count)
       (let ((pos (point-marker))
@@ -9967,15 +10105,17 @@ all statistics cookies in the buffer."
        (if (not (org-at-heading-p))
            (org-update-checkbox-count)
          (setq l1 (org-outline-level))
-         (setq end (save-excursion
-                     (outline-next-heading)
-                     (when (org-at-heading-p) (setq l2 (org-outline-level)))
-                     (point)))
+         (setq end
+                (save-excursion
+                 (outline-next-heading)
+                 (when (org-at-heading-p) (setq l2 (org-outline-level)))
+                 (point)))
          (if (and (save-excursion
                     (re-search-forward
                      "^[ \t]*\\([-+*]\\|[0-9]+[.)]\\) \\[[- X]\\]" end t))
-                  (not (save-excursion (re-search-forward
-                                        ":COOKIE_DATA:.*\\<todo\\>" end t))))
+                  (not (save-excursion
+                          (re-search-forward
+                          ":COOKIE_DATA:.*\\<todo\\>" end t))))
              (org-update-checkbox-count)
            (if (and l2 (> l2 l1))
                (progn
@@ -9996,8 +10136,9 @@ all statistics cookies in the buffer."
 When `org-hierarchical-todo-statistics' is nil, statistics will cover
 the entire subtree and this will travel up the hierarchy and update
 statistics everywhere."
-  (let* ((prop (save-excursion (org-up-heading-safe)
-                              (org-entry-get nil "COOKIE_DATA" 'inherit)))
+  (let* ((prop (save-excursion
+                 (org-up-heading-safe)
+                (org-entry-get nil "COOKIE_DATA" 'inherit)))
         (recursive (or (not org-hierarchical-todo-statistics)
                        (and prop (string-match "\\<recursive\\>" prop))))
         (lim (or (and prop (marker-position org-entry-property-inherited-from))
@@ -10242,7 +10383,8 @@ prefer a state in the current sequence over on in 
another sequence."
   "Return the TODO keyword of the current subtree."
   (save-excursion
     (org-back-to-heading t)
-    (and (let ((case-fold-search nil)) (looking-at org-todo-line-regexp))
+    (and (let ((case-fold-search nil))
+           (looking-at org-todo-line-regexp))
         (match-end 2)
         (match-string 2))))
 
@@ -10280,18 +10422,19 @@ this function is called before first heading.
 When optional argument TIMESTAMP is a string, extract the
 repeater from there instead."
   (save-match-data
-    (cond (timestamp
-          (and (string-match org-repeat-re timestamp)
-               (match-string-no-properties 1 timestamp)))
-         ((org-before-first-heading-p) nil)
-         (t
-          (save-excursion
-            (org-back-to-heading t)
-            (let ((end (org-entry-end-position)))
-              (catch :repeat
-                (while (re-search-forward org-repeat-re end t)
-                  (when (save-match-data (org-at-timestamp-p 'agenda))
-                    (throw :repeat (match-string-no-properties 1)))))))))))
+    (cond
+     (timestamp
+      (and (string-match org-repeat-re timestamp)
+          (match-string-no-properties 1 timestamp)))
+     ((org-before-first-heading-p) nil)
+     (t
+      (save-excursion
+       (org-back-to-heading t)
+       (let ((end (org-entry-end-position)))
+         (catch :repeat
+           (while (re-search-forward org-repeat-re end t)
+             (when (save-match-data (org-at-timestamp-p 'agenda))
+               (throw :repeat (match-string-no-properties 1)))))))))))
 
 (defvar org-last-changed-timestamp)
 (defvar org-last-inserted-timestamp)
@@ -10299,6 +10442,7 @@ repeater from there instead."
 (defvar org-log-note-purpose)
 (defvar org-log-note-how nil)
 (defvar org-log-note-extra)
+(defvar org-log-setup nil)
 (defun org-auto-repeat-maybe (done-word)
   "Check if the current headline contains a repeated time-stamp.
 
@@ -10317,10 +10461,11 @@ This function is run automatically after each state 
change to a DONE state."
         (end (copy-marker (org-entry-end-position))))
     (when (and repeat (not (= 0 (string-to-number (substring repeat 1)))))
       (when (eq org-log-repeat t) (setq org-log-repeat 'state))
-      (let ((to-state (or (org-entry-get nil "REPEAT_TO_STATE" 'selective)
-                         (and (stringp org-todo-repeat-to-state)
-                              org-todo-repeat-to-state)
-                         (and org-todo-repeat-to-state org-last-state))))
+      (let ((to-state
+             (or (org-entry-get nil "REPEAT_TO_STATE" 'selective)
+                (and (stringp org-todo-repeat-to-state)
+                     org-todo-repeat-to-state)
+                (and org-todo-repeat-to-state org-last-state))))
        (org-todo (cond ((and to-state (member to-state org-todo-keywords-1))
                         to-state)
                        ((eq interpret 'type) org-last-state)
@@ -10338,8 +10483,7 @@ This function is run automatically after each state 
change to a DONE state."
        (org-entry-put nil "LAST_REPEAT" (format-time-string
                                          (org-time-stamp-format t t))))
       (when org-log-repeat
-       (if (or (memq 'org-add-log-note (default-value 'post-command-hook))
-               (memq 'org-add-log-note post-command-hook))
+       (if org-log-setup
            ;; We are already setup for some record.
            (when (eq org-log-repeat 'note)
              ;; Make sure we take a note, not only a time stamp.
@@ -10776,7 +10920,8 @@ narrowing."
             (let ((beg (point)))
               (insert ":" drawer ":\n:END:\n")
               (org-indent-region beg (point))
-              (org-flag-region (line-end-position -1) (1- (point)) t 'outline))
+              (org-flag-region (line-end-position -1)
+                                (1- (point)) t 'outline))
             (end-of-line -1)))))
       (t
        (org-end-of-meta-data org-log-state-notes-insert-after-drawers)
@@ -10799,7 +10944,8 @@ EXTRA is additional text that will be inserted into the 
notes buffer."
        org-log-note-previous-state prev-state
        org-log-note-how how
        org-log-note-extra extra
-       org-log-note-effective-time (org-current-effective-time))
+       org-log-note-effective-time (org-current-effective-time)
+        org-log-setup t)
   (add-hook 'post-command-hook 'org-add-log-note 'append))
 
 (defun org-skip-over-state-notes ()
@@ -10828,6 +10974,7 @@ EXTRA is additional text that will be inserted into the 
notes buffer."
 (defun org-add-log-note (&optional _purpose)
   "Pop up a window for taking a note, and add this note later."
   (remove-hook 'post-command-hook 'org-add-log-note)
+  (setq org-log-setup nil)
   (setq org-log-note-window-configuration (current-window-configuration))
   (delete-other-windows)
   (move-marker org-log-note-return-to (point))
@@ -10841,19 +10988,19 @@ EXTRA is additional text that will be inserted into 
the notes buffer."
     (insert (format "# Insert note for %s.
 # Finish with C-c C-c, or cancel with C-c C-k.\n\n"
                    (cl-case org-log-note-purpose
-                    (clock-out "stopped clock")
-                    (done  "closed todo item")
-                    (reschedule "rescheduling")
-                    (delschedule "no longer scheduled")
-                    (redeadline "changing deadline")
-                    (deldeadline "removing deadline")
-                    (refile "refiling")
-                    (note "this entry")
-                    (state
-                     (format "state change from \"%s\" to \"%s\""
-                             (or org-log-note-previous-state "")
-                             (or org-log-note-state "")))
-                    (t (error "This should not happen")))))
+                     (clock-out "stopped clock")
+                     (done  "closed todo item")
+                     (reschedule "rescheduling")
+                     (delschedule "no longer scheduled")
+                     (redeadline "changing deadline")
+                     (deldeadline "removing deadline")
+                     (refile "refiling")
+                     (note "this entry")
+                     (state
+                      (format "state change from \"%s\" to \"%s\""
+                              (or org-log-note-previous-state "")
+                              (or org-log-note-state "")))
+                     (t (error "This should not happen")))))
     (when org-log-note-extra (insert org-log-note-extra))
     (setq-local org-finish-function 'org-store-log-note)
     (run-hooks 'org-log-buffer-setup-hook)))
@@ -10936,19 +11083,13 @@ EXTRA is additional text that will be inserted into 
the notes buffer."
             (indent-line-to ind)
             (insert line)))
         (message "Note stored")
-        (org-back-to-heading t))
-       ;; Fix `buffer-undo-list' when `org-store-log-note' is called
-       ;; from within `org-add-log-note' because `buffer-undo-list'
-       ;; is then modified outside of `org-with-remote-undo'.
-       (when (eq this-command 'org-agenda-todo)
-         (setcdr buffer-undo-list (cddr buffer-undo-list))))))
+        (org-back-to-heading t)))))
   ;; Don't add undo information when called from `org-agenda-todo'.
-  (let ((buffer-undo-list (eq this-command 'org-agenda-todo)))
-    (set-window-configuration org-log-note-window-configuration)
-    (with-current-buffer (marker-buffer org-log-note-return-to)
-      (goto-char org-log-note-return-to))
-    (move-marker org-log-note-return-to nil)
-    (when org-log-post-message (message "%s" org-log-post-message))))
+  (set-window-configuration org-log-note-window-configuration)
+  (with-current-buffer (marker-buffer org-log-note-return-to)
+    (goto-char org-log-note-return-to))
+  (move-marker org-log-note-return-to nil)
+  (when org-log-post-message (message "%s" org-log-post-message)))
 
 (defun org-remove-empty-drawer-at (pos)
   "Remove an empty drawer at position POS.
@@ -11182,14 +11323,17 @@ or a character."
            (setq
             new
             (if nump
-                (string-to-number
-                 (read-string (format "Priority %s-%s, SPC to remove: "
-                                      (number-to-string org-priority-highest)
-                                      (number-to-string org-priority-lowest))))
+                 (let ((msg (format "Priority %s-%s, SPC to remove: "
+                                   (number-to-string org-priority-highest)
+                                   (number-to-string org-priority-lowest))))
+                   (if (< 9 org-priority-lowest)
+                      (string-to-number (read-string msg))
+                     (message msg)
+                     (string-to-number (char-to-string 
(read-char-exclusive)))))
               (progn (message "Priority %c-%c, SPC to remove: "
-                                org-priority-highest org-priority-lowest)
-                       (save-match-data
-                         (setq new (read-char-exclusive)))))))
+                              org-priority-highest org-priority-lowest)
+                     (save-match-data
+                       (setq new (read-char-exclusive)))))))
          (when (and (= (upcase org-priority-highest) org-priority-highest)
                     (= (upcase org-priority-lowest) org-priority-lowest))
            (setq new (upcase new)))
@@ -11713,7 +11857,7 @@ an accumulator used in recursive calls."
                (org--tags-expand-group (cdr group) tag-groups expanded))))))
   expanded)
 
-(defun org-tags-expand (match &optional single-as-list downcased)
+(defun org-tags-expand (match &optional single-as-list)
   "Expand group tags in MATCH.
 
 This replaces every group tag in MATCH with a regexp tag search.
@@ -11740,24 +11884,18 @@ will be replaced like this:
 
 When the optional argument SINGLE-AS-LIST is non-nil, MATCH is
 assumed to be a single group tag, and the function will return
-the list of tags in this group.
-
-When DOWNCASED is non-nil, expand downcased TAGS."
+the list of tags in this group."
   (unless (org-string-nw-p match) (error "Invalid match tag: %S" match))
   (let ((tag-groups
-        (let ((g (or org-tag-groups-alist-for-agenda org-tag-groups-alist)))
-          (if (not downcased) g
-            (mapcar (lambda (s) (mapcar #'downcase s)) g)))))
+         (or org-tag-groups-alist-for-agenda org-tag-groups-alist)))
     (cond
-     (single-as-list (org--tags-expand-group
-                     (list (if downcased (downcase match) match))
-                     tag-groups nil))
+     (single-as-list (org--tags-expand-group (list match) tag-groups nil))
      (org-group-tags
       (let* ((case-fold-search t)
             (tag-syntax org-mode-syntax-table)
             (group-keys (mapcar #'car tag-groups))
             (key-regexp (concat "\\([+-]?\\)" (regexp-opt group-keys 'words)))
-            (return-match (if downcased (downcase match) match)))
+            (return-match match))
        ;; Mark regexp-expressions in the match-expression so that we
        ;; do not replace them later on.
        (let ((s 0))
@@ -11777,7 +11915,7 @@ When DOWNCASED is non-nil, expand downcased TAGS."
                 m                      ;regexp tag: ignore
               (let* ((operator (match-string 1 m))
                      (tag-token (let ((tag (match-string 2 m)))
-                                  (list (if downcased (downcase tag) tag))))
+                                  (list tag)))
                      regexp-tags regular-tags)
                 ;; Partition tags between regexp and regular tags.
                 ;; Remove curly bracket syntax from regexp tags.
@@ -11928,12 +12066,15 @@ in Lisp code use `org-set-tags' instead."
                      inherited-tags
                      table
                      (and org-fast-tag-selection-include-todo 
org-todo-key-alist))
-                  (let ((org-add-colon-after-tag-completion (< 1 (length 
table))))
-                    (org-trim (completing-read
-                               "Tags: "
-                               #'org-tags-completion-function
-                               nil nil (org-make-tag-string current-tags)
-                               'org-tags-history)))))))
+                  (let ((org-add-colon-after-tag-completion (< 1 (length 
table)))
+                         (crm-separator "[ \t]*:[ \t]*"))
+                    (mapconcat #'identity
+                                (completing-read-multiple
+                                "Tags: "
+                                org-last-tags-completion-table
+                                nil nil (org-make-tag-string current-tags)
+                                'org-tags-history)
+                                ":"))))))
          (org-set-tags tags)))))
     ;; `save-excursion' may not replace the point at the right
     ;; position.
@@ -12013,7 +12154,7 @@ This works in the agenda, and also in an Org buffer."
                     (org-global-tags-completion-table))
                  (org-global-tags-completion-table))))
           (completing-read
-           "Tag: " 'org-tags-completion-function nil nil nil
+           "Tag: " org-last-tags-completion-table nil nil nil
            'org-tags-history))
         (progn
           (message "[s]et or [r]emove? ")
@@ -12109,7 +12250,7 @@ Returns the new tags string, or nil to not change the 
current settings."
                                  fulltable))))
         (buf (current-buffer))
         (expert (eq org-fast-tag-selection-single-key 'expert))
-        (buffer-tags nil)
+        (tab-tags nil)
         (fwidth (+ maxlen 3 1 3))
         (ncol (/ (- (window-width) 4) fwidth))
         (i-face 'org-done)
@@ -12244,16 +12385,21 @@ Returns the new tags string, or nil to not change the 
current settings."
                    (setq current nil)
                    (when exit-after-next (setq exit-after-next 'now)))
                   ((= c ?\t)
-                   (condition-case nil
-                       (setq tg (completing-read
-                                 "Tag: "
-                                 (or buffer-tags
-                                     (with-current-buffer buf
-                                       (setq buffer-tags
-                                             (org-get-buffer-tags))))))
-                     (quit (setq tg "")))
+                    (condition-case nil
+                        (unless tab-tags
+                          (setq tab-tags
+                                (delq nil
+                                      (mapcar (lambda (x)
+                                                (let ((item (car-safe x)))
+                                                  (and (stringp item)
+                                                       (list item))))
+                                              (org--tag-add-to-alist
+                                               (with-current-buffer buf
+                                                 (org-get-buffer-tags))
+                                               table))))))
+                    (setq tg (completing-read "Tag: " tab-tags))
                    (when (string-match "\\S-" tg)
-                     (cl-pushnew (list tg) buffer-tags :test #'equal)
+                     (cl-pushnew (list tg) tab-tags :test #'equal)
                      (if (member tg current)
                          (setq current (delete tg current))
                        (push tg current)))
@@ -12361,12 +12507,12 @@ Inherited tags have the `inherited' text property."
 (defun org-map-entries (func &optional match scope &rest skip)
   "Call FUNC at each headline selected by MATCH in SCOPE.
 
-FUNC is a function or a lisp form.  The function will be called without
+FUNC is a function or a Lisp form.  The function will be called without
 arguments, with the cursor positioned at the beginning of the headline.
 The return values of all calls to the function will be collected and
 returned as a list.
 
-The call to FUNC will be wrapped into a save-excursion form, so FUNC
+The call to FUNC will be wrapped into a `save-excursion' form, so FUNC
 does not need to preserve point.  After evaluation, the cursor will be
 moved to the end of the line (presumably of the headline of the
 processed entry) and search continues from there.  Under some
@@ -12537,12 +12683,12 @@ it will be found.  If the drawer does not exist, 
create it if
 FORCE is non-nil, or return nil."
   (org-with-wide-buffer
    (let ((beg (cond (beg (goto-char beg))
-                     ((or (not (featurep 'org-inlinetask))
-                          (org-inlinetask-in-task-p))
-                      (org-back-to-heading-or-point-min t) (point))
-                     (t (org-with-limited-levels
-                         (org-back-to-heading-or-point-min t))
-                        (point)))))
+                   ((or (not (featurep 'org-inlinetask))
+                        (org-inlinetask-in-task-p))
+                    (org-back-to-heading-or-point-min t) (point))
+                   (t (org-with-limited-levels
+                       (org-back-to-heading-or-point-min t))
+                      (point)))))
      ;; Move point to its position according to its positional rules.
      (cond ((org-before-first-heading-p)
            (while (and (org-at-comment-p) (bolp)) (forward-line)))
@@ -13064,62 +13210,63 @@ decreases scheduled or deadline date by one day."
        ((not (stringp value)) (error "Properties values should be strings"))
        ((not (org--valid-property-p property))
         (user-error "Invalid property name: \"%s\"" property)))
-  (org-with-point-at pom
-    (if (or (not (featurep 'org-inlinetask)) (org-inlinetask-in-task-p))
-       (org-back-to-heading-or-point-min t)
-      (org-with-limited-levels (org-back-to-heading-or-point-min t)))
-    (let ((beg (point)))
-      (cond
-       ((equal property "TODO")
-       (cond ((not (org-string-nw-p value)) (setq value 'none))
-             ((not (member value org-todo-keywords-1))
-              (user-error "\"%s\" is not a valid TODO state" value)))
-       (org-todo value)
-       (org-align-tags))
-       ((equal property "PRIORITY")
-       (org-priority (if (org-string-nw-p value) (string-to-char value) ?\s))
-       (org-align-tags))
-       ((equal property "SCHEDULED")
-       (forward-line)
-       (if (and (looking-at-p org-planning-line-re)
-                (re-search-forward
-                 org-scheduled-time-regexp (line-end-position) t))
-           (cond ((string= value "earlier") (org-timestamp-change -1 'day))
-                 ((string= value "later") (org-timestamp-change 1 'day))
-                 ((string= value "") (org-schedule '(4)))
-                 (t (org-schedule nil value)))
-         (if (member value '("earlier" "later" ""))
-             (call-interactively #'org-schedule)
-           (org-schedule nil value))))
-       ((equal property "DEADLINE")
-       (forward-line)
-       (if (and (looking-at-p org-planning-line-re)
-                (re-search-forward
-                 org-deadline-time-regexp (line-end-position) t))
-           (cond ((string= value "earlier") (org-timestamp-change -1 'day))
-                 ((string= value "later") (org-timestamp-change 1 'day))
-                 ((string= value "") (org-deadline '(4)))
-                 (t (org-deadline nil value)))
-         (if (member value '("earlier" "later" ""))
-             (call-interactively #'org-deadline)
-           (org-deadline nil value))))
-       ((member property org-special-properties)
-       (error "The %s property cannot be set with `org-entry-put'" property))
-       (t
-       (let* ((range (org-get-property-block beg 'force))
-              (end (cdr range))
-              (case-fold-search t))
-         (goto-char (car range))
-         (if (re-search-forward (org-re-property property nil t) end t)
-             (progn (delete-region (match-beginning 0) (match-end 0))
-                    (goto-char (match-beginning 0)))
-           (goto-char end)
-           (insert "\n")
-           (backward-char))
-         (insert ":" property ":")
-         (when value (insert " " value))
-         (org-indent-line)))))
-    (run-hook-with-args 'org-property-changed-functions property value)))
+  (org-no-read-only
+   (org-with-point-at pom
+     (if (or (not (featurep 'org-inlinetask)) (org-inlinetask-in-task-p))
+        (org-back-to-heading-or-point-min t)
+       (org-with-limited-levels (org-back-to-heading-or-point-min t)))
+     (let ((beg (point)))
+       (cond
+        ((equal property "TODO")
+        (cond ((not (org-string-nw-p value)) (setq value 'none))
+              ((not (member value org-todo-keywords-1))
+               (user-error "\"%s\" is not a valid TODO state" value)))
+        (org-todo value)
+        (org-align-tags))
+        ((equal property "PRIORITY")
+        (org-priority (if (org-string-nw-p value) (string-to-char value) ?\s))
+        (org-align-tags))
+        ((equal property "SCHEDULED")
+        (forward-line)
+        (if (and (looking-at-p org-planning-line-re)
+                 (re-search-forward
+                  org-scheduled-time-regexp (line-end-position) t))
+            (cond ((string= value "earlier") (org-timestamp-change -1 'day))
+                  ((string= value "later") (org-timestamp-change 1 'day))
+                  ((string= value "") (org-schedule '(4)))
+                  (t (org-schedule nil value)))
+          (if (member value '("earlier" "later" ""))
+              (call-interactively #'org-schedule)
+            (org-schedule nil value))))
+        ((equal property "DEADLINE")
+        (forward-line)
+        (if (and (looking-at-p org-planning-line-re)
+                 (re-search-forward
+                  org-deadline-time-regexp (line-end-position) t))
+            (cond ((string= value "earlier") (org-timestamp-change -1 'day))
+                  ((string= value "later") (org-timestamp-change 1 'day))
+                  ((string= value "") (org-deadline '(4)))
+                  (t (org-deadline nil value)))
+          (if (member value '("earlier" "later" ""))
+              (call-interactively #'org-deadline)
+            (org-deadline nil value))))
+        ((member property org-special-properties)
+        (error "The %s property cannot be set with `org-entry-put'" property))
+        (t
+        (let* ((range (org-get-property-block beg 'force))
+               (end (cdr range))
+               (case-fold-search t))
+          (goto-char (car range))
+          (if (re-search-forward (org-re-property property nil t) end t)
+              (progn (delete-region (match-beginning 0) (match-end 0))
+                     (goto-char (match-beginning 0)))
+            (goto-char end)
+            (insert "\n")
+            (backward-char))
+          (insert ":" property ":")
+          (when value (insert " " value))
+          (org-indent-line)))))
+     (run-hook-with-args 'org-property-changed-functions property value))))
 
 (defun org-buffer-property-keys (&optional specials defaults columns)
   "Get all property keys in the current buffer.
@@ -13309,11 +13456,12 @@ This is computed according to 
`org-property-set-functions-alist'."
   (or (cdr (assoc property org-property-set-functions-alist))
       'org-completing-read))
 
-(defun org-read-property-value (property &optional pom)
+(defun org-read-property-value (property &optional pom default)
   "Read value for PROPERTY, as a string.
 When optional argument POM is non-nil, completion uses additional
 information, i.e., allowed or existing values at point or marker
-POM."
+POM.
+Optional argument DEFAULT provides a default value for PROPERTY."
   (let* ((completion-ignore-case t)
         (allowed
          (or (org-property-get-allowed-values nil property 'table)
@@ -13329,7 +13477,8 @@ POM."
      (if allowed
         (funcall set-function
                  prompt allowed nil
-                 (not (get-text-property 0 'org-unrestricted (caar allowed))))
+                 (not (get-text-property 0 'org-unrestricted (caar allowed)))
+                 default nil default)
        (let ((all (mapcar #'list
                          (append (org-property-values property)
                                  (and pom
@@ -13655,7 +13804,7 @@ If there is already a timestamp at the cursor, it is 
replaced.
 With two universal prefix arguments, insert an active timestamp
 with the current time without prompting the user.
 
-When called from lisp, the timestamp is inactive if INACTIVE is
+When called from Lisp, the timestamp is inactive if INACTIVE is
 non-nil."
   (interactive "P")
   (let* ((ts (cond
@@ -14047,6 +14196,19 @@ user."
               (setq ans (replace-match (format "%02d:%02d" hour minute)
                                        t t ans))))
 
+    ;; Help matching HHhMM times, similarly as for am/pm times.
+    (cl-loop for i from 1 to 2 do      ; twice, for end time as well
+            (when (and (not (string-match 
"\\(\\`\\|[^+]\\)[012]?[0-9]:[0-9][0-9]\\([ \t\n]\\|$\\)" ans))
+                       (string-match 
"\\(?:\\(?1:[012]?[0-9]\\)?h\\(?2:[0-5][0-9]\\)\\)\\|\\(?:\\(?1:[012]?[0-9]\\)h\\(?2:[0-5][0-9]\\)?\\)\\>"
 ans))
+              (setq hour (if (match-end 1)
+                             (string-to-number (match-string 1 ans))
+                           0)
+                    minute (if (match-end 2)
+                               (string-to-number (match-string 2 ans))
+                             0))
+              (setq ans (replace-match (format "%02d:%02d" hour minute)
+                                       t t ans))))
+
     ;; Check if a time range is given as a duration
     (when (string-match 
"\\([012]?[0-9]\\):\\([0-6][0-9]\\)\\+\\([012]?[0-9]\\)\\(:\\([0-5][0-9]\\)\\)?"
 ans)
       (setq hour (string-to-number (match-string 1 ans))
@@ -15201,7 +15363,7 @@ The value is a list, with zero or more of the symbols 
`effort', `appt',
   "Save all Org buffers without user confirmation."
   (interactive)
   (message "Saving all Org buffers...")
-  (save-some-buffers t (lambda () (derived-mode-p 'org-mode)))
+  (save-some-buffers t (lambda () (and (derived-mode-p 'org-mode) t)))
   (when (featurep 'org-id) (org-id-locations-save))
   (message "Saving all Org buffers... done"))
 
@@ -15215,9 +15377,9 @@ This function is useful in a setup where one tracks Org 
files
 with a version control system, to revert on one machine after pulling
 changes from another.  I believe the procedure must be like this:
 
-1. M-x org-save-all-org-buffers
+1. \\[org-save-all-org-buffers]
 2. Pull changes from the other machine, resolve conflicts
-3. M-x org-revert-all-org-buffers"
+3. \\[org-revert-all-org-buffers]"
   (interactive)
   (unless (yes-or-no-p "Revert all Org buffers from their files? ")
     (user-error "Abort"))
@@ -15306,13 +15468,12 @@ used by the agenda files.  If ARCHIVE is `ifmode', do 
this only if
                                 (if (file-directory-p f)
                                     (directory-files
                                      f t org-agenda-file-regexp)
-                                  (list f)))
+                                  (list (expand-file-name f org-directory))))
                               files)))
     (when org-agenda-skip-unavailable-files
       (setq files (delq nil
-                       (mapcar (function
-                                (lambda (file)
-                                  (and (file-readable-p file) file)))
+                       (mapcar (lambda (file)
+                                 (and (file-readable-p file) file))
                                files))))
     (when (or (eq archives t)
              (and (eq archives 'ifmode) (eq org-agenda-archives-mode t)))
@@ -15928,15 +16089,25 @@ Some of the options can be changed using the variable
                         (fg
                          (let ((color (plist-get org-format-latex-options
                                                  :foreground)))
-                           (if (and forbuffer (eq color 'auto))
-                               (face-attribute face :foreground nil 'default)
-                             color)))
+                            (if forbuffer
+                                (cond
+                                 ((eq color 'auto)
+                                  (face-attribute face :foreground nil 
'default))
+                                 ((eq color 'default)
+                                  (face-attribute 'default :foreground nil))
+                                 (t color))
+                              color)))
                         (bg
                          (let ((color (plist-get org-format-latex-options
                                                  :background)))
-                           (if (and forbuffer (eq color 'auto))
-                               (face-attribute face :background nil 'default)
-                             color)))
+                            (if forbuffer
+                                (cond
+                                 ((eq color 'auto)
+                                  (face-attribute face :background nil 
'default))
+                                 ((eq color 'default)
+                                  (face-attribute 'default :background nil))
+                                 (t color))
+                              color)))
                         (hash (sha1 (prin1-to-string
                                      (list org-format-latex-header
                                            org-latex-default-packages-alist
@@ -16155,10 +16326,10 @@ a HTML file."
     (if (eq fg 'default)
        (setq fg (org-latex-color :foreground))
       (setq fg (org-latex-color-format fg)))
-    (if (eq bg 'default)
-       (setq bg (org-latex-color :background))
-      (setq bg (org-latex-color-format
-               (if (string= bg "Transparent") "white" bg))))
+    (setq bg (cond
+             ((eq bg 'default) (org-latex-color :background))
+             ((string= bg "Transparent") nil)
+             (t (org-latex-color-format bg))))
     ;; Remove TeX \par at end of snippet to avoid trailing space.
     (if (string-suffix-p string "\n")
         (aset string (1- (length string)) ?%)
@@ -16167,8 +16338,10 @@ a HTML file."
       (insert latex-header)
       (insert "\n\\begin{document}\n"
              "\\definecolor{fg}{rgb}{" fg "}%\n"
-             "\\definecolor{bg}{rgb}{" bg "}%\n"
-             "\n\\pagecolor{bg}%\n"
+             (if bg
+                 (concat "\\definecolor{bg}{rgb}{" bg "}%\n"
+                         "\n\\pagecolor{bg}%\n")
+               "")
              "\n{\\color{fg}\n"
              string
              "\n}\n"
@@ -16438,30 +16611,7 @@ buffer boundaries with possible narrowing."
                                  (ignore-errors (org-attach-expand path)))
                               (expand-file-name path))))
                  (when (and file (file-exists-p file))
-                   (let ((width
-                          ;; Apply `org-image-actual-width' specifications.
-                          (cond
-                           ((eq org-image-actual-width t) nil)
-                           ((listp org-image-actual-width)
-                            (or
-                             ;; First try to find a width among
-                             ;; attributes associated to the paragraph
-                             ;; containing link.
-                             (pcase (org-element-lineage link '(paragraph))
-                               (`nil nil)
-                               (p
-                                (let* ((case-fold-search t)
-                                       (end (org-element-property 
:post-affiliated p))
-                                       (re "^[ \t]*#\\+attr_.*?: +.*?:width 
+\\(\\S-+\\)"))
-                                  (when (org-with-point-at
-                                            (org-element-property :begin p)
-                                          (re-search-forward re end t))
-                                    (string-to-number (match-string 1))))))
-                             ;; Otherwise, fall-back to provided number.
-                             (car org-image-actual-width)))
-                           ((numberp org-image-actual-width)
-                            org-image-actual-width)
-                           (t nil)))
+                   (let ((width (org-display-inline-image--width link))
                          (old (get-char-property-and-overlay
                                (org-element-property :begin link)
                                'org-image-overlay)))
@@ -16482,11 +16632,62 @@ buffer boundaries with possible narrowing."
                              (overlay-put
                               ov 'modification-hooks
                               (list 'org-display-inline-remove-overlay))
-                             (when (<= 26 emacs-major-version)
-                               (cl-assert (boundp 'image-map))
+                             (when (boundp 'image-map)
                                (overlay-put ov 'keymap image-map))
                              (push ov org-inline-image-overlays))))))))))))))))
 
+(defvar visual-fill-column-width) ; Silence compiler warning
+(defun org-display-inline-image--width (link)
+  "Determine the display width of the image LINK, in pixels.
+- When `org-image-actual-width' is t, the image's pixel width is used.
+- When `org-image-actual-width' is a number, that value will is used.
+- When `org-image-actual-width' is nil or a list, the first :width attribute
+  set (if it exists) is used to set the image width.  A width of X% is
+  divided by 100.
+  If no :width attribute is given and `org-image-actual-width' is a list with
+  a number as the car, then that number is used as the default value.
+  If the value is a float between 0 and 2, it interpreted as that proportion
+  of the text width in the buffer."
+  ;; Apply `org-image-actual-width' specifications.
+  (cond
+   ((eq org-image-actual-width t) nil)
+   ((listp org-image-actual-width)
+    (let* ((case-fold-search t)
+           (par (org-element-lineage link '(paragraph)))
+           (attr-re "^[ \t]*#\\+attr_.*?: +.*?:width +\\(\\S-+\\)")
+           (par-end (org-element-property :post-affiliated par))
+           ;; Try to find an attribute providing a :width.
+           (attr-width
+            (when (and par (org-with-point-at
+                               (org-element-property :begin par)
+                             (re-search-forward attr-re par-end t)))
+              (match-string 1)))
+           (attr-width-val
+            (cond
+             ((null attr-width) nil)
+             ((string-match-p "\\`[0-9.]+%" attr-width)
+              (/ (string-to-number attr-width) 100.0))
+             (t (string-to-number attr-width))))
+           ;; Fallback to `org-image-actual-width' if no explicit width is 
given.
+           (width (or attr-width-val (car org-image-actual-width))))
+      (if (and (floatp width) (<= 0.0 width 2.0))
+          ;; A float in [0,2] should be interpereted as this portion of
+          ;; the text width in the window.  This works well with cases like
+          ;; #+attr_latex: :width 0.X\{line,page,column,etc.}width,
+          ;; as the "0.X" is pulled out as a float.  We use 2 as the upper
+          ;; bound as cases such as 1.2\linewidth are feasible.
+          (round (* width
+                    (window-pixel-width)
+                    (/ (or (and (bound-and-true-p visual-fill-column-mode)
+                                (or visual-fill-column-width 
auto-fill-function))
+                           (when auto-fill-function fill-column)
+                           (window-text-width))
+                       (float (window-total-width)))))
+        width)))
+   ((numberp org-image-actual-width)
+    org-image-actual-width)
+   (t nil)))
+
 (defun org-display-inline-remove-overlay (ov after _beg _end &optional _len)
   "Remove inline-display overlay if a corresponding region is modified."
   (let ((inhibit-modification-hooks t))
@@ -16708,6 +16909,7 @@ because, in this case the deletion might narrow the 
column."
 (put 'org-delete-char 'delete-selection 'supersede)
 (put 'org-delete-backward-char 'delete-selection 'supersede)
 (put 'org-yank 'delete-selection 'yank)
+(put 'org-return 'delete-selection t)
 
 ;; Make `flyspell-mode' delay after some commands
 (put 'org-self-insert-command 'flyspell-delayed t)
@@ -16869,7 +17071,8 @@ When ARG is a numeric prefix, show contents of this 
level."
       (message "Content view to level: %d" arg)
       (org-content (prefix-numeric-value arg2))
       (org-cycle-show-empty-lines t)
-      (setq org-cycle-global-status 'overview)))
+      (setq org-cycle-global-status 'overview)
+      (run-hook-with-args 'org-cycle-hook 'overview)))
    (t (call-interactively 'org-global-cycle))))
 
 (defun org-shiftmetaleft ()
@@ -17061,6 +17264,9 @@ for more information."
       (transpose-regions a b c d)
       (goto-char c)))
    ((org-at-table-p) (org-call-with-arg 'org-table-move-row 'up))
+   ((and (featurep 'org-inlinetask)
+         (org-inlinetask-in-task-p))
+    (org-drag-element-backward))
    ((org-at-heading-p) (call-interactively 'org-move-subtree-up))
    ((org-at-item-p) (call-interactively 'org-move-item-up))
    (t (org-drag-element-backward))))
@@ -17091,6 +17297,9 @@ commands for more information."
       (transpose-regions a b c d)
       (goto-char d)))
    ((org-at-table-p) (call-interactively 'org-table-move-row))
+   ((and (featurep 'org-inlinetask)
+         (org-inlinetask-in-task-p))
+    (org-drag-element-forward))
    ((org-at-heading-p) (call-interactively 'org-move-subtree-down))
    ((org-at-item-p) (call-interactively 'org-move-item-down))
    (t (org-drag-element-forward))))
@@ -17354,7 +17563,7 @@ When in a source code block, call `org-edit-src-code'.
 When in a fixed-width region, call `org-edit-fixed-width-region'.
 When in an export block, call `org-edit-export-block'.
 When in a LaTeX environment, call `org-edit-latex-environment'.
-When at an #+INCLUDE keyword, visit the included file.
+When at an INCLUDE, SETUPFILE or BIBLIOGRAPHY keyword, visit the included file.
 When at a footnote reference, call `org-edit-footnote-reference'.
 When at a planning line call, `org-deadline' and/or `org-schedule'.
 When at an active timestamp, call `org-time-stamp'.
@@ -17380,14 +17589,14 @@ Otherwise, return a user error."
                       session params))))))
       (`keyword
        (unless (member (org-element-property :key element)
-                      '("INCLUDE" "SETUPFILE"))
+                      '("BIBLIOGRAPHY" "INCLUDE" "SETUPFILE"))
         (user-error "No special environment to edit here"))
        (let ((value (org-element-property :value element)))
         (unless (org-string-nw-p value) (user-error "No file to edit"))
         (let ((file (and (string-match "\\`\"\\(.*?\\)\"\\|\\S-+" value)
                          (or (match-string 1 value)
                              (match-string 0 value)))))
-          (when (org-file-url-p file)
+          (when (org-url-p file)
             (user-error "Files located with a URL cannot be edited"))
           (org-link-open-from-string
            (format "[[%s]]" (expand-file-name file))))))
@@ -17632,28 +17841,35 @@ This command does many different things, depending on 
context:
        (`statistics-cookie
         (call-interactively #'org-update-statistics-cookies))
        ((or `table `table-cell `table-row)
-        ;; At a table, recalculate every field and align it.  Also
-        ;; send the table if necessary.  If the table has
-        ;; a `table.el' type, just give up.  At a table row or cell,
-        ;; maybe recalculate line but always align table.
-        (if (eq (org-element-property :type context) 'table.el)
-            (message "%s" (substitute-command-keys "\\<org-mode-map>\
-Use `\\[org-edit-special]' to edit table.el tables"))
-          (if (or (eq type 'table)
-                  ;; Check if point is at a TBLFM line.
-                  (and (eq type 'table-row)
-                       (= (point) (org-element-property :end context))))
-              (save-excursion
-                (if (org-at-TBLFM-p)
-                    (progn (require 'org-table)
-                           (org-table-calc-current-TBLFM))
-                  (goto-char (org-element-property :contents-begin context))
-                  (org-call-with-arg 'org-table-recalculate (or arg t))
-                  (orgtbl-send-table 'maybe)))
-            (org-table-maybe-eval-formula)
-            (cond (arg (call-interactively #'org-table-recalculate))
-                  ((org-table-maybe-recalculate-line))
-                  (t (org-table-align))))))
+        ;; At a table, generate a plot if on the #+plot line,
+         ;; recalculate every field and align it otherwise.  Also
+        ;; send the table if necessary.
+         (cond
+          ((and (org-match-line "[ \t]*#\\+plot:")
+                (< (point) (org-element-property :post-affiliated context)))
+           (org-plot/gnuplot))
+          ;; If the table has a `table.el' type, just give up.
+          ((eq (org-element-property :type context) 'table.el)
+           (message "%s" (substitute-command-keys "\\<org-mode-map>\
+Use `\\[org-edit-special]' to edit table.el tables")))
+          ;; At a table row or cell, maybe recalculate line but always
+         ;; align table.
+          ((or (eq type 'table)
+               ;; Check if point is at a TBLFM line.
+               (and (eq type 'table-row)
+                    (= (point) (org-element-property :end context))))
+           (save-excursion
+             (if (org-at-TBLFM-p)
+                 (progn (require 'org-table)
+                        (org-table-calc-current-TBLFM))
+               (goto-char (org-element-property :contents-begin context))
+               (org-call-with-arg 'org-table-recalculate (or arg t))
+               (orgtbl-send-table 'maybe))))
+          (t
+           (org-table-maybe-eval-formula)
+           (cond (arg (call-interactively #'org-table-recalculate))
+                 ((org-table-maybe-recalculate-line))
+                 (t (org-table-align))))))
        ((or `timestamp (and `planning (guard (org-at-timestamp-p 'lax))))
         (org-timestamp-change 0 'day))
        ((and `nil (guard (org-at-heading-p)))
@@ -17668,7 +17884,7 @@ Use `\\[org-edit-special]' to edit table.el tables"))
           "`\\[org-ctrl-c-ctrl-c]' can do nothing useful here"))))))))
 
 (defun org-mode-restart ()
-"Restart `org-mode'."
+  "Restart `org-mode'."
   (interactive)
   (let ((indent-status (bound-and-true-p org-indent-mode)))
     (funcall major-mode)
@@ -17783,12 +17999,13 @@ will not happen if point is in a table or on a 
\"dead\"
 object (e.g., within a comment).  In these case, you need to use
 `org-open-at-point' directly."
   (interactive "i\nP\np")
-  (let ((context (if org-return-follows-link (org-element-context)
-                  (org-element-at-point))))
+  (let* ((context (if org-return-follows-link (org-element-context)
+                   (org-element-at-point)))
+         (element-type (org-element-type context)))
     (cond
      ;; In a table, call `org-table-next-row'.  However, before first
      ;; column or after last one, split the table.
-     ((or (and (eq 'table (org-element-type context))
+     ((or (and (eq 'table element-type)
               (not (eq 'table.el (org-element-property :type context)))
               (>= (point) (org-element-property :contents-begin context))
               (< (point) (org-element-property :contents-end context)))
@@ -17802,7 +18019,7 @@ object (e.g., within a comment).  In these case, you 
need to use
      ;; `org-return-follows-link' allows it.  Tolerate fuzzy
      ;; locations, e.g., in a comment, as `org-open-at-point'.
      ((and org-return-follows-link
-          (or (and (eq 'link (org-element-type context))
+          (or (and (eq 'link element-type)
                    ;; Ensure point is not on the white spaces after
                    ;; the link.
                    (let ((origin (point)))
@@ -17849,12 +18066,13 @@ object (e.g., within a comment).  In these case, you 
need to use
        (org--newline indent arg interactive))))))
 
 (defun org-return-and-maybe-indent ()
-  "Goto next table row, or insert a newline.
+  "Goto next table row, or insert a newline, maybe indented.
 Call `org-table-next-row' or `org-return', depending on context.
 See the individual commands for more information.
 
-When inserting a newline, indent the new line if
-`electric-indent-mode' is disabled."
+When inserting a newline, if `org-adapt-indentation' is t:
+indent the line if `electric-indent-mode' is disabled, don't
+indent it if it is enabled."
   (interactive)
   (org-return (not electric-indent-mode)))
 
@@ -17928,15 +18146,14 @@ when a numeric prefix argument is given, its value 
determines the
 number of stars to add."
   (interactive "P")
   (let ((skip-blanks
-        (function
-         ;; Return beginning of first non-blank line, starting from
-         ;; line at POS.
-         (lambda (pos)
-           (save-excursion
-             (goto-char pos)
-             (while (org-at-comment-p) (forward-line))
-             (skip-chars-forward " \r\t\n")
-             (point-at-bol)))))
+        ;; Return beginning of first non-blank line, starting from
+        ;; line at POS.
+        (lambda (pos)
+          (save-excursion
+            (goto-char pos)
+            (while (org-at-comment-p) (forward-line))
+            (skip-chars-forward " \r\t\n")
+            (point-at-bol))))
        beg end toggled)
     ;; Determine boundaries of changes.  If a universal prefix has
     ;; been given, put the list in a region.  If region ends at a bol,
@@ -18023,7 +18240,7 @@ an argument, unconditionally call `org-insert-heading'."
        (not (org-at-table-p))))
 
 ;; Define the Org mode menus
-(easy-menu-define org-org-menu org-mode-map "Org menu"
+(easy-menu-define org-org-menu org-mode-map "Org menu."
   `("Org"
     ("Show/Hide"
      ["Cycle Visibility" org-cycle :active (or (bobp) (outline-on-heading-p))]
@@ -18208,7 +18425,7 @@ an argument, unconditionally call `org-insert-heading'."
      ["Reload Org (after update)" org-reload t]
      ["Reload Org uncompiled" (org-reload t) :active t :keys "C-u C-c C-x 
!"])))
 
-(easy-menu-define org-tbl-menu org-mode-map "Org Table menu"
+(easy-menu-define org-tbl-menu org-mode-map "Org Table menu."
   '("Table"
     ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p)]
     ["Next Field" org-cycle (org-at-table-p)]
@@ -18349,7 +18566,7 @@ Your bug report will be posted to the Org mailing list.
 ------------------------------------------------------------------------")
     (save-excursion
       (when (re-search-backward "^\\(Subject: \\)Org mode version \\(.*?\\);[ 
\t]*\\(.*\\)" nil t)
-       (replace-match "\\1Bug: \\3 [\\2]")))))
+       (replace-match "\\1[BUG] \\3 [\\2]")))))
 
 
 (defun org-install-agenda-files-menu ()
@@ -18823,11 +19040,6 @@ ELEMENT."
         (t
          (goto-char start)
          (current-indentation))))
-      ((and
-       (eq org-adapt-indentation 'headline-data)
-       (memq type '(planning clock node-property property-drawer drawer)))
-       (org--get-expected-indentation
-       (org-element-property :parent element) t))
       ((memq type '(headline inlinetask nil))
        (if (org-match-line "[ \t]*$")
           (org--get-expected-indentation element t)
@@ -18867,7 +19079,7 @@ ELEMENT."
                            (org--get-expected-indentation
                             (org-element-property :parent previous) t))))))))))
       ;; Otherwise, move to the first non-blank line above.
-      ((not (eq org-adapt-indentation 'headline-data))
+      (t
        (beginning-of-line)
        (let ((pos (point)))
         (skip-chars-backward " \r\t\n")
@@ -18944,7 +19156,7 @@ Indentation is done according to the following rules:
        Else, indent like parent's first line.
 
     3. Otherwise, indent relatively to current level, if
-       `org-adapt-indentation' is non-nil, or to left margin.
+       `org-adapt-indentation' is t, or to left margin.
 
   - On a blank line at the end of an element, indent according to
     the type of the element.  More precisely
@@ -18969,7 +19181,15 @@ list structure.  Instead, use 
\\<org-mode-map>`\\[org-shiftmetaleft]' or \
 
 Also align node properties according to `org-property-format'."
   (interactive)
-  (unless (org-at-heading-p)
+  (unless (or (org-at-heading-p)
+              (and (eq org-adapt-indentation 'headline-data)
+                   (not (or (org-at-clock-log-p)
+                            (org-at-planning-p)))
+                   (save-excursion
+                     (beginning-of-line 1)
+                     (skip-chars-backward "\n")
+                     (or (org-at-heading-p)
+                         (looking-back ":END:.*" (point-at-bol))))))
     (let* ((element (save-excursion (beginning-of-line) 
(org-element-at-point)))
           (type (org-element-type element)))
       (cond ((and (memq type '(plain-list item))
@@ -18991,6 +19211,21 @@ Also align node properties according to 
`org-property-format'."
                     (org-with-point-at (org-element-property :end element)
                       (skip-chars-backward " \t\n")
                       (line-beginning-position))))
+             ;; At the beginning of a blank line, do some preindentation.  This
+             ;; signals org-src--edit-element to preserve the indentation on 
exit
+             (when (and (looking-at-p "^[[:space:]]*$")
+                        (not org-src-preserve-indentation))
+               (let ((element (org-element-at-point))
+                     block-content-ind some-ind)
+                 (org-with-point-at (org-element-property :begin element)
+                   (setq block-content-ind (+ (current-indentation)
+                                              
org-edit-src-content-indentation))
+                   (forward-line)
+                  (save-match-data (re-search-forward "^[ \t]*\\S-" nil t))
+                   (backward-char)
+                   (setq some-ind (if (looking-at-p "#\\+end_src")
+                                      block-content-ind 
(current-indentation))))
+                 (indent-line-to (min block-content-ind some-ind))))
             (org-babel-do-key-sequence-in-edit-buffer (kbd "TAB")))
            (t
             (let ((column (org--get-expected-indentation element nil)))
@@ -19297,7 +19532,11 @@ a footnote definition, try to fill the first paragraph 
within."
       ;; the buffer.  In that case, ignore filling.
       (cl-case (org-element-type element)
        ;; Use major mode filling function is source blocks.
-       (src-block (org-babel-do-key-sequence-in-edit-buffer (kbd "M-q")))
+       (src-block (org-babel-do-in-edit-buffer
+                    (push-mark (point-min))
+                    (goto-char (point-max))
+                    (setq mark-active t)
+                    (funcall-interactively #'fill-paragraph justify 'region)))
        ;; Align Org tables, leave table.el tables as-is.
        (table-row (org-table-align) t)
        (table
@@ -19432,7 +19671,9 @@ filling the current element."
     ;; previously unmodified), then flip the modification status back
     ;; to "unchanged".
     (when (and hash (equal hash (org-buffer-hash)))
-      (set-buffer-modified-p nil))))
+      (set-buffer-modified-p nil))
+    ;; Return non-nil.
+    t))
 
 (defun org-auto-fill-function ()
   "Auto-fill function."
@@ -19901,7 +20142,7 @@ it has a `diary' type."
 (defvar org--rds)
 
 (defun org-reftex-citation ()
-  "Use reftex-citation to insert a citation into the buffer.
+  "Use `reftex-citation' to insert a citation into the buffer.
 This looks for a line like
 
 #+BIBLIOGRAPHY: foo plain option:-d
@@ -20221,7 +20462,7 @@ interactive command with similar behavior."
        (call-interactively command))))))
 
 (defun org-yank-folding-would-swallow-text (beg end)
-  "Would hide-subtree at BEG swallow any text after END?"
+  "Would `hide-subtree' at BEG swallow any text after END?"
   (let (level)
     (org-with-limited-levels
      (save-excursion
@@ -20337,6 +20578,10 @@ This function considers both visible and invisible 
heading lines.
 With argument, move up ARG levels."
   (outline-up-heading arg t))
 
+(defvar-local org--up-heading-cache nil
+  "Buffer-local `org-up-heading-safe' cache.")
+(defvar-local org--up-heading-cache-tick nil
+  "Buffer `buffer-chars-modified-tick' in `org--up-heading-cache'.")
 (defun org-up-heading-safe ()
   "Move to the heading line of which the present line is a subheading.
 This version will not throw an error.  It will return the level of the
@@ -20346,10 +20591,28 @@ Also, this function will be a lot faster than 
`outline-up-heading',
 because it relies on stars being the outline starters.  This can really
 make a significant difference in outlines with very many siblings."
   (when (ignore-errors (org-back-to-heading t))
-    (let ((level-up (1- (funcall outline-level))))
-      (and (> level-up 0)
-          (re-search-backward (format "^\\*\\{1,%d\\} " level-up) nil t)
-          (funcall outline-level)))))
+    (let (level-cache)
+      (unless org--up-heading-cache
+        (setq org--up-heading-cache (make-hash-table)))
+      (if (and (eq (buffer-chars-modified-tick) org--up-heading-cache-tick)
+               (setq level-cache (gethash (point) org--up-heading-cache)))
+          (when (<= (point-min) (car level-cache) (point-max))
+            ;; Parent is inside accessible part of the buffer.
+            (progn (goto-char (car level-cache))
+                   (cdr level-cache)))
+        ;; Buffer modified.  Invalidate cache.
+        (unless (eq (buffer-chars-modified-tick) org--up-heading-cache-tick)
+          (setq-local org--up-heading-cache-tick
+                      (buffer-chars-modified-tick))
+          (clrhash org--up-heading-cache))
+        (let* ((level-up (1- (funcall outline-level)))
+               (pos (point))
+               (result (and (> level-up 0)
+                           (re-search-backward
+                             (format "^\\*\\{1,%d\\} " level-up) nil t)
+                           (funcall outline-level))))
+          (when result (puthash pos (cons (point) result) 
org--up-heading-cache))
+          result)))))
 
 (defun org-up-heading-or-point-min ()
   "Move to the heading line of which the present is a subheading, or point-min.
@@ -20409,10 +20672,10 @@ move point."
 Return t when a child was found.  Otherwise don't move point and
 return nil."
   (let (level (pos (point)) (re org-outline-regexp-bol))
-    (when (ignore-errors (org-back-to-heading t))
-      (setq level (outline-level))
+    (when (org-back-to-heading-or-point-min t)
+      (setq level (org-outline-level))
       (forward-char 1)
-      (if (and (re-search-forward re nil t) (> (outline-level) level))
+      (if (and (re-search-forward re nil t) (> (org-outline-level) level))
          (progn (goto-char (match-beginning 0)) t)
        (goto-char pos) nil))))
 
@@ -20446,7 +20709,7 @@ This is like outline-next-sibling, but invisible 
headings are ok."
     (unless (or (eobp) (< (funcall outline-level) level))
       (point))))
 
-(defun org-get-last-sibling ()
+(defun org-get-previous-sibling ()
   "Move to previous heading of the same level, and return point.
 If there is no such heading, return nil."
   (let ((opoint (point))
@@ -20503,8 +20766,7 @@ When optional argument FULL is t, also skip planning 
information,
 clocking lines and any kind of drawer.
 
 When FULL is non-nil but not t, skip planning information,
-clocking lines and only non-regular drawers, i.e. properties and
-logbook drawers."
+properties, clocking lines and logbook drawers."
   (org-back-to-heading t)
   (forward-line)
   ;; Skip planning information.
@@ -20858,7 +21120,11 @@ See `org-backward-paragraph'."
          (cond
           ;; There is a blank line above.  Move there.
           ((and (org-previous-line-empty-p)
-                (not (org-invisible-p (1- (line-end-position 0)))))
+                 (let ((lep (line-end-position 0)))
+                   ;; When the first headline start at point 2, don't choke 
while
+                   ;; checking with `org-invisible-p'.
+                   (or (= lep 1)
+                      (not (org-invisible-p (1- (line-end-position 0)))))))
            (forward-line -1))
           ;; At the beginning of the first element within a greater
           ;; element.  Move to the beginning of the greater element.
diff --git a/lisp/org/ox-ascii.el b/lisp/org/ox-ascii.el
index 70bd1c4df2..78e6fb4988 100644
--- a/lisp/org/ox-ascii.el
+++ b/lisp/org/ox-ascii.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
 ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -479,6 +480,9 @@ HOW determines the type of justification: it can be `left',
     (insert s)
     (goto-char (point-min))
     (let ((fill-column text-width)
+          ;; Ensure that `indent-tabs-mode' is nil so that indentation
+          ;; will always be achieved using spaces rather than tabs.
+          (indent-tabs-mode nil)
          ;; Disable `adaptive-fill-mode' so it doesn't prevent
          ;; filling lines matching `adaptive-fill-regexp'.
          (adaptive-fill-mode nil))
@@ -1033,7 +1037,7 @@ INFO is a plist used as a communication channel."
             ;; Format TITLE.  It may be filled if it is too wide,
             ;; that is wider than the two thirds of the total width.
             (title-len (min (apply #'max
-                                   (mapcar #'length
+                                   (mapcar #'string-width
                                            (org-split-string
                                             (concat title "\n" subtitle) 
"\n")))
                             (/ (* 2 text-width) 3)))
@@ -1376,7 +1380,7 @@ contextual information."
 ;;;; Inlinetask
 
 (defun org-ascii-format-inlinetask-default
-  (_todo _type _priority _name _tags contents width inlinetask info)
+    (_todo _type _priority _name _tags contents width inlinetask info)
   "Format an inline task element for ASCII export.
 See `org-ascii-format-inlinetask-function' for a description
 of the parameters."
@@ -1940,33 +1944,32 @@ CONTENTS is the row contents.  INFO is a plist used as
 a communication channel."
   (when (eq (org-element-property :type table-row) 'standard)
     (let ((build-hline
-          (function
-           (lambda (lcorner horiz vert rcorner)
-             (concat
-              (apply
-               'concat
-               (org-element-map table-row 'table-cell
-                 (lambda (cell)
-                   (let ((width (org-ascii--table-cell-width cell info))
-                         (borders (org-export-table-cell-borders cell info)))
-                     (concat
-                      ;; In order to know if CELL starts the row, do
-                      ;; not compare it with the first cell in the
-                      ;; row as there might be a special column.
-                      ;; Instead, compare it with first exportable
-                      ;; cell, obtained with `org-element-map'.
-                      (when (and (memq 'left borders)
-                                 (eq (org-element-map table-row 'table-cell
-                                       'identity info t)
-                                     cell))
-                        lcorner)
-                      (make-string (+ 2 width) (string-to-char horiz))
-                      (cond
-                       ((not (memq 'right borders)) nil)
-                       ((eq (car (last (org-element-contents table-row))) cell)
-                        rcorner)
-                       (t vert)))))
-                 info)) "\n"))))
+          (lambda (lcorner horiz vert rcorner)
+            (concat
+             (apply
+              'concat
+              (org-element-map table-row 'table-cell
+                (lambda (cell)
+                  (let ((width (org-ascii--table-cell-width cell info))
+                        (borders (org-export-table-cell-borders cell info)))
+                    (concat
+                     ;; In order to know if CELL starts the row, do
+                     ;; not compare it with the first cell in the
+                     ;; row as there might be a special column.
+                     ;; Instead, compare it with first exportable
+                     ;; cell, obtained with `org-element-map'.
+                     (when (and (memq 'left borders)
+                                (eq (org-element-map table-row 'table-cell
+                                      'identity info t)
+                                    cell))
+                       lcorner)
+                     (make-string (+ 2 width) (string-to-char horiz))
+                     (cond
+                      ((not (memq 'right borders)) nil)
+                      ((eq (car (last (org-element-contents table-row))) cell)
+                       rcorner)
+                      (t vert)))))
+                info)) "\n")))
          (utf8p (eq (plist-get info :ascii-charset) 'utf-8))
          (borders (org-export-table-cell-borders
                    (org-element-map table-row 'table-cell 'identity info t)
@@ -2088,7 +2091,7 @@ a communication channel."
 
 ;;;###autoload
 (defun org-ascii-export-as-ascii
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a text buffer.
 
 If narrowing is active in the current buffer, only export its
@@ -2123,7 +2126,7 @@ is non-nil."
 
 ;;;###autoload
 (defun org-ascii-export-to-ascii
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a text file.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox-beamer.el b/lisp/org/ox-beamer.el
index 6ed95e84d6..ca0f1c71ab 100644
--- a/lisp/org/ox-beamer.el
+++ b/lisp/org/ox-beamer.el
@@ -4,6 +4,7 @@
 
 ;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com>
 ;;         Nicolas Goaziou <n.goaziou AT gmail DOT com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: org, wp, tex
 
 ;; This file is part of GNU Emacs.
@@ -149,7 +150,7 @@ which is replaced with the subtitle."
 
 (defconst org-beamer-column-widths
   "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.0 :ETC"
-"The column widths that should be installed as allowed property values.")
+  "The column widths that should be installed as allowed property values.")
 
 (defconst org-beamer-environments-special
   '(("againframe"     "A")
@@ -379,13 +380,12 @@ used as a communication channel."
           :parent 'latex
           :transcoders
           (let ((protected-output
-                 (function
-                  (lambda (object contents info)
-                    (let ((code (org-export-with-backend
-                                 'beamer object contents info)))
-                      (if (org-string-nw-p code) (concat "\\protect" code)
-                        code))))))
-            (mapcar #'(lambda (type) (cons type protected-output))
+                 (lambda (object contents info)
+                   (let ((code (org-export-with-backend
+                                'beamer object contents info)))
+                     (if (org-string-nw-p code) (concat "\\protect" code)
+                       code)))))
+             (mapcar (lambda (type) (cons type protected-output))
                     '(bold footnote-reference italic strike-through timestamp
                            underline))))
          headline
@@ -426,16 +426,16 @@ used as a communication channel."
                    ;; Collect nonempty options from default value and
                    ;; headline's properties.
                    (cl-remove-if-not #'org-string-nw-p
-                    (append
-                     (org-split-string
-                      (plist-get info :beamer-frame-default-options) ",")
-                     (and beamer-opt
-                          (org-split-string
-                           ;; Remove square brackets if user provided
-                           ;; them.
-                           (and (string-match "^\\[?\\(.*\\)\\]?$" beamer-opt)
-                                (match-string 1 beamer-opt))
-                           ",")))))
+                                     (append
+                                      (org-split-string
+                                       (plist-get info 
:beamer-frame-default-options) ",")
+                                      (and beamer-opt
+                                           (org-split-string
+                                            ;; Remove square brackets if user 
provided
+                                            ;; them.
+                                            (and (string-match 
"^\\[?\\(.*\\)\\]?$" beamer-opt)
+                                                 (match-string 1 beamer-opt))
+                                            ",")))))
                   (fragile
                    ;; Add "fragile" option if necessary.
                    (and fragilep
@@ -812,17 +812,16 @@ holding export options."
      (org-latex-make-preamble info)
      ;; Insert themes.
      (let ((format-theme
-           (function
-            (lambda (prop command)
-              (let ((theme (plist-get info prop)))
-                (when theme
-                  (concat command
-                          (if (not (string-match "\\[.*\\]" theme))
-                              (format "{%s}\n" theme)
-                            (format "%s{%s}\n"
-                                    (match-string 0 theme)
-                                    (org-trim
-                                     (replace-match "" nil nil theme)))))))))))
+           (lambda (prop command)
+             (let ((theme (plist-get info prop)))
+               (when theme
+                 (concat command
+                         (if (not (string-match "\\[.*\\]" theme))
+                             (format "{%s}\n" theme)
+                           (format "%s{%s}\n"
+                                   (match-string 0 theme)
+                                   (org-trim
+                                    (replace-match "" nil nil theme))))))))))
        (mapconcat (lambda (args) (apply format-theme args))
                  '((:beamer-theme "\\usetheme")
                    (:beamer-color-theme "\\usecolortheme")
@@ -960,7 +959,7 @@ value."
 
 ;;;###autoload
 (defun org-beamer-export-as-latex
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer buffer.
 
 If narrowing is active in the current buffer, only export its
@@ -995,7 +994,7 @@ is non-nil."
 
 ;;;###autoload
 (defun org-beamer-export-to-latex
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer presentation (tex).
 
 If narrowing is active in the current buffer, only export its
@@ -1029,7 +1028,7 @@ Return output file's name."
 
 ;;;###autoload
 (defun org-beamer-export-to-pdf
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a Beamer presentation (PDF).
 
 If narrowing is active in the current buffer, only export its
@@ -1080,7 +1079,7 @@ aid, but the tag does not have any semantic meaning."
         (org-current-tag-alist
          (append '((:startgroup))
                  (mapcar (lambda (e) (cons (concat "B_" (car e))
-                                      (string-to-char (nth 1 e))))
+                                           (string-to-char (nth 1 e))))
                          envs)
                  '((:endgroup))
                  '(("BMCOL" . ?|))))
diff --git a/lisp/org/ox-html.el b/lisp/org/ox-html.el
index d8932996eb..a150b1fdb8 100644
--- a/lisp/org/ox-html.el
+++ b/lisp/org/ox-html.el
@@ -2,8 +2,9 @@
 
 ;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;      Jambunathan K <kjambunathan at gmail dot com>
+;; Maintainer: TEC <tecosaur@gmail.com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -113,6 +114,7 @@
   :options-alist
   '((:html-doctype "HTML_DOCTYPE" nil org-html-doctype)
     (:html-container "HTML_CONTAINER" nil org-html-container-element)
+    (:html-content-class "HTML_CONTENT_CLASS" nil org-html-content-class)
     (:description "DESCRIPTION" nil nil newline)
     (:keywords "KEYWORDS" nil nil space)
     (:html-html5-fancy nil "html5-fancy" org-html-html5-fancy)
@@ -192,7 +194,7 @@
 (defvar htmlize-buffer-places)  ; from htmlize.el
 
 (defvar org-html--pre/postamble-class "status"
-  "CSS class used for pre/postamble")
+  "CSS class used for pre/postamble.")
 
 (defconst org-html-doctype-alist
   '(("html4-strict" . "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"
@@ -231,10 +233,9 @@ property on the headline itself.")
     ("\\.\\.\\." . "&#x2026;"))                ; hellip
   "Regular expressions for special string conversion.")
 
-(defconst org-html-scripts
-  "<script type=\"text/javascript\">
-// @license 
magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a&dn=public-domain.txt
 Public Domain
-<!--/*--><![CDATA[/*><!--*/
+(defcustom org-html-scripts
+  "<script>
+// @license 
magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&amp;dn=gpl-3.0.txt 
GPL-v3-or-Later
      function CodeHighlightOn(elem, id)
      {
        var target = document.getElementById(id);
@@ -251,14 +252,16 @@ property on the headline itself.")
          target.classList.remove(\"code-highlighted\");
        }
      }
-    /*]]>*///-->
 // @license-end
 </script>"
-  "Basic JavaScript that is needed by HTML files produced by Org mode.")
+  "Basic JavaScript to allow highlighting references in code blocks."
+  :group 'org-export-html
+  :package-version '(Org . "9.5")
+  :type 'string)
 
-(defconst org-html-style-default
-  "<style type=\"text/css\">
- <!--/*--><![CDATA[/*><!--*/
+(defcustom org-html-style-default
+  "<style>
+  #content { max-width: 60em; margin: auto; }
   .title  { text-align: center;
              margin-bottom: .2em; }
   .subtitle { text-align: center;
@@ -279,8 +282,9 @@ property on the headline itself.")
   #postamble p, #preamble p { font-size: 90%; margin: .2em; }
   p.verse { margin-left: 3%; }
   pre {
-    border: 1px solid #ccc;
-    box-shadow: 3px 3px 3px #eee;
+    border: 1px solid #e6e6e6;
+    border-radius: 3px;
+    background-color: #f2f2f2;
     padding: 8pt;
     font-family: monospace;
     overflow: auto;
@@ -289,21 +293,21 @@ property on the headline itself.")
   pre.src {
     position: relative;
     overflow: auto;
-    padding-top: 1.2em;
   }
   pre.src:before {
     display: none;
     position: absolute;
-    background-color: white;
-    top: -10px;
-    right: 10px;
+    top: -8px;
+    right: 12px;
     padding: 3px;
-    border: 1px solid black;
+    color: #555;
+    background-color: #f2f2f299;
   }
   pre.src:hover:before { display: inline; margin-top: 14px;}
   /* Languages per Org manual */
   pre.src-asymptote:before { content: 'Asymptote'; }
   pre.src-awk:before { content: 'Awk'; }
+  pre.src-authinfo::before { content: 'Authinfo'; }
   pre.src-C:before { content: 'C'; }
   /* pre.src-C++ doesn't work in CSS */
   pre.src-clojure:before { content: 'Clojure'; }
@@ -439,12 +443,14 @@ property on the headline itself.")
   .org-info-js_search-highlight
     { background-color: #ffff00; color: #000000; font-weight: bold; }
   .org-svg { width: 90%; }
-  /*]]>*/-->
 </style>"
   "The default style specification for exported HTML files.
 You can use `org-html-head' and `org-html-head-extra' to add to
 this style.  If you don't want to include this default style,
-customize `org-html-head-include-default-style'.")
+customize `org-html-head-include-default-style'."
+  :group 'org-export-html
+  :package-version '(Org . "9.5")
+  :type 'string)
 
 
 ;;; User Configuration Variables
@@ -508,17 +514,15 @@ means to use the maximum value consistent with other 
options."
           org-html-infojs-opts-table)))
 
 (defcustom org-html-infojs-template
-  "<script type=\"text/javascript\" src=\"%SCRIPT_PATH\">
+  "<script src=\"%SCRIPT_PATH\">
 // @license 
magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&amp;dn=gpl-3.0.txt 
GPL-v3-or-Later
 // @license-end
 </script>
 
-<script type=\"text/javascript\">
+<script>
 // @license 
magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&amp;dn=gpl-3.0.txt 
GPL-v3-or-Later
-<!--/*--><![CDATA[/*><!--*/
 %MANAGER_OPTIONS
 org_html_manager.setup();  // activate after the parameters are set
-/*]]>*///-->
 // @license-end
 </script>"
   "The template for the export style additions when org-info.js is used.
@@ -653,9 +657,6 @@ The function must accept two parameters:
 
 The function should return the string to be exported.
 
-For example, the variable could be set to the following function
-in order to mimic default behavior:
-
 The default value simply returns the value of CONTENTS."
   :group 'org-export-html
   :version "24.4"
@@ -782,7 +783,7 @@ The function should return the string to be exported."
   "The MathJax command to use when referencing equations.
 
 This is a format control string that expects a single string argument
-specifying the label that is being referenced. The argument is
+specifying the label that is being referenced.  The argument is
 generated automatically on export.
 
 The default is to wrap equations in parentheses (using \"\\eqref{%s}\)\".
@@ -794,7 +795,7 @@ Most common values are:
   :group 'org-export-html
   :package-version '(Org . "9.4")
   :type 'string
-  :safe t)
+  :safe #'stringp)
 
 (defcustom org-html-with-latex org-export-with-latex
   "Non-nil means process LaTeX math snippets.
@@ -825,13 +826,13 @@ e.g. \"tex:mathjax\".  Allowed values are:
 ;;;; Links :: Generic
 
 (defcustom org-html-link-org-files-as-html t
-  "Non-nil means make file links to `file.org' point to `file.html'.
-When `org-mode' is exporting an `org-mode' file to HTML, links to
-non-html files are directly put into a href tag in HTML.
-However, links to other Org files (recognized by the extension
-\".org\") should become links to the corresponding HTML
-file, assuming that the linked `org-mode' file will also be
-converted to HTML.
+  "Non-nil means make file links to \"file.org\" point to \"file.html\".
+
+When Org mode is exporting an Org file to HTML, links to non-HTML files
+are directly put into a \"href\" tag in HTML.  However, links to other Org 
files
+(recognized by the extension \".org\") should become links to the corresponding
+HTML file, assuming that the linked Org file will also be converted to HTML.
+
 When nil, the links still point to the plain \".org\" file."
   :group 'org-export-html
   :type 'boolean)
@@ -848,16 +849,15 @@ link to the image."
   :type 'boolean)
 
 (defcustom org-html-inline-image-rules
-  `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg")))
-    ("http" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg")))
-    ("https" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg"))))
+  `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".webp")))
+    ("http" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".webp")))
+    ("https" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".webp"))))
   "Rules characterizing image files that can be inlined into HTML.
 A rule consists in an association whose key is the type of link
 to consider, and value is a regexp that will be matched against
 link's path."
   :group 'org-export-html
-  :version "24.4"
-  :package-version '(Org . "8.0")
+  :package-version '(Org . "9.5")
   :type '(alist :key-type (string :tag "Type")
                :value-type (regexp :tag "Path")))
 
@@ -903,7 +903,7 @@ numbers are enabled."
   :group 'org-export-html
   :package-version '(Org . "9.3")
   :type 'boolean
-  :safe t)
+  :safe #'booleanp)
 
 ;;;; Table
 
@@ -1060,13 +1060,7 @@ publishing, with :html-doctype."
 
 (defcustom org-html-html5-fancy nil
   "Non-nil means using new HTML5 elements.
-This variable is ignored for anything other than HTML5 export.
-
-For compatibility with Internet Explorer, it's probably a good
-idea to download some form of the html5shiv (for instance
-https://code.google.com/p/html5shiv/) and add it to your
-HTML_HEAD_EXTRA, so that your pages don't break for users of IE
-versions 8 and below."
+This variable is ignored for anything other than HTML5 export."
   :group 'org-export-html
   :version "24.4"
   :package-version '(Org . "8.0")
@@ -1084,6 +1078,16 @@ org-info.js for your website."
   :package-version '(Org . "8.0")
   :type 'string)
 
+(defcustom org-html-content-class "content"
+  "CSS class name to use for the top level content wrapper.
+Can be set with the in-buffer HTML_CONTENT_CLASS property or for
+publishing, with :html-content-class."
+  :group 'org-export-html
+  :version "27.2"
+  :package-version '(Org . "9.5")
+  :type 'string)
+
+
 (defcustom org-html-divs
   '((preamble  "div" "preamble")
     (content   "div" "content")
@@ -1110,15 +1114,15 @@ org-info.js for your website."
 
 (defconst org-html-checkbox-types
   '((unicode .
-     ((on . "&#x2611;") (off . "&#x2610;") (trans . "&#x2610;")))
+             ((on . "&#x2611;") (off . "&#x2610;") (trans . "&#x2610;")))
     (ascii .
-     ((on . "<code>[X]</code>")
-      (off . "<code>[&#xa0;]</code>")
-      (trans . "<code>[-]</code>")))
+           ((on . "<code>[X]</code>")
+            (off . "<code>[&#xa0;]</code>")
+            (trans . "<code>[-]</code>")))
     (html .
          ((on . "<input type='checkbox' checked='checked' />")
-         (off . "<input type='checkbox' />")
-         (trans . "<input type='checkbox' />"))))
+          (off . "<input type='checkbox' />")
+          (trans . "<input type='checkbox' />"))))
   "Alist of checkbox types.
 The cdr of each entry is an alist list three checkbox types for
 HTML export: `on', `off' and `trans'.
@@ -1129,7 +1133,7 @@ The choices are:
   `html'    HTML checkboxes
 
 Note that only the ascii characters implement tri-state
-checkboxes. The other two use the `off' checkbox for `trans'.")
+checkboxes.  The other two use the `off' checkbox for `trans'.")
 
 (defcustom org-html-checkbox-type 'ascii
   "The type of checkboxes to use for HTML export.
@@ -1192,7 +1196,7 @@ You can also customize this for each buffer, using 
something like
 
 For further information about MathJax options, see the MathJax documentation:
 
-  http://docs.mathjax.org/";
+  https://docs.mathjax.org/";
   :group 'org-export-html
   :package-version '(Org . "8.3")
   :type '(list :greedy t
@@ -1252,8 +1256,7 @@ For further information about MathJax options, see the 
MathJax documentation:
              }
 });
 </script>
-<script type=\"text/javascript\"
-        src=\"%PATH\"></script>"
+<script src=\"%PATH\"></script>"
   "The MathJax template.  See also `org-html-mathjax-options'."
   :group 'org-export-html
   :type 'string)
@@ -1414,10 +1417,9 @@ ignored."
 
 ;;;; Template :: Scripts
 
-(defcustom org-html-head-include-scripts t
+(defcustom org-html-head-include-scripts nil
   "Non-nil means include the JavaScript snippets in exported HTML files.
-The actual script is defined in `org-html-scripts' and should
-not be modified."
+The actual script is defined in `org-html-scripts'."
   :group 'org-export-html
   :version "24.4"
   :package-version '(Org . "8.0")
@@ -1425,6 +1427,23 @@ not be modified."
 
 ;;;; Template :: Styles
 
+(defcustom org-html-meta-tags #'org-html-meta-tags-default
+  "Form that is used to produce meta tags in the HTML head.
+
+Can be a list where each item is a list of arguments to be passed
+to `org-html--build-meta-entry'.  Any nil items are ignored.
+
+Also accept a function which gives such a list when called with a
+single argument (INFO, a communication plist)."
+  :group 'org-export-html
+  :package-version '(Org . "9.5")
+  :type '(choice
+         (repeat
+          (list (string :tag "Meta label")
+                (string :tag "label value")
+                (string :tag "Content value")))
+         function))
+
 (defcustom org-html-head-include-default-style t
   "Non-nil means include the default style in exported HTML files.
 The actual style is defined in `org-html-style-default' and
@@ -1447,14 +1466,12 @@ done, timestamp, timestamp-kwd, tag, target.
 
 For example, a valid value would be:
 
-   <style type=\"text/css\">
-    /*<![CDATA[*/
+   <style>
       p { font-weight: normal; color: gray; }
       h1 { color: black; }
       .title { text-align: center; }
       .todo, .timestamp-kwd { color: red; }
       .done { color: green; }
-    /*]]>*/
    </style>
 
 If you want to refer to an external style, use something like
@@ -1588,7 +1605,7 @@ CSS classes, then this prefix can be very useful."
 
 (defun org-html-html5-p (info)
   (let ((dt (downcase (plist-get info :html-doctype))))
-       (member dt '("html5" "xhtml5" "<!doctype html>"))))
+    (member dt '("html5" "xhtml5" "<!doctype html>"))))
 
 (defun org-html--html5-fancy-p (info)
   "Non-nil when exporting to HTML5 with fancy elements.
@@ -1680,43 +1697,20 @@ SOURCE is a string specifying the location of the image.
 ATTRIBUTES is a plist, as returned by
 `org-export-read-attribute'.  INFO is a plist used as
 a communication channel."
-  (if (string= "svg" (file-name-extension source))
-      (org-html--svg-image source attributes info)
-    (org-html-close-tag
-     "img"
-     (org-html--make-attribute-string
-      (org-combine-plists
-       (list :src source
-            :alt (if (string-match-p
-                      (concat "^" org-preview-latex-image-directory) source)
-                     (org-html-encode-plain-text
-                      (org-find-text-property-in-string 'org-latex-src source))
-                   (file-name-nondirectory source)))
-       attributes))
-     info)))
-
-(defun org-html--svg-image (source attributes info)
-  "Return \"object\" embedding svg file SOURCE with given ATTRIBUTES.
-INFO is a plist used as a communication channel.
-
-The special attribute \"fallback\" can be used to specify a
-fallback image file to use if the object embedding is not
-supported.  CSS class \"org-svg\" is assigned as the class of the
-object unless a different class is specified with an attribute."
-  (let ((fallback (plist-get attributes :fallback))
-       (attrs (org-html--make-attribute-string
-               (org-combine-plists
-                 ;; Remove fallback attribute, which is not meant to
-                 ;; appear directly in the attributes string, and
-                 ;; provide a default class if none is set.
-                 '(:class "org-svg") attributes '(:fallback nil)))))
-    (format "<object type=\"image/svg+xml\" data=\"%s\" %s>\n%s</object>"
-           source
-           attrs
-           (if fallback
-               (org-html-close-tag
-                "img" (format "src=\"%s\" %s" fallback attrs) info)
-             "Sorry, your browser does not support SVG."))))
+  (org-html-close-tag
+   "img"
+   (org-html--make-attribute-string
+    (org-combine-plists
+     (list :src source
+           :alt (if (string-match-p
+                     (concat "^" org-preview-latex-image-directory) source)
+                    (org-html-encode-plain-text
+                     (org-find-text-property-in-string 'org-latex-src source))
+                  (file-name-nondirectory source)))
+     (if (string= "svg" (file-name-extension source))
+         (org-combine-plists '(:class "org-svg") attributes '(:fallback nil))
+       attributes)))
+   info))
 
 (defun org-html--textarea-block (element)
   "Transcode ELEMENT into a textarea block.
@@ -1820,12 +1814,12 @@ INFO is a plist used as a communication channel."
                    (anchor (org-html--anchor
                             (format "fn.%d" n)
                             n
-                            (format " class=\"footnum\" href=\"#fnr.%d\"" n)
+                            (format " class=\"footnum\" href=\"#fnr.%d\" 
role=\"doc-backlink\"" n)
                             info))
                    (contents (org-trim (org-export-data def info))))
                (format "<div class=\"footdef\">%s %s</div>\n"
                        (format (plist-get info :html-footnote-format) anchor)
-                       (format "<div class=\"footpara\">%s</div>"
+                       (format "<div class=\"footpara\" 
role=\"doc-footnote\">%s</div>"
                                (if (not inline?) contents
                                  (format "<p class=\"footpara\">%s</p>"
                                          contents))))))))
@@ -1835,78 +1829,93 @@ INFO is a plist used as a communication channel."
 
 ;;; Template
 
+(defun org-html-meta-tags-default (info)
+  "A default value for `org-html-meta-tags'.
+
+Generate a list items, each of which is a list of arguments that can
+be passed to `org-html--build-meta-entry', to generate meta tags to be
+included in the HTML head.
+
+Use document's plist INFO to derive relevant information for the tags."
+  (let ((author (and (plist-get info :with-author)
+                     (let ((auth (plist-get info :author)))
+                       ;; Return raw Org syntax.
+                       (and auth (org-element-interpret-data auth))))))
+    (list
+     (when (org-string-nw-p author)
+       (list "name" "author" author))
+     (when (org-string-nw-p (plist-get info :description))
+       (list "name" "description"
+             (plist-get info :description)))
+     (when (org-string-nw-p (plist-get info :keywords))
+       (list "name" "keywords" (plist-get info :keywords)))
+     '("name" "generator" "Org Mode"))))
+
+(defun org-html--build-meta-entry
+    (label identity &optional content-format &rest content-formatters)
+  "Build a meta tag using the provided information.
+
+Construct <meta> tag of form <meta LABEL=\"IDENTITY\" />, or when 
CONTENT-FORMAT
+is present: <meta LABEL=\"IDENTITY\" content=\"{content}\" />
+
+Here {content} is determined by applying any CONTENT-FORMATTERS to the
+CONTENT-FORMAT and encoding the result as plain text."
+  (concat "<meta "
+         (format "%s=\"%s" label identity)
+         (when content-format
+           (concat "\" content=\""
+                   (replace-regexp-in-string
+                    "\"" "&quot;"
+                    (org-html-encode-plain-text
+                     (if content-formatters
+                         (apply #'format content-format content-formatters)
+                       content-format)))))
+         "\" />\n"))
+
 (defun org-html--build-meta-info (info)
   "Return meta tags for exported document.
 INFO is a plist used as a communication channel."
-  (let* ((protect-string
-          (lambda (str)
-            (replace-regexp-in-string
-             "\"" "&quot;" (org-html-encode-plain-text str))))
-         (title (org-export-data (plist-get info :title) info))
-         ;; Set title to an invisible character instead of leaving it
-         ;; empty, which is invalid.
-         (title (if (org-string-nw-p title) title "&lrm;"))
-         (author (and (plist-get info :with-author)
-                      (let ((auth (plist-get info :author)))
-                       ;; Return raw Org syntax.
-                        (and auth (org-element-interpret-data auth)))))
-         (description (plist-get info :description))
-         (keywords (plist-get info :keywords))
-         (charset (or (and org-html-coding-system
-                           (fboundp 'coding-system-get)
-                           (coding-system-get org-html-coding-system
-                                              'mime-charset))
-                      "iso-8859-1")))
+  (let* ((title (org-html-plain-text
+                (org-element-interpret-data (plist-get info :title)) info))
+        ;; Set title to an invisible character instead of leaving it
+        ;; empty, which is invalid.
+        (title (if (org-string-nw-p title) title "&lrm;"))
+        (charset (or (and org-html-coding-system
+                          (fboundp 'coding-system-get)
+                          (symbol-name
+                           (coding-system-get org-html-coding-system
+                                              'mime-charset)))
+                     "iso-8859-1")))
     (concat
      (when (plist-get info :time-stamp-file)
        (format-time-string
        (concat "<!-- "
                (plist-get info :html-metadata-timestamp-format)
                " -->\n")))
-     (format
-      (if (org-html-html5-p info)
-         (org-html-close-tag "meta" "charset=\"%s\"" info)
-       (org-html-close-tag
-        "meta" "http-equiv=\"Content-Type\" content=\"text/html;charset=%s\""
-        info))
-      charset) "\n"
+
+     (if (org-html-html5-p info)
+        (org-html--build-meta-entry "charset" charset)
+       (org-html--build-meta-entry "http-equiv" "Content-Type"
+                                  (concat "text/html;charset=" charset)))
+
      (let ((viewport-options
            (cl-remove-if-not (lambda (cell) (org-string-nw-p (cadr cell)))
                              (plist-get info :html-viewport))))
-       (and viewport-options
-           (concat
-            (org-html-close-tag
-             "meta"
-             (format "name=\"viewport\" content=\"%s\""
-                     (mapconcat
-                      (lambda (elm) (format "%s=%s" (car elm) (cadr elm)))
-                      viewport-options ", "))
-             info)
-            "\n")))
+       (if viewport-options
+          (org-html--build-meta-entry "name" "viewport"
+                                      (mapconcat
+                                       (lambda (elm)
+                                          (format "%s=%s" (car elm) (cadr 
elm)))
+                                       viewport-options ", "))))
+
      (format "<title>%s</title>\n" title)
-     (org-html-close-tag "meta" "name=\"generator\" content=\"Org mode\"" info)
-     "\n"
-     (and (org-string-nw-p author)
-         (concat
-          (org-html-close-tag "meta"
-                              (format "name=\"author\" content=\"%s\""
-                                      (funcall protect-string author))
-                              info)
-          "\n"))
-     (and (org-string-nw-p description)
-         (concat
-          (org-html-close-tag "meta"
-                              (format "name=\"description\" content=\"%s\"\n"
-                                      (funcall protect-string description))
-                              info)
-          "\n"))
-     (and (org-string-nw-p keywords)
-         (concat
-          (org-html-close-tag "meta"
-                              (format "name=\"keywords\" content=\"%s\""
-                                      (funcall protect-string keywords))
-                              info)
-          "\n")))))
+
+     (mapconcat
+      (lambda (args) (apply #'org-html--build-meta-entry args))
+      (delq nil (if (functionp org-html-meta-tags)
+                   (funcall org-html-meta-tags info)
+                 org-html-meta-tags))
+      ""))))
 
 (defun org-html--build-head (info)
   "Return information for the <head>..</head> of the HTML output.
@@ -2088,7 +2097,10 @@ holding export options."
    (org-html--build-pre/postamble 'preamble info)
    ;; Document contents.
    (let ((div (assq 'content (plist-get info :html-divs))))
-     (format "<%s id=\"%s\">\n" (nth 1 div) (nth 2 div)))
+     (format "<%s id=\"%s\" class=\"%s\">\n"
+             (nth 1 div)
+             (nth 2 div)
+             (plist-get info :html-content-class)))
    ;; Document title.
    (when (plist-get info :with-title)
      (let ((title (and (plist-get info :with-title)
@@ -2104,7 +2116,7 @@ holding export options."
          (if subtitle
              (format
               (if html5-fancy
-                  "<p class=\"subtitle\">%s</p>\n"
+                  "<p class=\"subtitle\" role=\"doc-subtitle\">%s</p>\n"
                 (concat "\n" (org-html-close-tag "br" nil info) "\n"
                         "<span class=\"subtitle\">%s</span>\n"))
               (org-export-data subtitle info))
@@ -2232,7 +2244,7 @@ is the language used for CODE, as a string, or nil."
            (if (and beg end) (substring code beg end) code)))))))))
 
 (defun org-html-do-format-code
-  (code &optional lang refs retain-labels num-start wrap-lines)
+    (code &optional lang refs retain-labels num-start wrap-lines)
   "Format CODE string as source code.
 Optional arguments LANG, REFS, RETAIN-LABELS, NUM-START, WRAP-LINES
 are, respectively, the language of the source code, as a string, an
@@ -2305,14 +2317,14 @@ of contents as a string, or nil if it is empty."
                         (org-export-get-relative-level headline info)))
                 (org-export-collect-headlines info depth scope))))
     (when toc-entries
-      (let ((toc (concat "<div id=\"text-table-of-contents\">"
+      (let ((toc (concat "<div id=\"text-table-of-contents\" role=\"doc-toc\">"
                         (org-html--toc-text toc-entries)
                         "</div>\n")))
        (if scope toc
          (let ((outer-tag (if (org-html--html5-fancy-p info)
                               "nav"
                             "div")))
-           (concat (format "<%s id=\"table-of-contents\">\n" outer-tag)
+           (concat (format "<%s id=\"table-of-contents\" role=\"doc-toc\">\n" 
outer-tag)
                    (let ((top-level (plist-get info :html-toplevel-hlevel)))
                      (format "<h%d>%s</h%d>\n"
                              top-level
@@ -2585,7 +2597,7 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
      (format
       (plist-get info :html-footnote-format)
       (org-html--anchor
-       id n (format " class=\"footref\" href=\"#fn.%d\"" n) info)))))
+       id n (format " class=\"footref\" href=\"#fn.%d\" role=\"doc-backlink\"" 
n) info)))))
 
 ;;;; Headline
 
@@ -2650,7 +2662,7 @@ holding contextual information."
                                 (format
                                  "<span class=\"section-number-%d\">%s</span> "
                                  level
-                                 (mapconcat #'number-to-string numbers ".")))
+                                 (concat (mapconcat #'number-to-string numbers 
".") ".")))
                            formatted-text)
                           level)
                   ;; When there is no section, pretend there is an
@@ -2720,7 +2732,7 @@ holding contextual information."
             todo todo-type priority text tags contents info)))
 
 (defun org-html-format-inlinetask-default-function
-  (todo todo-type priority text tags contents info)
+    (todo todo-type priority text tags contents info)
   "Default format function for inlinetasks.
 See `org-html-format-inlinetask-function' for details."
   (format "<div class=\"inlinetask\">\n<b>%s</b>%s\n%s</div>"
@@ -3020,7 +3032,8 @@ images, set it to:
                     (`paragraph element)
                     (`link (org-export-get-parent element)))))
     (and (eq (org-element-type paragraph) 'paragraph)
-        (or (not (fboundp 'org-html-standalone-image-predicate))
+        (or (not (and (boundp 'org-html-standalone-image-predicate)
+                       (fboundp org-html-standalone-image-predicate)))
             (funcall org-html-standalone-image-predicate paragraph))
         (catch 'exit
           (let ((link-count 0))
@@ -3464,12 +3477,12 @@ contextual information."
   (if (org-export-read-attribute :attr_html src-block :textarea)
       (org-html--textarea-block src-block)
     (let* ((lang (org-element-property :language src-block))
-         (code (org-html-format-code src-block info))
-         (label (let ((lbl (org-html--reference src-block info t)))
-                  (if lbl (format " id=\"%s\"" lbl) "")))
-         (klipsify  (and  (plist-get info :html-klipsify-src)
-                           (member lang '("javascript" "js"
-                                         "ruby" "scheme" "clojure" "php" 
"html")))))
+          (code (org-html-format-code src-block info))
+          (label (let ((lbl (org-html--reference src-block info t)))
+                   (if lbl (format " id=\"%s\"" lbl) "")))
+          (klipsify  (and  (plist-get info :html-klipsify-src)
+                            (member lang '("javascript" "js"
+                                          "ruby" "scheme" "clojure" "php" 
"html")))))
       (if (not lang) (format "<pre class=\"example\"%s>\n%s</pre>" label code)
        (format "<div class=\"org-src-container\">\n%s%s\n</div>"
                ;; Build caption.
@@ -3773,7 +3786,7 @@ contextual information."
 
 ;;;###autoload
 (defun org-html-export-as-html
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to an HTML buffer.
 
 If narrowing is active in the current buffer, only export its
@@ -3818,7 +3831,7 @@ to convert it."
 
 ;;;###autoload
 (defun org-html-export-to-html
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a HTML file.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox-icalendar.el b/lisp/org/ox-icalendar.el
index b8834c4ce1..9170059156 100644
--- a/lisp/org/ox-icalendar.el
+++ b/lisp/org/ox-icalendar.el
@@ -2,8 +2,9 @@
 
 ;; Copyright (C) 2004-2021 Free Software Foundation, Inc.
 
-;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Author: Carsten Dominik <carsten.dominik@gmail.com>
 ;;      Nicolas Goaziou <n dot goaziou at gmail dot com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 ;; Homepage: https://orgmode.org
 
@@ -32,6 +33,7 @@
 ;;; Code:
 
 (require 'cl-lib)
+(require 'org-agenda)
 (require 'ox-ascii)
 (declare-function org-bbdb-anniv-export-ical "ol-bbdb" nil)
 
@@ -281,7 +283,6 @@ re-read the iCalendar file.")
                     (inlinetask . ignore)
                     (planning . ignore)
                     (section . ignore)
-                    (inner-template . (lambda (c i) c))
                     (template . org-icalendar-template))
   :options-alist
   '((:exclude-tags
@@ -370,7 +371,6 @@ A headline is blocked when either
                   (1- (length org-icalendar-date-time-format)))
              ?Z))
 
-(defvar org-agenda-default-appointment-duration) ; From org-agenda.el.
 (defun org-icalendar-convert-timestamp (timestamp keyword &optional end tz)
   "Convert TIMESTAMP to iCalendar format.
 
@@ -722,7 +722,7 @@ Return VEVENT component as a string."
             "END:VEVENT"))))
 
 (defun org-icalendar--vtodo
-  (entry uid summary location description categories timezone class)
+    (entry uid summary location description categories timezone class)
   "Create a VTODO component.
 
 ENTRY is either a headline or an inlinetask element.  UID is the
@@ -849,7 +849,7 @@ CALSCALE:GREGORIAN\n"
 
 ;;;###autoload
 (defun org-icalendar-export-to-ics
-  (&optional async subtreep visible-only body-only)
+    (&optional async subtreep visible-only body-only)
   "Export current buffer to an iCalendar file.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox-koma-letter.el b/lisp/org/ox-koma-letter.el
new file mode 100644
index 0000000000..6a895a6a24
--- /dev/null
+++ b/lisp/org/ox-koma-letter.el
@@ -0,0 +1,989 @@
+;;; ox-koma-letter.el --- KOMA Scrlttr2 Back-End for Org Export Engine  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2007-2021  Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <n.goaziou AT gmail DOT com>
+;;         Alan Schmitt <alan.schmitt AT polytechnique DOT org>
+;;         Viktor Rosenfeld <listuser36 AT gmail DOT com>
+;;         Rasmus Pank Roulund <emacs AT pank DOT eu>
+;; Maintainer: Marco Wahl <marcowahlsoft@gmail.com>
+;; Keywords: org, wp, tex
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This library implements a KOMA Scrlttr2 back-end, derived from the
+;; LaTeX one.
+;;
+;; Depending on the desired output format, three commands are provided
+;; for export: `org-koma-letter-export-as-latex' (temporary buffer),
+;; `org-koma-letter-export-to-latex' ("tex" file) and
+;; `org-koma-letter-export-to-pdf' ("pdf" file).
+;;
+;; On top of buffer keywords supported by `latex' back-end (see
+;; `org-latex-options-alist'), this back-end introduces the following
+;; keywords:
+;;   - CLOSING: see `org-koma-letter-closing',
+;;   - FROM_ADDRESS: see `org-koma-letter-from-address',
+;;   - LCO: see `org-koma-letter-class-option-file',
+;;   - OPENING: see `org-koma-letter-opening',
+;;   - PHONE_NUMBER: see `org-koma-letter-phone-number',
+;;   - URL: see `org-koma-letter-url',
+;;   - FROM_LOGO: see `org-koma-letter-from-logo',
+;;   - SIGNATURE: see `org-koma-letter-signature',
+;;   - PLACE: see `org-koma-letter-place',
+;;   - LOCATION: see `org-koma-letter-location',
+;;   - TO_ADDRESS:  If unspecified this is set to "\mbox{}".
+;;
+;; TO_ADDRESS, FROM_ADDRESS, LOCATION, CLOSING, and SIGNATURE can also
+;; be specified using "special headings" with the special tags
+;; specified in `org-koma-letter-special-tags-in-letter'.  LaTeX line
+;; breaks are not necessary for TO_ADDRESS, FROM_ADDRESS and LOCATION.
+;; If both a headline and a keyword specify a to or from address the
+;; value is determined in accordance with
+;; `org-koma-letter-prefer-special-headings'.
+;;
+;; A number of OPTIONS settings can be set to change which contents is
+;; exported.
+;;   - backaddress (see `org-koma-letter-use-backaddress')
+;;   - foldmarks (see `org-koma-letter-use-foldmarks')
+;;   - phone (see `org-koma-letter-use-phone')
+;;   - url (see `org-koma-letter-use-url')
+;;   - from-logo (see `org-koma-letter-use-from-logo')
+;;   - email (see `org-koma-letter-use-email')
+;;   - place (see `org-koma-letter-use-place')
+;;   - location (see `org-koma-letter-use-location')
+;;   - subject, a list of format options
+;;     (see `org-koma-letter-subject-format')
+;;   - after-closing-order, a list of the ordering of headings with
+;;     special tags after closing (see
+;;     `org-koma-letter-special-tags-after-closing')
+;;   - after-letter-order, as above, but after the end of the letter
+;;     (see `org-koma-letter-special-tags-after-letter').
+;;
+;; The following variables works differently from the main LaTeX class
+;;   - AUTHOR: Default to user-full-name but may be disabled.
+;;     (See also `org-koma-letter-author'.)
+;;   - EMAIL: Same as AUTHOR.  (See also `org-koma-letter-email'.)
+;;
+;; FROM_LOGO uses LaTeX markup.  FROM_LOGO provides the
+;; "includegraphics" command to tell LaTeX where to find the logo.
+;; This command needs to know the logo's directory and file name.  The
+;; directory can either be relative or absolute, just as you would
+;; expect.  LaTeX can use three file types for the logo: PDF, JPEG, or
+;; PNG.  The logo can either include or exclude its extension, which
+;; might surprise you.  When you exclude its extension, LaTeX will
+;; search the directory for the "best" quality graphics format.  For
+;; example if it finds both logo.pdf and logo.png then it will
+;; identify the PDF as "better", and include "logo.pdf".  This can be
+;; useful, for example, when you are mocking up a logo in the PNG
+;; raster format and then switch over to the higher quality PDF vector
+;; format.  When you include the file extension then LaTeX will
+;; include it without searching for higher quality file types.
+;; Whatever file type you choose, it will probably require a few
+;; design iterations to get the best looking logo size for your
+;; letter.  Finally, the directory and file name are specified
+;; *without* quotes.  Here are some examples with commentary, in the
+;; location of your letter, with a logo named "logo", to get you
+;; started:
+;;
+;;   Logo in the same directory: \includegraphics{logo}
+;;       or a sub-directory:     \includegraphics{logos/production/logo}
+;;
+;;   Logos specified using absolute paths on Linux or Windows:
+;;
+;;       \includegraphics{~/correspondence/logo}
+;;       \includegraphics{~/correspondence/logos/production/logo}
+;;       \includegraphics{c:/you/correspondence/logo}
+;;       \includegraphics{c:/you/correspondence/logos/production/logo}
+;;
+;;   Logos in the same directory where the "better" quality PDF will
+;;   be chosen over the JPG:
+;;
+;;       \includegraphics{logo.pdf}
+;;       \includegraphics{logo.png}
+;;
+;; Headlines are in general ignored.  However, headlines with special
+;; tags can be used for specified contents like postscript (ps),
+;; carbon copy (cc), enclosures (encl) and code to be inserted after
+;; \end{letter} (after_letter).  Specials tags are defined in
+;; `org-koma-letter-special-tags-after-closing' and
+;; `org-koma-letter-special-tags-after-letter'.  Currently members of
+;; `org-koma-letter-special-tags-after-closing' used as macros and the
+;; content of the headline is the argument.
+;;
+;; Headlines with to and from may also be used rather than the keyword
+;; approach described above.  If both a keyword and a headline with
+;; information is present precedence is determined by
+;; `org-koma-letter-prefer-special-headings'.
+;;
+;; You need an appropriate association in `org-latex-classes' in order
+;; to use the KOMA Scrlttr2 class.  By default, a sparse scrlttr2
+;; class is provided: "default-koma-letter".  You can also add you own
+;; letter class.  For instance:
+;;
+;;   (add-to-list 'org-latex-classes
+;;                '("my-letter"
+;;                  "\\documentclass\[%
+;;   DIV=14,
+;;   fontsize=12pt,
+;;   parskip=half,
+;;   subject=titled,
+;;   backaddress=false,
+;;   fromalign=left,
+;;   fromemail=true,
+;;   fromphone=true\]\{scrlttr2\}
+;;   \[DEFAULT-PACKAGES]
+;;   \[PACKAGES]
+;;   \[EXTRA]"))
+;;
+;; Then, in your Org document, be sure to require the proper class
+;; with:
+;;
+;;    #+LATEX_CLASS: my-letter
+;;
+;; Or by setting `org-koma-letter-default-class'.
+;;
+;; You may have to load (LaTeX) Babel as well, e.g., by adding
+;; it to `org-latex-packages-alist',
+;;
+;;    (add-to-list 'org-latex-packages-alist '("AUTO" "babel" nil))
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'ox-latex)
+
+;; Install a default letter class.
+(unless (assoc "default-koma-letter" org-latex-classes)
+  (add-to-list 'org-latex-classes
+               '("default-koma-letter" "\\documentclass[11pt]{scrlttr2}")))
+
+
+;;; User-Configurable Variables
+
+(defgroup org-export-koma-letter nil
+  "Options for exporting to KOMA scrlttr2 class in LaTeX export."
+  :tag "Org Koma-Letter"
+  :group 'org-export)
+
+(defcustom org-koma-letter-class-option-file "NF"
+  "Letter Class Option File.
+This option can also be set with the LCO keyword."
+  :type 'string)
+
+(defcustom org-koma-letter-author 'user-full-name
+  "Sender's name.
+
+This variable defaults to calling the function `user-full-name'
+which just returns the current function `user-full-name'.
+Alternatively a string, nil or a function may be given.
+Functions must return a string.
+
+This option can also be set with the AUTHOR keyword."
+  :type '(radio (function-item user-full-name)
+                (string)
+                (function)
+                (const :tag "Do not export author" nil)))
+
+(defcustom org-koma-letter-email 'org-koma-letter-email
+  "Sender's email address.
+
+This variable defaults to the value `org-koma-letter-email' which
+returns `user-mail-address'.  Alternatively a string, nil or
+a function may be given.  Functions must return a string.
+
+This option can also be set with the EMAIL keyword."
+  :type '(radio (function-item org-koma-letter-email)
+                (string)
+                (function)
+                (const :tag "Do not export email" nil)))
+
+(defcustom org-koma-letter-from-address ""
+  "Sender's address, as a string.
+This option can also be set with one or more FROM_ADDRESS
+keywords."
+  :type 'string)
+
+(defcustom org-koma-letter-phone-number ""
+  "Sender's phone number, as a string.
+This option can also be set with the PHONE_NUMBER keyword."
+  :type 'string)
+
+(defcustom org-koma-letter-url ""
+  "Sender's URL, e. g., the URL of her homepage.
+This option can also be set with the URL keyword."
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-koma-letter-from-logo ""
+  "Commands for inserting the sender's logo, e. g., \\includegraphics{logo}.
+This option can also be set with the FROM_LOGO keyword."
+  :type 'string
+  :safe #'stringp)
+
+(defcustom org-koma-letter-place ""
+  "Place from which the letter is sent, as a string.
+This option can also be set with the PLACE keyword."
+  :type 'string)
+
+(defcustom org-koma-letter-location ""
+  "Sender's extension field, as a string.
+
+This option can also be set with the LOCATION keyword.
+Moreover, when:
+  (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+      or there is no LOCATION keyword or the LOCATION keyword is
+      empty;
+  (2) the letter contains a headline with the special
+      tag \"location\";
+then the location will be set as the content of the location
+special heading.
+
+The location field is typically printed right of the address
+field (See Figure 4.9. in the English manual of 2015-10-03)."
+  :type 'string)
+
+(defcustom org-koma-letter-opening ""
+  "Letter's opening, as a string.
+
+This option can also be set with the OPENING keyword.  Moreover,
+when:
+  (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+      or the CLOSING keyword is empty
+  (2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
+  (3) the letter contains a headline without a special
+      tag (e.g. \"to\" or \"ps\");
+then the opening will be implicitly set as the untagged headline title."
+  :type 'string)
+
+(defcustom org-koma-letter-closing ""
+  "Letter's closing, as a string.
+This option can also be set with the CLOSING keyword.  Moreover,
+when:
+  (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+      or the CLOSING keyword is empty;
+  (2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
+  (3) the letter contains a headline with the special
+      tag \"closing\";
+then the opening will be set as the title of the closing special
+heading title."
+  :type 'string)
+
+(defcustom org-koma-letter-signature ""
+  "Signature, as a string.
+This option can also be set with the SIGNATURE keyword.
+Moreover, when:
+  (1) Either `org-koma-letter-prefer-special-headings' is non-nil
+      or there is no CLOSING keyword or the CLOSING keyword is empty;
+  (2) `org-koma-letter-headline-is-opening-maybe' is non-nil;
+  (3) the letter contains a headline with the special
+      tag \"closing\";
+then the signature will be  set as the content of the
+closing special heading.
+
+Note if the content is empty the signature will not be set."
+  :type 'string)
+
+(defcustom org-koma-letter-prefer-special-headings nil
+  "Non-nil means prefer headlines over keywords for TO and FROM.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"special-headings:t\"."
+  :type 'boolean)
+
+(defcustom org-koma-letter-subject-format t
+  "Non-nil means include the subject.
+
+Support formatting options.
+
+When t, insert a subject using default options.  When nil, do not
+insert a subject at all.  It can also be a list of symbols among
+the following ones:
+
+ `afteropening'  Subject after opening
+ `beforeopening' Subject before opening
+ `centered'      Subject centered
+ `left'          Subject left-justified
+ `right'         Subject right-justified
+ `titled'        Add title/description to subject
+ `underlined'    Set subject underlined
+ `untitled'      Do not add title/description to subject
+
+Please refer to the KOMA-script manual (Table 4.16. in the
+English manual of 2012-07-22).
+
+This option can also be set with the OPTIONS keyword, e.g.:
+\"subject:(underlined centered)\"."
+  :type
+  '(choice
+    (const :tag "No export" nil)
+    (const :tag "Default options" t)
+    (set :tag "Configure options"
+         (const :tag "Subject after opening" afteropening)
+         (const :tag "Subject before opening" beforeopening)
+         (const :tag "Subject centered" centered)
+         (const :tag "Subject left-justified" left)
+         (const :tag "Subject right-justified" right)
+         (const :tag "Add title or description to subject" underlined)
+         (const :tag "Set subject underlined" titled)
+         (const :tag "Do not add title or description to subject" untitled))))
+
+(defcustom org-koma-letter-use-backaddress nil
+  "Non-nil prints return address in line above to address.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"backaddress:t\"."
+  :type 'boolean)
+
+(defcustom org-koma-letter-use-foldmarks t
+  "Configure appearance of folding marks.
+
+When t, activate default folding marks.  When nil, do not insert
+folding marks at all.  It can also be a list of symbols among the
+following ones:
+
+  `B'  Activate upper horizontal mark on left paper edge
+  `b'  Deactivate upper horizontal mark on left paper edge
+
+  `H'  Activate all horizontal marks on left paper edge
+  `h'  Deactivate all horizontal marks on left paper edge
+
+  `L'  Activate left vertical mark on upper paper edge
+  `l'  Deactivate left vertical mark on upper paper edge
+
+  `M'  Activate middle horizontal mark on left paper edge
+  `m'  Deactivate middle horizontal mark on left paper edge
+
+  `P'  Activate punch or center mark on left paper edge
+  `p'  Deactivate punch or center mark on left paper edge
+
+  `T'  Activate lower horizontal mark on left paper edge
+  `t'  Deactivate lower horizontal mark on left paper edge
+
+  `V'  Activate all vertical marks on upper paper edge
+  `v'  Deactivate all vertical marks on upper paper edge
+
+This option can also be set with the OPTIONS keyword, e.g.:
+\"foldmarks:(b l m t)\"."
+  :type '(choice
+          (const :tag "Activate default folding marks" t)
+          (const :tag "Deactivate folding marks" nil)
+          (set
+           :tag "Configure folding marks"
+           (const :tag "Activate upper horizontal mark on left paper edge" B)
+           (const :tag "Deactivate upper horizontal mark on left paper edge" b)
+           (const :tag "Activate all horizontal marks on left paper edge" H)
+           (const :tag "Deactivate all horizontal marks on left paper edge" h)
+           (const :tag "Activate left vertical mark on upper paper edge" L)
+           (const :tag "Deactivate left vertical mark on upper paper edge" l)
+           (const :tag "Activate middle horizontal mark on left paper edge" M)
+           (const :tag "Deactivate middle horizontal mark on left paper edge" 
m)
+           (const :tag "Activate punch or center mark on left paper edge" P)
+           (const :tag "Deactivate punch or center mark on left paper edge" p)
+           (const :tag "Activate lower horizontal mark on left paper edge" T)
+           (const :tag "Deactivate lower horizontal mark on left paper edge" t)
+           (const :tag "Activate all vertical marks on upper paper edge" V)
+           (const :tag "Deactivate all vertical marks on upper paper edge" 
v))))
+
+(defcustom org-koma-letter-use-phone nil
+  "Non-nil prints sender's phone number.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"phone:t\"."
+  :type 'boolean)
+
+(defcustom org-koma-letter-use-url nil
+  "Non-nil prints sender's URL.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"url:t\"."
+  :type 'boolean
+  :safe #'booleanp)
+
+(defcustom org-koma-letter-use-from-logo nil
+  "Non-nil prints sender's FROM_LOGO.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"from-logo:t\"."
+  :type 'boolean
+  :safe #'booleanp)
+
+(defcustom org-koma-letter-use-email nil
+  "Non-nil prints sender's email address.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"email:t\"."
+  :type 'boolean)
+
+(defcustom org-koma-letter-use-place t
+  "Non-nil prints the letter's place next to the date.
+This option can also be set with the OPTIONS keyword, e.g.:
+\"place:nil\"."
+  :type 'boolean)
+
+(defcustom org-koma-letter-default-class "default-koma-letter"
+  "Default class for `org-koma-letter'.
+The value must be a member of `org-latex-classes'."
+  :type 'string)
+
+(defcustom org-koma-letter-headline-is-opening-maybe t
+  "Non-nil means a headline may be used as an opening and closing.
+See also `org-koma-letter-opening' and
+`org-koma-letter-closing'."
+  :type 'boolean)
+
+(defcustom org-koma-letter-prefer-subject nil
+  "Non-nil means title should be interpreted as subject if subject is missing.
+This option can also be set with the OPTIONS keyword,
+e.g. \"title-subject:t\"."
+  :type 'boolean)
+
+(defconst org-koma-letter-special-tags-in-letter '(to from closing location)
+  "Header tags related to the letter itself.")
+
+(defconst org-koma-letter-special-tags-after-closing '(after_closing ps encl 
cc)
+  "Header tags to be inserted in the letter after closing.")
+
+(defconst org-koma-letter-special-tags-as-macro '(ps encl cc)
+  "Header tags to be inserted as macros.")
+
+(defconst org-koma-letter-special-tags-after-letter '(after_letter)
+  "Header tags to be inserted after the letter.")
+
+(defvar org-koma-letter-special-contents nil
+  "Holds special content temporarily.")
+
+
+;;; Define Back-End
+
+(org-export-define-derived-backend 'koma-letter 'latex
+  :options-alist
+  '((:latex-class "LATEX_CLASS" nil org-koma-letter-default-class t)
+    (:lco "LCO" nil org-koma-letter-class-option-file)
+    (:author "AUTHOR" nil (org-koma-letter--get-value org-koma-letter-author) 
parse)
+    (:author-changed-in-buffer-p "AUTHOR" nil nil t)
+    (:from-address "FROM_ADDRESS" nil org-koma-letter-from-address newline)
+    (:phone-number "PHONE_NUMBER" nil org-koma-letter-phone-number)
+    (:url "URL" nil org-koma-letter-url)
+    (:from-logo "FROM_LOGO" nil org-koma-letter-from-logo)
+    (:email "EMAIL" nil (org-koma-letter--get-value org-koma-letter-email) t)
+    (:to-address "TO_ADDRESS" nil nil newline)
+    (:place "PLACE" nil org-koma-letter-place)
+    (:location "LOCATION" nil org-koma-letter-location)
+    (:subject "SUBJECT" nil nil parse)
+    (:opening "OPENING" nil org-koma-letter-opening parse)
+    (:closing "CLOSING" nil org-koma-letter-closing parse)
+    (:signature "SIGNATURE" nil org-koma-letter-signature newline)
+    (:special-headings nil "special-headings" 
org-koma-letter-prefer-special-headings)
+    (:special-tags-as-macro nil nil org-koma-letter-special-tags-as-macro)
+    (:special-tags-in-letter nil nil org-koma-letter-special-tags-in-letter)
+    (:special-tags-after-closing nil "after-closing-order"
+                                 org-koma-letter-special-tags-after-closing)
+    (:special-tags-after-letter nil "after-letter-order"
+                                org-koma-letter-special-tags-after-letter)
+    (:with-backaddress nil "backaddress" org-koma-letter-use-backaddress)
+    (:with-email nil "email" org-koma-letter-use-email)
+    (:with-foldmarks nil "foldmarks" org-koma-letter-use-foldmarks)
+    (:with-phone nil "phone" org-koma-letter-use-phone)
+    (:with-url nil "url" org-koma-letter-use-url)
+    (:with-from-logo nil "from-logo" org-koma-letter-use-from-logo)
+    (:with-place nil "place" org-koma-letter-use-place)
+    (:with-subject nil "subject" org-koma-letter-subject-format)
+    (:with-title-as-subject nil "title-subject" org-koma-letter-prefer-subject)
+    (:with-headline-opening nil nil org-koma-letter-headline-is-opening-maybe)
+    ;; Special properties non-nil when a setting happened in buffer.
+    ;; They are used to prioritize in-buffer settings over "lco"
+    ;; files.  See `org-koma-letter-template'.
+    (:inbuffer-author "AUTHOR" nil 'koma-letter:empty)
+    (:inbuffer-from "FROM" nil 'koma-letter:empty)
+    (:inbuffer-email "EMAIL" nil 'koma-letter:empty)
+    (:inbuffer-phone-number "PHONE_NUMBER" nil 'koma-letter:empty)
+    (:inbuffer-url "URL" nil 'koma-letter:empty)
+    (:inbuffer-from-logo "FROM_LOGO" nil 'koma-letter:empty)
+    (:inbuffer-place "PLACE" nil 'koma-letter:empty)
+    (:inbuffer-location "LOCATION" nil 'koma-letter:empty)
+    (:inbuffer-signature "SIGNATURE" nil 'koma-letter:empty)
+    (:inbuffer-with-backaddress nil "backaddress" 'koma-letter:empty)
+    (:inbuffer-with-email nil "email" 'koma-letter:empty)
+    (:inbuffer-with-foldmarks nil "foldmarks" 'koma-letter:empty)
+    (:inbuffer-with-phone nil "phone" 'koma-letter:empty)
+    (:inbuffer-with-url nil "url" 'koma-letter:empty)
+    (:inbuffer-with-from-logo nil "from-logo" 'koma-letter:empty)
+    (:inbuffer-with-place nil "place" 'koma-letter:empty))
+  :translate-alist '((export-block . org-koma-letter-export-block)
+                     (export-snippet . org-koma-letter-export-snippet)
+                     (headline . org-koma-letter-headline)
+                     (keyword . org-koma-letter-keyword)
+                     (template . org-koma-letter-template))
+  :menu-entry
+  '(?k "Export with KOMA Scrlttr2"
+       ((?L "As LaTeX buffer" org-koma-letter-export-as-latex)
+        (?l "As LaTeX file" org-koma-letter-export-to-latex)
+        (?p "As PDF file" org-koma-letter-export-to-pdf)
+        (?o "As PDF file and open"
+            (lambda (a s v b)
+              (if a (org-koma-letter-export-to-pdf t s v b)
+                (org-open-file (org-koma-letter-export-to-pdf nil s v b))))))))
+
+
+
+;;; Helper functions
+
+(defun org-koma-letter-email ()
+  "Return the current `user-mail-address'."
+  user-mail-address)
+
+;; The following is taken from/inspired by ox-grof.el
+;; Thanks, Luis!
+
+(defun org-koma-letter--get-tagged-contents (key)
+  "Get contents from a headline tagged with KEY.
+The contents is stored in `org-koma-letter-special-contents'."
+  (let ((value (cdr (assoc-string (org-koma-letter--get-value key)
+                                  org-koma-letter-special-contents))))
+    (when value (org-string-nw-p (org-trim value)))))
+
+(defun org-koma-letter--get-value (value)
+  "Turn value into a string whenever possible.
+Determines if VALUE is nil, a string, a function or a symbol and
+return a string or nil."
+  (when value
+    (cond ((stringp value) value)
+          ((functionp value) (funcall value))
+          ((symbolp value) (symbol-name value))
+          (t value))))
+
+(defun org-koma-letter--special-contents-inline (keywords info)
+  "Process KEYWORDS members of `org-koma-letter-special-contents'.
+
+KEYWORDS is a list of symbols.  Return them as a string to be
+formatted.
+
+The function is used for inserting content of special headings
+such as the one tagged with PS."
+  (mapconcat
+   (lambda (keyword)
+     (let* ((name (org-koma-letter--get-value keyword))
+            (value (org-koma-letter--get-tagged-contents name))
+            (macrop (memq keyword (plist-get info :special-tags-as-macro))))
+       (cond ((not value) nil)
+             (macrop (format "\\%s{%s}\n" name value))
+             (t value))))
+   keywords
+   "\n"))
+
+
+(defun org-koma-letter--add-latex-newlines (string)
+  "Replace regular newlines with LaTeX newlines (i.e. `\\\\')."
+  (let ((str (org-trim string)))
+    (when (org-string-nw-p str)
+      (replace-regexp-in-string "\n" "\\\\\\\\\n" str))))
+
+
+
+;;; Transcode Functions
+
+;;;; Export Block
+
+(defun org-koma-letter-export-block (export-block _contents _info)
+  "Transcode an EXPORT-BLOCK element into KOMA Scrlttr2 code.
+CONTENTS is nil.  INFO is a plist used as a communication
+channel."
+  (when (member (org-element-property :type export-block)
+               '("KOMA-LETTER" "LATEX"))
+    (org-remove-indentation (org-element-property :value export-block))))
+
+;;;; Export Snippet
+
+(defun org-koma-letter-export-snippet (export-snippet _contents _info)
+  "Transcode an EXPORT-SNIPPET object into KOMA Scrlttr2 code.
+CONTENTS is nil.  INFO is a plist used as a communication
+channel."
+  (when (memq (org-export-snippet-backend export-snippet) '(latex koma-letter))
+    (org-element-property :value export-snippet)))
+
+;;;; Keyword
+
+(defun org-koma-letter-keyword (keyword contents info)
+  "Transcode a KEYWORD element into KOMA Scrlttr2 code.
+CONTENTS is nil.  INFO is a plist used as a communication
+channel."
+  (let ((key (org-element-property :key keyword))
+        (value (org-element-property :value keyword)))
+    ;; Handle specifically KOMA-LETTER keywords.  Otherwise, fallback
+    ;; to `latex' back-end.
+    (if (equal key "KOMA-LETTER") value
+      (org-export-with-backend 'latex keyword contents info))))
+
+;; Headline
+
+(defun org-koma-letter-headline (headline contents info)
+  "Transcode a HEADLINE element from Org to LaTeX.
+CONTENTS holds the contents of the headline.  INFO is a plist
+holding contextual information.
+
+Note that if a headline is tagged with a tag from
+`org-koma-letter-special-tags' it will not be exported, but
+stored in `org-koma-letter-special-contents' and included at the
+appropriate place."
+  (let ((special-tag (org-koma-letter--special-tag headline info)))
+    (if (not special-tag)
+        contents
+      (push (cons special-tag contents) org-koma-letter-special-contents)
+      "")))
+
+(defun org-koma-letter--special-tag (headline info)
+  "Non-nil if HEADLINE is a special headline.
+INFO is a plist holding contextual information.  Return first
+special tag headline."
+  (let ((special-tags (append
+                       (plist-get info :special-tags-in-letter)
+                       (plist-get info :special-tags-after-closing)
+                       (plist-get info :special-tags-after-letter))))
+    (cl-some (lambda (tag) (and (assoc-string tag special-tags) tag))
+            (org-export-get-tags headline info))))
+
+(defun org-koma-letter--keyword-or-headline (plist-key pred info)
+  "Return the correct version of opening or closing.
+PLIST-KEY should be a key in info, typically :opening
+or :closing.  PRED is a predicate run on headline to determine
+which title to use which takes two arguments, a headline element
+and an info plist.  INFO is a plist holding contextual
+information.  Return the preferred candidate for the exported of
+PLIST-KEY."
+  (let* ((keyword-candidate (plist-get info plist-key))
+         (headline-candidate (when (and (plist-get info :with-headline-opening)
+                                        (or (plist-get info :special-headings)
+                                            (not keyword-candidate)))
+                               (org-element-map (plist-get info :parse-tree)
+                                   'headline
+                                 (lambda (h)
+                                   (and (funcall pred h info)
+                                       (org-element-property :title h)))
+                                 info t))))
+    (org-export-data (or headline-candidate keyword-candidate "") info)))
+
+;;;; Template
+
+(defun org-koma-letter-template (contents info)
+  "Return complete document string after KOMA Scrlttr2 conversion.
+CONTENTS is the transcoded contents string.  INFO is a plist
+holding export options."
+  (concat
+   ;; Time-stamp.
+   (and (plist-get info :time-stamp-file)
+        (format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
+   ;; LaTeX compiler
+   (org-latex--insert-compiler info)
+   ;; Document class and packages.
+   (org-latex-make-preamble info)
+   ;; Settings.  They can come from three locations, in increasing
+   ;; order of precedence: global variables, LCO files and in-buffer
+   ;; settings.  Thus, we first insert settings coming from global
+   ;; variables, then we insert LCO files, and, eventually, we insert
+   ;; settings coming from buffer keywords.
+   (org-koma-letter--build-settings 'global info)
+   (mapconcat (lambda (file) (format "\\LoadLetterOption{%s}\n" file))
+              (split-string (or (plist-get info :lco) ""))
+              "")
+   (org-koma-letter--build-settings 'buffer info)
+   ;; Date.
+   (format "\\date{%s}\n" (org-export-data (org-export-get-date info) info))
+   ;; Hyperref, document start, and subject and title.
+   (let* ((with-subject (plist-get info :with-subject))
+          (with-title (plist-get info :with-title))
+          (title-as-subject (and with-subject
+                                 (plist-get info :with-title-as-subject)))
+          (subject* (org-string-nw-p
+                     (org-export-data (plist-get info :subject) info)))
+          (title* (and with-title
+                       (org-string-nw-p
+                        (org-export-data (plist-get info :title) info))))
+          (subject (cond ((not with-subject) nil)
+                         (title-as-subject (or subject* title*))
+                         (t subject*)))
+          (title (cond ((not with-title) nil)
+                       (title-as-subject (and subject* title*))
+                       (t title*)))
+          (hyperref-template (plist-get info :latex-hyperref-template))
+          (spec (append (list (cons ?t (or title subject "")))
+                        (org-latex--format-spec info))))
+     (concat
+      (when (and with-subject (not (eq with-subject t)))
+        (format "\\KOMAoption{subject}{%s}\n"
+                (if (symbolp with-subject) with-subject
+                  (mapconcat #'symbol-name with-subject ","))))
+      ;; Hyperref.
+      (and (stringp hyperref-template)
+          (format-spec hyperref-template spec))
+      ;; Document start.
+      "\\begin{document}\n\n"
+      ;; Subject and title.
+      (when subject (format "\\setkomavar{subject}{%s}\n" subject))
+      (when title (format "\\setkomavar{title}{%s}\n" title))
+      (when (or (org-string-nw-p title) (org-string-nw-p subject)) "\n")))
+   ;; Letter start.
+   (let ((keyword-val (plist-get info :to-address))
+         (heading-val (org-koma-letter--get-tagged-contents 'to)))
+     (format "\\begin{letter}{%%\n%s}\n\n"
+             (org-koma-letter--add-latex-newlines
+              (or (if (plist-get info :special-headings)
+                      (or heading-val keyword-val)
+                    (or keyword-val heading-val))
+                  "\\mbox{}"))))
+   ;; Opening.
+   (format "\\opening{%s}\n\n"
+           (org-koma-letter--keyword-or-headline
+            :opening
+           (lambda (h i)
+             (not (org-koma-letter--special-tag h i)))
+            info))
+   ;; Letter body.
+   contents
+   ;; Closing.
+   (format "\\closing{%s}\n"
+          (org-koma-letter--keyword-or-headline
+           :closing
+           (lambda (h i)
+             (let ((special-tag (org-koma-letter--special-tag h i)))
+               (and special-tag
+                    (string= "closing" special-tag))))
+           info))
+   (org-koma-letter--special-contents-inline
+    (plist-get info :special-tags-after-closing) info)
+   ;; Letter end.
+   "\n\\end{letter}\n"
+   (org-koma-letter--special-contents-inline
+    (plist-get info :special-tags-after-letter) info)
+   ;; Document end.
+   "\n\\end{document}"))
+
+(defun org-koma-letter--build-settings (scope info)
+  "Build settings string according to type.
+SCOPE is either `global' or `buffer'.  INFO is a plist used as
+a communication channel."
+  (let* ((check-scope
+          ;; Non-nil value when SETTING was defined in SCOPE.
+          (lambda (setting)
+            (let ((property (intern (format ":inbuffer-%s" setting))))
+              (if (eq scope 'global)
+                  (eq (plist-get info property) 'koma-letter:empty)
+                (not (eq (plist-get info property) 'koma-letter:empty))))))
+         (heading-or-key-value
+          (lambda (heading key &optional scoped)
+            (let* ((heading-val
+                    (org-koma-letter--get-tagged-contents heading))
+                   (key-val (org-string-nw-p (plist-get info key)))
+                   (scopedp (funcall check-scope (or scoped heading))))
+              (and (or (and key-val scopedp) heading-val)
+                   (not (and (eq scope 'global) heading-val))
+                   (if scopedp key-val heading-val))))))
+    (concat
+     ;; Name.
+     (let ((author (plist-get info :author)))
+       (and author
+            (funcall check-scope 'author)
+            (format "\\setkomavar{fromname}{%s}\n"
+                    (org-export-data author info))))
+     ;; From.
+     (let ((from (funcall heading-or-key-value 'from :from-address)))
+       (and from
+            (format "\\setkomavar{fromaddress}{%s}\n"
+                    (org-koma-letter--add-latex-newlines from))))
+     ;; Email.
+     (let ((email (plist-get info :email)))
+       (and email
+            (funcall check-scope 'email)
+            (format "\\setkomavar{fromemail}{%s}\n" email)))
+     (and (funcall check-scope 'with-email)
+          (format "\\KOMAoption{fromemail}{%s}\n"
+                  (if (plist-get info :with-email) "true" "false")))
+     ;; Phone number.
+     (let ((phone-number (plist-get info :phone-number)))
+       (and (org-string-nw-p phone-number)
+            (funcall check-scope 'phone-number)
+            (format "\\setkomavar{fromphone}{%s}\n" phone-number)))
+     (and (funcall check-scope 'with-phone)
+          (format "\\KOMAoption{fromphone}{%s}\n"
+                  (if (plist-get info :with-phone) "true" "false")))
+     ;; URL
+     (let ((url (plist-get info :url)))
+       (and (org-string-nw-p url)
+            (funcall check-scope 'url)
+            (format "\\setkomavar{fromurl}{%s}\n" url)))
+     (and (funcall check-scope 'with-url)
+          (format "\\KOMAoption{fromurl}{%s}\n"
+                  (if (plist-get info :with-url) "true" "false")))
+     ;; From Logo
+     (let ((from-logo (plist-get info :from-logo)))
+       (and (org-string-nw-p from-logo)
+            (funcall check-scope 'from-logo)
+            (format "\\setkomavar{fromlogo}{%s}\n" from-logo)))
+     (and (funcall check-scope 'with-from-logo)
+          (format "\\KOMAoption{fromlogo}{%s}\n"
+                  (if (plist-get info :with-from-logo) "true" "false")))
+     ;; Signature.
+     (let* ((heading-val
+             (and (plist-get info :with-headline-opening)
+                  (pcase (org-koma-letter--get-tagged-contents 'closing)
+                    ((and (pred org-string-nw-p) closing) (org-trim closing))
+                    (_ nil))))
+            (signature (org-string-nw-p (plist-get info :signature)))
+            (signature-scope (funcall check-scope 'signature)))
+       (and (or (and signature signature-scope)
+                heading-val)
+            (not (and (eq scope 'global) heading-val))
+            (format "\\setkomavar{signature}{%s}\n"
+                    (if signature-scope signature heading-val))))
+     ;; Back address.
+     (and (funcall check-scope 'with-backaddress)
+          (format "\\KOMAoption{backaddress}{%s}\n"
+                  (if (plist-get info :with-backaddress) "true" "false")))
+     ;; Place.
+     (let ((with-place-set (funcall check-scope 'with-place))
+           (place-set (funcall check-scope 'place)))
+       (and (or (and with-place-set place-set)
+                (and (eq scope 'buffer) (or with-place-set place-set)))
+            (format "\\setkomavar{place}{%s}\n"
+                    (if (plist-get info :with-place) (plist-get info :place)
+                      ""))))
+     ;; Location.
+     (let ((location (funcall heading-or-key-value 'location :location)))
+       (and location
+            (format "\\setkomavar{location}{%s}\n" location)))
+     ;; Folding marks.
+     (and (funcall check-scope 'with-foldmarks)
+          (let ((foldmarks (plist-get info :with-foldmarks)))
+            (cond ((consp foldmarks)
+                   (format "\\KOMAoptions{foldmarks=true,foldmarks=%s}\n"
+                           (mapconcat #'symbol-name foldmarks "")))
+                  (foldmarks "\\KOMAoptions{foldmarks=true}\n")
+                  (t "\\KOMAoptions{foldmarks=false}\n")))))))
+
+
+
+;;; Commands
+
+;;;###autoload
+(defun org-koma-letter-export-as-latex
+    (&optional async subtreep visible-only body-only ext-plist)
+  "Export current buffer as a KOMA Scrlttr2 letter.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org KOMA-LETTER Export*\".  It
+will be displayed if `org-export-show-temporary-export-buffer' is
+non-nil."
+  (interactive)
+  (let (org-koma-letter-special-contents)
+    (org-export-to-buffer 'koma-letter "*Org KOMA-LETTER Export*"
+      async subtreep visible-only body-only ext-plist
+      (lambda () (LaTeX-mode)))))
+
+;;;###autoload
+(defun org-koma-letter-export-to-latex
+    (&optional async subtreep visible-only body-only ext-plist)
+  "Export current buffer as a KOMA Scrlttr2 letter (tex).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+When optional argument PUB-DIR is set, use it as the publishing
+directory.
+
+Return output file's name."
+  (interactive)
+  (let ((outfile (org-export-output-file-name ".tex" subtreep))
+        (org-koma-letter-special-contents))
+    (org-export-to-file 'koma-letter outfile
+      async subtreep visible-only body-only ext-plist)))
+
+;;;###autoload
+(defun org-koma-letter-export-to-pdf
+    (&optional async subtreep visible-only body-only ext-plist)
+  "Export current buffer as a KOMA Scrlttr2 letter (pdf).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously.  The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export the sub-tree
+at point, extracting information from the headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+When optional argument BODY-ONLY is non-nil, only write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return PDF file's name."
+  (interactive)
+  (let ((file (org-export-output-file-name ".tex" subtreep))
+        (org-koma-letter-special-contents))
+    (org-export-to-file 'koma-letter file
+      async subtreep visible-only body-only ext-plist
+      (lambda (file) (org-latex-compile file)))))
+
+
+(provide 'ox-koma-letter)
+;;; ox-koma-letter.el ends here
diff --git a/lisp/org/ox-latex.el b/lisp/org/ox-latex.el
index 149492fa84..3e3967033a 100644
--- a/lisp/org/ox-latex.el
+++ b/lisp/org/ox-latex.el
@@ -121,6 +121,7 @@
     (:latex-classes nil nil org-latex-classes)
     (:latex-default-figure-position nil nil org-latex-default-figure-position)
     (:latex-default-table-environment nil nil 
org-latex-default-table-environment)
+    (:latex-default-quote-environment nil nil 
org-latex-default-quote-environment)
     (:latex-default-table-mode nil nil org-latex-default-table-mode)
     (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format)
     (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format)
@@ -296,7 +297,7 @@
     ("uk" "ukrainian")
     ("ur" "urdu")
     ("vi" "vietnamese"))
-  "Alist between language code and corresponding Polyglossia option")
+  "Alist between language code and corresponding Polyglossia option.")
 
 (defconst org-latex-table-matrix-macros '(("bordermatrix" . "\\cr")
                                          ("qbordermatrix" . "\\cr")
@@ -307,14 +308,14 @@
   (format
    "\\`[ \t]*\\\\begin{%s\\*?}"
    (regexp-opt
-          '("equation" "eqnarray" "math" "displaymath"
-            "align"  "gather" "multline" "flalign"  "alignat"
-            "xalignat" "xxalignat"
-            "subequations"
-            ;; breqn
-            "dmath" "dseries" "dgroup" "darray"
-            ;; empheq
-            "empheq")))
+    '("equation" "eqnarray" "math" "displaymath"
+      "align"  "gather" "multline" "flalign"  "alignat"
+      "xalignat" "xxalignat"
+      "subequations"
+      ;; breqn
+      "dmath" "dseries" "dgroup" "darray"
+      ;; empheq
+      "empheq")))
   "Regexp of LaTeX math environments.")
 
 
@@ -345,7 +346,7 @@ symbols are: `image', `table', `src-block' and 
`special-block'."
               (const :tag "Special blocks" special-block))))
 
 (defcustom org-latex-prefer-user-labels nil
-   "Use user-provided labels instead of internal ones when non-nil.
+  "Use user-provided labels instead of internal ones when non-nil.
 
 When this variable is non-nil, Org will use the value of
 CUSTOM_ID property, NAME keyword or Org target as the key for the
@@ -380,6 +381,9 @@ will be exported to LaTeX as:
   This is section \\ref{sec:foo}.
   And this is still section \\ref{sec:foo}.
 
+A non-default value of `org-latex-reference-command' will change the
+command (\\ref by default) used to create label references.
+
 Note, however, that setting this variable introduces a limitation
 on the possible values for CUSTOM_ID and NAME.  When this
 variable is non-nil, Org passes their value to \\label unchanged.
@@ -399,6 +403,18 @@ references."
   :version "26.1"
   :package-version '(Org . "8.3"))
 
+(defcustom org-latex-reference-command "\\ref{%s}"
+  "Format string that takes a reference to produce a LaTeX reference command.
+
+The reference is a label such as sec:intro.  A format string of \"\\ref{%s}\"
+produces numbered references and will always work.  It may be desirable to make
+use of a package such as hyperref or cleveref and then change the format string
+to \"\\autoref{%s}\" or \"\\cref{%s}\" for example."
+  :group 'org-export-latex
+  :type 'string
+  :package-version '(Org . "9.5")
+  :safe #'stringp)
+
 ;;;; Preamble
 
 (defcustom org-latex-default-class "article"
@@ -772,6 +788,13 @@ default we use here encompasses both."
   :package-version '(Org . "8.0")
   :type 'string)
 
+(defcustom org-latex-default-quote-environment "quote"
+  "Default environment used to `quote' blocks."
+  :group 'org-export-latex
+  :package-version '(Org . "9.5")
+  :type 'string
+  :safe #'stringp)
+
 (defcustom org-latex-default-table-mode 'table
   "Default mode for tables.
 
@@ -932,7 +955,7 @@ using customize, or with
   (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\"))
 
 In addition, it is necessary to install pygments
-\(URL `http://pygments.org>'), and to configure the variable
+\(URL `https://pygments.org>'), and to configure the variable
 `org-latex-pdf-process' so that the -shell-escape option is
 passed to pdflatex.
 
@@ -956,7 +979,7 @@ URL 
`https://orgmode.org/worg/org-tutorials/org-latex-preview.html'."
     (tex "TeX") (latex "[LaTeX]TeX")
     (shell-script "bash")
     (gnuplot "Gnuplot")
-    (ocaml "Caml") (caml "Caml")
+    (ocaml "[Objective]Caml") (caml "Caml")
     (sql "SQL") (sqlite "sql")
     (makefile "make")
     (R "r"))
@@ -1157,9 +1180,11 @@ A better approach is to use a compiler suit such as 
`latexmk'."
   :package-version '(Org . "9.0"))
 
 (defcustom org-latex-pdf-process
-  '("%latex -interaction nonstopmode -output-directory %o %f"
-    "%latex -interaction nonstopmode -output-directory %o %f"
-    "%latex -interaction nonstopmode -output-directory %o %f")
+  (if (executable-find "latexmk")
+      '("latexmk -f -pdf -%latex -interaction=nonstopmode -output-directory=%o 
%f")
+    '("%latex -interaction nonstopmode -output-directory %o %f"
+      "%latex -interaction nonstopmode -output-directory %o %f"
+      "%latex -interaction nonstopmode -output-directory %o %f"))
   "Commands to process a LaTeX file to a PDF file.
 
 This is a list of strings, each of them will be given to the
@@ -1203,7 +1228,7 @@ file name as its single argument."
          (const :tag "texi2dvi"
                 ("cd %o; LATEX=\"%latex\" texi2dvi -p -b -V %b.tex"))
          (const :tag "latexmk"
-                ("latexmk -g -pdf -pdflatex=\"%latex\" -outdir=%o %f"))
+                ("latexmk -f -pdf -%latex -interaction=nonstopmode 
-output-directory=%o %f"))
          (function)))
 
 (defcustom org-latex-logfiles-extensions
@@ -1486,7 +1511,10 @@ nil."
               (pcase-let ((`(,keyword ,value) pair))
                 (concat keyword
                         (and (> (length value) 0)
-                             (concat "=" value)))))
+                             (concat "="
+                                      (if (string-match-p (rx (any "[]")) 
value)
+                                          (format "{%s}" value)
+                                        value))))))
             options
             ","))
 
@@ -1521,22 +1549,23 @@ INFO is a plist used as a communication channel.  See
                 separator
                 (replace-regexp-in-string "\n" " " text)
                 separator)))
-      ;; Handle the `protectedtexttt' special case: Protect some
-      ;; special chars and use "\texttt{%s}" format string.
-      (protectedtexttt
-       (format "\\texttt{%s}"
-              (replace-regexp-in-string
-               "--\\|[\\{}$%&_#~^]"
-               (lambda (m)
-                 (cond ((equal m "--") "-{}-")
-                       ((equal m "\\") "\\textbackslash{}")
-                       ((equal m "~") "\\textasciitilde{}")
-                       ((equal m "^") "\\textasciicircum{}")
-                       (t (org-latex--protect-text m))))
-               text nil t)))
+      (protectedtexttt (org-latex--protect-texttt text))
       ;; Else use format string.
       (t (format fmt text)))))
 
+(defun org-latex--protect-texttt (text)
+  "Protect special chars, then wrap TEXT in \"\\texttt{}\"."
+  (format "\\texttt{%s}"
+          (replace-regexp-in-string
+           "--\\|[\\{}$%&_#~^]"
+           (lambda (m)
+             (cond ((equal m "--") "-{}-")
+                   ((equal m "\\") "\\textbackslash{}")
+                   ((equal m "~") "\\textasciitilde{}")
+                   ((equal m "^") "\\textasciicircum{}")
+                   (t (org-latex--protect-text m))))
+           text nil t)))
+
 (defun org-latex--delayed-footnotes-definitions (element info)
   "Return footnotes definitions in ELEMENT as a string.
 
@@ -1604,9 +1633,9 @@ INFO is a plist used as a communication channel."
   "Insert LaTeX_compiler info into the document.
 INFO is a plist used as a communication channel."
   (let ((compiler (plist-get info :latex-compiler)))
-       (and (org-string-nw-p org-latex-compiler-file-string)
-           (member (or compiler "") org-latex-compilers)
-           (format org-latex-compiler-file-string compiler))))
+    (and (org-string-nw-p org-latex-compiler-file-string)
+        (member (or compiler "") org-latex-compilers)
+        (format org-latex-compiler-file-string compiler))))
 
 
 ;;; Filters
@@ -1888,10 +1917,11 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
                (org-export-get-footnote-definition footnote-reference info)
                info t)))
       ;; Use \footnotemark if reference is within another footnote
-      ;; reference, footnote definition, table cell or item's tag.
+      ;; reference, footnote definition, table cell, verse block, or
+      ;; item's tag.
       ((or (org-element-lineage footnote-reference
                                '(footnote-reference footnote-definition
-                                                    table-cell))
+                                                    table-cell verse-block))
           (eq 'item (org-element-type
                      (org-export-get-parent-element footnote-reference))))
        "\\footnotemark")
@@ -1903,7 +1933,8 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
                  ;; Only insert a \label if there exist another
                  ;; reference to def.
                  (cond ((not label) "")
-                       ((org-element-map (plist-get info :parse-tree) 
'footnote-reference
+                       ((org-element-map (plist-get info :parse-tree)
+                            'footnote-reference
                           (lambda (f)
                             (and (not (eq f footnote-reference))
                                  (equal (org-element-property :label f) label)
@@ -1952,10 +1983,16 @@ holding contextual information."
           ;; Create a temporary export back-end that hard-codes
           ;; "\underline" within "\section" and alike.
           (section-back-end
-           (org-export-create-backend
-            :parent 'latex
-            :transcoders
-            '((underline . (lambda (o c i) (format "\\underline{%s}" c))))))
+            (org-export-create-backend
+             :parent 'latex
+             :transcoders
+             '((underline . (lambda (o c i) (format "\\underline{%s}" c)))
+               ;; LaTeX isn't happy when you try to use \verb inside the 
argument of other
+               ;; commands (like \section, etc.), and this causes compilation 
to fail.
+               ;; So, within headings it's a good idea to replace any 
instances of \verb
+               ;; with \texttt.
+               (code . (lambda (o _ _) (org-latex--protect-texttt 
(org-element-property :value o))))
+               (verbatim . (lambda (o _ _) (org-latex--protect-texttt 
(org-element-property :value o)))))))
           (text
            (org-export-data-with-backend
             (org-element-property :title headline) section-back-end info))
@@ -2089,8 +2126,8 @@ contextual information."
   (let* ((code (org-element-property :value inline-src-block))
         (separator (org-latex--find-verb-separator code)))
     (cl-case (plist-get info :latex-listings)
-      ;; Do not use a special package: transcode it verbatim.
-      ((nil) (format "\\texttt{%s}" (org-latex--text-markup code 'code info)))
+      ;; Do not use a special package: transcode it verbatim, as code.
+      ((nil) (org-latex--text-markup code 'code info))
       ;; Use minted package.
       (minted
        (let* ((org-lang (org-element-property :language inline-src-block))
@@ -2375,8 +2412,8 @@ used as a communication channel."
                        ((string= float "sideways") 'sideways)
                        ((string= float "multicolumn") 'multicolumn)
                        ((and (plist-member attr :float) (not float)) 'nonfloat)
-                       ((or float
-                            (org-element-property :caption parent)
+                        (float float)
+                       ((or (org-element-property :caption parent)
                             (org-string-nw-p (plist-get attr :caption)))
                         'figure)
                        (t 'nonfloat))))
@@ -2468,6 +2505,18 @@ used as a communication channel."
                                                   nil t))))
     ;; Return proper string, depending on FLOAT.
     (pcase float
+      ((and (pred stringp) env-string)
+       (format "\\begin{%s}%s
+%s%s
+%s%s
+%s\\end{%s}"
+               env-string
+               placement
+               (if caption-above-p caption "")
+               (if center "\\centering" "")
+               comment-include image-code
+               (if caption-above-p "" caption)
+               env-string))
       (`wrap (format "\\begin{wrapfigure}%s
 %s%s
 %s%s
@@ -2574,7 +2623,7 @@ INFO is a plist holding contextual information.  See
           (let ((label (org-latex--label destination info t)))
             (if (and (not desc)
                      (org-export-numbered-headline-p destination info))
-                (format "\\ref{%s}" label)
+                (format org-latex-reference-command label)
               (format "\\hyperref[%s]{%s}" label
                       (or desc
                           (org-export-data
@@ -2582,7 +2631,7 @@ INFO is a plist holding contextual information.  See
           ;; Fuzzy link points to a target.  Do as above.
          (otherwise
           (let ((ref (org-latex--label destination info t)))
-            (if (not desc) (format "\\ref{%s}" ref)
+            (if (not desc) (format org-latex-reference-command ref)
               (format "\\hyperref[%s]{%s}" ref desc)))))))
      ;; Coderef: replace link with the reference name or the
      ;; equivalent line number.
@@ -2874,9 +2923,19 @@ channel."
   "Transcode a QUOTE-BLOCK element from Org to LaTeX.
 CONTENTS holds the contents of the block.  INFO is a plist
 holding contextual information."
-  (org-latex--wrap-label
-   quote-block (format "\\begin{quote}\n%s\\end{quote}" contents) info))
-
+  (let ((environment
+        (or (org-export-read-attribute :attr_latex quote-block :environment)
+            (plist-get info :latex-default-quote-environment)))
+       (options
+        (or (org-export-read-attribute :attr_latex quote-block :options)
+            "")))
+    (org-latex--wrap-label
+     quote-block (format "\\begin{%s}%s\n%s\\end{%s}"
+                        environment
+                        options
+                        contents
+                        environment)
+     info)))
 
 ;;;; Radio Target
 
@@ -2935,22 +2994,20 @@ contextual information."
       (cond
        ;; Case 1.  No source fontification.
        ((or (not lang) (not listings))
-       (let* ((caption-str (org-latex--caption/label-string src-block info))
-              (float-env
-               (cond ((string= "multicolumn" float)
-                      (format "\\begin{figure*}[%s]\n%s%%s\n%s\\end{figure*}"
-                              (plist-get info :latex-default-figure-position)
-                              (if caption-above-p caption-str "")
-                              (if caption-above-p "" caption-str)))
-                     (caption (concat
-                               (if caption-above-p caption-str "")
-                               "%s"
-                               (if caption-above-p "" (concat "\n" 
caption-str))))
-                     (t "%s"))))
-         (format
-          float-env
-          (concat (format "\\begin{verbatim}\n%s\\end{verbatim}"
-                          (org-export-format-code-default src-block info))))))
+       (let ((caption-str (org-latex--caption/label-string src-block info))
+              (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}"
+                                (org-export-format-code-default src-block 
info))))
+          (cond ((string= "multicolumn" float)
+                 (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}"
+                         (plist-get info :latex-default-figure-position)
+                         (if caption-above-p caption-str "")
+                         verbatim
+                         (if caption-above-p "" caption-str)))
+                (caption (concat
+                          (if caption-above-p caption-str "")
+                          verbatim
+                          (if caption-above-p "" (concat "\n" caption-str))))
+                (t verbatim))))
        ;; Case 2.  Custom environment.
        (custom-env
        (let ((caption-str (org-latex--caption/label-string src-block info))
@@ -3198,9 +3255,9 @@ centered."
 (defun org-latex--decorate-table (table attributes caption above? info)
   "Decorate TABLE string with caption and float environment.
 
-ATTRIBUTES is the plist containing is LaTeX attributes.  CAPTION
-is its caption, as a string or nil.  It is located above the
-table if ABOVE? is non-nil.  INFO is the plist containing current
+ATTRIBUTES is the plist containing LaTeX attributes.  CAPTION is
+its caption, as a string or nil.  It is located above the table
+if ABOVE? is non-nil.  INFO is the plist containing current
 export parameters.
 
 Return new environment, as a string."
@@ -3209,7 +3266,8 @@ Return new environment, as a string."
            (cond ((and (not float) (plist-member attributes :float)) nil)
                  ((member float '("sidewaystable" "sideways")) "sidewaystable")
                  ((equal float "multicolumn") "table*")
-                 ((or float (org-string-nw-p caption)) "table")
+                  (float float)
+                 ((org-string-nw-p caption) "table")
                  (t nil))))
         (placement
          (or (plist-get attributes :placement)
@@ -3504,29 +3562,44 @@ channel."
   "Transcode a VERSE-BLOCK element from Org to LaTeX.
 CONTENTS is verse block contents.  INFO is a plist holding
 contextual information."
-  (org-latex--wrap-label
-   verse-block
-   ;; In a verse environment, add a line break to each newline
-   ;; character and change each white space at beginning of a line
-   ;; into a space of 1 em.  Also change each blank line with
-   ;; a vertical space of 1 em.
-   (format "\\begin{verse}\n%s\\end{verse}"
-          (replace-regexp-in-string
-           "^[ \t]+" (lambda (m) (format "\\hspace*{%dem}" (length m)))
-           (replace-regexp-in-string
-            "^[ \t]*\\\\\\\\$" "\\vspace*{1em}"
-            (replace-regexp-in-string
-             "\\([ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n"
-             contents nil t) nil t) nil t))
-   info))
-
+  (let* ((lin (org-export-read-attribute :attr_latex verse-block :lines))
+         (latcode (org-export-read-attribute :attr_latex verse-block 
:latexcode))
+         (cent (org-export-read-attribute :attr_latex verse-block :center))
+         (attr (concat
+               (if cent "[\\versewidth]" "")
+               (if lin (format "\n\\poemlines{%s}" lin) "")
+               (if latcode (format "\n%s" latcode) "")))
+         (versewidth (org-export-read-attribute :attr_latex verse-block 
:versewidth))
+         (vwidth (if versewidth (format "\\settowidth{\\versewidth}{%s}\n" 
versewidth) ""))
+         (linreset (if lin "\n\\poemlines{0}" "")))
+    (concat
+     (org-latex--wrap-label
+      verse-block
+      ;; In a verse environment, add a line break to each newline
+      ;; character and change each white space at beginning of a line
+      ;; into a space of 1 em.  Also change each blank line with
+      ;; a vertical space of 1 em.
+      (format "%s\\begin{verse}%s\n%s\\end{verse}%s"
+             vwidth
+             attr
+             (replace-regexp-in-string
+              "^[ \t]+" (lambda (m) (format "\\hspace*{%dem}" (length m)))
+              (replace-regexp-in-string
+               "^[ \t]*\\\\\\\\$" "\\vspace*{1em}"
+               (replace-regexp-in-string
+                "\\([ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n"
+                contents nil t) nil t) nil t) linreset)
+      info)
+     ;; Insert footnote definitions, if any, after the environment, so
+     ;; the special formatting above is not applied to them.
+     (org-latex--delayed-footnotes-definitions verse-block info))))
 
 
 ;;; End-user functions
 
 ;;;###autoload
 (defun org-latex-export-as-latex
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer as a LaTeX buffer.
 
 If narrowing is active in the current buffer, only export its
@@ -3570,7 +3643,7 @@ command to convert it."
 
 ;;;###autoload
 (defun org-latex-export-to-latex
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a LaTeX file.
 
 If narrowing is active in the current buffer, only export its
@@ -3602,7 +3675,7 @@ file-local settings."
 
 ;;;###autoload
 (defun org-latex-export-to-pdf
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to LaTeX then process through to PDF.
 
 If narrowing is active in the current buffer, only export its
@@ -3660,12 +3733,12 @@ produced."
                     (match-string 0)))
              "pdflatex"))
         (process (if (functionp org-latex-pdf-process) org-latex-pdf-process
-                   ;; Replace "%latex" and "%bibtex" with,
-                   ;; respectively, "%L" and "%B" so as to adhere to
-                   ;; `format-spec' specifications.
+                   ;; Replace "%latex" with "%L" and "%bib" and
+                   ;; "%bibtex" with "%B" to adhere to `format-spec'
+                   ;; specifications.
                    (mapcar (lambda (command)
                              (replace-regexp-in-string
-                              "%\\(?:bib\\|la\\)tex\\>"
+                               "%\\(?:\\(?:bib\\|la\\)tex\\|bib\\)\\>"
                               (lambda (m) (upcase (substring m 0 2)))
                               command))
                            org-latex-pdf-process)))
diff --git a/lisp/org/ox-man.el b/lisp/org/ox-man.el
index 27d2dedb8e..6d3476cdae 100644
--- a/lisp/org/ox-man.el
+++ b/lisp/org/ox-man.el
@@ -186,7 +186,7 @@ When nil, no transformation is made."
     (ldap "ldap") (opa "opa")
     (php "php") (postscript "postscript") (prolog "prolog")
     (properties "properties") (makefile "makefile")
-    (tml "tml") (vala "vala") (vbscript "vbscript") (xorg "xorg"))
+    (tml "tml") (vbscript "vbscript") (xorg "xorg"))
   "Alist mapping languages to their listing language counterpart.
 The key is a symbol, the major mode symbol without the \"-mode\".
 The value is the string that should be inserted as the language
@@ -301,12 +301,12 @@ CONTENTS is the transcoded contents string.  INFO is a 
plist
 holding export options."
   (let* ((title (when (plist-get info :with-title)
                  (org-export-data (plist-get info :title) info)))
-        (attr (read (format "(%s)"
-                            (mapconcat
-                             #'identity
-                             (list (plist-get info :man-class-options))
-                             " "))))
-        (section-item (plist-get attr :section-id)))
+         (attr (read (format "(%s)"
+                             (mapconcat
+                              #'identity
+                              (list (plist-get info :man-class-options))
+                              " "))))
+         (section-item (plist-get attr :section-id)))
 
     (concat
 
@@ -365,9 +365,9 @@ holding contextual information."
 
 (defun org-man-drawer (_drawer contents _info)
   "Transcode a DRAWER element from Org to Man.
-   DRAWER holds the drawer information
-   CONTENTS holds the contents of the block.
-   INFO is a plist holding contextual information. "
+DRAWER holds the drawer information
+CONTENTS holds the contents of the block.
+INFO is a plist holding contextual information."
   contents)
 
 
@@ -825,10 +825,10 @@ contextual information."
    ;; Case 1: verbatim table.
    ((or (plist-get info :man-tables-verbatim)
         (let ((attr (read (format "(%s)"
-                 (mapconcat
-                  #'identity
-                  (org-element-property :attr_man table)
-                  " ")))))
+                                  (mapconcat
+                                   #'identity
+                                   (org-element-property :attr_man table)
+                                   " ")))))
 
           (and attr (plist-get attr :verbatim))))
 
@@ -1053,7 +1053,7 @@ contextual information."
 ;;; Interactive functions
 
 (defun org-man-export-to-man
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a Man file.
 
 If narrowing is active in the current buffer, only export its
@@ -1086,7 +1086,7 @@ Return output file's name."
       async subtreep visible-only body-only ext-plist)))
 
 (defun org-man-export-to-pdf
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to Groff then process through to PDF.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox-md.el b/lisp/org/ox-md.el
index f4afe6b30e..348b6d01dc 100644
--- a/lisp/org/ox-md.el
+++ b/lisp/org/ox-md.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
 ;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: org, wp, markdown
 
 ;; This file is part of GNU Emacs.
@@ -57,10 +58,10 @@ This variable can be set to either `atx' or `setext'."
   "Format string for the footnotes section.
 The first %s placeholder will be replaced with the localized Footnotes section
 heading, the second with the contents of the Footnotes section."
- :group 'org-export-md
- :type 'string
- :version "26.1"
- :package-version '(Org . "9.0"))
+  :group 'org-export-md
+  :type 'string
+  :version "26.1"
+  :package-version '(Org . "9.0"))
 
 (defcustom org-md-footnote-format "<sup>%s</sup>"
   "Format string for the footnote reference.
@@ -100,6 +101,8 @@ The %s will be replaced by the footnote reference itself."
                     (italic . org-md-italic)
                     (item . org-md-item)
                     (keyword . org-md-keyword)
+                     (latex-environment . org-md-latex-environment)
+                     (latex-fragment . org-md-latex-fragment)
                     (line-break . org-md-line-break)
                     (link . org-md-link)
                     (node-property . org-md-node-property)
@@ -210,9 +213,9 @@ the section."
                (underline (concat (make-string (length title) underline-char)
                                  "\n")))
           (concat "\n" anchor-lines title tags "\n" underline "\n"))
-        ;; Use "Atx" style
-        (let ((level-mark (make-string level ?#)))
-          (concat "\n" anchor-lines level-mark " " title tags "\n\n")))))
+      ;; Use "Atx" style
+      (let ((level-mark (make-string level ?#)))
+        (concat "\n" anchor-lines level-mark " " title tags "\n\n")))))
 
 (defun org-md--build-toc (info &optional n _keyword scope)
   "Return a table of contents.
@@ -460,6 +463,35 @@ channel."
     (_ (org-export-with-backend 'html keyword contents info))))
 
 
+;;;; Latex Environment
+
+(defun org-md-latex-environment (latex-environment _contents info)
+  "Transcode a LATEX-ENVIRONMENT object from Org to Markdown.
+CONTENTS is nil.  INFO is a plist holding contextual information."
+  (when (plist-get info :with-latex)
+    (let ((latex-frag (org-remove-indentation
+                       (org-element-property :value latex-environment)))
+          (label (org-html--reference latex-environment info t)))
+      (if (org-string-nw-p label)
+          (replace-regexp-in-string "\\`.*"
+                                    (format "\\&\n\\\\label{%s}" label)
+                                    latex-frag)
+        latex-frag))))
+
+;;;; Latex Fragment
+
+(defun org-md-latex-fragment (latex-fragment _contents info)
+  "Transcode a LATEX-FRAGMENT object from Org to Markdown.
+CONTENTS is nil.  INFO is a plist holding contextual information."
+  (when (plist-get info :with-latex)
+    (let ((frag (org-element-property :value latex-fragment)))
+      (cond
+       ((string-match-p "^\\\\(" frag)
+        (concat "$" (substring frag 2 -2) "$"))
+       ((string-match-p "^\\\\\\[" frag)
+        (concat "$$" (substring frag 2 -2) "$$"))
+       (t frag))))) ; either already $-deliminated or a macro
+
 ;;;; Line Break
 
 (defun org-md-line-break (_line-break _contents _info)
@@ -543,7 +575,12 @@ INFO is a plist holding contextual information.  See
      ((string= type "coderef")
       (format (org-export-get-coderef-format path desc)
              (org-export-resolve-coderef path info)))
-     ((equal type "radio") desc)
+     ((string= type "radio")
+      (let ((destination (org-export-resolve-radio-link link info)))
+       (if (not destination) desc
+         (format "<a href=\"#%s\">%s</a>"
+                 (org-export-get-reference destination info)
+                 desc))))
      (t (if (not desc) (format "<%s>" path)
          (format "[%s](%s)" desc path))))))
 
diff --git a/lisp/org/ox-odt.el b/lisp/org/ox-odt.el
index a076d15978..f186ebb16a 100644
--- a/lisp/org/ox-odt.el
+++ b/lisp/org/ox-odt.el
@@ -251,7 +251,7 @@ Use `org-odt-add-automatic-style' to add update this 
variable.'")
 
 (defvar org-odt-object-counters nil
   "Running counters for various OBJECT-TYPEs.
-Use this to generate automatic names and style-names. See
+Use this to generate automatic names and style-names.  See
 `org-odt-add-automatic-style'.")
 
 (defvar org-odt-src-block-paragraph-format
@@ -277,8 +277,7 @@ according to the default face identified by the 
`htmlfontify'.")
 (defvar org-odt-default-image-sizes-alist
   '(("as-char" . (5 . 0.4))
     ("paragraph" . (5 . 5)))
-  "Hardcoded image dimensions one for each of the anchor
-  methods.")
+  "Hardcoded image dimensions one for each of the anchor methods.")
 
 ;; A4 page size is 21.0 by 29.7 cms
 ;; The default page settings has 2cm margin on each of the sides. So
@@ -450,7 +449,7 @@ Valid values are one of:
 4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
 ...))
 
-In case of option 1, an in-built styles.xml is used. See
+In case of option 1, an in-built styles.xml is used.  See
 `org-odt-styles-dir' for more information.
 
 In case of option 3, the specified file is unzipped and the
@@ -982,7 +981,7 @@ See `org-odt--build-date-styles' for implementation 
details."
 ;;;; Frame
 
 (defun org-odt--frame (text width height style &optional extra
-                             anchor-type &rest title-and-desc)
+                           anchor-type &rest title-and-desc)
   (let ((frame-attrs
         (concat
          (if width (format " svg:width=\"%0.2fcm\"" width) "")
@@ -1044,7 +1043,7 @@ See `org-odt--build-date-styles' for implementation 
details."
 ;;;; Textbox
 
 (defun org-odt--textbox (text width height style &optional
-                               extra anchor-type)
+                             extra anchor-type)
   (org-odt--frame
    (format "\n<draw:text-box %s>%s\n</draw:text-box>"
           (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
@@ -1778,8 +1777,8 @@ INFO is a plist holding contextual information."
          (if (functionp format-function) format-function
            (cl-function
             (lambda (todo todo-type priority text tags
-                     &key _level _section-number _headline-label
-                     &allow-other-keys)
+                          &key _level _section-number _headline-label
+                          &allow-other-keys)
               (funcall (plist-get info :odt-format-headline-function)
                        todo todo-type priority text tags))))))
     (apply format-function
@@ -1852,7 +1851,7 @@ holding contextual information."
         contents))))))
 
 (defun org-odt-format-headline-default-function
-  (todo todo-type priority text tags)
+    (todo todo-type priority text tags)
   "Default format function for a headline.
 See `org-odt-format-headline-function' for details."
   (concat
@@ -1930,7 +1929,7 @@ holding contextual information."
             todo todo-type priority text tags contents)))
 
 (defun org-odt-format-inlinetask-default-function
-  (todo todo-type priority name tags contents)
+    (todo todo-type priority name tags contents)
   "Default format function for inlinetasks.
 See `org-odt-format-inlinetask-function' for details."
   (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
@@ -2176,7 +2175,7 @@ SHORT-CAPTION are strings."
 ;;;; Links :: Inline Images
 
 (defun org-odt--copy-image-file (path)
-  "Return the internal name of the file"
+  "Return the internal name of the file."
   (let* ((image-type (file-name-extension path))
         (media-type (format "image/%s" image-type))
         (target-dir "Images/")
@@ -2199,7 +2198,7 @@ SHORT-CAPTION are strings."
 (declare-function image-size "image.c" (spec &optional pixels frame))
 
 (defun org-odt--image-size
-  (file info &optional user-width user-height scale dpi embed-as)
+    (file info &optional user-width user-height scale dpi embed-as)
   (let* ((--pixels-to-cms
           (lambda (pixels dpi)
             (let ((cms-per-inch 2.54)
@@ -2380,7 +2379,7 @@ used as a communication channel."
        (concat equation "<text:tab/>" label))))))
 
 (defun org-odt--copy-formula-file (src-file)
-  "Return the internal name of the file"
+  "Return the internal name of the file."
   (let* ((target-dir (format "Formula-%04d/"
                             (cl-incf org-odt-embedded-formulas-count)))
         (target-file (concat target-dir "content.xml")))
@@ -2400,7 +2399,7 @@ used as a communication channel."
        ;; Case 2: OpenDocument formula.
        ((string= ext "odf")
        (org-odt--zip-extract src-file "content.xml"
-                               (concat org-odt-zip-dir target-dir)))
+                             (concat org-odt-zip-dir target-dir)))
        (t (error "%s is not a formula file" src-file))))
     ;; Enter the formula file in to manifest.
     (org-odt-create-manifest-file-entry "text/xml" target-file)
@@ -2468,15 +2467,14 @@ used as a communication channel."
         (outer (nth 2 frame-cfg))
         ;; User-specified frame params (from #+ATTR_ODT spec)
         (user user-frame-params)
-        (--merge-frame-params (function
-                               (lambda (default user)
-                                 "Merge default and user frame params."
-                                 (if (not user) default
-                                   (cl-assert (= (length default) 3))
-                                   (cl-assert (= (length user) 3))
-                                   (cl-loop for u in user
-                                            for d in default
-                                            collect (or u d)))))))
+        (--merge-frame-params (lambda (default user)
+                                "Merge default and user frame params."
+                                (if (not user) default
+                                  (cl-assert (= (length default) 3))
+                                  (cl-assert (= (length user) 3))
+                                  (cl-loop for u in user
+                                           for d in default
+                                           collect (or u d))))))
     (cond
      ;; Case 1: Image/Formula has no caption.
      ;;         There is only one frame, one that surrounds the image
@@ -2652,7 +2650,7 @@ Return nil, otherwise."
           (format "<text:bookmark-ref 
text:reference-format=\"number-all-superior\" 
text:ref-name=\"%s\">%s</text:bookmark-ref>"
                   label
                   (mapconcat (lambda (n) (if (not n) " "
-                                      (concat (number-to-string n) ".")))
+                                           (concat (number-to-string n) ".")))
                              item-numbers "")))))
      ;; Case 2: Locate a regular and numbered headline in the
      ;; hierarchy.  Display its section number.
@@ -3032,7 +3030,7 @@ holding contextual information."
            (anchor (plist-get attributes :anchor)))
        (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
                "Text_20_body" (org-odt--textbox contents width height
-                                                  style extra anchor))))
+                                                style extra anchor))))
      (t contents))))
 
 
@@ -3773,13 +3771,13 @@ contextual information."
                       ;; paragraph.
                       (latex-environment
                        (org-element-adopt-elements
-                        (list 'paragraph
-                              (list :style "OrgFormula"
-                                    :name
-                                    (org-element-property :name latex-*)
-                                    :caption
-                                    (org-element-property :caption latex-*)))
-                        link))
+                           (list 'paragraph
+                                 (list :style "OrgFormula"
+                                       :name
+                                       (org-element-property :name latex-*)
+                                       :caption
+                                       (org-element-property :caption 
latex-*)))
+                         link))
                       ;; LaTeX fragment.  No special action.
                       (latex-fragment link))))
                ;; Note down the object that link replaces.
@@ -3842,15 +3840,15 @@ contextual information."
                (mapcar
                 (lambda (item)
                   (org-element-adopt-elements
-                   (list 'item (list :checkbox (org-element-property
-                                                :checkbox item)))
-                   (list 'paragraph (list :style "Text_20_body_20_bold")
-                         (or (org-element-property :tag item) "(no term)"))
-                   (org-element-adopt-elements
-                    (list 'plain-list (list :type 'descriptive-2))
-                    (apply 'org-element-adopt-elements
-                           (list 'item nil)
-                           (org-element-contents item)))))
+                      (list 'item (list :checkbox (org-element-property
+                                                   :checkbox item)))
+                    (list 'paragraph (list :style "Text_20_body_20_bold")
+                          (or (org-element-property :tag item) "(no term)"))
+                    (org-element-adopt-elements
+                        (list 'plain-list (list :type 'descriptive-2))
+                      (apply 'org-element-adopt-elements
+                             (list 'item nil)
+                             (org-element-contents item)))))
                 (org-element-contents el)))))
       nil)
     info)
diff --git a/lisp/org/ox-org.el b/lisp/org/ox-org.el
index 26259d8752..fcf876854f 100644
--- a/lisp/org/ox-org.el
+++ b/lisp/org/ox-org.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
 
 ;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: org, wp
 
 ;; This file is part of GNU Emacs.
@@ -140,7 +141,7 @@ CONTENTS and INFO are ignored."
 CONTENTS is its contents, as a string or nil.  INFO is ignored."
   (let ((case-fold-search t))
     (replace-regexp-in-string
-     "^[ \t]*#\\+ATTR_[-_A-Za-z0-9]+:\\(?: .*\\)?\n" ""
+     "^[ \t]*#\\+attr_[-_a-z0-9]+:\\(?: .*\\)?\n" ""
      (org-export-expand blob contents t))))
 
 (defun org-org-headline (headline contents info)
@@ -184,26 +185,26 @@ as a communication channel."
               (org-element-map (plist-get info :parse-tree) 'keyword
                 (lambda (k)
                   (and (string-equal (org-element-property :key k) "OPTIONS")
-                       (concat "#+OPTIONS: "
+                       (concat "#+options: "
                                (org-element-property :value k)))))
               "\n"))
    (and (plist-get info :with-title)
-       (format "#+TITLE: %s\n" (org-export-data (plist-get info :title) info)))
+       (format "#+title: %s\n" (org-export-data (plist-get info :title) info)))
    (and (plist-get info :with-date)
        (let ((date (org-export-data (org-export-get-date info) info)))
          (and (org-string-nw-p date)
-              (format "#+DATE: %s\n" date))))
+              (format "#+date: %s\n" date))))
    (and (plist-get info :with-author)
        (let ((author (org-export-data (plist-get info :author) info)))
          (and (org-string-nw-p author)
-              (format "#+AUTHOR: %s\n" author))))
+              (format "#+author: %s\n" author))))
    (and (plist-get info :with-email)
        (let ((email (org-export-data (plist-get info :email) info)))
          (and (org-string-nw-p email)
-              (format "#+EMAIL: %s\n" email))))
+              (format "#+email: %s\n" email))))
    (and (plist-get info :with-creator)
        (org-string-nw-p (plist-get info :creator))
-       (format "#+CREATOR: %s\n" (plist-get info :creator)))
+       (format "#+creator: %s\n" (plist-get info :creator)))
    contents))
 
 (defun org-org-timestamp (timestamp _contents _info)
@@ -238,7 +239,7 @@ a communication channel."
 
 ;;;###autoload
 (defun org-org-export-as-org
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to an Org buffer.
 
 If narrowing is active in the current buffer, only export its
@@ -273,7 +274,7 @@ non-nil."
 
 ;;;###autoload
 (defun org-org-export-to-org
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to an Org file.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox-publish.el b/lisp/org/ox-publish.el
index 6f82b48572..bc9b17ab3e 100644
--- a/lisp/org/ox-publish.el
+++ b/lisp/org/ox-publish.el
@@ -2,7 +2,7 @@
 ;; Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
 ;; Author: David O'Toole <dto@gnu.org>
-;; Maintainer: Carsten Dominik <carsten at orgmode dot org>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: hypermedia, outlines, wp
 
 ;; This file is part of GNU Emacs.
@@ -358,7 +358,7 @@ You can overwrite this default per project in your
   (concat "X" (if (fboundp 'sha1) (sha1 filename) (md5 filename))))
 
 (defun org-publish-needed-p
-  (filename &optional pub-dir pub-func _true-pub-dir base-dir)
+    (filename &optional pub-dir pub-func _true-pub-dir base-dir)
   "Non-nil if FILENAME should be published in PUB-DIR using PUB-FUNC.
 TRUE-PUB-DIR is where the file will truly end up.  Currently we
 are not using this - maybe it can eventually be used to check if
@@ -375,7 +375,7 @@ still decide about that independently."
     rtn))
 
 (defun org-publish-update-timestamp
-  (filename &optional pub-dir pub-func _base-dir)
+    (filename &optional pub-dir pub-func _base-dir)
   "Update publishing timestamp for file FILENAME.
 If there is no timestamp, create one."
   (let ((key (org-publish-timestamp-filename filename pub-dir pub-func))
@@ -617,7 +617,8 @@ files, when entire projects are published (see
                          (abbreviate-file-name filename))))
         (project-plist (cdr project))
         (publishing-function
-         (pcase (org-publish-property :publishing-function project)
+         (pcase (org-publish-property :publishing-function project
+                                       'org-html-publish-to-html)
            (`nil (user-error "No publishing function chosen"))
            ((and f (pred listp)) f)
            (f (list f))))
@@ -1064,7 +1065,7 @@ publishing directory."
                  (setq full-index
                        (sort (nreverse full-index)
                              (lambda (a b) (string< (downcase (car a))
-                                               (downcase (car b)))))))
+                                                    (downcase (car b)))))))
       (let ((index (org-publish-cache-get-file-property file :index)))
        (dolist (term index)
          (unless (member term full-index) (push term full-index)))))
@@ -1270,7 +1271,7 @@ If FREE-CACHE, empty the cache."
   org-publish-cache)
 
 (defun org-publish-reset-cache ()
-  "Empty org-publish-cache and reset it nil."
+  "Empty `org-publish-cache' and reset it nil."
   (message "%s" "Resetting org-publish-cache")
   (when (hash-table-p org-publish-cache)
     (clrhash org-publish-cache))
@@ -1290,29 +1291,28 @@ the file including them will be republished as well."
         (org-inhibit-startup t)
         included-files-ctime)
     (when (equal (file-name-extension filename) "org")
-      (let ((visiting (find-buffer-visiting filename))
-           (buf (find-file-noselect filename))
-           (case-fold-search t))
-       (unwind-protect
-           (with-current-buffer buf
-             (goto-char (point-min))
-             (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t)
-               (let ((element (org-element-at-point)))
-                 (when (eq 'keyword (org-element-type element))
-                   (let* ((value (org-element-property :value element))
-                          (filename
-                           (and (string-match "\\`\\(\".+?\"\\|\\S-+\\)" value)
-                                (let ((m (org-strip-quotes
-                                          (match-string 1 value))))
-                                  ;; Ignore search suffix.
-                                  (if (string-match "::.*?\\'" m)
-                                      (substring m 0 (match-beginning 0))
-                                    m)))))
-                     (when filename
-                       (push (org-publish-cache-ctime-of-src
-                              (expand-file-name filename))
-                             included-files-ctime)))))))
-         (unless visiting (kill-buffer buf)))))
+      (let ((case-fold-search t))
+       (with-temp-buffer
+          (delay-mode-hooks
+            (org-mode)
+            (insert-file-contents filename)
+           (goto-char (point-min))
+           (while (re-search-forward "^[ \t]*#\\+INCLUDE:" nil t)
+             (let ((element (org-element-at-point)))
+               (when (eq 'keyword (org-element-type element))
+                 (let* ((value (org-element-property :value element))
+                        (include-filename
+                         (and (string-match "\\`\\(\".+?\"\\|\\S-+\\)" value)
+                              (let ((m (org-strip-quotes
+                                        (match-string 1 value))))
+                                ;; Ignore search suffix.
+                                (if (string-match "::.*?\\'" m)
+                                    (substring m 0 (match-beginning 0))
+                                  m)))))
+                   (when include-filename
+                     (push (org-publish-cache-ctime-of-src
+                            (expand-file-name include-filename 
(file-name-directory filename)))
+                           included-files-ctime))))))))))
     (or (null pstamp)
        (let ((ctime (org-publish-cache-ctime-of-src filename)))
          (or (time-less-p pstamp ctime)
@@ -1320,7 +1320,7 @@ the file including them will be republished as well."
                       included-files-ctime))))))
 
 (defun org-publish-cache-set-file-property
-  (filename property value &optional project-name)
+    (filename property value &optional project-name)
   "Set the VALUE for a PROPERTY of file FILENAME in publishing cache to VALUE.
 Use cache file of PROJECT-NAME.  If the entry does not exist, it
 will be created.  Return VALUE."
diff --git a/lisp/org/ox-texinfo.el b/lisp/org/ox-texinfo.el
index 6e8d0d6214..8b949b361a 100644
--- a/lisp/org/ox-texinfo.el
+++ b/lisp/org/ox-texinfo.el
@@ -2,6 +2,7 @@
 
 ;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
 ;; Author: Jonathan Leech-Pepin <jonathan.leechpepin at gmail dot com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -420,8 +421,8 @@ If two strings share the same prefix (e.g. \"ISO-8859-1\" 
and
 (defun org-texinfo--normalize-headlines (tree _backend info)
   "Normalize headlines in TREE.
 
-BACK-END is the symbol specifying back-end used for export. INFO
-is a plist used as a communication channel.
+BACK-END is the symbol specifying back-end used for export.
+INFO is a plist used as a communication channel.
 
 Make sure every headline in TREE contains a section, since those
 are required to install a menu.  Also put exactly one blank line
@@ -489,16 +490,18 @@ node or anchor name is unique."
          ;; Org exports deeper elements before their parents.  If two
          ;; node names collide -- e.g., they have the same title --
          ;; within the same hierarchy, the second one would get the
-         ;; shorter node name.  This is counter-intuitive.
-         ;; Consequently, we ensure that every parent headline get
-         ;; its node beforehand. As a recursive operation, this
+         ;; smaller node name.  This is counter-intuitive.
+         ;; Consequently, we ensure that every parent headline gets
+         ;; its node beforehand.  As a recursive operation, this
          ;; achieves the desired effect.
          (let ((parent (org-element-lineage datum '(headline))))
            (when (and parent (not (assq parent cache)))
              (org-texinfo--get-node parent info)
              (setq cache (plist-get info :texinfo-node-cache))))
-         ;; Ensure NAME is unique and not reserved node name "Top".
-         (while (or (equal name "Top") (rassoc name cache))
+         ;; Ensure NAME is unique and not reserved node name "Top",
+          ;; no matter what case is used.
+         (while (or (string-equal "Top" (capitalize name))
+                     (rassoc name cache))
            (setq name (concat basename (format " (%d)" (cl-incf salt)))))
          (plist-put info :texinfo-node-cache (cons (cons datum name) cache))
          name))))
@@ -559,6 +562,14 @@ strings (e.g., returned by `org-export-get-caption')."
     (format "@float %s%s\n%s\n%s%s@end float"
            type (if label (concat "," label) "") value caption-str short-str)))
 
+(defun org-texinfo--sectioning-structure (info)
+  "Return sectioning structure used in the document.
+INFO is a plist holding export options."
+  (let ((class (plist-get info :texinfo-class)))
+    (pcase (assoc class (plist-get info :texinfo-classes))
+      (`(,_ ,_ . ,sections) sections)
+      (_ (user-error "Unknown Texinfo class: %S" class)))))
+
 ;;; Template
 
 (defun org-texinfo-template (contents info)
@@ -838,9 +849,17 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
 
 FOOTNOTE is the footnote to define.  CONTENTS is nil.  INFO is a
 plist holding contextual information."
-  (let ((def (org-export-get-footnote-definition footnote info)))
+  (let* ((contents (org-export-get-footnote-definition footnote info))
+         (data (org-export-data contents info)))
     (format "@footnote{%s}"
-           (org-trim (org-export-data def info)))))
+            ;; It is invalid to close a footnote on a line starting
+            ;; with "@end".  As a safety net, we leave a newline
+            ;; character before the closing brace.  However, when the
+            ;; footnote ends with a paragraph, it is visually pleasing
+            ;; to move the brace right after its end.
+            (if (eq 'paragraph (org-element-type (org-last contents)))
+                (org-trim data)
+              data))))
 
 ;;;; Headline
 
@@ -858,25 +877,22 @@ holding contextual information."
           (notoc? (org-export-excluded-from-toc-p headline info))
           (command
            (and
-            (not (org-export-low-level-p headline info))
-            (let ((class (plist-get info :texinfo-class)))
-              (pcase (assoc class (plist-get info :texinfo-classes))
-                (`(,_ ,_ . ,sections)
-                 (pcase (nth (1- (org-export-get-relative-level headline info))
-                             sections)
-                   (`(,numbered ,unnumbered ,unnumbered-no-toc ,appendix)
-                    (cond
-                     ((org-not-nil
-                       (org-export-get-node-property :APPENDIX headline t))
-                      appendix)
-                     (numbered? numbered)
-                     (index unnumbered)
-                     (notoc? unnumbered-no-toc)
-                     (t unnumbered)))
-                   (`nil nil)
-                   (_ (user-error "Invalid Texinfo class specification: %S"
-                                  class))))
-                (_ (user-error "Unknown Texinfo class: %S" class))))))
+             (not (org-export-low-level-p headline info))
+            (let ((sections (org-texinfo--sectioning-structure info)))
+               (pcase (nth (1- (org-export-get-relative-level headline info))
+                          sections)
+                (`(,numbered ,unnumbered ,unnumbered-no-toc ,appendix)
+                 (cond
+                  ((org-not-nil
+                    (org-export-get-node-property :APPENDIX headline t))
+                   appendix)
+                  (numbered? numbered)
+                  (index unnumbered)
+                  (notoc? unnumbered-no-toc)
+                  (t unnumbered)))
+                (`nil nil)
+                (_ (user-error "Invalid Texinfo class specification: %S"
+                               (plist-get info :texinfo-class)))))))
           (todo
            (and (plist-get info :with-todo-keywords)
                 (let ((todo (org-element-property :todo-keyword headline)))
@@ -894,11 +910,12 @@ holding contextual information."
           (contents
            (concat "\n"
                    (if (org-string-nw-p contents) (concat "\n" contents) "")
-                   (and index (format "\n@printindex %s\n" index)))))
+                   (and index (format "\n@printindex %s\n" index))))
+           (node (org-texinfo--get-node headline info)))
       (if (not command)
          (concat (and (org-export-first-sibling-p headline info)
                       (format "@%s\n" (if numbered? 'enumerate 'itemize)))
-                 "@item\n" full-text "\n"
+                 (format "@item\n@anchor{%s}%s\n" node full-text)
                  contents
                  (if (org-export-last-sibling-p headline info)
                      (format "@end %s" (if numbered? 'enumerate 'itemize))
@@ -906,13 +923,12 @@ holding contextual information."
        (concat
         ;; Even if HEADLINE is using @subheading and al., leave an
         ;; anchor so cross-references in the Org document still work.
-        (format (if notoc? "@anchor{%s}\n" "@node %s\n")
-                (org-texinfo--get-node headline info))
+        (format (if notoc? "@anchor{%s}\n" "@node %s\n") node)
         (format command full-text)
         contents))))))
 
 (defun org-texinfo-format-headline-default-function
-  (todo _todo-type priority text tags)
+    (todo _todo-type priority text tags)
   "Default format function for a headline.
 See `org-texinfo-format-headline-function' for details."
   (concat (and todo (format "@strong{%s} " todo))
@@ -949,7 +965,7 @@ holding contextual information."
             todo todo-type priority title tags contents)))
 
 (defun org-texinfo-format-inlinetask-default-function
-  (todo _todo-type priority title tags contents)
+    (todo _todo-type priority title tags contents)
   "Default format function for inlinetasks.
 See `org-texinfo-format-inlinetask-function' for details."
   (let ((full-title
@@ -1111,7 +1127,9 @@ current state of the export, as a plist."
         (path  (org-element-property :path link))
         (filename
          (file-name-sans-extension
-          (if (file-name-absolute-p path) (expand-file-name path) path)))
+          (if (file-name-absolute-p path)
+               (expand-file-name path)
+             (file-relative-name path))))
         (extension (file-name-extension path))
         (attributes (org-export-read-attribute :attr_texinfo parent))
         (height (or (plist-get attributes :height) ""))
@@ -1192,7 +1210,7 @@ a plist containing contextual information."
              ;; Colons are used as a separator between title and node
              ;; name.  Remove them.
              (replace-regexp-in-string
-              "[ \t]+:+" ""
+              "[ \t]*:+" ""
               (org-texinfo--sanitize-title
                (org-export-get-alt-title h info) info)))
             (node (org-texinfo--get-node h info))
@@ -1215,12 +1233,15 @@ holding contextual information."
                               :texinfo-entries-cache)))
         (cached-entries (gethash scope cache 'no-cache)))
     (if (not (eq cached-entries 'no-cache)) cached-entries
-      (puthash scope
-              (cl-remove-if
-               (lambda (h)
-                 (org-not-nil (org-export-get-node-property :COPYING h t)))
-               (org-export-collect-headlines info 1 scope))
-              cache))))
+      (let* ((sections (org-texinfo--sectioning-structure info))
+             (max-depth (length sections)))
+        (puthash scope
+                (cl-remove-if
+                 (lambda (h)
+                   (or (org-not-nil (org-export-get-node-property :COPYING h 
t))
+                        (< max-depth (org-export-get-relative-level h info))))
+                 (org-export-collect-headlines info 1 scope))
+                cache)))))
 
 ;;;; Node Property
 
@@ -1585,7 +1606,7 @@ channel."
 
 (defun org-texinfo-verse-block (_verse-block contents _info)
   "Transcode a VERSE-BLOCK element from Org to Texinfo.
-CONTENTS is verse block contents. INFO is a plist holding
+CONTENTS is verse block contents.  INFO is a plist holding
 contextual information."
   (format "@display\n%s@end display" contents))
 
@@ -1594,7 +1615,7 @@ contextual information."
 
 ;;;###autoload
 (defun org-texinfo-export-to-texinfo
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to a Texinfo file.
 
 If narrowing is active in the current buffer, only export its
@@ -1645,7 +1666,7 @@ Usage: emacs -batch -f 
org-texinfo-export-to-texinfo-batch INFILE OUTFILE"
 
 ;;;###autoload
 (defun org-texinfo-export-to-info
-  (&optional async subtreep visible-only body-only ext-plist)
+    (&optional async subtreep visible-only body-only ext-plist)
   "Export current buffer to Texinfo then process through to INFO.
 
 If narrowing is active in the current buffer, only export its
diff --git a/lisp/org/ox.el b/lisp/org/ox.el
index d412f57360..9ab813a1b1 100644
--- a/lisp/org/ox.el
+++ b/lisp/org/ox.el
@@ -3,6 +3,7 @@
 ;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
 
 ;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
+;; Maintainer: Nicolas Goaziou <n.goaziou at gmail dot com>
 ;; Keywords: outlines, hypermedia, calendar, wp
 
 ;; This file is part of GNU Emacs.
@@ -73,6 +74,8 @@
 
 (require 'cl-lib)
 (require 'ob-exp)
+(require 'oc)
+(require 'oc-basic)    ;default value for `org-cite-export-processors'
 (require 'ol)
 (require 'org-element)
 (require 'org-macro)
@@ -139,7 +142,9 @@
     (:with-tasks nil "tasks" org-export-with-tasks)
     (:with-timestamps nil "<" org-export-with-timestamps)
     (:with-title nil "title" org-export-with-title)
-    (:with-todo-keywords nil "todo" org-export-with-todo-keywords))
+    (:with-todo-keywords nil "todo" org-export-with-todo-keywords)
+    ;; Citations processing.
+    (:cite-export "CITE_EXPORT" nil org-cite-export-processors))
   "Alist between export properties and ways to set them.
 
 The key of the alist is the property name, and the value is a list
@@ -1207,12 +1212,12 @@ keywords are understood:
       or
 
       \\='(?l \"Export to LaTeX\"
-           (?p \"As PDF file\" org-latex-export-to-pdf)
-           (?o \"As PDF file and open\"
-               (lambda (a s v b)
-                 (if a (org-latex-export-to-pdf t s v b)
-                   (org-open-file
-                    (org-latex-export-to-pdf nil s v b)))))))
+           ((?p \"As PDF file\" org-latex-export-to-pdf)
+            (?o \"As PDF file and open\"
+                (lambda (a s v b)
+                  (if a (org-latex-export-to-pdf t s v b)
+                    (org-open-file
+                     (org-latex-export-to-pdf nil s v b)))))))
 
       or the following, which will be added to the previous
       sub-menu,
@@ -1386,11 +1391,13 @@ e.g., `org-export-create-backend'.  It specifies which 
back-end
 specific items to read, if any."
   (let ((line
         (let ((s 0) alist)
-          (while (string-match "\\(.+?\\):\\((.*?)\\|\\S-*\\)[ \t]*" options s)
+          (while (string-match "\\(.+?\\):\\((.*?)\\|\\S-+\\)?[ \t]*" options 
s)
             (setq s (match-end 0))
-            (push (cons (match-string 1 options)
-                        (read (match-string 2 options)))
-                  alist))
+            (let ((value (match-string 2 options)))
+               (when value
+                 (push (cons (match-string 1 options)
+                             (read value))
+                      alist))))
           alist))
        ;; Priority is given to back-end specific options.
        (all (append (org-export-get-all-options backend)
@@ -1569,7 +1576,7 @@ process."
                 plist
                 prop
                 ;; Evaluate default value provided.
-                (let ((value (eval (nth 3 cell))))
+                (let ((value (eval (nth 3 cell) t)))
                   (if (eq (nth 4 cell) 'parse)
                       (org-element-parse-secondary-string
                        value (org-element-restriction 'keyword))
@@ -1878,6 +1885,8 @@ Return a string."
                (cond
                 ;; Ignored element/object.
                 ((memq data (plist-get info :ignore-list)) nil)
+                 ;; Raw code.
+                 ((eq type 'raw) (car (org-element-contents data)))
                 ;; Plain text.
                 ((eq type 'plain-text)
                  (org-export-filter-apply-functions
@@ -1944,7 +1953,7 @@ Return a string."
           data
           (cond
            ((not results) "")
-           ((memq type '(org-data plain-text nil)) results)
+           ((memq type '(nil org-data plain-text raw)) results)
            ;; Append the same white space between elements or objects
            ;; as in the original buffer, and call appropriate filters.
            (t
@@ -2559,16 +2568,16 @@ another buffer, effectively cloning the original buffer 
there.
 
 The function assumes BUFFER's major mode is `org-mode'."
   (with-current-buffer buffer
-    `(lambda ()
-       (let ((inhibit-modification-hooks t))
-        ;; Set major mode. Ignore `org-mode-hook' as it has been run
-        ;; already in BUFFER.
-        (let ((org-mode-hook nil) (org-inhibit-startup t)) (org-mode))
-        ;; Copy specific buffer local variables and variables set
-        ;; through BIND keywords.
-        ,@(let ((bound-variables (org-export--list-bound-variables))
-                vars)
-            (dolist (entry (buffer-local-variables (buffer-base-buffer)) vars)
+    (let ((str (org-with-wide-buffer (buffer-string)))
+          (narrowing
+           (if (org-region-active-p)
+              (list (region-beginning) (region-end))
+            (list (point-min) (point-max))))
+         (pos (point))
+         (varvals
+          (let ((bound-variables (org-export--list-bound-variables))
+                (varvals nil))
+            (dolist (entry (buffer-local-variables (buffer-base-buffer)))
               (when (consp entry)
                 (let ((var (car entry))
                       (val (cdr entry)))
@@ -2583,27 +2592,35 @@ The function assumes BUFFER's major mode is `org-mode'."
                        ;; Skip unreadable values, as they cannot be
                        ;; sent to external process.
                        (or (not val) (ignore-errors (read (format "%S" val))))
-                       (push `(set (make-local-variable (quote ,var))
-                                   (quote ,val))
-                             vars))))))
-        ;; Whole buffer contents.
-        (insert ,(org-with-wide-buffer (buffer-string)))
-        ;; Narrowing.
-        ,(if (org-region-active-p)
-             `(narrow-to-region ,(region-beginning) ,(region-end))
-           `(narrow-to-region ,(point-min) ,(point-max)))
-        ;; Current position of point.
-        (goto-char ,(point))
-        ;; Overlays with invisible property.
-        ,@(let (ov-set)
-            (dolist (ov (overlays-in (point-min) (point-max)) ov-set)
+                       (push (cons var val) varvals)))))
+             varvals))
+         (ols
+          (let (ov-set)
+            (dolist (ov (overlays-in (point-min) (point-max)))
               (let ((invis-prop (overlay-get ov 'invisible)))
                 (when invis-prop
-                  (push `(overlay-put
-                          (make-overlay ,(overlay-start ov)
-                                        ,(overlay-end ov))
-                          'invisible (quote ,invis-prop))
-                        ov-set)))))))))
+                  (push (list (overlay-start ov) (overlay-end ov)
+                              invis-prop)
+                        ov-set))))
+            ov-set)))
+      (lambda ()
+       (let ((inhibit-modification-hooks t))
+         ;; Set major mode. Ignore `org-mode-hook' as it has been run
+         ;; already in BUFFER.
+         (let ((org-mode-hook nil) (org-inhibit-startup t)) (org-mode))
+         ;; Copy specific buffer local variables and variables set
+         ;; through BIND keywords.
+         (pcase-dolist (`(,var . ,val) varvals)
+           (set (make-local-variable var) val))
+         ;; Whole buffer contents.
+         (insert str)
+         ;; Narrowing.
+         (apply #'narrow-to-region narrowing)
+         ;; Current position of point.
+         (goto-char pos)
+         ;; Overlays with invisible property.
+         (pcase-dolist (`(,start ,end ,invis) ols)
+           (overlay-put (make-overlay start end) 'invisible invis)))))))
 
 (defun org-export--delete-comment-trees ()
   "Delete commented trees and commented inlinetasks in the buffer.
@@ -2709,8 +2726,8 @@ a list of footnote definitions or in the widened buffer."
          ) ;; seen
       (dolist (l (funcall list-labels tree))
        (cond ;; ((member l seen))
-             ((member l known-definitions) (push l defined))
-             (t (push l undefined)))))
+        ((member l known-definitions) (push l defined))
+        (t (push l undefined)))))
     ;; Complete MISSING-DEFINITIONS by finding the definition of every
     ;; undefined label, first by looking into DEFINITIONS, then by
     ;; searching the widened buffer.  This is a recursive process
@@ -2722,7 +2739,7 @@ a list of footnote definitions or in the widened buffer."
               (cond
                ((cl-some
                  (lambda (d) (and (equal (org-element-property :label d) label)
-                             d))
+                                  d))
                  definitions))
                ((pcase (org-footnote-get-definition label)
                   (`(,_ ,beg . ,_)
@@ -2785,16 +2802,16 @@ containing their first reference."
    ;; the definitions at the end of the tree.
    (org-footnote-section
     (org-element-adopt-elements
-     tree
-     (org-element-create 'headline
-                        (list :footnote-section-p t
-                              :level 1
-                              :title org-footnote-section
-                              :raw-value org-footnote-section)
-                        (apply #'org-element-create
-                               'section
-                               nil
-                               (nreverse definitions)))))
+        tree
+      (org-element-create 'headline
+                         (list :footnote-section-p t
+                               :level 1
+                               :title org-footnote-section
+                               :raw-value org-footnote-section)
+                         (apply #'org-element-create
+                                'section
+                                nil
+                                (nreverse definitions)))))
    ;; Otherwise add each definition at the end of the section where it
    ;; is first referenced.
    (t
@@ -2817,8 +2834,8 @@ containing their first reference."
                                          d))
                                   definitions)))
                            (org-element-adopt-elements
-                            (org-element-lineage reference '(section))
-                            definition)
+                               (org-element-lineage reference '(section))
+                             definition)
                            ;; Also insert definitions for nested
                            ;; references, if any.
                            (funcall insert-definitions definition))))))))))
@@ -2947,10 +2964,8 @@ Return code as a string."
                             (org-export-backend-name backend))
         (org-export-expand-include-keyword)
         (org-export--delete-comment-trees)
-        (org-macro-initialize-templates)
-        (org-macro-replace-all (append org-macro-templates
-                                       org-export-global-macros)
-                               parsed-keywords)
+        (org-macro-initialize-templates org-export-global-macros)
+        (org-macro-replace-all org-macro-templates parsed-keywords)
         ;; Refresh buffer properties and radio targets after previous
         ;; potentially invasive changes.
         (org-set-regexps-and-options)
@@ -2977,6 +2992,10 @@ Return code as a string."
         (setq info
               (org-combine-plists
                info (org-export-get-environment backend subtreep ext-plist)))
+         ;; Pre-process citations environment, i.e. install
+        ;; bibliography list, and citation processor in INFO.
+        (org-cite-store-bibliography info)
+         (org-cite-store-export-processor info)
         ;; De-activate uninterpreted data from parsed keywords.
         (dolist (entry (append (org-export-get-all-options backend)
                                org-export-options-alist))
@@ -3010,6 +3029,11 @@ Return code as a string."
         ;; Now tree is complete, compute its properties and add them
         ;; to communication channel.
         (setq info (org-export--collect-tree-properties tree info))
+         ;; Process citations and bibliography.  Replace each citation
+        ;; and "print_bibliography" keyword in the parse tree with
+        ;; the output of the selected citation export processor.
+         (org-cite-process-citations info)
+         (org-cite-process-bibliography info)
         ;; Eventually transcode TREE.  Wrap the resulting string into
         ;; a template.
         (let* ((body (org-element-normalize-string
@@ -3022,16 +3046,19 @@ Return code as a string."
                              (funcall inner-template body info))
                            info))
                (template (cdr (assq 'template
-                                    (plist-get info :translate-alist)))))
+                                    (plist-get info :translate-alist))))
+                (output
+                 (if (or (not (functionp template)) body-only) full-body
+                  (funcall template full-body info))))
+           ;; Call citation export finalizer.
+           (setq output (org-cite-finalize-export output info))
           ;; Remove all text properties since they cannot be
           ;; retrieved from an external process.  Finally call
           ;; final-output filter and return result.
           (org-no-properties
            (org-export-filter-apply-functions
             (plist-get info :filter-final-output)
-            (if (or (not (functionp template)) body-only) full-body
-              (funcall template full-body info))
-            info))))))))
+            output info))))))))
 
 ;;;###autoload
 (defun org-export-string-as (string backend &optional body-only ext-plist)
@@ -3104,22 +3131,22 @@ locally for the subtree through node properties."
          (keyword (unless (assoc keyword keywords)
                     (let ((value
                            (if (eq (nth 4 entry) 'split)
-                               (mapconcat #'identity (eval (nth 3 entry)) " ")
-                             (eval (nth 3 entry)))))
+                               (mapconcat #'identity (eval (nth 3 entry) t) " 
")
+                             (eval (nth 3 entry) t))))
                       (push (cons keyword value) keywords))))
          (option (unless (assoc option options)
-                   (push (cons option (eval (nth 3 entry))) options))))))
+                   (push (cons option (eval (nth 3 entry) t)) options))))))
     ;; Move to an appropriate location in order to insert options.
     (unless subtreep (beginning-of-line))
     ;; First (multiple) OPTIONS lines.  Never go past fill-column.
     (when options
       (let ((items
             (mapcar
-             #'(lambda (opt) (format "%s:%S" (car opt) (cdr opt)))
+              (lambda (opt) (format "%s:%S" (car opt) (cdr opt)))
              (sort options (lambda (k1 k2) (string< (car k1) (car k2)))))))
        (if subtreep
            (org-entry-put
-            node "EXPORT_OPTIONS" (mapconcat 'identity items " "))
+            node "EXPORT_OPTIONS" (mapconcat #'identity items " "))
          (while items
            (insert "#+options:")
            (let ((width 10))
@@ -3609,7 +3636,7 @@ will become the empty string."
         (attributes
          (let ((value (org-element-property attribute element)))
            (when value
-             (let ((s (mapconcat 'identity value " ")) result)
+             (let ((s (mapconcat #'identity value " ")) result)
                (while (string-match
                        "\\(?:^\\|[ \t]+\\)\\(:[-a-zA-Z0-9_]+\\)\\([ 
\t]+\\|$\\)"
                        s)
@@ -3659,7 +3686,8 @@ the communication channel used for export, as a plist."
   (when (symbolp backend) (setq backend (org-export-get-backend backend)))
   (org-export-barf-if-invalid-backend backend)
   (let ((type (org-element-type data)))
-    (when (memq type '(nil org-data)) (error "No foreign transcoder 
available"))
+    (when (memq type '(nil org-data raw))
+      (error "No foreign transcoder available"))
     (let* ((all-transcoders (org-export-get-all-transcoders backend))
           (transcoder (cdr (assq type all-transcoders))))
       (unless (functionp transcoder) (error "No foreign transcoder available"))
@@ -4194,10 +4222,10 @@ Return modified DATA."
                             (or rules org-export-default-inline-image-rule))
                ;; Replace contents with image link.
                (org-element-adopt-elements
-                (org-element-set-contents l nil)
-                (with-temp-buffer
-                  (save-excursion (insert contents))
-                  (org-element-link-parser))))))))
+                   (org-element-set-contents l nil)
+                 (with-temp-buffer
+                   (save-excursion (insert contents))
+                   (org-element-link-parser))))))))
       info nil nil t))
   data)
 
@@ -4553,6 +4581,17 @@ objects of the same type."
            ((funcall predicate el info) (cl-incf counter) nil)))
         info 'first-match)))))
 
+;;;; For Raw objects
+;;
+;; `org-export-raw-string' builds a pseudo-object out of a string
+;; that any export back-end returns as-is.
+
+(defun org-export-raw-string (s)
+  "Return a raw object containing string S.
+A raw string is exported as-is, with no additional processing
+from the export back-end."
+  (unless (stringp s) (error "Wrong raw contents type: %S" s))
+  (org-element-create 'raw nil s))
 
 ;;;; For Src-Blocks
 ;;
@@ -4702,7 +4741,7 @@ code."
             ;; should start six columns after the widest line of code,
             ;; wrapped with parenthesis.
             (max-width
-             (+ (apply 'max (mapcar 'length code-lines))
+             (+ (apply #'max (mapcar #'length code-lines))
                 (if (not num-start) 0 (length (format num-fmt num-start))))))
        (org-export-format-code
         code
@@ -5082,8 +5121,8 @@ INFO is a plist used as a communication channel."
   ;; A cell ends a column group either when it is at the end of a row
   ;; or when it has a right border.
   (or (eq (car (last (org-element-contents
-                        (org-export-get-parent table-cell))))
-            table-cell)
+                     (org-export-get-parent table-cell))))
+         table-cell)
       (memq 'right (org-export-table-cell-borders table-cell info))))
 
 (defun org-export-table-row-starts-rowgroup-p (table-row info)
@@ -5398,6 +5437,16 @@ transcoding it."
      (secondary-closing
       :utf-8 "‘" :html "&lsquo;" :latex "\\grq{}" :texinfo "@quoteleft{}")
      (apostrophe :utf-8 "’" :html "&rsquo;"))
+    ("el"
+     (primary-opening
+      :utf-8 "«" :html "&laquo;" :latex "\\guillemotleft{}"
+      :texinfo "@guillemetleft{}")
+     (primary-closing
+      :utf-8 "»" :html "&raquo;" :latex "\\guillemotright{}"
+      :texinfo "@guillemetright{}")
+     (secondary-opening :utf-8 "“" :html "&ldquo;" :latex "``" :texinfo "``")
+     (secondary-closing :utf-8 "”" :html "&rdquo;" :latex "''" :texinfo "''")
+     (apostrophe :utf-8 "’" :html "&rsquo;"))
     ("en"
      (primary-opening :utf-8 "“" :html "&ldquo;" :latex "``" :texinfo "``")
      (primary-closing :utf-8 "”" :html "&rdquo;" :latex "''" :texinfo "''")
@@ -5437,6 +5486,12 @@ transcoding it."
      (secondary-closing
       :utf-8 "‘" :html "&lsquo;" :latex "\\grq{}" :texinfo "@quoteleft{}")
      (apostrophe :utf-8 "’" :html "&rsquo;"))
+    ("it"
+     (primary-opening :utf-8 "“" :html "&ldquo;" :latex "``" :texinfo "``")
+     (primary-closing :utf-8 "”" :html "&rdquo;" :latex "''" :texinfo "''")
+     (secondary-opening :utf-8 "‘" :html "&lsquo;" :latex "`" :texinfo "`")
+     (secondary-closing :utf-8 "’" :html "&rsquo;" :latex "'" :texinfo "'")
+     (apostrophe :utf-8 "’" :html "&rsquo;"))
     ("no"
      ;; https://nn.wikipedia.org/wiki/Sitatteikn
      (primary-opening
@@ -5483,7 +5538,7 @@ transcoding it."
      (apostrophe :utf-8 "’" :html "&rsquo;"))
     ("ru"
      ;; 
https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D0%B2%D1%8B%D1%87%D0%BA%D0%B8#.D0.9A.D0.B0.D0.B2.D1.8B.D1.87.D0.BA.D0.B8.2C_.D0.B8.D1.81.D0.BF.D0.BE.D0.BB.D1.8C.D0.B7.D1.83.D0.B5.D0.BC.D1.8B.D0.B5_.D0.B2_.D1.80.D1.83.D1.81.D1.81.D0.BA.D0.BE.D0.BC_.D1.8F.D0.B7.D1.8B.D0.BA.D0.B5
-     ;; http://www.artlebedev.ru/kovodstvo/sections/104/
+     ;; https://www.artlebedev.ru/kovodstvo/sections/104/
      (primary-opening :utf-8 "«" :html "&laquo;" :latex "{}<<"
                      :texinfo "@guillemetleft{}")
      (primary-closing :utf-8 "»" :html "&raquo;" :latex ">>{}"
@@ -5745,6 +5800,7 @@ them."
      ("ru" :html "&#1040;&#1074;&#1090;&#1086;&#1088;" :utf-8 "Автор")
      ("sl" :default "Avtor")
      ("sv" :html "F&ouml;rfattare")
+     ("tr" :default "Yazar")
      ("uk" :html "&#1040;&#1074;&#1090;&#1086;&#1088;" :utf-8 "Автор")
      ("zh-CN" :html "&#20316;&#32773;" :utf-8 "作者")
      ("zh-TW" :html "&#20316;&#32773;" :utf-8 "作者"))
@@ -5757,12 +5813,14 @@ them."
      ("it" :default "Continua da pagina precedente")
      ("ja" :default "前ページからの続き")
      ("nl" :default "Vervolg van vorige pagina")
+     ("pl" :default "Ciąg dalszy poprzedniej strony")
      ("pt" :default "Continuação da página anterior")
      ("pt_BR" :html "Continua&ccedil;&atilde;o da p&aacute;gina anterior" 
:ascii "Continuacao da pagina anterior" :default "Continuação da página 
anterior")
      ("ro" :default "Continuare de pe pagina precedentă")
      ("ru" :html 
"(&#1055;&#1088;&#1086;&#1076;&#1086;&#1083;&#1078;&#1077;&#1085;&#1080;&#1077;)"
       :utf-8 "(Продолжение)")
-     ("sl" :default "Nadaljevanje s prejšnje strani"))
+     ("sl" :default "Nadaljevanje s prejšnje strani")
+     ("tr" :default "Önceki sayfadan devam ediyor"))
     ("Continued on next page"
      ("ar" :default "التتمة في الصفحة التالية")
      ("cs" :default "Pokračuje na další stránce")
@@ -5772,18 +5830,21 @@ them."
      ("it" :default "Continua alla pagina successiva")
      ("ja" :default "次ページに続く")
      ("nl" :default "Vervolg op volgende pagina")
+     ("pl" :default "Kontynuacja na następnej stronie")
      ("pt" :default "Continua na página seguinte")
      ("pt_BR" :html "Continua na pr&oacute;xima p&aacute;gina" :ascii 
"Continua na proxima pagina" :default "Continua na próxima página")
      ("ro" :default "Continuare pe pagina următoare")
      ("ru" :html 
"(&#1055;&#1088;&#1086;&#1076;&#1086;&#1083;&#1078;&#1077;&#1085;&#1080;&#1077; 
&#1089;&#1083;&#1077;&#1076;&#1091;&#1077;&#1090;)"
       :utf-8 "(Продолжение следует)")
-     ("sl" :default "Nadaljevanje na naslednji strani"))
+     ("sl" :default "Nadaljevanje na naslednji strani")
+     ("tr" :default "Devamı sonraki sayfada"))
     ("Created"
      ("cs" :default "Vytvořeno")
      ("nl" :default "Gemaakt op")  ;; must be followed by a date or date+time
      ("pt_BR" :default "Criado em")
      ("ro" :default "Creat")
-     ("sl" :default "Ustvarjeno"))
+     ("sl" :default "Ustvarjeno")
+     ("tr" :default "Oluşturuldu"))
     ("Date"
      ("ar" :default "بتاريخ")
      ("ca" :default "Data")
@@ -5808,6 +5869,7 @@ them."
      ("ru" :html "&#1044;&#1072;&#1090;&#1072;" :utf-8 "Дата")
      ("sl" :default "Datum")
      ("sv" :default "Datum")
+     ("tr" :default "Tarih")
      ("uk" :html "&#1044;&#1072;&#1090;&#1072;" :utf-8 "Дата")
      ("zh-CN" :html "&#26085;&#26399;" :utf-8 "日期")
      ("zh-TW" :html "&#26085;&#26399;" :utf-8 "日期"))
@@ -5831,6 +5893,7 @@ them."
       :utf-8 "Уравнение")
      ("sl" :default "Enačba")
      ("sv" :default "Ekvation")
+     ("tr" :default "Eşitlik")
      ("zh-CN" :html "&#26041;&#31243;" :utf-8 "方程"))
     ("Figure"
      ("ar" :default "شكل")
@@ -5850,6 +5913,7 @@ them."
      ("ro" :default "Imaginea")
      ("ru" :html "&#1056;&#1080;&#1089;&#1091;&#1085;&#1086;&#1082;" :utf-8 
"Рисунок")
      ("sv" :default "Illustration")
+     ("tr" :default "Şekil")
      ("zh-CN" :html "&#22270;" :utf-8 "图"))
     ("Figure %d:"
      ("ar" :default "شكل %d:")
@@ -5871,6 +5935,7 @@ them."
      ("ru" :html "&#1056;&#1080;&#1089;. %d.:" :utf-8 "Рис. %d.:")
      ("sl" :default "Slika %d")
      ("sv" :default "Illustration %d")
+     ("tr" :default "Şekil %d:")
      ("zh-CN" :html "&#22270;%d&nbsp;" :utf-8 "图%d "))
     ("Footnotes"
      ("ar" :default "الهوامش")
@@ -5879,7 +5944,7 @@ them."
      ("da" :default "Fodnoter")
      ("de" :html "Fu&szlig;noten" :default "Fußnoten")
      ("eo" :default "Piednotoj")
-     ("es" :ascii "Nota al pie de pagina" :html "Nota al pie de p&aacute;gina" 
:default "Nota al pie de página")
+     ("es" :ascii "Notas al pie de pagina" :html "Notas al pie de 
p&aacute;gina" :default "Notas al pie de página")
      ("et" :html "Allm&#228;rkused" :utf-8 "Allmärkused")
      ("fi" :default "Alaviitteet")
      ("fr" :default "Notes de bas de page")
@@ -5897,6 +5962,7 @@ them."
      ("ru" :html "&#1057;&#1085;&#1086;&#1089;&#1082;&#1080;" :utf-8 "Сноски")
      ("sl" :default "Opombe")
      ("sv" :default "Fotnoter")
+     ("tr" :default "Dipnotlar")
      ("uk" :html "&#1055;&#1088;&#1080;&#1084;&#1110;&#1090;&#1082;&#1080;"
       :utf-8 "Примітки")
      ("zh-CN" :html "&#33050;&#27880;" :utf-8 "脚注")
@@ -5917,6 +5983,7 @@ them."
      ("ru" :html "&#1057;&#1087;&#1080;&#1089;&#1086;&#1082; 
&#1088;&#1072;&#1089;&#1087;&#1077;&#1095;&#1072;&#1090;&#1086;&#1082;"
       :utf-8 "Список распечаток")
      ("sl" :default "Seznam programskih izpisov")
+     ("tr" :default "Program Listesi")
      ("zh-CN" :html "&#20195;&#30721;&#30446;&#24405;" :utf-8 "代码目录"))
     ("List of Tables"
      ("ar" :default "قائمة بالجداول")
@@ -5939,6 +6006,7 @@ them."
       :utf-8 "Список таблиц")
      ("sl" :default "Seznam tabel")
      ("sv" :default "Tabeller")
+     ("tr" :default "Tablo Listesi")
      ("zh-CN" :html "&#34920;&#26684;&#30446;&#24405;" :utf-8 "表格目录"))
     ("Listing"
      ("ar" :default "برنامج")
@@ -5958,6 +6026,7 @@ them."
      ("ru" :html 
"&#1056;&#1072;&#1089;&#1087;&#1077;&#1095;&#1072;&#1090;&#1082;&#1072;"
       :utf-8 "Распечатка")
      ("sl" :default "Izpis programa")
+     ("tr" :default "Program")
      ("zh-CN" :html "&#20195;&#30721;" :utf-8 "代码"))
     ("Listing %d:"
      ("ar" :default "برنامج %d:")
@@ -5977,6 +6046,7 @@ them."
      ("ru" :html 
"&#1056;&#1072;&#1089;&#1087;&#1077;&#1095;&#1072;&#1090;&#1082;&#1072; %d.:"
       :utf-8 "Распечатка %d.:")
      ("sl" :default "Izpis programa %d")
+     ("tr" :default "Program %d:")
      ("zh-CN" :html "&#20195;&#30721;%d&nbsp;" :utf-8 "代码%d "))
     ("References"
      ("ar" :default "المراجع")
@@ -5988,7 +6058,8 @@ them."
      ("nl" :default "Bronverwijzingen")
      ("pt_BR" :html "Refer&ecirc;ncias" :default "Referências" :ascii 
"Referencias")
      ("ro" :default "Bibliografie")
-     ("sl" :default "Reference"))
+     ("sl" :default "Reference")
+     ("tr" :default "Referanslar"))
     ("See figure %s"
      ("cs" :default "Viz obrázek %s")
      ("fr" :default "cf. figure %s"
@@ -5998,7 +6069,8 @@ them."
       :html "Zie figuur&nbsp;%s" :latex "Zie figuur~%s")
      ("pt_BR" :default "Veja a figura %s")
      ("ro" :default "Vezi figura %s")
-     ("sl" :default "Glej sliko %s"))
+     ("sl" :default "Glej sliko %s")
+     ("tr" :default "bkz. şekil %s"))
     ("See listing %s"
      ("cs" :default "Viz program %s")
      ("fr" :default "cf. programme %s"
@@ -6007,7 +6079,8 @@ them."
       :html "Zie programma&nbsp;%s" :latex "Zie programma~%s")
      ("pt_BR" :default "Veja a listagem %s")
      ("ro" :default "Vezi tabelul %s")
-     ("sl" :default "Glej izpis programa %s"))
+     ("sl" :default "Glej izpis programa %s")
+     ("tr" :default "bkz. program %s"))
     ("See section %s"
      ("ar" :default "انظر قسم %s")
      ("cs" :default "Viz sekce %s")
@@ -6026,6 +6099,7 @@ them."
      ("ru" :html "&#1057;&#1084;. &#1088;&#1072;&#1079;&#1076;&#1077;&#1083; 
%s"
       :utf-8 "См. раздел %s")
      ("sl" :default "Glej poglavje %d")
+     ("tr" :default "bkz. bölüm %s")
      ("zh-CN" :html "&#21442;&#35265;&#31532;%s&#33410;" :utf-8 "参见第%s节"))
     ("See table %s"
      ("cs" :default "Viz tabulka %s")
@@ -6036,7 +6110,8 @@ them."
       :html "Zie tabel&nbsp;%s" :latex "Zie tabel~%s")
      ("pt_BR" :default "Veja a tabela %s")
      ("ro" :default "Vezi tabelul %s")
-     ("sl" :default "Glej tabelo %s"))
+     ("sl" :default "Glej tabelo %s")
+     ("tr" :default "bkz. tablo %s"))
     ("Table"
      ("ar" :default "جدول")
      ("cs" :default "Tabulka")
@@ -6052,6 +6127,7 @@ them."
      ("ro" :default "Tabel")
      ("ru" :html "&#1058;&#1072;&#1073;&#1083;&#1080;&#1094;&#1072;"
       :utf-8 "Таблица")
+     ("tr" :default "Tablo")
      ("zh-CN" :html "&#34920;" :utf-8 "表"))
     ("Table %d:"
      ("ar" :default "جدول %d:")
@@ -6074,6 +6150,7 @@ them."
       :utf-8 "Таблица %d.:")
      ("sl" :default "Tabela %d")
      ("sv" :default "Tabell %d")
+     ("tr" :default "Tablo %d")
      ("zh-CN" :html "&#34920;%d&nbsp;" :utf-8 "表%d "))
     ("Table of Contents"
      ("ar" :default "قائمة المحتويات")
@@ -6101,6 +6178,7 @@ them."
       :utf-8 "Содержание")
      ("sl" :default "Kazalo")
      ("sv" :html "Inneh&aring;ll")
+     ("tr" :default "İçindekiler")
      ("uk" :html "&#1047;&#1084;&#1110;&#1089;&#1090;" :utf-8 "Зміст")
      ("zh-CN" :html "&#30446;&#24405;" :utf-8 "目录")
      ("zh-TW" :html "&#30446;&#37636;" :utf-8 "目錄"))
@@ -6119,6 +6197,7 @@ them."
      ("ru" :html 
"&#1053;&#1077;&#1080;&#1079;&#1074;&#1077;&#1089;&#1090;&#1085;&#1072;&#1103; 
&#1089;&#1089;&#1099;&#1083;&#1082;&#1072;"
       :utf-8 "Неизвестная ссылка")
      ("sl" :default "Neznana referenca")
+     ("tr" :default "Bilinmeyen referans")
      ("zh-CN" :html "&#26410;&#30693;&#24341;&#29992;" :utf-8 "未知引用")))
   "Dictionary for export engine.
 
@@ -6176,97 +6255,93 @@ to `:default' encoding.  If it fails, return S."
 ;; For back-ends, `org-export-add-to-stack' add a new source to stack.
 ;; It should be used whenever `org-export-async-start' is called.
 
-(defmacro org-export-async-start  (fun &rest body)
+(defun org-export-async-start  (fun body)
   "Call function FUN on the results returned by BODY evaluation.
 
-FUN is an anonymous function of one argument.  BODY evaluation
-happens in an asynchronous process, from a buffer which is an
-exact copy of the current one.
+FUN is an anonymous function of one argument.  BODY should be a valid
+ELisp source expression.  BODY evaluation happens in an asynchronous process,
+from a buffer which is an exact copy of the current one.
 
 Use `org-export-add-to-stack' in FUN in order to register results
 in the stack.
 
 This is a low level function.  See also `org-export-to-buffer'
 and `org-export-to-file' for more specialized functions."
-  (declare (indent 1) (debug t))
-  (org-with-gensyms (process temp-file copy-fun proc-buffer coding)
-    ;; Write the full sexp evaluating BODY in a copy of the current
-    ;; buffer to a temporary file, as it may be too long for program
-    ;; args in `start-process'.
-    `(with-temp-message "Initializing asynchronous export process"
-       (let ((,copy-fun (org-export--generate-copy-script (current-buffer)))
-             (,temp-file (make-temp-file "org-export-process"))
-             (,coding buffer-file-coding-system))
-         (with-temp-file ,temp-file
-           (insert
-            ;; Null characters (from variable values) are inserted
-            ;; within the file.  As a consequence, coding system for
-            ;; buffer contents will not be recognized properly.  So,
-            ;; we make sure it is the same as the one used to display
-            ;; the original buffer.
-            (format ";; -*- coding: %s; -*-\n%S"
-                    ,coding
-                    `(with-temp-buffer
-                       (when org-export-async-debug '(setq debug-on-error t))
-                       ;; Ignore `kill-emacs-hook' and code evaluation
-                       ;; queries from Babel as we need a truly
-                       ;; non-interactive process.
-                       (setq kill-emacs-hook nil
-                             org-babel-confirm-evaluate-answer-no t)
-                       ;; Initialize export framework.
-                       (require 'ox)
-                       ;; Re-create current buffer there.
-                       (funcall ,,copy-fun)
-                       (restore-buffer-modified-p nil)
-                       ;; Sexp to evaluate in the buffer.
-                       (print (progn ,,@body))))))
-         ;; Start external process.
-         (let* ((process-connection-type nil)
-                (,proc-buffer (generate-new-buffer-name "*Org Export 
Process*"))
-                (,process
-                (apply
-                 #'start-process
-                 (append
-                  (list "org-export-process"
-                        ,proc-buffer
-                        (expand-file-name invocation-name invocation-directory)
-                        "--batch")
-                  (if org-export-async-init-file
-                      (list "-Q" "-l" org-export-async-init-file)
-                    (list "-l" user-init-file))
-                  (list "-l" ,temp-file)))))
-           ;; Register running process in stack.
-           (org-export-add-to-stack (get-buffer ,proc-buffer) nil ,process)
-           ;; Set-up sentinel in order to catch results.
-           (let ((handler ,fun))
-             (set-process-sentinel
-              ,process
-              `(lambda (p status)
-                 (let ((proc-buffer (process-buffer p)))
-                   (when (eq (process-status p) 'exit)
-                     (unwind-protect
-                         (if (zerop (process-exit-status p))
-                             (unwind-protect
-                                 (let ((results
-                                        (with-current-buffer proc-buffer
-                                          (goto-char (point-max))
-                                          (backward-sexp)
-                                          (read (current-buffer)))))
-                                   (funcall ,handler results))
-                               (unless org-export-async-debug
-                                 (and (get-buffer proc-buffer)
-                                      (kill-buffer proc-buffer))))
-                           (org-export-add-to-stack proc-buffer nil p)
-                           (ding)
-                           (message "Process `%s' exited abnormally" p))
-                       (unless org-export-async-debug
-                         (delete-file ,,temp-file)))))))))))))
+  (declare (indent 1))
+  ;; Write the full sexp evaluating BODY in a copy of the current
+  ;; buffer to a temporary file, as it may be too long for program
+  ;; args in `start-process'.
+  (with-temp-message "Initializing asynchronous export process"
+    (let ((copy-fun (org-export--generate-copy-script (current-buffer)))
+          (temp-file (make-temp-file "org-export-process")))
+      (let ((coding-system-for-write 'utf-8-emacs-unix))
+        (write-region
+         ;; Null characters (from variable values) are inserted
+         ;; within the file.  As a consequence, coding system for
+         ;; buffer contents could fail to be recognized properly.
+         (format ";; -*- coding: utf-8-emacs-unix; lexical-binding:t -*-\n%S"
+                 `(with-temp-buffer
+                    ,(when org-export-async-debug '(setq debug-on-error t))
+                    ;; Ignore `kill-emacs-hook' and code evaluation
+                    ;; queries from Babel as we need a truly
+                    ;; non-interactive process.
+                    (setq kill-emacs-hook nil
+                          org-babel-confirm-evaluate-answer-no t)
+                    ;; Initialize export framework.
+                    (require 'ox)
+                    ;; Re-create current buffer there.
+                    (funcall ',copy-fun)
+                    (restore-buffer-modified-p nil)
+                    ;; Sexp to evaluate in the buffer.
+                    (print ,body)))
+         nil temp-file nil 'silent))
+      ;; Start external process.
+      (let* ((process-connection-type nil)
+             (proc-buffer (generate-new-buffer-name "*Org Export Process*"))
+             (process
+             (apply
+              #'start-process
+              (append
+               (list "org-export-process"
+                     proc-buffer
+                     (expand-file-name invocation-name invocation-directory)
+                     "--batch")
+               (if org-export-async-init-file
+                   (list "-Q" "-l" org-export-async-init-file)
+                 (list "-l" user-init-file))
+               (list "-l" temp-file)))))
+        ;; Register running process in stack.
+        (org-export-add-to-stack (get-buffer proc-buffer) nil process)
+        ;; Set-up sentinel in order to catch results.
+        (let ((handler fun))
+          (set-process-sentinel
+           process
+           (lambda (p _status)
+             (let ((proc-buffer (process-buffer p)))
+               (when (eq (process-status p) 'exit)
+                 (unwind-protect
+                     (if (zerop (process-exit-status p))
+                         (unwind-protect
+                             (let ((results
+                                    (with-current-buffer proc-buffer
+                                      (goto-char (point-max))
+                                      (backward-sexp)
+                                      (read (current-buffer)))))
+                               (funcall handler results))
+                           (unless org-export-async-debug
+                             (and (get-buffer proc-buffer)
+                                  (kill-buffer proc-buffer))))
+                       (org-export-add-to-stack proc-buffer nil p)
+                       (ding)
+                       (message "Process `%s' exited abnormally" p))
+                   (unless org-export-async-debug
+                     (delete-file temp-file))))))))))))
 
 ;;;###autoload
 (defun org-export-to-buffer
-  (backend buffer
-          &optional async subtreep visible-only body-only ext-plist
-          post-process)
+    (backend buffer
+            &optional async subtreep visible-only body-only ext-plist
+            post-process)
   "Call `org-export-as' with output to a specified buffer.
 
 BACKEND is either an export back-end, as returned by, e.g.,
@@ -6301,14 +6376,15 @@ This function returns BUFFER."
   (declare (indent 2))
   (if async
       (org-export-async-start
-         `(lambda (output)
-            (with-current-buffer (get-buffer-create ,buffer)
-              (erase-buffer)
-              (setq buffer-file-coding-system ',buffer-file-coding-system)
-              (insert output)
-              (goto-char (point-min))
-              (org-export-add-to-stack (current-buffer) ',backend)
-              (ignore-errors (funcall ,post-process))))
+         (let ((cs buffer-file-coding-system))
+           (lambda (output)
+             (with-current-buffer (get-buffer-create buffer)
+               (erase-buffer)
+               (setq buffer-file-coding-system cs)
+               (insert output)
+               (goto-char (point-min))
+               (org-export-add-to-stack (current-buffer) backend)
+               (ignore-errors (funcall post-process)))))
        `(org-export-as
          ',backend ,subtreep ,visible-only ,body-only ',ext-plist))
     (let ((output
@@ -6329,8 +6405,8 @@ This function returns BUFFER."
 
 ;;;###autoload
 (defun org-export-to-file
-  (backend file &optional async subtreep visible-only body-only ext-plist
-          post-process)
+    (backend file &optional async subtreep visible-only body-only ext-plist
+            post-process)
   "Call `org-export-as' with output to a specified file.
 
 BACKEND is either an export back-end, as returned by, e.g.,
@@ -6364,11 +6440,12 @@ or FILE."
   (declare (indent 2))
   (if (not (file-writable-p file)) (error "Output file not writable")
     (let ((ext-plist (org-combine-plists `(:output-file ,file) ext-plist))
-         (encoding (or org-export-coding-system buffer-file-coding-system)))
+         (encoding (or org-export-coding-system buffer-file-coding-system))
+          auto-mode-alist)
       (if async
           (org-export-async-start
-             `(lambda (file)
-                (org-export-add-to-stack (expand-file-name file) ',backend))
+             (lambda (file)
+               (org-export-add-to-stack (expand-file-name file) backend))
            `(let ((output
                    (org-export-as
                     ',backend ,subtreep ,visible-only ,body-only
@@ -6422,7 +6499,10 @@ Return file name as a string."
                         (throw :found
                                (org-element-property :value element))))))))
             ;; Extract from buffer's associated file, if any.
-            (and visited-file (file-name-nondirectory visited-file))
+            (and visited-file
+                  (file-name-nondirectory
+                   ;; For a .gpg visited file, remove the .gpg extension:
+                   (replace-regexp-in-string "\\.gpg\\'" "" visited-file)))
             ;; Can't determine file name on our own: ask user.
             (read-file-name
              "Output file: " pub-dir nil nil nil
@@ -6483,7 +6563,7 @@ If optional argument SOURCE is non-nil, remove it 
instead."
   (let ((source (or source (org-export--stack-source-at-point))))
     (setq org-export-stack-contents
          (cl-remove-if (lambda (el) (equal (car el) source))
-                        org-export-stack-contents))))
+                       org-export-stack-contents))))
 
 (defun org-export-stack-view (&optional in-emacs)
   "View export results at point in stack.
@@ -6499,16 +6579,16 @@ within Emacs."
 (defvar org-export-stack-mode-map
   (let ((km (make-sparse-keymap)))
     (set-keymap-parent km tabulated-list-mode-map)
-    (define-key km " " 'next-line)
-    (define-key km "\C-n" 'next-line)
-    (define-key km [down] 'next-line)
-    (define-key km "\C-p" 'previous-line)
-    (define-key km "\C-?" 'previous-line)
-    (define-key km [up] 'previous-line)
-    (define-key km "C" 'org-export-stack-clear)
-    (define-key km "v" 'org-export-stack-view)
-    (define-key km (kbd "RET") 'org-export-stack-view)
-    (define-key km "d" 'org-export-stack-remove)
+    (define-key km " " #'next-line)
+    (define-key km "\C-n" #'next-line)
+    (define-key km [down] #'next-line)
+    (define-key km "\C-p" #'previous-line)
+    (define-key km "\C-?" #'previous-line)
+    (define-key km [up] #'previous-line)
+    (define-key km "C"  #'org-export-stack-clear)
+    (define-key km "v"  #'org-export-stack-view)
+    (define-key km (kbd "RET") #'org-export-stack-view)
+    (define-key km "d" #'org-export-stack-remove)
     km)
   "Keymap for Org Export Stack.")
 
@@ -6706,7 +6786,7 @@ back to standard interface."
            ;; on the first key, if any.  A nil value means KEY will
            ;; only be activated at first level.
            (if (or (eq access-key t) (eq access-key first-key))
-               (propertize key 'face 'org-warning)
+               (propertize key 'face 'org-dispatcher-highlight)
              key)))
         (fontify-value
          (lambda (value)
@@ -6725,16 +6805,16 @@ back to standard interface."
                          (cond ((and (numberp key-a) (numberp key-b))
                                 (< key-a key-b))
                                ((numberp key-b) t)))))
-               'car-less-than-car))
+               #'car-less-than-car))
         ;; Compute a list of allowed keys based on the first key
         ;; pressed, if any.  Some keys
         ;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always
         ;; available.
         (allowed-keys
          (nconc (list 2 22 19 6 1)
-                (if (not first-key) (org-uniquify (mapcar 'car entries))
+                (if (not first-key) (org-uniquify (mapcar #'car entries))
                   (let (sub-menu)
-                    (dolist (entry entries (sort (mapcar 'car sub-menu) '<))
+                    (dolist (entry entries (sort (mapcar #'car sub-menu) #'<))
                       (when (eq (car entry) first-key)
                         (setq sub-menu (append (nth 2 entry) sub-menu))))))
                 (cond ((eq first-key ?P) (list ?f ?p ?x ?a))
diff --git a/lisp/outline.el b/lisp/outline.el
index 52a94b4d9f..cefb811703 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -35,6 +35,8 @@
 
 ;;; Code:
 
+(eval-when-compile (require 'cl-lib))
+
 (defgroup outlines nil
   "Support for hierarchical outlining."
   :prefix "outline-"
@@ -272,6 +274,24 @@ in the file it applies to.")
 (defvar outline-font-lock-faces
   [outline-1 outline-2 outline-3 outline-4
    outline-5 outline-6 outline-7 outline-8])
+
+(defcustom outline-minor-mode-use-buttons nil
+  "If non-nil, use clickable buttons on the headings.
+Note that this feature is not meant to be used in editing
+buffers (yet) -- that will be amended in a future version.
+
+The `outline-minor-mode-buttons' variable specifies how the
+buttons should look."
+  :type 'boolean
+  :version "29.1")
+
+(defcustom outline-minor-mode-buttons
+  '(("▶️" "🔽" outline--valid-emoji-p)
+    ("▶" "▼" outline--valid-char-p))
+  "List of close/open pairs to use if using buttons."
+  :type 'sexp
+  :version "29.1")
+
 
 (defvar outline-level #'outline-level
   "Function of no args to compute a header's nesting level in an outline.
@@ -388,6 +408,8 @@ faces to major mode's faces."
                          (goto-char (match-beginning 0))
                          (not (get-text-property (point) 'face))))
             (overlay-put overlay 'face (outline-font-lock-face)))
+          (when outline-minor-mode-use-buttons
+            (outline--insert-open-button))
           (when outline-minor-mode-cycle
             (overlay-put overlay 'keymap outline-minor-mode-cycle-map)))
         (goto-char (match-end 0))))))
@@ -807,6 +829,7 @@ If FLAG is nil then text is shown, while if FLAG is t the 
text is hidden."
       (overlay-put o 'isearch-open-invisible
                   (or outline-isearch-open-invisible-function
                       #'outline-isearch-open-invisible))))
+  (outline--fix-up-all-buttons from to)
   ;; Seems only used by lazy-lock.  I.e. obsolete.
   (run-hooks 'outline-view-change-hook))
 
@@ -923,11 +946,79 @@ Note that this does not hide the lines preceding the 
first heading line."
 
 (define-obsolete-function-alias 'show-all #'outline-show-all "25.1")
 
-(defun outline-hide-subtree ()
-  "Hide everything after this heading at deeper levels."
-  (interactive)
+(defun outline-hide-subtree (&optional event)
+  "Hide everything after this heading at deeper levels.
+If non-nil, EVENT should be a mouse event."
+  (interactive (list last-nonmenu-event))
+  (when (mouse-event-p event)
+    (mouse-set-point event))
+  (when (and outline-minor-mode-use-buttons outline-minor-mode)
+    (outline--insert-close-button))
   (outline-flag-subtree t))
 
+(defun outline--make-button (type)
+  (cl-loop for (close open test) in outline-minor-mode-buttons
+           when (and (funcall test close) (funcall test open))
+           return (concat (if (eq type 'close)
+                              close
+                            open)
+                          " " (buffer-substring (point) (1+ (point))))))
+
+(defun outline--valid-emoji-p (string)
+  (when-let ((font (and (display-multi-font-p)
+                        (car (internal-char-font nil ?😀)))))
+    (font-has-char-p font (aref string 0))))
+
+(defun outline--valid-char-p (string)
+  (char-displayable-p (aref string 0)))
+
+(defun outline--make-button-overlay (type)
+  (let ((o (seq-find (lambda (o)
+                       (overlay-get o 'outline-button))
+                     (overlays-at (point)))))
+    (unless o
+      (setq o (make-overlay (point) (1+ (point))))
+      (overlay-put o 'follow-link 'mouse-face)
+      (overlay-put o 'mouse-face 'highlight)
+      (overlay-put o 'outline-button t))
+    (overlay-put o 'display (outline--make-button type))
+    o))
+
+(defun outline--insert-open-button ()
+  (save-excursion
+    (beginning-of-line)
+    (let ((o (outline--make-button-overlay 'open)))
+      (overlay-put o 'help-echo "Click to hide")
+      (overlay-put o 'keymap
+                   (define-keymap
+                     :parent outline-minor-mode-cycle-map
+                     ["RET"] #'outline-hide-subtree
+                     ["<mouse-2>"] #'outline-hide-subtree)))))
+
+(defun outline--insert-close-button ()
+  (save-excursion
+    (beginning-of-line)
+    (let ((o (outline--make-button-overlay 'close)))
+      (overlay-put o 'help-echo "Click to show")
+      (overlay-put o 'keymap
+                   (define-keymap
+                     :parent outline-minor-mode-cycle-map
+                     ["RET"] #'outline-show-subtree
+                     ["<mouse-2>"] #'outline-show-subtree)))))
+
+(defun outline--fix-up-all-buttons (&optional from to)
+  (when from
+    (save-excursion
+      (goto-char from)
+      (setq from (line-beginning-position))))
+  (when outline-minor-mode-use-buttons
+    (outline-map-region
+     (lambda ()
+       (if (eq (outline--cycle-state) 'show-all)
+           (outline--insert-open-button)
+         (outline--insert-close-button)))
+     (or from (point-min)) (or to (point-max)))))
+
 (define-obsolete-function-alias 'hide-subtree #'outline-hide-subtree "25.1")
 
 (defun outline-hide-leaves ()
@@ -943,9 +1034,13 @@ Note that this does not hide the lines preceding the 
first heading line."
 
 (define-obsolete-function-alias 'hide-leaves #'outline-hide-leaves "25.1")
 
-(defun outline-show-subtree ()
+(defun outline-show-subtree (&optional event)
   "Show everything after this heading at deeper levels."
-  (interactive)
+  (interactive (list last-nonmenu-event))
+  (when (mouse-event-p event)
+    (mouse-set-point event))
+  (when (and outline-minor-mode-use-buttons outline-minor-mode)
+    (outline--insert-open-button))
   (outline-flag-subtree nil))
 
 (define-obsolete-function-alias 'show-subtree #'outline-show-subtree "25.1")
@@ -1295,7 +1390,8 @@ Return either 'hide-all, 'headings-only, or 'show-all."
      (t
       (outline-show-all)
       (setq outline--cycle-buffer-state 'show-all)
-      (message "Show all")))))
+      (message "Show all")))
+    (outline--fix-up-all-buttons)))
 
 (defvar outline-navigation-repeat-map
   (let ((map (make-sparse-keymap)))
diff --git a/lisp/paren.el b/lisp/paren.el
index 708605f794..7e7cf6c262 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -88,6 +88,14 @@ is not highlighted, the cursor being regarded as adequate to 
mark
 its position."
   :type 'boolean)
 
+(defcustom show-paren-context-when-offscreen nil
+  "If non-nil, show context in the echo area when the openparen is offscreen.
+The context is usually the line that contains the openparen,
+except if the openparen is on its own line, in which case the
+context includes the previous nonblank line."
+  :type 'boolean
+  :version "29.1")
+
 (defvar show-paren--idle-timer nil)
 (defvar show-paren--overlay
   (let ((ol (make-overlay (point) (point) nil t))) (delete-overlay ol) ol)
@@ -107,6 +115,8 @@ after `show-paren-delay' seconds of Emacs idle time.
 This is a global minor mode.  To toggle the mode in a single buffer,
 use `show-paren-local-mode'."
   :global t :group 'paren-showing
+  :initialize 'custom-initialize-delay
+  :init-value t
   ;; Enable or disable the mechanism.
   ;; First get rid of the old idle timer.
   (when show-paren--idle-timer
@@ -310,6 +320,19 @@ It is the default value of `show-paren-data-function'."
                             (current-buffer))
             (move-overlay show-paren--overlay
                           there-beg there-end (current-buffer)))
+          ;; If `show-paren-open-line-when-offscreen' is t and point
+          ;; is at a close paren, show the line that contains the
+          ;; openparen in the echo area.
+          (let ((openparen (min here-beg there-beg)))
+            (if (and show-paren-context-when-offscreen
+                     (< there-beg here-beg)
+                     (not (pos-visible-in-window-p openparen)))
+                (let ((open-paren-line-string
+                       (blink-paren-open-paren-line-string openparen))
+                      (message-log-max nil))
+                  (minibuffer-message
+                   "Matches %s"
+                   (substring-no-properties open-paren-line-string)))))
           ;; Always set the overlay face, since it varies.
           (overlay-put show-paren--overlay 'priority show-paren-priority)
           (overlay-put show-paren--overlay 'face face))))))
diff --git a/lisp/play/doctor.el b/lisp/play/doctor.el
index b855f7e35a..33fecaa188 100644
--- a/lisp/play/doctor.el
+++ b/lisp/play/doctor.el
@@ -1011,8 +1011,8 @@ Put dialogue in buffer."
 
 (defun doctor-subjsearch (sent key type)
   "Search for the subject of a sentence SENT, looking for the noun closest
-to and preceding KEY by at least TYPE words.  Set global variable 
`doctor-subj' to
-the subject noun, and return the portion of the sentence following it."
+to and preceding KEY by at least TYPE words.  Set global variable `doctor-subj'
+to the subject noun, and return the portion of the sentence following it."
   (let ((i (- (length sent) (length (memq key sent)) type)))
     (while (and (> i -1) (not (doctor-nounp (nth i sent))))
       (setq i (1- i)))
diff --git a/lisp/play/mpuz.el b/lisp/play/mpuz.el
index ff174fed6c..df2b6fc867 100644
--- a/lisp/play/mpuz.el
+++ b/lisp/play/mpuz.el
@@ -153,7 +153,7 @@ You may abort a game by typing 
\\<mpuz-mode-map>\\[mpuz-offer-abort]."
        (index 10)
        elem)
     (while letters
-      (setq elem    (nth (random index) letters)
+      (setq elem    (seq-random-elt letters)
            letters (delq elem letters)
            index   (1- index))
       (aset mpuz-digit-to-letter index elem)
diff --git a/lisp/play/zone.el b/lisp/play/zone.el
index 27aa48f4c9..a5d4ac9dc6 100644
--- a/lisp/play/zone.el
+++ b/lisp/play/zone.el
@@ -596,7 +596,7 @@ If the element is a function or a list of a function and a 
number,
          (forward-line -1)
          (delete-region (point) (line-beginning-position 2))
          (goto-char (point-min))
-         (insert (nth (random (length lines)) lines)))
+         (insert (seq-random-elt lines)))
        (message (concat (make-string (random (- (frame-width) 5)) ? ) "grrr"))
        (sit-for 0.1)))))
 
diff --git a/lisp/printing.el b/lisp/printing.el
index fb718f9aa6..dfa5a6ef76 100644
--- a/lisp/printing.el
+++ b/lisp/printing.el
@@ -5133,7 +5133,7 @@ If menu binding was not done, calls `pr-menu-bind'."
   (and (eq (symbol-value infile-sym) t)
        (set infile-sym (pr-ps-infile-preprint prompt)))
   (or (symbol-value infile-sym)
-      (error "%s: input PostScript file name is missing" prompt))
+      (error "%s: Input PostScript file name is missing" prompt))
   ;; output file
   (and (eq (symbol-value outfile-sym) t)
        (set outfile-sym (and current-prefix-arg
diff --git a/lisp/proced.el b/lisp/proced.el
index fec2a29c84..e959e91c6e 100644
--- a/lisp/proced.el
+++ b/lisp/proced.el
@@ -658,6 +658,7 @@ After displaying or updating a Proced buffer, Proced runs 
the normal hook
 `proced-post-display-hook'.
 
 \\{proced-mode-map}"
+  :interactive nil
   (abbrev-mode 0)
   (auto-fill-mode 0)
   (setq buffer-read-only t
@@ -721,7 +722,7 @@ Proced buffers."
 With prefix ARG, update this buffer automatically if ARG is positive,
 otherwise do not update.  Sets the variable `proced-auto-update-flag'.
 The time interval for updates is specified via `proced-auto-update-interval'."
-  (interactive (list (or current-prefix-arg 'toggle)))
+  (interactive (list (or current-prefix-arg 'toggle)) proced-mode)
   (setq proced-auto-update-flag
         (cond ((eq arg 'toggle) (not proced-auto-update-flag))
               (arg (> (prefix-numeric-value arg) 0))
@@ -733,19 +734,19 @@ The time interval for updates is specified via 
`proced-auto-update-interval'."
 
 (defun proced-mark (&optional count)
   "Mark the current (or next COUNT) processes."
-  (interactive "p")
+  (interactive "p" proced-mode)
   (proced-do-mark t count))
 
 (defun proced-unmark (&optional count)
   "Unmark the current (or next COUNT) processes."
-  (interactive "p")
+  (interactive "p" proced-mode)
   (proced-do-mark nil count))
 
 (defun proced-unmark-backward (&optional count)
   "Unmark the previous (or COUNT previous) processes."
   ;; Analogous to `dired-unmark-backward',
   ;; but `ibuffer-unmark-backward' behaves different.
-  (interactive "p")
+  (interactive "p" proced-mode)
   (proced-do-mark nil (- (or count 1))))
 
 (defun proced-do-mark (mark &optional count)
@@ -762,7 +763,7 @@ The time interval for updates is specified via 
`proced-auto-update-interval'."
 
 (defun proced-toggle-marks ()
   "Toggle marks: marked processes become unmarked, and vice versa."
-  (interactive)
+  (interactive nil proced-mode)
   (let ((mark-re (proced-marker-regexp))
         buffer-read-only)
     (save-excursion
@@ -788,14 +789,14 @@ Otherwise move one line forward after inserting the mark."
   "Mark all processes.
 If `transient-mark-mode' is turned on and the region is active,
 mark the region."
-  (interactive)
+  (interactive nil proced-mode)
   (proced-do-mark-all t))
 
 (defun proced-unmark-all ()
   "Unmark all processes.
 If `transient-mark-mode' is turned on and the region is active,
 unmark the region."
-  (interactive)
+  (interactive nil proced-mode)
   (proced-do-mark-all nil))
 
 (defun proced-do-mark-all (mark)
@@ -830,14 +831,14 @@ mark the region."
 (defun proced-mark-children (ppid &optional omit-ppid)
   "Mark child processes of process PPID.
 Also mark process PPID unless prefix OMIT-PPID is non-nil."
-  (interactive (list (proced-pid-at-point) current-prefix-arg))
+  (interactive (list (proced-pid-at-point) current-prefix-arg) proced-mode)
   (proced-mark-process-alist
    (proced-filter-children proced-process-alist ppid omit-ppid)))
 
 (defun proced-mark-parents (cpid &optional omit-cpid)
   "Mark parent processes of process CPID.
 Also mark CPID unless prefix OMIT-CPID is non-nil."
-  (interactive (list (proced-pid-at-point) current-prefix-arg))
+  (interactive (list (proced-pid-at-point) current-prefix-arg) proced-mode)
   (proced-mark-process-alist
    (proced-filter-parents proced-process-alist cpid omit-cpid)))
 
@@ -870,7 +871,7 @@ If `transient-mark-mode' is turned on and the region is 
active,
 omit the processes in region.
 If QUIET is non-nil suppress status message.
 Returns count of omitted lines."
-  (interactive "P")
+  (interactive "P" proced-mode)
   (let ((mark-re (proced-marker-regexp))
         (count 0)
         buffer-read-only)
@@ -947,7 +948,8 @@ Set variable `proced-filter' to SCHEME.  Revert listing."
   (interactive
    (let ((scheme (completing-read "Filter: "
                                   proced-filter-alist nil t)))
-     (list (if (string= "" scheme) nil (intern scheme)))))
+     (list (if (string= "" scheme) nil (intern scheme))))
+   proced-mode)
   ;; only update if necessary
   (unless (eq proced-filter scheme)
     (setq proced-filter scheme)
@@ -1057,7 +1059,7 @@ Each parent process is followed by its child processes.
 The process tree inherits the chosen sorting order of the process listing,
 that is, child processes of the same parent process are sorted using
 the selected sorting order."
-  (interactive (list (or current-prefix-arg 'toggle)))
+  (interactive (list (or current-prefix-arg 'toggle)) proced-mode)
   (setq proced-tree-flag
         (cond ((eq arg 'toggle) (not proced-tree-flag))
               (arg (> (prefix-numeric-value arg) 0))
@@ -1140,7 +1142,7 @@ This command refines an already existing process listing 
generated initially
 based on the value of the variable `proced-filter'.  It does not change
 this variable.  It does not revert the listing.  If you frequently need
 a certain refinement, consider defining a new filter in `proced-filter-alist'."
-  (interactive (list last-input-event))
+  (interactive (list last-input-event) proced-mode)
   (if event (posn-set-point (event-end event)))
   (let ((key (get-text-property (point) 'proced-key))
         (pid (get-text-property (point) 'proced-pid)))
@@ -1269,7 +1271,8 @@ in the mode line, using \"+\" or \"-\" for ascending or 
descending order."
                                    nil t)))
      (list (if (string= "" scheme) nil (intern scheme))
            ;; like 'toggle in `define-derived-mode'
-           (or current-prefix-arg 'no-arg))))
+           (or current-prefix-arg 'no-arg)))
+   proced-mode)
 
   (setq proced-descend
         ;; If `proced-sort-interactive' is called repeatedly for the same
@@ -1290,37 +1293,37 @@ in the mode line, using \"+\" or \"-\" for ascending or 
descending order."
 (defun proced-sort-pcpu (&optional arg)
   "Sort Proced buffer by percentage CPU time (%CPU).
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'pcpu arg))
 
 (defun proced-sort-pmem (&optional arg)
   "Sort Proced buffer by percentage memory usage (%MEM).
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'pmem arg))
 
 (defun proced-sort-pid (&optional arg)
   "Sort Proced buffer by PID.
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'pid arg))
 
 (defun proced-sort-start (&optional arg)
   "Sort Proced buffer by time the command started (START).
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'start arg))
 
 (defun proced-sort-time (&optional arg)
   "Sort Proced buffer by CPU time (TIME).
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'time arg))
 
 (defun proced-sort-user (&optional arg)
   "Sort Proced buffer by USER.
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list (or current-prefix-arg 'no-arg)))
+  (interactive (list (or current-prefix-arg 'no-arg)) proced-mode)
   (proced-sort-interactive 'user arg))
 
 (defun proced-sort-header (event &optional arg)
@@ -1329,7 +1332,7 @@ EVENT is a mouse event with starting position in the 
header line.
 It is converted to the corresponding attribute key.
 This command updates the variable `proced-sort'.
 Prefix ARG controls sort order, see `proced-sort-interactive'."
-  (interactive (list last-input-event (or last-prefix-arg 'no-arg)))
+  (interactive (list last-input-event (or last-prefix-arg 'no-arg)) 
proced-mode)
   (let ((start (event-start event))
         col key)
     (save-selected-window
@@ -1534,7 +1537,8 @@ With prefix REVERT non-nil revert listing."
    (let ((scheme (completing-read "Format: "
                                   proced-format-alist nil t)))
      (list (if (string= "" scheme) nil (intern scheme))
-           current-prefix-arg)))
+           current-prefix-arg))
+   proced-mode)
   ;; only update if necessary
   (when (or (not (eq proced-format scheme)) revert)
     (setq proced-format scheme)
@@ -1566,7 +1570,7 @@ Suppress status information if QUIET is nil.
 After updating a displayed Proced buffer run the normal hook
 `proced-post-display-hook'."
   ;; This is the main function that generates and updates the process listing.
-  (interactive "P")
+  (interactive "P" proced-mode)
   (setq revert (or revert (not proced-process-alist)))
   (or quiet (message (if revert "Updating process information..."
                        "Updating process display...")))
@@ -1772,11 +1776,12 @@ supported but discouraged.  It will be removed in a 
future version of Emacs."
            `(:annotation-function
              ,(lambda (s) (cdr (assoc s proced-signal-list))))))
      (proced-with-processes-buffer process-alist
-       (list (completing-read (concat "Send signal [" pnum
-                                      "] (default TERM): ")
+       (list (completing-read (format-prompt "Send signal [%s]"
+                                             "TERM" pnum)
                               proced-signal-list
                               nil nil nil nil "TERM")
-             process-alist))))
+             process-alist)))
+   proced-mode)
 
   (unless (and signal process-alist)
     ;; Discouraged usage (supported for backward compatibility):
@@ -1797,8 +1802,8 @@ supported but discouraged.  It will be removed in a 
future version of Emacs."
              `(:annotation-function
                ,(lambda (s) (cdr (assoc s proced-signal-list))))))
         (proced-with-processes-buffer process-alist
-          (setq signal (completing-read (concat "Send signal [" pnum
-                                                "] (default TERM): ")
+          (setq signal (completing-read (format-prompt "Send signal [%s]"
+                                                       "TERM" pnum)
                                         proced-signal-list
                                         nil nil nil nil "TERM"))))))
 
@@ -1861,7 +1866,8 @@ the normal hook `proced-after-send-signal-hook'."
    (let ((process-alist (proced-marked-processes)))
      (proced-with-processes-buffer process-alist
        (list (read-number "New priority: ")
-             process-alist))))
+             process-alist)))
+   proced-mode)
   (if (numberp priority)
       (setq priority (number-to-string priority)))
   (let (failures)
@@ -1893,7 +1899,7 @@ the normal hook `proced-after-send-signal-hook'."
   "Pop up a buffer with error log output from Proced.
 A group of errors from a single command ends with a formfeed.
 Thus, use \\[backward-page] to find the beginning of a group of errors."
-  (interactive)
+  (interactive nil proced-mode)
   (if (get-buffer proced-log-buffer)
       (save-selected-window
         ;; move `proced-log-buffer' to the front of the buffer list
@@ -1945,7 +1951,7 @@ STRING is an overall summary of the failures."
 
 (defun proced-help ()
   "Provide help for the Proced user."
-  (interactive)
+  (interactive nil proced-mode)
   (proced-why)
   (if (eq last-command 'proced-help)
       (describe-mode)
@@ -1955,7 +1961,7 @@ STRING is an overall summary of the failures."
   "Undo in a Proced buffer.
 This doesn't recover killed processes, it just undoes changes in the Proced
 buffer.  You can use it to recover marks."
-  (interactive)
+  (interactive nil proced-mode)
   (let (buffer-read-only)
     (undo))
   (message "Change in Proced buffer undone.
diff --git a/lisp/progmodes/antlr-mode.el b/lisp/progmodes/antlr-mode.el
index a74ca1ed23..0b7945430d 100644
--- a/lisp/progmodes/antlr-mode.el
+++ b/lisp/progmodes/antlr-mode.el
@@ -570,7 +570,7 @@ See \\[antlr-show-makefile-rules] and 
`antlr-unknown-file-formats'.")
   "The following Makefile rules define the dependencies for all (non-
 expanded) grammars in directory \"%s\".\n
 They are stored in the kill-ring, i.e., you can insert them with C-y
-into your Makefile.  You can also invoke M-x antlr-show-makefile-rules
+into your Makefile.  You can also invoke \\[antlr-show-makefile-rules]
 from within a Makefile to insert them directly.\n\n\n"
   "Introduction to use with \\[antlr-show-makefile-rules].
 It is a format string and used with substitution DIRECTORY/%s where
@@ -2167,7 +2167,8 @@ command `antlr-show-makefile-rules' for detail."
     (unless in-makefile
       (copy-region-as-kill (point-min) (point-max))
       (goto-char (point-min))
-      (insert (format antlr-help-rules-intro dirname)))))
+      (insert (format (substitute-command-keys antlr-help-rules-intro)
+                      dirname)))))
 
 ;;;###autoload
 (defun antlr-show-makefile-rules ()
diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el
index fd014a38d9..d7092a37d4 100644
--- a/lisp/progmodes/bug-reference.el
+++ b/lisp/progmodes/bug-reference.el
@@ -72,7 +72,7 @@ so that it is considered safe, see `enable-local-variables'.")
                 (get s 'bug-reference-url-format)))))
 
 (defcustom bug-reference-bug-regexp
-  "\\(\\(?:[Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR 
[a-z+-]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
+  "\\(\\b\\(?:[Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR 
[a-z+-]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
   "Regular expression matching bug references.
 The first subexpression defines the region of the bug-reference
 overlay, i.e., the region being fontified and made clickable in
@@ -269,8 +269,9 @@ via the internet it might also be http.")
 ;; pull/17 page if 17 is a PR.  Explicit user/project#17 links to
 ;; possibly different projects are also supported.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql github)) protocol)
-  `(,(concat "[/@]" host-domain "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
+  (host-domain (_forge-type (eql 'github)) protocol)
+  `(,(concat "[/@]" (regexp-quote host-domain)
+             "[/:]\\([.A-Za-z0-9_/-]+?\\)\\(?:\\.git\\)?/?\\'")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
     ,(lambda (groups)
        (let ((ns-project (nth 1 groups)))
@@ -284,9 +285,9 @@ via the internet it might also be http.")
 ;; namespace/project#18 or namespace/project!17 references to possibly
 ;; different projects are also supported.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql gitlab)) protocol)
+  (host-domain (_forge-type (eql 'gitlab)) protocol)
   `(,(concat "[/@]" (regexp-quote host-domain)
-             "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
+             "[/:]\\([.A-Za-z0-9_/-]+?\\)\\(?:\\.git\\)?/?\\'")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\([#!]\\)\\([0-9]+\\)\\)\\>"
     ,(lambda (groups)
        (let ((ns-project (nth 1 groups)))
@@ -301,9 +302,9 @@ via the internet it might also be http.")
 
 ;; Gitea: The systematics is exactly as for Github projects.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql gitea)) protocol)
+  (host-domain (_forge-type (eql 'gitea)) protocol)
   `(,(concat "[/@]" (regexp-quote host-domain)
-             "[/:]\\([.A-Za-z0-9_/-]+\\)\\.git")
+             "[/:]\\([.A-Za-z0-9_/-]+?\\)\\(?:\\.git\\)?/?\\'")
     "\\(\\([.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
     ,(lambda (groups)
        (let ((ns-project (nth 1 groups)))
@@ -322,7 +323,7 @@ via the internet it might also be http.")
 ;; repo without tracker, or a repo with a tracker using a different
 ;; name, etc.  So we can only try to make a good guess.
 (cl-defmethod bug-reference--build-forge-setup-entry
-  (host-domain (_forge-type (eql sourcehut)) protocol)
+  (host-domain (_forge-type (eql 'sourcehut)) protocol)
   `(,(concat "[/@]\\(?:git\\|hg\\)." (regexp-quote host-domain)
              "[/:]\\(~[.A-Za-z0-9_/-]+\\)")
     "\\(\\(~[.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\)\\>"
@@ -350,7 +351,7 @@ generated from `bug-reference-forge-alist'."
             ;; `bug-reference-url-format' and
             ;; `bug-reference-bug-regexp' aren't set already.
             ("git\\.\\(?:sv\\|savannah\\)\\.gnu\\.org:"
-             "\\<\\(\\(?:[Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)\\>"
+             "\\(\\b\\(?:[Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)\\>"
              ,(lambda (_) "https://debbugs.gnu.org/%s";))
 
             ;; Entries for the software forges of
@@ -395,7 +396,7 @@ applicable."
      ,(regexp-opt '("@debbugs.gnu.org" "-devel@gnu.org"
                     ;; List-Id of Gnus devel mailing list.
                     "ding.gnus.org"))
-     "\\([Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
+     "\\(\\b[Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
      "https://debbugs.gnu.org/%s";))
   "An alist for setting up `bug-reference-mode' in mail modes.
 
@@ -526,7 +527,7 @@ From, and Cc against HEADER-REGEXP in
   `((,(concat "#" (regexp-opt '("emacs" "gnus" "org-mode" "rcirc"
                                 "erc") 'words))
      "Libera.Chat"
-     "\\([Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
+     "\\(\\b[Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)"
      "https://debbugs.gnu.org/%s";))
   "An alist for setting up `bug-reference-mode' in IRC modes.
 
diff --git a/lisp/progmodes/cc-cmds.el b/lisp/progmodes/cc-cmds.el
index 6c3da667bf..5024972804 100644
--- a/lisp/progmodes/cc-cmds.el
+++ b/lisp/progmodes/cc-cmds.el
@@ -64,7 +64,6 @@ point is used to decide where the old indentation is on a 
lines that
 is otherwise empty (ignoring any line continuation backslash), but
 that's not done if IGNORE-POINT-POS is non-nil.  Returns the amount of
 indentation change \(in columns)."
-
   (let ((line-cont-backslash (save-excursion
                               (end-of-line)
                               (eq (char-before) ?\\)))
@@ -480,7 +479,7 @@ function to control that."
 
 ;; This function is only used in XEmacs.
 (defun c-hungry-delete ()
-  "Delete a non-whitespace char, or all whitespace up to the next 
non-whitespace char.
+  "Delete non-whitespace char, or all whitespace up to next non-whitespace 
char.
 The direction of deletion depends on the configuration: If the
 function `delete-forward-p' is defined and returns non-nil, it deletes
 forward using `c-hungry-delete-forward'.  Otherwise it deletes
@@ -1897,16 +1896,18 @@ defun."
            (if (< arg 0)
                (c-while-widening-to-decl-block
                 (< (setq arg (- (c-forward-to-nth-EOF-\;-or-} (- arg) where))) 
0)))
-           ;; Move forward to the next opening brace....
-           (when (and (= arg 0)
-                      (progn
-                        (c-while-widening-to-decl-block
-                         (not (c-syntactic-re-search-forward "{" nil 'eob)))
-                        (eq (char-before) ?{)))
-             (backward-char)
-             ;; ... and backward to the function header.
-             (c-beginning-of-decl-1)
-             t))
+           (prog1
+               ;; Move forward to the next opening brace....
+               (when (and (= arg 0)
+                          (progn
+                            (c-while-widening-to-decl-block
+                             (not (c-syntactic-re-search-forward "{" nil 
'eob)))
+                            (eq (char-before) ?{)))
+                 (backward-char)
+                 ;; ... and backward to the function header.
+                 (c-beginning-of-decl-1)
+                 t)
+             (c-keep-region-active)))
 
        ;; Move backward to the opening brace of a function, making successively
        ;; larger portions of the buffer visible as necessary.
@@ -2058,9 +2059,9 @@ the open-parenthesis that starts a defun; see 
`beginning-of-defun'."
       (= arg 0))))
 
 (defun c-defun-name-1 ()
-  "Return the name of the current defun, at the current narrowing,
-or nil if there isn't one.  \"Defun\" here means a function, or
-other top level construct with a brace block."
+  "Return name of current defun, at current narrowing, or nil if there isn't 
one.
+\"Defun\" here means a function, or other top level construct
+with a brace block."
   (c-save-buffer-state
       (beginning-of-defun-function end-of-defun-function
        where pos decl0 decl type-pos tag-pos case-fold-search)
@@ -3414,7 +3415,8 @@ to call `c-scan-conditionals' directly instead."
   (interactive "p")
   (let ((new-point (c-scan-conditionals count target-depth with-else)))
     (push-mark)
-    (goto-char new-point)))
+    (goto-char new-point))
+  (c-keep-region-active))
 
 (defun c-scan-conditionals (count &optional target-depth with-else)
   "Scan forward across COUNT preprocessor conditionals.
@@ -3655,9 +3657,9 @@ continuation backslashes, unless 
`c-auto-align-backslashes' is nil."
       (set-marker here nil))))
 
 (defun c-indent-region (start end &optional quiet)
-  "Indent syntactically every line whose first char is between START
-and END inclusive.  If the optional argument QUIET is non-nil then no
-syntactic errors are reported, even if `c-report-syntactic-errors' is
+  "Indent syntactically lines whose first char is between START and END 
inclusive.
+If the optional argument QUIET is non-nil then no syntactic
+errors are reported, even if `c-report-syntactic-errors' is
 non-nil."
   (save-excursion
     (goto-char end)
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 20cdb72ccf..a4568bd4ef 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -165,12 +165,16 @@
 (defvar c-doc-line-join-end-ch)
 (defvar c-syntactic-context)
 (defvar c-syntactic-element)
+(defvar c-new-id-start)
+(defvar c-new-id-end)
+(defvar c-new-id-is-type)
 (cc-bytecomp-defvar c-min-syn-tab-mkr)
 (cc-bytecomp-defvar c-max-syn-tab-mkr)
 (cc-bytecomp-defun c-clear-syn-tab)
 (cc-bytecomp-defun c-clear-string-fences)
 (cc-bytecomp-defun c-restore-string-fences)
 (cc-bytecomp-defun c-remove-string-fences)
+(cc-bytecomp-defun c-fontify-new-found-type)
 
 
 ;; Make declarations for all the `c-lang-defvar' variables in cc-langs.
@@ -6813,21 +6817,32 @@ comment at the start of cc-engine.el for more info."
   (setq c-found-types
        (make-hash-table :test #'equal :weakness nil)))
 
-(defun c-add-type (from to)
-  ;; Add the given region as a type in `c-found-types'.  If the region
-  ;; doesn't match an existing type but there is a type which is equal
-  ;; to the given one except that the last character is missing, then
-  ;; the shorter type is removed.  That's done to avoid adding all
-  ;; prefixes of a type as it's being entered and font locked.  This
-  ;; doesn't cover cases like when characters are removed from a type
-  ;; or added in the middle.  We'd need the position of point when the
-  ;; font locking is invoked to solve this well.
+(defun c-add-type-1 (from to)
+  ;; Add the given region as a type in `c-found-types'.  Prepare occurrences
+  ;; of this new type for fontification throughout the buffer.
   ;;
   ;; This function might do hidden buffer changes.
   (let ((type (c-syntactic-content from to c-recognize-<>-arglists)))
     (unless (gethash type c-found-types)
-      (remhash (substring type 0 -1) c-found-types)
-      (puthash type t c-found-types))))
+      (puthash type t c-found-types)
+      (when (and (eq (string-match c-symbol-key type) 0)
+                (eq (match-end 0) (length type)))
+       (c-fontify-new-found-type type)))))
+
+(defun c-add-type (from to)
+  ;; Add the given region as a type in `c-found-types'.  Also perform the
+  ;; actions of `c-add-type-1'.  If the region is or overlaps an identifier
+  ;; which might be being typed in, don't record it.  This is tested by
+  ;; checking `c-new-id-start' and `c-new-id-end'.  That's done to avoid
+  ;; adding all prefixes of a type as it's being entered and font locked.
+  ;; This is a bit rough and ready, but now covers adding characters into the
+  ;; middle of an identifer.
+  ;;
+  ;; This function might do hidden buffer changes.
+  (if (and c-new-id-start c-new-id-end
+          (<= from c-new-id-end) (>= to c-new-id-start))
+      (setq c-new-id-is-type t)
+    (c-add-type-1 from to)))
 
 (defun c-unfind-type (name)
   ;; Remove the "NAME" from c-found-types, if present.
@@ -10409,6 +10424,7 @@ This function might do hidden buffer changes."
                              ;; are directly inside a class (etc.) called 
"bar".
                              (save-excursion
                                (and
+                                type-start
                                 (progn
                                   (goto-char name-start)
                                   (not (memq (c-forward-type) '(nil maybe))))
@@ -12086,7 +12102,10 @@ comment at the start of cc-engine.el for more info."
           (and (c-major-mode-is 'pike-mode)
                c-decl-block-key)))
     (while (eq braceassignp 'dontknow)
-      (cond ((eq (char-after) ?\;)
+      (cond ((or (eq (char-after) ?\;)
+                (save-excursion
+                  (progn (c-backward-syntactic-ws)
+                         (c-at-vsemi-p))))
             (setq braceassignp nil))
            ((and class-key
                  (looking-at class-key))
@@ -14010,7 +14029,8 @@ comment at the start of cc-engine.el for more info."
              ;; clause - we assume only C++ needs it.
              (c-syntactic-skip-backward "^;,=" lim t))
            (setq placeholder (point))
-           (memq (char-before) '(?, ?= ?<)))
+           (and (memq (char-before) '(?, ?= ?<))
+                (not (c-crosses-statement-barrier-p (point) indent-point))))
          (cond
 
           ;; CASE 5D.6: Something like C++11's "using foo = <type-exp>"
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index bc0ae6cc95..9355409b2a 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -93,10 +93,14 @@
 (cc-bytecomp-defvar c-preprocessor-face-name)
 (cc-bytecomp-defvar c-reference-face-name)
 (cc-bytecomp-defvar c-block-comment-flag)
+(cc-bytecomp-defvar c-type-finder-pos)
+(cc-bytecomp-defvar c-inhibit-type-finder)
+(cc-bytecomp-defvar c-type-finder-timer)
 (cc-bytecomp-defun c-fontify-recorded-types-and-refs)
 (cc-bytecomp-defun c-font-lock-declarators)
 (cc-bytecomp-defun c-font-lock-objc-method)
 (cc-bytecomp-defun c-font-lock-invalid-string)
+(cc-bytecomp-defun c-before-context-fl-expand-region)
 
 
 ;; Note that font-lock in XEmacs doesn't expand face names as
@@ -919,13 +923,6 @@ casts and declarations are fontified.  Used on level 2 and 
higher."
   ;; This function does hidden buffer changes.
 
   ;;(message "c-font-lock-complex-decl-prepare %s %s" (point) limit)
-
-  ;; Clear the list of found types if we start from the start of the
-  ;; buffer, to make it easier to get rid of misspelled types and
-  ;; variables that have gotten recognized as types in malformed code.
-  (when (bobp)
-    (c-clear-found-types))
-
   (c-skip-comments-and-strings limit)
   (when (< (point) limit)
 
@@ -1605,6 +1602,175 @@ casts and declarations are fontified.  Used on level 2 
and higher."
 
        nil))))
 
+(defun c-find-types-background (start limit)
+  ;; Find any "found types" between START and LIMIT.  Allow any such types to
+  ;; be entered into `c-found-types' by the action of `c-forward-name' or
+  ;; `c-forward-type' called from this function.  This process also causes
+  ;; occurrences of the type to be prepared for fontification throughout the
+  ;; buffer.
+  ;;
+  ;; Return POINT at the end of the function.  This should be at or after
+  ;; LIMIT, and not later than the next decl-spot after LIMIT.
+  ;;
+  ;; This function is called from the timer `c-type-finder-timer'.  It may do
+  ;; hidden buffer changes.
+  (save-excursion
+    (save-restriction
+      (widen)
+      (goto-char start)
+      ;; If we're in a (possibly large) literal, skip over it.
+      (let ((lit-bounds (nth 2 (c-full-pp-to-literal (point)))))
+       (if lit-bounds
+           (goto-char (cdr lit-bounds))))
+      (when (< (point) limit)
+       (let (;; o - 'decl if we're in an arglist containing declarations
+             ;;   (but if `c-recognize-paren-inits' is set it might also be
+             ;;   an initializer arglist);
+             ;; o - '<> if the arglist is of angle bracket type;
+             ;; o - 'arglist if it's some other arglist;
+             ;; o - nil, if not in an arglist at all.  This includes the
+             ;;   parenthesized condition which follows "if", "while", etc.
+             context
+             ;; A list of starting positions of possible type declarations, or 
of
+             ;; the typedef preceding one, if any.
+             last-cast-end
+             ;; The result from `c-forward-decl-or-cast-1'.
+             decl-or-cast
+             ;; The maximum of the end positions of all the checked type
+             ;; decl expressions in the successfully identified
+             ;; declarations.  The position might be either before or
+             ;; after the syntactic whitespace following the last token
+             ;; in the type decl expression.
+             (max-type-decl-end 0)
+             ;; Same as `max-type-decl-*', but used when we're before
+             ;; `token-pos'.
+             (max-type-decl-end-before-token 0)
+             )
+         (goto-char start)
+         (c-find-decl-spots
+          limit
+          c-decl-start-re
+          nil                          ; (eval c-maybe-decl-faces)
+
+          (lambda (match-pos inside-macro &optional toplev)
+            ;; Note to maintainers: don't use `limit' inside this lambda form;
+            ;; c-find-decl-spots sometimes narrows to less than `limit'.
+            (if (and c-macro-with-semi-re
+                     (looking-at c-macro-with-semi-re))
+                ;; Don't do anything more if we're looking at something that
+                ;; can't start a declaration.
+                t
+
+              ;; Set `context' and `c-restricted-<>-arglists'.  Look for
+              ;; "<" for the sake of C++-style template arglists.
+              ;; "Ignore "(" when it's part of a control flow construct
+              ;; (e.g. "for (").
+              (let ((got-context
+                     (c-get-fontification-context
+                      match-pos
+                      (< match-pos (if inside-macro
+                                       max-type-decl-end-before-token
+                                     max-type-decl-end))
+                      toplev)))
+                (setq context (car got-context)
+                      c-restricted-<>-arglists (cdr got-context)))
+
+              ;; In QT, "more" is an irritating keyword that expands to 
nothing.
+              ;; We skip over it to prevent recognition of "more slots: 
<symbol>"
+              ;; as a bitfield declaration.
+              (when (and (c-major-mode-is 'c++-mode)
+                         (looking-at
+                          (concat "\\(more\\)\\([^" c-symbol-chars 
"]\\|$\\)")))
+                (goto-char (match-end 1))
+                (c-forward-syntactic-ws))
+
+              ;; Now analyze the construct.  This analysis will cause
+              ;; `c-forward-name' and `c-forward-type' to call `c-add-type',
+              ;; triggering the desired recognition and fontification of
+              ;; these found types.
+              (when (not (eq context 'not-decl))
+                (setq decl-or-cast
+                      (c-forward-decl-or-cast-1
+                       match-pos context last-cast-end))
+
+                (cond
+                 ((eq decl-or-cast 'cast)
+                  ;; Save the position after the previous cast so we can feed
+                  ;; it to `c-forward-decl-or-cast-1' in the next round.  That
+                  ;; helps it discover cast chains like "(a) (b) c".
+                  (setq last-cast-end (point))
+                  nil)
+                 (decl-or-cast
+                  ;; We've found a declaration.
+
+                  ;; Set `max-type-decl-end' or 
`max-type-decl-end-before-token'
+                  ;; under the assumption that we're after the first type decl
+                  ;; expression in the declaration now.  That's not really 
true;
+                  ;; we could also be after a parenthesized initializer
+                  ;; expression in C++, but this is only used as a last resort
+                  ;; to slant ambiguous expression/declarations, and overall
+                  ;; it's worth the risk to occasionally fontify an expression
+                  ;; as a declaration in an initializer expression compared to
+                  ;; getting ambiguous things in normal function prototypes
+                  ;; fontified as expressions.
+                  (if inside-macro
+                      (when (> (point) max-type-decl-end-before-token)
+                        (setq max-type-decl-end-before-token (point)))
+                    (when (> (point) max-type-decl-end)
+                      (setq max-type-decl-end (point)))))
+                 (t t))))))))
+      (point))))
+
+(defun c-type-finder-timer-func ()
+  ;; A CC Mode idle timer function for finding "found types".  It triggers
+  ;; every `c-type-finder-repeat-time' seconds and processes buffer chunks of
+  ;; size around `c-type-finder-chunk-size' characters, and runs for (a little
+  ;; over) `c-type-finder-time-slot' seconds.  The types it finds are inserted
+  ;; into `c-found-types', and their occurrences throughout the buffer are
+  ;; prepared for fontification.
+  (when (and c-type-finder-time-slot
+            (boundp 'font-lock-support-mode)
+            (eq font-lock-support-mode 'jit-lock-mode))
+    (if c-inhibit-type-finder ; No processing immediately after a GC operation.
+       (setq c-inhibit-type-finder nil)
+      (let* ((stop-time (+ (float-time) c-type-finder-time-slot))
+            (buf-list (buffer-list)))
+       ;; One CC Mode buffer needing processing each time around this loop.
+       (while (and buf-list
+                   (< (float-time) stop-time))
+         ;; Cdr through BUF-LIST to find the next buffer needing processing.
+         (while (and buf-list
+                     (not (with-current-buffer (car buf-list) 
c-type-finder-pos)))
+           (setq buf-list (cdr buf-list)))
+         (when buf-list
+           (with-current-buffer (car buf-list)
+             ;; (message "%s" (current-buffer)) ; Useful diagnostic.
+             (save-restriction
+               (widen)
+               ;; Process one `c-type-finder-chunk-size' chunk each time
+               ;; around this loop.
+               (while (and c-type-finder-pos
+                           (< (float-time) stop-time))
+                 ;; Process one chunk per iteration.
+                 (save-match-data
+                   (c-save-buffer-state
+                       (case-fold-search
+                        (beg (marker-position c-type-finder-pos))
+                        (end (min (+ beg c-type-finder-chunk-size) 
(point-max)))
+                        (region (c-before-context-fl-expand-region beg end)))
+                     (setq beg (car region)
+                           end (cdr region))
+                     (setq beg (max (c-find-types-background beg end) end))
+                     (move-marker c-type-finder-pos
+                                  (if (save-excursion (goto-char beg) (eobp))
+                                      nil
+                                    beg))
+                     (when (not (marker-position c-type-finder-pos))
+                       (setq c-type-finder-pos nil))))))))))))
+  ;; Set the timer to run again.
+  (setq c-type-finder-timer
+       (run-at-time c-type-finder-repeat-time nil #'c-type-finder-timer-func)))
+
 (defun c-font-lock-enum-body (limit)
   ;; Fontify the identifiers of each enum we find by searching forward.
   ;;
@@ -2255,6 +2421,46 @@ higher."
     ;; defvar will install its default value later on.
     (makunbound def-var)))
 
+;; `c-re-redisplay-timer' is a timer which, when triggered, causes a
+;; redisplay.
+(defvar c-re-redisplay-timer nil)
+
+(defun c-force-redisplay (start end)
+  ;; Force redisplay immediately.  This assumes `font-lock-support-mode' is
+  ;; 'jit-lock-mode.  Set the variable `c-re-redisplay-timer' to nil.
+  (jit-lock-force-redisplay (copy-marker start) (copy-marker end))
+  (setq c-re-redisplay-timer nil))
+
+(defun c-fontify-new-found-type (type)
+  ;; Cause the fontification of TYPE, a string, wherever it occurs in the
+  ;; buffer.  If TYPE is currently displayed in a window, cause redisplay to
+  ;; happen "instantaneously".  These actions are done only when jit-lock-mode
+  ;; is active.
+  (when (and (boundp 'font-lock-support-mode)
+            (eq font-lock-support-mode 'jit-lock-mode))
+    (c-save-buffer-state
+       ((window-boundaries
+         (mapcar (lambda (win)
+                   (cons (window-start win)
+                         (window-end win)))
+                 (get-buffer-window-list (current-buffer) 'no-mini t)))
+        (target-re (concat "\\_<" type "\\_>")))
+      (save-excursion
+       (save-restriction
+         (widen)
+         (goto-char (point-min))
+         (while (re-search-forward target-re nil t)
+           (put-text-property (match-beginning 0) (match-end 0)
+                              'fontified nil)
+           (dolist (win-boundary window-boundaries)
+             (when (and (< (match-beginning 0) (cdr win-boundary))
+                        (> (match-end 0) (car win-boundary))
+                        (c-get-char-property (match-beginning 0) 'fontified)
+                        (not c-re-redisplay-timer))
+               (setq c-re-redisplay-timer
+                     (run-with-timer 0 nil #'c-force-redisplay
+                                     (match-beginning 0) (match-end 
0)))))))))))
+
 
 ;;; C.
 
diff --git a/lisp/progmodes/cc-langs.el b/lisp/progmodes/cc-langs.el
index 36f12369fc..53f6206a82 100644
--- a/lisp/progmodes/cc-langs.el
+++ b/lisp/progmodes/cc-langs.el
@@ -680,7 +680,7 @@ A search for this regexp starting at the end of the 
corresponding
 opener must find the first closer as the first match.
 
 Such a closer must include a \" character.  (match-string 1)
-matches the actual delimiter and and (match-string 2) matches the
+matches the actual delimiter and (match-string 2) matches the
 actual \".  If a delimiter contains several \"s, it is
 recommended to regard the last of them as \"the\" \"."
   t nil
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 8b30241449..f9435c9cee 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -129,6 +129,16 @@
 ;   '
 (require 'cc-fonts) ;)
 
+(defvar c-type-finder-timer nil)
+;; The variable which holds the repeating idle timer which triggers off the
+;; background type finding search.
+
+(defvar c-inhibit-type-finder nil)
+;; When non-nil (set by `c-post-gc-hook') don't perform the type finding
+;; activities the next time `c-type-finder-timer' triggers.  This ensures
+;; keyboard/mouse input will be dealt with when garbage collection is taking a
+;; large portion of CPU time.
+
 ;; The following three really belong to cc-fonts.el, but they are required
 ;; even when cc-fonts.el hasn't been loaded (this happens in XEmacs when
 ;; font-lock-mode is nil).
@@ -179,6 +189,18 @@
   (when c-buffer-is-cc-mode
     (save-restriction
       (widen)
+      (let ((lst (buffer-list)))
+       (catch 'found
+         (dolist (b lst)
+           (if (and (not (eq b (current-buffer)))
+                    (with-current-buffer b
+                      c-buffer-is-cc-mode))
+               (throw 'found nil)))
+         (remove-hook 'post-command-hook 'c-post-command)
+         (remove-hook 'post-gc-hook 'c-post-gc-hook)
+         (and c-type-finder-timer
+              (progn (cancel-timer c-type-finder-timer)
+                     (setq c-type-finder-timer nil)))))
       (c-save-buffer-state ()
        (c-clear-char-properties (point-min) (point-max) 'category)
        (c-clear-char-properties (point-min) (point-max) 'syntax-table)
@@ -574,6 +596,12 @@ preferably use the `c-mode-menu' language constant 
directly."
 ;; currently no such text property.
 (make-variable-buffer-local 'c-max-syn-tab-mkr)
 
+;; `c-type-finder-pos' is a marker marking the current place in a CC Mode
+;; buffer which is due to be searched next for "found types", or nil if the
+;; searching is complete.
+(defvar c-type-finder-pos nil)
+(make-variable-buffer-local 'c-type-finder-pos)
+
 (defun c-basic-common-init (mode default-style)
   "Initialize the syntax handling routines and the line breaking/filling code.
 Intended to be used by other packages that embed CC Mode.
@@ -745,6 +773,19 @@ that requires a literal mode spec at compile time."
   ;; would do since font-lock uses a(n implicit) depth of 0) so we don't need
   ;; c-after-font-lock-init.
   (add-hook 'after-change-functions 'c-after-change nil t)
+  (add-hook 'post-command-hook 'c-post-command)
+  (setq c-type-finder-pos
+       (save-restriction
+         (widen)
+         (move-marker (make-marker) (point-min))))
+
+  ;; Install the functionality for seeking "found types" at mode startup:
+  (or c-type-finder-timer
+      (setq c-type-finder-timer
+           (run-at-time
+            c-type-finder-repeat-time nil #'c-type-finder-timer-func)))
+  (add-hook 'post-gc-hook #'c-post-gc-hook)
+
   (when (boundp 'font-lock-extend-after-change-region-function)
     (set (make-local-variable 'font-lock-extend-after-change-region-function)
          'c-extend-after-change-region))) ; Currently (2009-05) used by all
@@ -1402,7 +1443,7 @@ Note that the style variables are always made local to 
the buffer."
                     (memq (char-after) c-string-delims))
            (c-clear-syn-tab (point)))))
       (c-clear-syn-tab (point)))
-     (t (c-benign-error "c-remove-string-fences: wrong position")))))
+     (t (c-benign-error "c-remove-string-fences: Wrong position")))))
 
 (defun c-before-change-check-unbalanced-strings (beg end)
   ;; If BEG or END is inside an unbalanced string, remove the syntax-table
@@ -1950,6 +1991,46 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
        ;; confused by already processed single quotes.
        (narrow-to-region (point) (point-max))))))
 
+;; The next two variables record the bounds of an identifier currently being
+;; typed in.  These are used to prevent such a partial identifier being
+;; recorded as a found type by c-add-type.
+(defvar c-new-id-start nil)
+(make-variable-buffer-local 'c-new-id-start)
+(defvar c-new-id-end nil)
+(make-variable-buffer-local 'c-new-id-end)
+;; The next variable, when non-nil, records that the previous two variables
+;; define a type.
+(defvar c-new-id-is-type nil)
+(make-variable-buffer-local 'c-new-id-is-type)
+
+(defun c-update-new-id (end)
+  ;; Note the bounds of any identifier that END is in or just after, in
+  ;; `c-new-id-start' and `c-new-id-end'.  Otherwise set these variables to
+  ;; nil.
+  (save-excursion
+    (goto-char end)
+    (let ((id-beg (c-on-identifier)))
+      (setq c-new-id-start id-beg
+           c-new-id-end (and id-beg
+                             (progn (c-end-of-current-token) (point)))))))
+
+
+(defun c-post-command ()
+  ;; If point was inside of a new identifier and no longer is, record that
+  ;; fact.
+  (when (and c-buffer-is-cc-mode
+            c-new-id-start c-new-id-end
+            (or (> (point) c-new-id-end)
+                (< (point) c-new-id-start)))
+    (when c-new-id-is-type
+      (c-add-type-1 c-new-id-start c-new-id-end))
+    (setq c-new-id-start nil
+         c-new-id-end nil
+         c-new-id-is-type nil)))
+
+(defun c-post-gc-hook (&optional _stats) ; For XEmacs.
+  (setq c-inhibit-type-finder t))
+
 (defun c-before-change (beg end)
   ;; Function to be put on `before-change-functions'.  Primarily, this calls
   ;; the language dependent `c-get-state-before-change-functions'.  It is
@@ -1969,11 +2050,16 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
   (unless (c-called-from-text-property-change-p)
     (save-restriction
       (widen)
+      ;; Clear the list of found types if we make a change at the start of the
+      ;; buffer, to make it easier to get rid of misspelled types and
+      ;; variables that have gotten recognized as types in malformed code.
+      (when (eq beg (point-min))
+       (c-clear-found-types))
       (if c-just-done-before-change
-         ;; We have two consecutive calls to `before-change-functions' without
-         ;; an intervening `after-change-functions'.  An example of this is bug
-         ;; #38691.  To protect CC Mode, assume that the entire buffer has
-         ;; changed.
+         ;; We have two consecutive calls to `before-change-functions'
+         ;; without an intervening `after-change-functions'.  An example of
+         ;; this is bug #38691.  To protect CC Mode, assume that the entire
+         ;; buffer has changed.
          (setq beg (point-min)
                end (point-max)
                c-just-done-before-change 'whole-buffer)
@@ -2151,6 +2237,7 @@ Note that this is a strict tail, so won't match, e.g. 
\"0x....\".")
                                                      c->-as-paren-syntax)
                    (c-clear-char-property-with-value beg end 'syntax-table 
nil)))
 
+               (c-update-new-id end)
                (c-trim-found-types beg end old-len) ; maybe we don't
                                                     ; need all of these.
                (c-invalidate-sws-region-after beg end old-len)
@@ -2549,17 +2636,24 @@ This function is called from `c-common-init', once per 
mode initialization."
 
 At the time of call, point is just after the newly inserted CHAR.
 
-When CHAR is \", t will be returned unless the \" is marked with
-a string fence syntax-table text property.  For other characters,
-the default value of `electric-pair-inhibit-predicate' is called
-and its value returned.
+When CHAR is \" and not within a comment, t will be returned if
+the quotes on the current line are already balanced (i.e. if the
+last \" is not marked with a string fence syntax-table text
+property).  For other cases, the default value of
+`electric-pair-inhibit-predicate' is called and its value
+returned.
 
 This function is the appropriate value of
 `electric-pair-inhibit-predicate' for CC Mode modes, which mark
 invalid strings with such a syntax table text property on the
 opening \" and the next unescaped end of line."
-  (if (eq char ?\")
-      (not (equal (get-text-property (1- (point)) 'c-fl-syn-tab) '(15)))
+  (if (and (eq char ?\")
+          (not (memq (cadr (c-semi-pp-to-literal (1- (point)))) '(c c++))))
+      (let ((last-quote (save-match-data
+                         (save-excursion
+                           (goto-char (c-point 'eoll))
+                           (search-backward "\"")))))
+       (not (equal (c-get-char-property last-quote 'c-fl-syn-tab) '(15))))
     (funcall (default-value 'electric-pair-inhibit-predicate) char)))
 
 
diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el
index 8869c56573..40a43c32ed 100644
--- a/lisp/progmodes/cc-vars.el
+++ b/lisp/progmodes/cc-vars.el
@@ -179,7 +179,7 @@ STYLE stands for the choice where the value is taken from 
some
 style setting.  PREAMBLE is optionally prepended to FOO; that is,
 if FOO contains :tag or :value, the respective two-element list
 component is ignored."
-  (declare (debug (symbolp form stringp &rest)))
+  (declare (debug (symbolp form stringp &rest)) (indent defun))
   (let* ((expanded-doc (concat doc "
 
 This is a style variable.  Apart from the valid values described
@@ -1524,6 +1524,39 @@ working due to this change."
   :type 'boolean
   :group 'c)
 
+(defcustom c-type-finder-time-slot 0.05
+  "The length in seconds of a background type search time slot.
+
+In CC Mode modes, \"found types\" wouldn't always get cleanly
+fontified without the background searching for them which happens
+in the seconds after starting Emacs or initializing the major
+mode.
+
+This background searching can be disabled by setting this option
+to nil."
+  :type '(choice (const :tag "disabled" nil)
+                number)
+  :group 'c)
+
+(defcustom c-type-finder-repeat-time 0.1
+  "The interval, in seconds, at which background type searches occur.
+
+This interval must be greater than `c-type-finder-time-slot'."
+  :type 'number
+  :group 'c)
+
+(defcustom c-type-finder-chunk-size 1000
+  "The size, in characters, of a chunk for background type search.
+
+Chunks of this size are searched atomically for \"found types\"
+just after starting Emacs or initializing the major mode.
+
+This chunk size is a balance between efficiency (with larger
+values) and responsiveness of the keyboard (with smaller values).
+See also `c-type-finder-time-slot'."
+  :type 'integer
+  :group 'c)
+
 (define-widget 'c-extra-types-widget 'radio
   "Internal CC Mode widget for the `*-font-lock-extra-types' variables."
   :args '((const :tag "none" nil)
@@ -1770,7 +1803,7 @@ variables.")
                      ; all XEmacsen.
          ((null c-macro-names-with-semicolon)
           nil)
-         (t (error "c-make-macro-with-semi-re: invalid \
+         (t (error "c-make-macro-with-semi-re: Invalid \
 c-macro-names-with-semicolon: %s"
                    c-macro-names-with-semicolon))))))
 
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index 73f9806811..14da588020 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -662,7 +662,8 @@ has just been matched, and should correspondingly preserve 
this match data.
 TYPE is 2 or nil for a real error or 1 for warning or 0 for info.
 TYPE can also be of the form (WARNING . INFO).  In that case this
 will be equivalent to 1 if the WARNING'th subexpression matched
-or else equivalent to 0 if the INFO'th subexpression matched.
+or else equivalent to 0 if the INFO'th subexpression matched,
+or else equivalent to 2 if neither of them matched.
 See `compilation-error-face', `compilation-warning-face',
 `compilation-info-face' and `compilation-skip-threshold'.
 
@@ -2227,6 +2228,7 @@ The parent is always `compilation-mode' and the 
customizable `compilation-...'
 variables are also set from the name of the mode you have chosen,
 by replacing the first word, e.g., `compilation-scroll-output' from
 `grep-scroll-output' if that variable exists."
+  (declare (indent defun))
   (let ((mode-name (replace-regexp-in-string "-mode\\'" "" (symbol-name 
mode))))
     `(define-derived-mode ,mode compilation-mode ,name
        ,doc
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index c371a84b9d..a23505a9d3 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -507,9 +507,9 @@ Currently used with `cperl-check-syntax' only."
   :group 'cperl-help-system)
 
 (defcustom cperl-indent-region-fix-constructs 1
-  "Amount of space to insert between `}' and `else' or `elsif'
-in `cperl-indent-region'.  Set to nil to leave as is.  Values other
-than 1 and nil will probably not work."
+  "Amount of space to insert between `}' and `else' or `elsif'.
+Used by `cperl-indent-region'.  Set to nil to leave as is.
+Values other than 1 and nil will probably not work."
   :type '(choice (const nil) (const 1))
   :group 'cperl-indentation-details)
 
@@ -5951,7 +5951,7 @@ default function."
                                         (eval cperl--basic-identifier-rx)))
                    (0+ blank) "(")
 ;;         '("\\<for\\(each\\)?\\([ \t]+\\(state\\|my\\|local\\|our\\)\\)?[ 
\t]*\\(\\$[a-zA-Z_][a-zA-Z_0-9]*\\)[ \t]*("
-             4 font-lock-variable-name-face)
+             1 font-lock-variable-name-face)
            ;; Avoid $!, and s!!, qq!! etc. when not fontifying syntactically
            '("\\(?:^\\|[^smywqrx$]\\)\\(!\\)" 1 font-lock-negation-char-face)
            '("\\[\\(\\^\\)" 1 font-lock-negation-char-face prepend)))
diff --git a/lisp/progmodes/cpp.el b/lisp/progmodes/cpp.el
index d800365e66..baee72b332 100644
--- a/lisp/progmodes/cpp.el
+++ b/lisp/progmodes/cpp.el
@@ -702,11 +702,8 @@ BRANCH should be either nil (false branch), t (true 
branch) or `both'."
          (x-popup-menu cpp-button-event
                        (list prompt (cons prompt cpp-face-default-list)))
        (let ((name (car (rassq default cpp-face-default-list))))
-         (cdr (assoc (completing-read (if name
-                                          (concat prompt
-                                                  " (default " name "): ")
-                                        (concat prompt ": "))
-                                      cpp-face-default-list nil t)
+          (cdr (assoc (completing-read (format-prompt "%s" name prompt)
+                                       cpp-face-default-list nil t)
                      cpp-face-all-list))))
       default))
 
diff --git a/lisp/progmodes/ebnf-dtd.el b/lisp/progmodes/ebnf-dtd.el
index 9185711848..d4bfdaa995 100644
--- a/lisp/progmodes/ebnf-dtd.el
+++ b/lisp/progmodes/ebnf-dtd.el
@@ -62,7 +62,7 @@
 ;;
 ;;    Document authors are encouraged to avoid "compatibility characters", as
 ;;    defined in section 6.8 of [Unicode] (see also D21 in section 3.6 of
-;;    [Unicode3]). The characters defined in the following ranges are also
+;;    [Unicode3]).  The characters defined in the following ranges are also
 ;;    discouraged.  They are either control characters or permanently undefined
 ;;    Unicode characters:
 ;;
diff --git a/lisp/progmodes/ebrowse.el b/lisp/progmodes/ebrowse.el
index ab0329d7ee..6e416d064a 100644
--- a/lisp/progmodes/ebrowse.el
+++ b/lisp/progmodes/ebrowse.el
@@ -1330,9 +1330,9 @@ Pop to member buffer if no prefix ARG, to tree buffer 
otherwise."
   "Set the indentation width of the tree display."
   (interactive)
   (let ((width (string-to-number (read-string
-                                  (concat "Indentation (default "
-                                          (int-to-string ebrowse--indentation)
-                                          "): ")
+                                  (format-prompt
+                                   "Indentation"
+                                   (int-to-string ebrowse--indentation))
                                   nil nil ebrowse--indentation))))
     (when (cl-plusp width)
       (setq-local ebrowse--indentation width)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 0b2395d976..7da93a351a 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -210,7 +210,7 @@ All commands in `lisp-mode-shared-map' are inherited by 
this map.")
   (emacs-lisp--before-compile-buffer)
   (require 'bytecomp)
   (byte-recompile-file buffer-file-name nil 0)
-  (load buffer-file-name))
+  (load (byte-compile-dest-file buffer-file-name)))
 
 (declare-function native-compile "comp")
 (defun emacs-lisp-native-compile-and-load ()
@@ -532,6 +532,53 @@ It can be quoted, or be inside a quoted form."
             0))
      ((facep sym) (find-definition-noselect sym 'defface)))))
 
+(defvar obarray-cache nil
+  "If non-nil, a hash table of cached obarray-related information.
+The cache holds information specific to the current state of the
+Elisp obarray.  If the obarray is modified by any means (such as
+interning or uninterning a symbol), this variable is set to nil.")
+
+(defun elisp--completion-local-symbols ()
+  "Compute collections of all Elisp symbols for completion purposes.
+The return value is compatible with the COLLECTION form described
+in `completion-at-point-functions' (which see)."
+  (cl-flet ((obarray-plus-shorthands ()
+              (let (retval)
+                (mapatoms
+                 (lambda (s)
+                   (push s retval)
+                   (cl-loop
+                    for (shorthand . longhand) in read-symbol-shorthands
+                    for full-name = (symbol-name s)
+                    when (string-prefix-p longhand full-name)
+                    do (let ((sym (make-symbol
+                                   (concat shorthand
+                                           (substring full-name
+                                                      (length longhand))))))
+                         (put sym 'shorthand t)
+                         (push sym retval)
+                         retval))))
+                retval)))
+    (cond ((null read-symbol-shorthands) obarray)
+          ((and obarray-cache
+                (gethash (cons (current-buffer) read-symbol-shorthands)
+                         obarray-cache)))
+          (obarray-cache
+            (puthash (cons (current-buffer) read-symbol-shorthands)
+                     (obarray-plus-shorthands)
+                     obarray-cache))
+          (t
+            (setq obarray-cache (make-hash-table :test #'equal))
+            (puthash (cons (current-buffer) read-symbol-shorthands)
+                     (obarray-plus-shorthands)
+                     obarray-cache)))))
+
+(defun elisp--shorthand-aware-fboundp (sym)
+  (fboundp (intern-soft (symbol-name sym))))
+
+(defun elisp--shorthand-aware-boundp (sym)
+  (boundp (intern-soft (symbol-name sym))))
+
 (defun elisp-completion-at-point ()
   "Function used for `completion-at-point-functions' in `emacs-lisp-mode'.
 If the context at point allows only a certain category of
@@ -579,36 +626,41 @@ functions are annotated with \"<f>\" via the
                     ;; the current form and use it to provide a more
                     ;; specific completion table in more cases.
                     ((eq fun-sym 'ignore-error)
-                     (list t obarray
+                     (list t (elisp--completion-local-symbols)
                            :predicate (lambda (sym)
                                         (get sym 'error-conditions))))
                     ((elisp--expect-function-p beg)
-                     (list nil obarray
-                           :predicate #'fboundp
+                     (list nil (elisp--completion-local-symbols)
+                           :predicate
+                           #'elisp--shorthand-aware-fboundp
                            :company-kind #'elisp--company-kind
                            :company-doc-buffer #'elisp--company-doc-buffer
                            :company-docsig #'elisp--company-doc-string
-                           :company-location #'elisp--company-location))
+                           :company-location #'elisp--company-location
+                           :company-deprecated #'elisp--company-deprecated))
                     (quoted
-                     (list nil obarray
+                     (list nil (elisp--completion-local-symbols)
                            ;; Don't include all symbols (bug#16646).
                            :predicate (lambda (sym)
-                                        (or (boundp sym)
-                                            (fboundp sym)
-                                            (featurep sym)
-                                            (symbol-plist sym)))
+                                        ;; shorthand-aware
+                                        (let ((sym (intern-soft (symbol-name 
sym))))
+                                          (or (boundp sym)
+                                              (fboundp sym)
+                                              (featurep sym)
+                                              (symbol-plist sym))))
                            :annotation-function
                            (lambda (str) (if (fboundp (intern-soft str)) " 
<f>"))
                            :company-kind #'elisp--company-kind
                            :company-doc-buffer #'elisp--company-doc-buffer
                            :company-docsig #'elisp--company-doc-string
-                           :company-location #'elisp--company-location))
+                           :company-location #'elisp--company-location
+                           :company-deprecated #'elisp--company-deprecated))
                     (t
                      (list nil (completion-table-merge
                                 elisp--local-variables-completion-table
                                 (apply-partially 
#'completion-table-with-predicate
-                                                 obarray
-                                                 #'boundp
+                                                 
(elisp--completion-local-symbols)
+                                                 
#'elisp--shorthand-aware-boundp
                                                  'strict))
                            :company-kind
                            (lambda (s)
@@ -617,7 +669,8 @@ functions are annotated with \"<f>\" via the
                                'variable))
                            :company-doc-buffer #'elisp--company-doc-buffer
                            :company-docsig #'elisp--company-doc-string
-                           :company-location #'elisp--company-location)))
+                           :company-location #'elisp--company-location
+                           :company-deprecated #'elisp--company-deprecated)))
                  ;; Looks like a funcall position.  Let's double check.
                  (save-excursion
                    (goto-char (1- beg))
@@ -645,11 +698,11 @@ functions are annotated with \"<f>\" via the
                                       (ignore-errors
                                         (forward-sexp 2)
                                         (< (point) beg)))))
-                        (list t obarray
+                        (list t (elisp--completion-local-symbols)
                               :predicate (lambda (sym) (get sym 
'error-conditions))))
                        ;; `ignore-error' with a list CONDITION parameter.
                        ('ignore-error
-                        (list t obarray
+                        (list t (elisp--completion-local-symbols)
                               :predicate (lambda (sym)
                                            (get sym 'error-conditions))))
                        ((and (or ?\( 'let 'let*)
@@ -659,18 +712,20 @@ functions are annotated with \"<f>\" via the
                                         (up-list -1))
                                       (forward-symbol -1)
                                       (looking-at "\\_<let\\*?\\_>"))))
-                        (list t obarray
-                              :predicate #'boundp
+                        (list t (elisp--completion-local-symbols)
+                              :predicate #'elisp--shorthand-aware-boundp
                               :company-kind (lambda (_) 'variable)
                               :company-doc-buffer #'elisp--company-doc-buffer
                               :company-docsig #'elisp--company-doc-string
-                              :company-location #'elisp--company-location))
-                       (_ (list nil obarray
-                                :predicate #'fboundp
+                              :company-location #'elisp--company-location
+                              :company-deprecated #'elisp--company-deprecated))
+                       (_ (list nil (elisp--completion-local-symbols)
+                                :predicate #'elisp--shorthand-aware-fboundp
                                 :company-kind #'elisp--company-kind
                                 :company-doc-buffer #'elisp--company-doc-buffer
                                 :company-docsig #'elisp--company-doc-string
                                 :company-location #'elisp--company-location
+                                :company-deprecated #'elisp--company-deprecated
                                 ))))))))
           (nconc (list beg end)
                  (if (null (car table-etc))
@@ -693,6 +748,11 @@ functions are annotated with \"<f>\" via the
      ((facep sym) 'color)
      (t 'text))))
 
+(defun elisp--company-deprecated (str)
+  (let ((sym (intern-soft str)))
+    (or (get sym 'byte-obsolete-variable)
+        (get sym 'byte-obsolete-info))))
+
 (defun lisp-completion-at-point (&optional _predicate)
   (declare (obsolete elisp-completion-at-point "25.1"))
   (elisp-completion-at-point))
@@ -827,17 +887,17 @@ namespace but with lower confidence."
         ;;             ^ index K   ^ index J   ^ index I
         (let* ((i (elisp--xref-list-index))
                (i-head (looking-at-sym))
-               (i-paren (and i-head (eq (char-before) ?\()
+               (i-paren (and i (eq (char-before) ?\()
                              (progn (backward-char) t)))
                (i-quoted (and i-paren (memq (char-before) '(?\' ?`))))
                (j (and i-paren (elisp--xref-list-index)))
                (j-head (and j (looking-at-sym)))
-               (j-paren (and j-head (eq (char-before) ?\()
+               (j-paren (and j (eq (char-before) ?\()
                              (progn (backward-char) t)))
                (j-quoted (and j-paren (memq (char-before) '(?\' ?`))))
                (k (and j-paren (elisp--xref-list-index)))
                (k-head (and k (looking-at-sym)))
-               (k-paren (and k-head (eq (char-before) ?\()
+               (k-paren (and k (eq (char-before) ?\()
                              (progn (backward-char) t)))
                (k-quoted (and k-paren (memq (char-before) '(?\' ?`)))))
           (cond
@@ -2075,5 +2135,8 @@ Runs in a batch-mode Emacs.  Interactively use variable
     (terpri)
     (pp collected)))
 
+
+(put 'read-symbol-shorthands 'safe-local-variable #'consp)
+
 (provide 'elisp-mode)
 ;;; elisp-mode.el ends here
diff --git a/lisp/progmodes/erts-mode.el b/lisp/progmodes/erts-mode.el
new file mode 100644
index 0000000000..8a271ec318
--- /dev/null
+++ b/lisp/progmodes/erts-mode.el
@@ -0,0 +1,220 @@
+;;; erts-mode.el --- major mode to edit erts files  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Keywords: tools
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl-lib))
+(require 'ert)
+
+(defgroup erts-mode nil
+  "Major mode for editing Emacs test files."
+  :group 'lisp)
+
+(defface erts-mode-specification-name
+  '((((class color)
+      (background dark))
+     :foreground "green")
+    (((class color)
+      (background light))
+     :foreground "cornflower blue")
+    (t
+     :bold t))
+  "Face used for displaying specification names."
+  :group 'erts-mode)
+
+(defface erts-mode-specification-value
+  '((((class color)
+      (background dark))
+     :foreground "DeepSkyBlue1")
+    (((class color)
+      (background light))
+     :foreground "blue")
+    (t
+     :bold t))
+  "Face used for displaying specificaton values."
+  :group 'erts-mode)
+
+(defface erts-mode-start-test
+  '((t :inherit font-lock-keyword-face))
+  "Face used for displaying specificaton test start markers."
+  :group 'erts-mode)
+
+(defface erts-mode-end-test
+  '((t :inherit font-lock-comment-face))
+  "Face used for displaying specificaton test start markers."
+  :group 'erts-mode)
+
+(defvar erts-mode-map
+  (let ((map (make-keymap)))
+    (set-keymap-parent map prog-mode-map)
+    (define-key map "\C-c\C-r" 'erts-tag-region)
+    (define-key map "\C-c\C-c" 'erts-run-test)
+    map))
+
+(defvar erts-mode-font-lock-keywords
+  ;; Specifications.
+  `((erts-mode--match-not-in-test
+     ("^\\([^ \t\n:]+:\\)[ \t]*\\(.*\\(\n[ \t].*\\)*\\)\n?"
+      (progn (goto-char (match-beginning 0)) (match-end 0)) nil
+      (1 'erts-mode-specification-name)
+      (2 'erts-mode-specification-value)))
+    ("^=-=$" 0 'erts-mode-start-test)
+    ("^=-=-=$" 0 'erts-mode-end-test)))
+
+(defun erts-mode--match-not-in-test (_limit)
+  (when (erts-mode--in-test-p (point))
+    (erts-mode--end-of-test))
+  (let ((start (point)))
+    (goto-char
+     (if (re-search-forward "^=-=$" nil t)
+         (match-beginning 0)
+       (point-max)))
+    (if (< (point) start)
+        nil
+      ;; Here we disregard LIMIT so that we may extend the area again.
+      (set-match-data (list start (point)))
+      (point))))
+
+(defun erts-mode--end-of-test ()
+  (search-forward "^=-=-=\n" nil t))
+
+(defun erts-mode--in-test-p (point)
+  "Say whether POINT is in a test."
+  (save-excursion
+    (goto-char point)
+    (beginning-of-line)
+    (if (looking-at "=-=\\(-=\\)?$")
+        t
+      (let ((test-start (save-excursion
+                          (re-search-backward "^=-=\n" nil t))))
+        ;; Before the first test.
+        (and test-start
+             (let ((test-end (re-search-backward "^=-=-=\n" nil t)))
+               (or (null test-end)
+                   ;; Between tests.
+                   (> test-start test-end))))))))
+
+;;;###autoload
+(define-derived-mode erts-mode prog-mode "erts"
+  "Major mode for editing erts (Emacs testing) files.
+This mode mainly provides some font locking.
+
+\\{erts-mode-map}"
+  (setq-local font-lock-defaults '(erts-mode-font-lock-keywords t)))
+
+(defun erts-tag-region (start end name)
+  "Tag the region between START and END as a test.
+Interactively, this is the region.
+
+NAME should be a string appropriate for output by ert if the test fails.
+If NAME is nil or the empty string, a name will be auto-generated."
+  (interactive "r\nsTest name: " erts-mode)
+  ;; Automatically make a name.
+  (when (zerop (length name))
+    (save-excursion
+      (goto-char (point-min))
+      (let ((names nil))
+        (while (re-search-forward "^Name:[ \t]*\\(.*\\)" nil t)
+          (let ((name (match-string 1)))
+            (unless (erts-mode--in-test-p (point))
+              (push name names))))
+        (setq name
+              (cl-loop with base = (file-name-sans-extension (buffer-name))
+                       for i from 1
+                       for name = (format "%s%d" base i)
+                       unless (member name names)
+                       return name)))))
+  (save-excursion
+    (goto-char end)
+    (unless (bolp)
+      (insert "\n"))
+    (insert "=-=-=\n")
+    (goto-char start)
+    (insert "Name: " name "\n\n")
+    (insert "=-=\n")))
+
+(defun erts-run-test (test-function &optional verbose)
+  "Run the current test.
+If the current erts file doesn't define a test function, the user
+will be prompted for one.
+
+If VERBOSE (interactively, the prefix), display a diff of the
+expected results and the actual results in a separate buffer."
+  (interactive
+   (list (save-excursion
+           ;; Find the preceding Code spec.
+           (while (and (re-search-backward "^Code:" nil t)
+                       (erts-mode--in-test-p (point))))
+           (if (and (not (erts-mode--in-test-p (point)))
+                    (re-search-forward "^=-=$" nil t))
+               (progn
+                 (goto-char (match-beginning 0))
+                 (cdr (assq 'code (ert--erts-specifications (point)))))
+             (read-string "Transformation function: ")))
+         current-prefix-arg)
+   erts-mode)
+  (save-excursion
+    (erts-mode--goto-start-of-test)
+    (condition-case arg
+        (ert-test--erts-test
+         (list (cons 'dummy t)
+               (cons 'code (car (read-from-string test-function))))
+         (buffer-file-name))
+      (:success (message "Test successful"))
+      (ert-test-failed
+       (if (not verbose)
+           (message "Test failure; result: \n%s"
+                    (substring-no-properties (cadr (cadr arg))))
+         (message "Test failure")
+         (let (expected got)
+           (unwind-protect
+               (progn
+                 (with-current-buffer
+                     (setq expected (generate-new-buffer "erts expected"))
+                   (insert (nth 1 (cadr arg))))
+                 (with-current-buffer
+                     (setq got (generate-new-buffer "erts results"))
+                   (insert (nth 2 (cadr arg))))
+                 (diff-buffers expected got))
+             (kill-buffer expected)
+             (kill-buffer got))))))))
+
+(defun erts-mode--goto-start-of-test ()
+  (if (not (erts-mode--in-test-p (point)))
+      (re-search-forward "^=-=\n" nil t)
+    (re-search-backward "^=-=\n" nil t)
+    (let ((potential-start (match-end 0)))
+      ;; See if we're in a two-clause ("before" and "after") test or not.
+      (if-let ((start (and (save-excursion (re-search-backward "^=-=\n" nil t))
+                           (match-end 0))))
+          (let ((end (save-excursion (re-search-backward "^=-=-=\n" nil t))))
+            (if (or (not end)
+                    (> start end))
+                ;; We are, so go to the real start.
+                (goto-char start)
+              (goto-char potential-start)))
+        (goto-char potential-start)))))
+
+(provide 'erts-mode)
+
+;;; erts-mode.el ends here
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index e6af2b12c7..d833612cd9 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -145,7 +145,9 @@ Otherwise, `find-tag-default' is used."
   :type '(choice (const nil) function))
 
 (define-obsolete-variable-alias 'find-tag-marker-ring-length
-  'xref-marker-ring-length "25.1")
+  'tags-location-ring-length "25.1")
+
+(defvar tags-location-ring-length 16)
 
 (defcustom tags-tag-face 'default
   "Face for tags in the output of `tags-apropos'."
@@ -180,10 +182,11 @@ Example value:
                       (sexp :tag "Tags to search")))
   :version "21.1")
 
-(defvaralias 'find-tag-marker-ring 'xref--marker-ring)
+;; Obsolete variable kept for compatibility. We don't use it in any way.
+(defvar find-tag-marker-ring (make-ring 16))
 (make-obsolete-variable
  'find-tag-marker-ring
- "use `xref-push-marker-stack' or `xref-pop-marker-stack' instead."
+ "use `xref-push-marker-stack' or `xref-go-back' instead."
  "25.1")
 
 (defvar default-tags-table-function nil
@@ -191,7 +194,7 @@ Example value:
 This function receives no arguments and should return the default
 tags table file to use for the current buffer.")
 
-(defvar tags-location-ring (make-ring xref-marker-ring-length)
+(defvar tags-location-ring (make-ring tags-location-ring-length)
   "Ring of markers which are locations visited by \\[find-tag].
 Pop back to the last location with \\[negative-argument] \\[find-tag].")
 
@@ -292,7 +295,7 @@ file the tag was in."
            (or (locate-dominating-file default-directory "TAGS")
                default-directory)))
      (list (read-file-name
-            "Visit tags table (default TAGS): "
+            (format-prompt "Visit tags table" "TAGS")
             ;; default to TAGS from default-directory up to root.
             default-tag-dir
             (expand-file-name "TAGS" default-tag-dir)
@@ -625,7 +628,7 @@ Returns t if it visits a tags table, or nil if there are no 
more in the list."
                  (car list))
                ;; Finally, prompt the user for a file name.
                (expand-file-name
-                (read-file-name "Visit tags table (default TAGS): "
+                 (read-file-name (format-prompt "Visit tags table" "TAGS")
                                 default-directory
                                 "TAGS"
                                 t))))))
@@ -731,13 +734,13 @@ Returns t if it visits a tags table, or nil if there are 
no more in the list."
   (interactive)
   ;; Clear out the markers we are throwing away.
   (let ((i 0))
-    (while (< i xref-marker-ring-length)
+    (while (< i tags-location-ring-length)
       (if (aref (cddr tags-location-ring) i)
          (set-marker (aref (cddr tags-location-ring) i) nil))
       (setq i (1+ i))))
   (xref-clear-marker-stack)
   (setq tags-file-name nil
-       tags-location-ring (make-ring xref-marker-ring-length)
+       tags-location-ring (make-ring tags-location-ring-length)
        tags-table-list nil
        tags-table-computed-list nil
        tags-table-computed-list-for nil
@@ -1068,7 +1071,7 @@ See documentation of variable `tags-file-name'."
           regexp next-p t))
 
 ;;;###autoload
-(defalias 'pop-tag-mark 'xref-pop-marker-stack)
+(defalias 'pop-tag-mark 'xref-go-back)
 
 
 (defvar tag-lines-already-matched nil
@@ -2161,18 +2164,16 @@ file name, add `tag-partial-file-name-match-p' to the 
list value.")
          (nreverse res))))
    tags-apropos-additional-actions))
 
-(defclass xref-etags-location (xref-location)
-  ((tag-info :type list   :initarg :tag-info)
-   (file     :type string :initarg :file
-             :reader xref-location-group))
-  :documentation "Location of an etags tag.")
+(cl-defstruct (xref-etags-location
+               (:constructor xref-make-etags-location (tag-info file)))
+  "Location of an etags tag."
+  tag-info file)
 
-(defun xref-make-etags-location (tag-info file)
-  (make-instance 'xref-etags-location :tag-info tag-info
-                 :file (expand-file-name file)))
+(cl-defmethod xref-location-group ((l xref-etags-location))
+  (xref-etags-location-file l))
 
 (cl-defmethod xref-location-marker ((l xref-etags-location))
-  (with-slots (tag-info file) l
+  (pcase-let (((cl-struct xref-etags-location tag-info file) l))
     (let ((buffer (find-file-noselect file)))
       (with-current-buffer buffer
         (save-excursion
@@ -2182,25 +2183,20 @@ file name, add `tag-partial-file-name-match-p' to the 
list value.")
             (point-marker)))))))
 
 (cl-defmethod xref-location-line ((l xref-etags-location))
-  (with-slots (tag-info) l
+  (pcase-let (((cl-struct xref-etags-location tag-info) l))
     (nth 1 tag-info)))
 
-(defclass xref-etags-apropos-location (xref-location)
-  ((symbol :type symbol :initarg :symbol)
-   (goto-fun :type function :initarg :goto-fun)
-   (group :type string :initarg :group
-          :reader xref-location-group))
-  :documentation "Location of an additional apropos etags symbol.")
+(cl-defstruct (xref-etags-apropos-location
+               (:constructor xref-make-etags-apropos-location (symbol goto-fun 
group)))
+  "Location of an additional apropos etags symbol."
+  symbol goto-fun group)
 
-(defun xref-make-etags-apropos-location (symbol goto-fun group)
-  (make-instance 'xref-etags-apropos-location
-                 :symbol symbol
-                 :goto-fun goto-fun
-                 :group group))
+(cl-defmethod xref-location-group ((l xref-etags-apropos-location))
+  (xref-etags-apropos-location-group l))
 
 (cl-defmethod xref-location-marker ((l xref-etags-apropos-location))
   (save-window-excursion
-    (with-slots (goto-fun symbol) l
+    (pcase-let (((cl-struct xref-etags-apropos-location goto-fun symbol) l))
       (funcall goto-fun symbol)
       (point-marker))))
 
diff --git a/lisp/progmodes/f90.el b/lisp/progmodes/f90.el
index f9e6101e7a..acc0d96ea5 100644
--- a/lisp/progmodes/f90.el
+++ b/lisp/progmodes/f90.el
@@ -345,6 +345,7 @@ The options are `downcase-word', `upcase-word', 
`capitalize-word' and nil."
                  ;; there are spaces.
                  "contiguous" "submodule" "concurrent" "codimension"
                  "sync all" "sync memory" "critical" "image_index" "error stop"
+                 "impure"
                  ))
    "\\_>")
   "Regexp used by the function `f90-change-keywords'.")
diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index 27b46a45c5..7f2aa0f469 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -902,7 +902,7 @@ can also be executed interactively independently of
                                      temp-dir))))
 
 (defun flymake-proc--delete-temp-directory (dir-name)
-  "Attempt to delete temp dir created by 
`flymake-proc-create-temp-with-folder-structure', do not fail on error."
+  "Attempt to delete temp dir DIR-NAME, do not fail on error."
   (let* ((temp-dir    temporary-file-directory)
         (suffix      (substring dir-name (1+ (length (directory-file-name 
temp-dir))))))
 
@@ -919,7 +919,8 @@ can also be executed interactively independently of
 (defvar-local flymake-proc--base-dir nil)
 
 (defun flymake-proc-init-create-temp-buffer-copy (create-temp-f)
-  "Make a temporary copy of the current buffer, save its name in buffer data 
and return the name."
+  "Make a temporary copy of the current buffer, save its name in buffer data.
+Return the name."
   (let*  ((source-file-name       buffer-file-name)
          (temp-source-file-name  (funcall create-temp-f source-file-name 
"flymake")))
 
@@ -1007,7 +1008,7 @@ Return full-name.  Names are real, not patched."
                       buildfile-name source-file-name)))))
 
 (defun flymake-proc--init-create-temp-source-and-master-buffer-copy 
(get-incl-dirs-f create-temp-f master-file-masks include-regexp)
-  "Find master file (or buffer), create its copy along with a copy of the 
source file."
+  "Find master file (or buffer), create its copy and a copy of the source 
file."
   (let* ((source-file-name       buffer-file-name)
         (temp-source-file-name  (flymake-proc-init-create-temp-buffer-copy 
create-temp-f))
         (master-and-temp-master (flymake-proc--create-master-file
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index 9418debe5e..403925c855 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -266,7 +266,9 @@ If set to nil, don't suppress any zero counters."
         (warning-type-format
          (format " [%s %s]"
                  (or sublog 'flymake)
-                 (current-buffer))))
+                 ;; Handle file names with "%" correctly.  (Bug#51549)
+                 (string-replace "%" "%%"
+                                 (buffer-name (current-buffer))))))
     (display-warning (list 'flymake sublog)
                      (apply #'format-message msg args)
                      (if (numberp level)
@@ -1334,7 +1336,7 @@ default) no filter is applied."
     [ "Go to next problem"      flymake-goto-next-error t ]
     [ "Go to previous problem"  flymake-goto-prev-error t ]
     [ "Check now"               flymake-start t ]
-    [ "List all problems"       flymake-show-diagnostics-buffer t ]
+    [ "List all problems"       flymake-show-buffer-diagnostics t ]
     "--"
     [ "Go to log buffer"        flymake-switch-to-log-buffer t ]
     [ "Turn off Flymake"        flymake-mode t ]))
@@ -1599,7 +1601,7 @@ buffer."
   ;; been set to a valid buffer.  This could happen when this function
   ;; is called too early.  For example 'global-display-line-numbers-mode'
   ;; calls us from its mode hook, when the diagnostic buffer has just
-  ;; been created by 'flymake-show-diagnostics-buffer', but is not yet
+  ;; been created by 'flymake-show-buffer-diagnostics', but is not yet
   ;; set up properly (Bug#40529).
   (when (bufferp flymake--diagnostics-buffer-source)
     (with-current-buffer flymake--diagnostics-buffer-source
@@ -1654,7 +1656,7 @@ buffer."
   "Diagnostics list meant for listing, not highlighting.
 This variable holds an alist ((FILE-NAME . DIAGS) ...) where
 FILE-NAME is a string holding an absolute file name and DIAGS is
-a list of diagnostic objects created with with
+a list of diagnostic objects created with
 `flymake-make-diagnostic'.  These diagnostics are never annotated
 as overlays in actual buffers: they merely serve as temporary
 stand-ins for more accurate diagnostics that are produced once
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index 3e5b8e2f32..39fcfd341c 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -766,7 +766,9 @@ NOARG must be t when this macro is used outside `gud-def'."
       ;; Apparently we're not running with -i=mi (or we're, for
       ;; instance, debugging something inside a Docker instance with
       ;; Emacs on the outside).
-      (let ((msg "Error: Either -i=mi wasn't specified on the GDB command 
line, or the extra socket couldn't be established.  Consider using `M-x 
gud-gdb' instead."))
+      (let ((msg (substitute-command-keys
+                  "Error: Either -i=mi wasn't specified on the GDB command 
line,\
+ or the extra socket couldn't be established.  Consider using \\[gud-gdb] 
instead.")))
         (message msg)
         (setq string (concat (propertize msg 'font-lock-face 'error)
                              "\n" string)))
@@ -1610,6 +1612,7 @@ this trigger is subscribed to `gdb-buf-publisher' and 
called with
 ;; Used to display windows with thread-bound buffers
 (defmacro def-gdb-preempt-display-buffer (name buffer &optional doc
                                               split-horizontal)
+  (declare (indent defun))
   `(defun ,name (&optional thread)
      ,(when doc doc)
      (message "%s" thread)
@@ -3010,6 +3013,7 @@ calling `gdb-current-context-command').
 Triggers defined by this command are meant to be used as a
 trigger argument when describing buffer types with
 `gdb-set-buffer-rules'."
+  (declare (indent defun))
   `(defun ,trigger-name (&optional signal)
      (when
          (or (not ,signal-list)
@@ -3030,6 +3034,7 @@ Erase current buffer and evaluate CUSTOM-DEFUN.
 Then call `gdb-update-buffer-name'.
 
 If NOPRESERVE is non-nil, window point is not restored after CUSTOM-DEFUN."
+  (declare (indent defun))
   `(defun ,handler-name ()
      (let* ((inhibit-read-only t)
             ,@(unless nopreserve
@@ -3053,6 +3058,7 @@ See `def-gdb-auto-update-trigger'.
 
 HANDLER-NAME handler uses customization of CUSTOM-DEFUN.
 See `def-gdb-auto-update-handler'."
+  (declare (indent defun))
   `(progn
      (def-gdb-auto-update-trigger ,trigger-name
        ,gdb-command
@@ -3471,6 +3477,7 @@ corresponding to the mode line clicked."
 CUSTOM-DEFUN may use locally bound `thread' variable, which will
 be the value of `gdb-thread' property of the current line.
 If `gdb-thread' is nil, error is signaled."
+  (declare (indent defun))
   `(defun ,name (&optional event)
      ,(when doc doc)
      (interactive (list last-input-event))
@@ -3486,6 +3493,7 @@ If `gdb-thread' is nil, error is signaled."
                                                      &optional doc)
   "Define a NAME which will call BUFFER-COMMAND with id of thread
 on the current line."
+  (declare (indent defun))
   `(def-gdb-thread-buffer-command ,name
      (,buffer-command (gdb-mi--field thread 'id))
      ,doc))
@@ -3541,6 +3549,7 @@ on the current line."
   "Define a NAME which will execute GUD-COMMAND with
 `gdb-thread-number' locally bound to id of thread on the current
 line."
+  (declare (indent defun))
   `(def-gdb-thread-buffer-command ,name
      (if gdb-non-stop
          (let ((gdb-thread-number (gdb-mi--field thread 'id))
@@ -3709,6 +3718,7 @@ in `gdb-memory-format'."
 
 (defmacro def-gdb-set-positive-number (name variable echo-string &optional doc)
   "Define a function NAME which reads new VAR value from minibuffer."
+  (declare (indent defun))
   `(defun ,name (event)
      ,(when doc doc)
      (interactive "e")
@@ -3737,6 +3747,7 @@ in `gdb-memory-format'."
   "Define a function NAME to switch memory buffer to use FORMAT.
 
 DOC is an optional documentation string."
+  (declare (indent defun))
   `(defun ,name () ,(when doc doc)
      (interactive)
      (customize-set-variable 'gdb-memory-format ,format)
@@ -3806,6 +3817,7 @@ DOC is an optional documentation string."
   "Define a function NAME to switch memory unit size to UNIT-SIZE.
 
 DOC is an optional documentation string."
+  (declare (indent defun))
   `(defun ,name () ,(when doc doc)
      (interactive)
      (customize-set-variable 'gdb-memory-unit ,unit-size)
@@ -3830,6 +3842,7 @@ The defined function switches Memory buffer to show 
address
 stored in ADDRESS-VAR variable.
 
 DOC is an optional documentation string."
+  (declare (indent defun))
   `(defun ,name
      ,(when doc doc)
      (interactive)
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index ec2850737c..001989e39a 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -1057,11 +1057,9 @@ REGEXP is used as a string in the prompt."
               default-extension
               (car grep-files-history)
               (car (car grep-files-aliases))))
-        (files (completing-read
-                (concat "Search for \"" regexp
-                        "\" in files matching wildcard"
-                        (if default (concat " (default " default ")"))
-                        ": ")
+         (files (completing-read
+                 (format-prompt "Search for \"%s\" in files matching wildcard"
+                                default regexp)
                 #'read-file-name-internal
                 nil nil nil 'grep-files-history
                 (delete-dups
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index 2061d41480..9b884c4ff8 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -3539,8 +3539,8 @@ Treats actions as defuns."
               #'gdb-script-end-of-defun)
   (setq-local font-lock-defaults
               '(gdb-script-font-lock-keywords nil nil ((?_ . "w")) nil
-                (font-lock-syntactic-face-function
-                 . gdb-script-font-lock-syntactic-face)))
+                                              
(font-lock-syntactic-face-function
+                                               . 
gdb-script-font-lock-syntactic-face)))
   ;; Recognize docstrings.
   (setq-local syntax-propertize-function
               gdb-script-syntax-propertize-function)
diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index a18a67249a..87732c1048 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -2456,7 +2456,7 @@ This allows #ifdef VAR to be hidden."
                            (t
                             nil))))
           (var (read-minibuffer "Define what? " default))
-          (val (read-from-minibuffer (format "Set %s to? (default 1): " var)
+          (val (read-from-minibuffer (format-prompt "Set %s to?" "1" var)
                                      nil nil t nil "1")))
      (list var val)))
   (hif-set-var var (or val 1))
diff --git a/lisp/progmodes/idlw-shell.el b/lisp/progmodes/idlw-shell.el
index fc3d603f06..5a31ad3508 100644
--- a/lisp/progmodes/idlw-shell.el
+++ b/lisp/progmodes/idlw-shell.el
@@ -105,8 +105,9 @@ process buffer."
   :type 'regexp)
 
 (defcustom idlwave-shell-process-name "idl"
-  "Name to be associated with the IDL process.  The buffer for the
-process output is made by surrounding this name with `*'s."
+  "Name to be associated with the IDL process.
+The buffer for the process output is made by surrounding this
+name with `*'s."
   :group 'idlwave-shell-general-setup
   :type 'string)
 
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index d6828eeffb..9aaabd8a0e 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -245,7 +245,7 @@ would yield:
   :type 'boolean)
 
 (defcustom idlwave-indent-parens-nested nil
-  "Non-nil means, indent continuation lines with parens by nesting
+  "Non-nil means indent continuation lines with parens by nesting
 lines at consecutively deeper levels."
  :group 'idlwave-code-formatting
   :type 'boolean)
@@ -1522,7 +1522,8 @@ No spaces before and 1 after a comma
 A minimum of 1 space before and after `=' (see `idlwave-expand-equal').
    (idlwave-action-and-binding \"=\"  (lambda (_) (idlwave-expand-equal -1 
-1)))
 Capitalize system variables - action only
-   (idlwave-action-and-binding idlwave-sysvar (lambda (_) (capitalize-word 1) 
t))"
+   (idlwave-action-and-binding idlwave-sysvar
+                               (lambda (_) (capitalize-word 1) t))"
   (if (not (equal select 'noaction))
       ;; Add action
       (let* ((table (if select 'idlwave-indent-action-table
@@ -7285,8 +7286,7 @@ The list is cached in `idlwave-class-info' for faster 
access."
                                   inherits))
            (if (> (cdr cl) 999)
              (error
-              "Class scan: inheritance depth exceeded. Circular inheritance?")
-             ))
+               "Class scan: inheritance depth exceeded.  Circular 
inheritance?")))
          (setq all-inherits (nreverse rtn))
          (nconc info (list (cons 'all-inherits all-inherits)))
          all-inherits))))))
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 845ca8609d..f11995127d 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -33,7 +33,7 @@
 ;; The main features of this JavaScript mode are syntactic
 ;; highlighting (enabled with `font-lock-mode' or
 ;; `global-font-lock-mode'), automatic indentation and filling of
-;; comments, C preprocessor fontification, and MozRepl integration.
+;; comments, and C preprocessor fontification.
 ;;
 ;; General Remarks:
 ;;
@@ -51,7 +51,6 @@
   (require 'cc-fonts))
 (require 'newcomment)
 (require 'imenu)
-(require 'moz nil t)
 (require 'json)
 (require 'prog-mode)
 
@@ -59,12 +58,9 @@
   (require 'cl-lib)
   (require 'ido))
 
-(defvar inferior-moz-buffer)
-(defvar moz-repl-name)
 (defvar ido-cur-list)
 (defvar electric-layout-rules)
 (declare-function ido-mode "ido" (&optional arg))
-(declare-function inferior-moz-process "ext:mozrepl" ())
 
 ;;; Constants
 
@@ -485,25 +481,22 @@ seldom use, either globally or on a per-buffer basis."
                              (list 'const x))
                            js--available-frameworks)))
 
-(defcustom js-js-switch-tabs
-  (and (memq system-type '(darwin)) t)
+(defvar js-js-switch-tabs (and (memq system-type '(darwin)) t)
   "Whether `js-mode' should display tabs while selecting them.
 This is useful only if the windowing system has a good mechanism
-for preventing Firefox from stealing the keyboard focus."
-  :type 'boolean)
+for preventing Firefox from stealing the keyboard focus.")
+(make-obsolete-variable 'js-js-switch-tabs "MozRepl no longer exists" "28.1")
 
-(defcustom js-js-tmpdir
-  (locate-user-emacs-file "js/js")
+(defvar js-js-tmpdir (locate-user-emacs-file "js/js")
   "Temporary directory used by `js-mode' to communicate with Mozilla.
-This directory must be readable and writable by both Mozilla and Emacs."
-  :type 'directory
-  :version "28.1")
+This directory must be readable and writable by both Mozilla and Emacs.")
+(make-obsolete-variable 'js-js-tmpdir "MozRepl no longer exists" "28.1")
 
-(defcustom js-js-timeout 5
+(defvar js-js-timeout 5
   "Reply timeout for executing commands in Mozilla via `js-mode'.
 The value is given in seconds.  Increase this value if you are
-getting timeout messages."
-  :type 'integer)
+getting timeout messages.")
+(make-obsolete-variable 'js-js-timeout "MozRepl no longer exists" "28.1")
 
 (defcustom js-indent-first-init nil
   "Non-nil means specially indent the first variable declaration's initializer.
@@ -671,18 +664,7 @@ This variable is like `sgml-attribute-offset'."
 
 (defvar js-mode-map
   (let ((keymap (make-sparse-keymap)))
-    (define-key keymap [(control ?c) (meta ?:)] #'js-eval)
-    (define-key keymap [(control ?c) (control ?j)] #'js-set-js-context)
-    (define-key keymap [(control meta ?x)] #'js-eval-defun)
     (define-key keymap [(meta ?.)] #'js-find-symbol)
-    (easy-menu-define nil keymap "JavaScript Menu"
-      '("JavaScript"
-        ["Select New Mozilla Context..." js-set-js-context
-         (fboundp #'inferior-moz-process)]
-        ["Evaluate Expression in Mozilla Context..." js-eval
-         (fboundp #'inferior-moz-process)]
-        ["Send Current Function to Mozilla..." js-eval-defun
-         (fboundp #'inferior-moz-process)]))
     keymap)
   "Keymap for `js-mode'.")
 
@@ -3308,10 +3290,7 @@ marker."
           (setf (car bounds) (point))))
       (buffer-substring (car bounds) (cdr bounds)))))
 
-(defvar find-tag-marker-ring)           ; etags
-
-;; etags loads ring.
-(declare-function ring-insert "ring" (ring item))
+(declare-function xref-push-marker-stack "xref" (&optional m))
 
 (defun js-find-symbol (&optional arg)
   "Read a JavaScript symbol and jump to it.
@@ -3319,7 +3298,7 @@ With a prefix argument, restrict symbols to those from the
 current buffer.  Pushes a mark onto the tag ring just like
 `find-tag'."
   (interactive "P")
-  (require 'etags)
+  (require 'xref)
   (let (symbols marker)
     (if (not arg)
         (setq symbols (js--get-all-known-symbols))
@@ -3331,1111 +3310,11 @@ current buffer.  Pushes a mark onto the tag ring just 
like
                        symbols "Jump to: "
                        (js--guess-symbol-at-point))))
 
-    (ring-insert find-tag-marker-ring (point-marker))
+    (xref-push-marker-stack)
     (switch-to-buffer (marker-buffer marker))
     (push-mark)
     (goto-char marker)))
 
-;;; MozRepl integration
-
-(define-error 'js-moz-bad-rpc "Mozilla RPC Error") ;; '(timeout error))
-(define-error 'js-js-error "JavaScript Error") ;; '(js-error error))
-
-(defun js--wait-for-matching-output
-  (process regexp timeout &optional start)
-  "Wait TIMEOUT seconds for PROCESS to output a match for REGEXP.
-On timeout, return nil.  On success, return t with match data
-set.  If START is non-nil, look for output starting from START.
-Otherwise, use the current value of `process-mark'."
-  (with-current-buffer (process-buffer process)
-    (cl-loop with start-pos = (or start
-                                  (marker-position (process-mark process)))
-            with end-time = (time-add nil timeout)
-            for time-left = (float-time (time-subtract end-time nil))
-             do (goto-char (point-max))
-             if (looking-back regexp start-pos) return t
-             while (> time-left 0)
-             do (accept-process-output process time-left nil t)
-             do (goto-char (process-mark process))
-             finally do (signal
-                         'js-moz-bad-rpc
-                         (list (format "Timed out waiting for output matching 
%S" regexp))))))
-
-(cl-defstruct js--js-handle
-  ;; Integer, mirrors the value we see in JS
-  (id nil :read-only t)
-
-  ;; Process to which this thing belongs
-  (process nil :read-only t))
-
-(defun js--js-handle-expired-p (x)
-  (not (eq (js--js-handle-process x)
-           (inferior-moz-process))))
-
-(defvar js--js-references nil
-  "Maps Elisp JavaScript proxy objects to their JavaScript IDs.")
-
-(defvar js--js-process nil
-  "The most recent MozRepl process object.")
-
-(defvar js--js-gc-idle-timer nil
-  "Idle timer for cleaning up JS object references.")
-
-(defvar js--js-last-gcs-done nil)
-
-(defconst js--moz-interactor
-  (replace-regexp-in-string
-   "[ \n]+" " "
-   ; */" Make Emacs happy
-"(function(repl) {
-  repl.defineInteractor('js', {
-    onStart: function onStart(repl) {
-      if(!repl._jsObjects) {
-        repl._jsObjects = {};
-        repl._jsLastID = 0;
-        repl._jsGC = this._jsGC;
-      }
-      this._input = '';
-    },
-
-    _jsGC: function _jsGC(ids_in_use) {
-      var objects = this._jsObjects;
-      var keys = [];
-      var num_freed = 0;
-
-      for(var pn in objects) {
-        keys.push(Number(pn));
-      }
-
-      keys.sort(function(x, y) x - y);
-      ids_in_use.sort(function(x, y) x - y);
-      var i = 0;
-      var j = 0;
-
-      while(i < ids_in_use.length && j < keys.length) {
-        var id = ids_in_use[i++];
-        while(j < keys.length && keys[j] !== id) {
-          var k_id = keys[j++];
-          delete objects[k_id];
-          ++num_freed;
-        }
-        ++j;
-      }
-
-      while(j < keys.length) {
-        var k_id = keys[j++];
-        delete objects[k_id];
-        ++num_freed;
-      }
-
-      return num_freed;
-    },
-
-    _mkArray: function _mkArray() {
-      var result = [];
-      for(var i = 0; i < arguments.length; ++i) {
-        result.push(arguments[i]);
-      }
-      return result;
-    },
-
-    _parsePropDescriptor: function _parsePropDescriptor(parts) {
-      if(typeof parts === 'string') {
-        parts = [ parts ];
-      }
-
-      var obj = parts[0];
-      var start = 1;
-
-      if(typeof obj === 'string') {
-        obj = window;
-        start = 0;
-      } else if(parts.length < 2) {
-        throw new Error('expected at least 2 arguments');
-      }
-
-      for(var i = start; i < parts.length - 1; ++i) {
-        obj = obj[parts[i]];
-      }
-
-      return [obj, parts[parts.length - 1]];
-    },
-
-    _getProp: function _getProp(/*...*/) {
-      if(arguments.length === 0) {
-        throw new Error('no arguments supplied to getprop');
-      }
-
-      if(arguments.length === 1 &&
-         (typeof arguments[0]) !== 'string')
-      {
-        return arguments[0];
-      }
-
-      var [obj, propname] = this._parsePropDescriptor(arguments);
-      return obj[propname];
-    },
-
-    _putProp: function _putProp(properties, value) {
-      var [obj, propname] = this._parsePropDescriptor(properties);
-      obj[propname] = value;
-    },
-
-    _delProp: function _delProp(propname) {
-      var [obj, propname] = this._parsePropDescriptor(arguments);
-      delete obj[propname];
-    },
-
-    _typeOf: function _typeOf(thing) {
-      return typeof thing;
-    },
-
-    _callNew: function(constructor) {
-      if(typeof constructor === 'string')
-      {
-        constructor = window[constructor];
-      } else if(constructor.length === 1 &&
-                typeof constructor[0] !== 'string')
-      {
-        constructor = constructor[0];
-      } else {
-        var [obj,propname] = this._parsePropDescriptor(constructor);
-        constructor = obj[propname];
-      }
-
-      /* Hacky, but should be robust */
-      var s = 'new constructor(';
-      for(var i = 1; i < arguments.length; ++i) {
-        if(i != 1) {
-          s += ',';
-        }
-
-        s += 'arguments[' + i + ']';
-      }
-
-      s += ')';
-      return eval(s);
-    },
-
-    _callEval: function(thisobj, js) {
-      return eval.call(thisobj, js);
-    },
-
-    getPrompt: function getPrompt(repl) {
-      return 'EVAL>'
-    },
-
-    _lookupObject: function _lookupObject(repl, id) {
-      if(typeof id === 'string') {
-        switch(id) {
-        case 'global':
-          return window;
-        case 'nil':
-          return null;
-        case 't':
-          return true;
-        case 'false':
-          return false;
-        case 'undefined':
-          return undefined;
-        case 'repl':
-          return repl;
-        case 'interactor':
-          return this;
-        case 'NaN':
-          return NaN;
-        case 'Infinity':
-          return Infinity;
-        case '-Infinity':
-          return -Infinity;
-        default:
-          throw new Error('No object with special id:' + id);
-        }
-      }
-
-      var ret = repl._jsObjects[id];
-      if(ret === undefined) {
-        throw new Error('No object with id:' + id + '(' + typeof id + ')');
-      }
-      return ret;
-    },
-
-    _findOrAllocateObject: function _findOrAllocateObject(repl, value) {
-      if(typeof value !== 'object'  && typeof value !== 'function') {
-        throw new Error('_findOrAllocateObject called on non-object('
-                        + typeof(value) + '): '
-                        + value)
-      }
-
-      for(var id in repl._jsObjects) {
-        id = Number(id);
-        var obj = repl._jsObjects[id];
-        if(obj === value) {
-          return id;
-        }
-      }
-
-      var id = ++repl._jsLastID;
-      repl._jsObjects[id] = value;
-      return id;
-    },
-
-    _fixupList: function _fixupList(repl, list) {
-      for(var i = 0; i < list.length; ++i) {
-        if(list[i] instanceof Array) {
-          this._fixupList(repl, list[i]);
-        } else if(typeof list[i] === 'object') {
-          var obj = list[i];
-          if(obj.funcall) {
-            var parts = obj.funcall;
-            this._fixupList(repl, parts);
-            var [thisobj, func] = this._parseFunc(parts[0]);
-            list[i] = func.apply(thisobj, parts.slice(1));
-          } else if(obj.objid) {
-            list[i] = this._lookupObject(repl, obj.objid);
-          } else {
-            throw new Error('Unknown object type: ' + obj.toSource());
-          }
-        }
-      }
-    },
-
-    _parseFunc: function(func) {
-      var thisobj = null;
-
-      if(typeof func === 'string') {
-        func = window[func];
-      } else if(func instanceof Array) {
-        if(func.length === 1 && typeof func[0] !== 'string') {
-          func = func[0];
-        } else {
-          [thisobj, func] = this._parsePropDescriptor(func);
-          func = thisobj[func];
-        }
-      }
-
-      return [thisobj,func];
-    },
-
-    _encodeReturn: function(value, array_as_mv) {
-      var ret;
-
-      if(value === null) {
-        ret = ['special', 'null'];
-      } else if(value === true) {
-        ret = ['special', 'true'];
-      } else if(value === false) {
-        ret = ['special', 'false'];
-      } else if(value === undefined) {
-        ret = ['special', 'undefined'];
-      } else if(typeof value === 'number') {
-        if(isNaN(value)) {
-          ret = ['special', 'NaN'];
-        } else if(value === Infinity) {
-          ret = ['special', 'Infinity'];
-        } else if(value === -Infinity) {
-          ret = ['special', '-Infinity'];
-        } else {
-          ret = ['atom', value];
-        }
-      } else if(typeof value === 'string') {
-        ret = ['atom', value];
-      } else if(array_as_mv && value instanceof Array) {
-        ret = ['array', value.map(this._encodeReturn, this)];
-      } else {
-        ret = ['objid', this._findOrAllocateObject(repl, value)];
-      }
-
-      return ret;
-    },
-
-    _handleInputLine: function _handleInputLine(repl, line) {
-      var ret;
-      var array_as_mv = false;
-
-      try {
-        if(line[0] === '*') {
-          array_as_mv = true;
-          line = line.substring(1);
-        }
-        var parts = eval(line);
-        this._fixupList(repl, parts);
-        var [thisobj, func] = this._parseFunc(parts[0]);
-        ret = this._encodeReturn(
-          func.apply(thisobj, parts.slice(1)),
-          array_as_mv);
-      } catch(x) {
-        ret = ['error', x.toString() ];
-      }
-
-      var JSON = 
Components.classes['@mozilla.org/dom/json;1'].createInstance(Components.interfaces.nsIJSON);
-      repl.print(JSON.encode(ret));
-      repl._prompt();
-    },
-
-    handleInput: function handleInput(repl, chunk) {
-      this._input += chunk;
-      var match, line;
-      while(match = this._input.match(/.*\\n/)) {
-        line = match[0];
-
-        if(line === 'EXIT\\n') {
-          repl.popInteractor();
-          repl._prompt();
-          return;
-        }
-
-        this._input = this._input.substring(line.length);
-        this._handleInputLine(repl, line);
-      }
-    }
-  });
-})
-")
-
-  "String to set MozRepl up into a simple-minded evaluation mode.")
-
-(defun js--js-encode-value (x)
-  "Marshall the given value for JS.
-Strings and numbers are JSON-encoded.  Lists (including nil) are
-made into JavaScript array literals and their contents encoded
-with `js--js-encode-value'."
-  (cond ((or (stringp x) (numberp x)) (json-encode x))
-        ((symbolp x) (format "{objid:%S}" (symbol-name x)))
-        ((js--js-handle-p x)
-
-         (when (js--js-handle-expired-p x)
-           (error "Stale JS handle"))
-
-         (format "{objid:%s}" (js--js-handle-id x)))
-
-        ((sequencep x)
-         (if (eq (car-safe x) 'js--funcall)
-             (format "{funcall:[%s]}"
-                     (mapconcat #'js--js-encode-value (cdr x) ","))
-           (concat
-            "[" (mapconcat #'js--js-encode-value x ",") "]")))
-        (t
-         (error "Unrecognized item: %S" x))))
-
-(defconst js--js-prompt-regexp "\\(repl[0-9]*\\)> $")
-(defconst js--js-repl-prompt-regexp "^EVAL>$")
-(defvar js--js-repl-depth 0)
-
-(defun js--js-wait-for-eval-prompt ()
-  (js--wait-for-matching-output
-   (inferior-moz-process)
-   js--js-repl-prompt-regexp js-js-timeout
-
-   ;; start matching against the beginning of the line in
-   ;; order to catch a prompt that's only partially arrived
-   (save-excursion (forward-line 0) (point))))
-
-;; Presumably "inferior-moz-process" loads comint.
-(declare-function comint-send-string "comint" (process string))
-(declare-function comint-send-input "comint"
-                  (&optional no-newline artificial))
-
-(defun js--js-enter-repl ()
-  (inferior-moz-process) ; called for side-effect
-  (with-current-buffer inferior-moz-buffer
-    (goto-char (point-max))
-
-    ;; Do some initialization the first time we see a process
-    (unless (eq (inferior-moz-process) js--js-process)
-      (setq js--js-process (inferior-moz-process))
-      (setq js--js-references (make-hash-table :test 'eq :weakness t))
-      (setq js--js-repl-depth 0)
-
-      ;; Send interactor definition
-      (comint-send-string js--js-process js--moz-interactor)
-      (comint-send-string js--js-process
-                          (concat "(" moz-repl-name ")\n"))
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-prompt-regexp
-       js-js-timeout))
-
-    ;; Sanity check
-    (when (looking-back js--js-prompt-regexp
-                        (save-excursion (forward-line 0) (point)))
-      (setq js--js-repl-depth 0))
-
-    (if (> js--js-repl-depth 0)
-        ;; If js--js-repl-depth > 0, we *should* be seeing an
-        ;; EVAL> prompt. If we don't, give Mozilla a chance to catch
-        ;; up with us.
-        (js--js-wait-for-eval-prompt)
-
-      ;; Otherwise, tell Mozilla to enter the interactor mode
-      (insert (match-string-no-properties 1)
-              ".pushInteractor('js')")
-      (comint-send-input nil t)
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-repl-prompt-regexp
-       js-js-timeout))
-
-    (cl-incf js--js-repl-depth)))
-
-(defun js--js-leave-repl ()
-  (cl-assert (> js--js-repl-depth 0))
-  (when (= 0 (cl-decf js--js-repl-depth))
-    (with-current-buffer inferior-moz-buffer
-      (goto-char (point-max))
-      (js--js-wait-for-eval-prompt)
-      (insert "EXIT")
-      (comint-send-input nil t)
-      (js--wait-for-matching-output
-       (inferior-moz-process) js--js-prompt-regexp
-       js-js-timeout))))
-
-(defsubst js--js-not (value)
-  (memq value '(nil null false undefined)))
-
-(defsubst js--js-true (value)
-  (not (js--js-not value)))
-
-(eval-and-compile
-  (defun js--optimize-arglist (arglist)
-    "Convert immediate js< and js! references to deferred ones."
-    (cl-loop for item in arglist
-             if (eq (car-safe item) 'js<)
-             collect (append (list 'list ''js--funcall
-                                   '(list 'interactor "_getProp"))
-                             (js--optimize-arglist (cdr item)))
-             else if (eq (car-safe item) 'js>)
-             collect (append (list 'list ''js--funcall
-                                   '(list 'interactor "_putProp"))
-
-                             (if (atom (cadr item))
-                                 (list (cadr item))
-                               (list
-                                (append
-                                 (list 'list ''js--funcall
-                                       '(list 'interactor "_mkArray"))
-                                 (js--optimize-arglist (cadr item)))))
-                             (js--optimize-arglist (cddr item)))
-             else if (eq (car-safe item) 'js!)
-             collect (pcase-let ((`(,_ ,function . ,body) item))
-                       (append (list 'list ''js--funcall
-                                     (if (consp function)
-                                         (cons 'list
-                                               (js--optimize-arglist function))
-                                       function))
-                               (js--optimize-arglist body)))
-             else
-             collect item)))
-
-(defmacro js--js-get-service (class-name interface-name)
-    `(js! ("Components" "classes" ,class-name "getService")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro js--js-create-instance (class-name interface-name)
-  `(js! ("Components" "classes" ,class-name "createInstance")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro js--js-qi (object interface-name)
-  `(js! (,object "QueryInterface")
-        (js< "Components" "interfaces" ,interface-name)))
-
-(defmacro with-js (&rest forms)
-  "Run FORMS with the Mozilla repl set up for js commands.
-Inside the lexical scope of `with-js', `js?', `js!',
-`js-new', `js-eval', `js-list', `js<', `js>', `js-get-service',
-`js-create-instance', and `js-qi' are defined."
-  (declare (indent 0) (debug t))
-  `(progn
-     (js--js-enter-repl)
-     (unwind-protect
-         (cl-macrolet ((js? (&rest body) `(js--js-true ,@body))
-                       (js! (function &rest body)
-                            `(js--js-funcall
-                              ,(if (consp function)
-                                   (cons 'list
-                                         (js--optimize-arglist function))
-                                 function)
-                              ,@(js--optimize-arglist body)))
-
-                       (js-new (function &rest body)
-                               `(js--js-new
-                                 ,(if (consp function)
-                                      (cons 'list
-                                            (js--optimize-arglist function))
-                                    function)
-                                 ,@body))
-
-                       (js-eval (thisobj js)
-                                `(js--js-eval
-                                  ,@(js--optimize-arglist
-                                     (list thisobj js))))
-
-                       (js-list (&rest args)
-                                `(js--js-list
-                                  ,@(js--optimize-arglist args)))
-
-                       (js-get-service (&rest args)
-                                       `(js--js-get-service
-                                         ,@(js--optimize-arglist args)))
-
-                       (js-create-instance (&rest args)
-                                           `(js--js-create-instance
-                                             ,@(js--optimize-arglist args)))
-
-                       (js-qi (&rest args)
-                              `(js--js-qi
-                                ,@(js--optimize-arglist args)))
-
-                       (js< (&rest body) `(js--js-get
-                                           ,@(js--optimize-arglist body)))
-                       (js> (props value)
-                            `(js--js-funcall
-                              '(interactor "_putProp")
-                              ,(if (consp props)
-                                   (cons 'list
-                                         (js--optimize-arglist props))
-                                 props)
-                              ,@(js--optimize-arglist (list value))
-                              ))
-                       (js-handle? (arg) `(js--js-handle-p ,arg)))
-           ,@forms)
-       (js--js-leave-repl))))
-
-(defvar js--js-array-as-list nil
-  "Whether to listify any Array returned by a Mozilla function.
-If nil, the whole Array is treated as a JS symbol.")
-
-(defun js--js-decode-retval (result)
-  (pcase (intern (cl-first result))
-    ('atom (cl-second result))
-    ('special (intern (cl-second result)))
-    ('array
-     (mapcar #'js--js-decode-retval (cl-second result)))
-    ('objid
-     (or (gethash (cl-second result)
-                  js--js-references)
-         (puthash (cl-second result)
-                  (make-js--js-handle
-                   :id (cl-second result)
-                   :process (inferior-moz-process))
-                  js--js-references)))
-
-    ('error (signal 'js-js-error (list (cl-second result))))
-    (x (error "Unmatched case in js--js-decode-retval: %S" x))))
-
-(defvar comint-last-input-end)
-
-(defun js--js-funcall (function &rest arguments)
-  "Call the Mozilla function FUNCTION with arguments ARGUMENTS.
-If function is a string, look it up as a property on the global
-object and use the global object for `this'.
-If FUNCTION is a list with one element, use that element as the
-function with the global object for `this', except that if that
-single element is a string, look it up on the global object.
-If FUNCTION is a list with more than one argument, use the list
-up to the last value as a property descriptor and the last
-argument as a function."
-
-  (with-js
-   (let ((argstr (js--js-encode-value
-                  (cons function arguments))))
-
-     (with-current-buffer inferior-moz-buffer
-       ;; Actual funcall
-       (when js--js-array-as-list
-         (insert "*"))
-       (insert argstr)
-       (comint-send-input nil t)
-       (js--wait-for-matching-output
-        (inferior-moz-process) "EVAL>"
-        js-js-timeout)
-       (goto-char comint-last-input-end)
-
-       ;; Read the result
-       (let* ((json-array-type 'list)
-              (result (prog1 (json-read)
-                        (goto-char (point-max)))))
-         (js--js-decode-retval result))))))
-
-(defun js--js-new (constructor &rest arguments)
-  "Call CONSTRUCTOR as a constructor, with arguments ARGUMENTS.
-CONSTRUCTOR is a JS handle, a string, or a list of these things."
-  (apply #'js--js-funcall
-         '(interactor "_callNew")
-         constructor arguments))
-
-(defun js--js-eval (thisobj js)
-  (js--js-funcall '(interactor "_callEval") thisobj js))
-
-(defun js--js-list (&rest arguments)
-  "Return a Lisp array resulting from evaluating each of ARGUMENTS."
-  (let ((js--js-array-as-list t))
-    (apply #'js--js-funcall '(interactor "_mkArray")
-           arguments)))
-
-(defun js--js-get (&rest props)
-  (apply #'js--js-funcall '(interactor "_getProp") props))
-
-(defun js--js-put (props value)
-  (js--js-funcall '(interactor "_putProp") props value))
-
-(defun js-gc (&optional force)
-  "Tell the repl about any objects we don't reference anymore.
-With argument, run even if no intervening GC has happened."
-  (interactive)
-
-  (when force
-    (setq js--js-last-gcs-done nil))
-
-  (let ((this-gcs-done gcs-done) keys num)
-    (when (and js--js-references
-               (boundp 'inferior-moz-buffer)
-               (buffer-live-p inferior-moz-buffer)
-
-               ;; Don't bother running unless we've had an intervening
-               ;; garbage collection; without a gc, nothing is deleted
-               ;; from the weak hash table, so it's pointless telling
-               ;; MozRepl about that references we still hold
-               (not (eq js--js-last-gcs-done this-gcs-done))
-
-               ;; Are we looking at a normal prompt? Make sure not to
-               ;; interrupt the user if he's doing something
-               (with-current-buffer inferior-moz-buffer
-                 (save-excursion
-                   (goto-char (point-max))
-                   (looking-back js--js-prompt-regexp
-                                 (save-excursion (forward-line 0) (point))))))
-
-      (setq keys (cl-loop for x being the hash-keys
-                          of js--js-references
-                          collect x))
-      (setq num (js--js-funcall '(repl "_jsGC") (or keys [])))
-
-      (setq js--js-last-gcs-done this-gcs-done)
-      (when (called-interactively-p 'interactive)
-        (message "Cleaned %s entries" num))
-
-      num)))
-
-(run-with-idle-timer 30 t #'js-gc)
-
-(defun js-eval (js)
-  "Evaluate the JavaScript in JS and return JSON-decoded result."
-  (interactive "MJavaScript to evaluate: ")
-  (with-js
-   (let* ((content-window (js--js-content-window
-                           (js--get-js-context)))
-          (result (js-eval content-window js)))
-     (when (called-interactively-p 'interactive)
-       (message "%s" (js! "String" result)))
-     result)))
-
-(defun js--get-tabs ()
-  "Enumerate all JavaScript contexts available.
-Each context is a list:
-   (TITLE URL BROWSER TAB TABBROWSER) for content documents
-   (TITLE URL WINDOW) for windows
-
-All tabs of a given window are grouped together.  The most recent
-window is first.  Within each window, the tabs are returned
-left-to-right."
-  (with-js
-   (let (windows)
-
-     (cl-loop with window-mediator = (js! ("Components" "classes"
-                                           
"@mozilla.org/appshell/window-mediator;1"
-                                           "getService")
-                                          (js< "Components" "interfaces"
-                                               "nsIWindowMediator"))
-              with enumerator = (js! (window-mediator "getEnumerator") nil)
-
-              while (js? (js! (enumerator "hasMoreElements")))
-              for window = (js! (enumerator "getNext"))
-              for window-info = (js-list window
-                                         (js< window "document" "title")
-                                         (js! (window "location" "toString"))
-                                         (js< window "closed")
-                                         (js< window "windowState"))
-
-              unless (or (js? (cl-fourth window-info))
-                         (eq (cl-fifth window-info) 2))
-              do (push window-info windows))
-
-     (cl-loop for (window title location) in windows
-              collect (list title location window)
-
-              for gbrowser = (js< window "gBrowser")
-              if (js-handle? gbrowser)
-              nconc (cl-loop
-                     for x below (js< gbrowser "browsers" "length")
-                     collect (js-list (js< gbrowser
-                                           "browsers"
-                                           x
-                                           "contentDocument"
-                                           "title")
-
-                                      (js! (gbrowser
-                                            "browsers"
-                                            x
-                                            "contentWindow"
-                                            "location"
-                                            "toString"))
-                                      (js< gbrowser
-                                           "browsers"
-                                           x)
-
-                                      (js! (gbrowser
-                                            "tabContainer"
-                                            "childNodes"
-                                            "item")
-                                           x)
-
-                                      gbrowser))))))
-
-(defvar js-read-tab-history nil)
-
-(declare-function ido-chop "ido" (items elem))
-
-(defun js--read-tab (prompt)
-  "Read a Mozilla tab with prompt PROMPT.
-Return a cons of (TYPE . OBJECT).  TYPE is either `window' or
-`tab', and OBJECT is a JavaScript handle to a ChromeWindow or a
-browser, respectively."
-
-  ;; Prime IDO
-  (unless ido-mode
-    (ido-mode 1)
-    (ido-mode -1))
-
-  (with-js
-   (let ((tabs (js--get-tabs)) selected-tab-cname
-         selected-tab prev-hitab)
-
-     ;; Disambiguate names
-     (setq tabs
-           (cl-loop with tab-names = (make-hash-table :test 'equal)
-                    for tab in tabs
-                    for cname = (format "%s (%s)"
-                                        (cl-second tab) (cl-first tab))
-                    for num = (cl-incf (gethash cname tab-names -1))
-                    if (> num 0)
-                    do (setq cname (format "%s <%d>" cname num))
-                    collect (cons cname tab)))
-
-     (cl-labels
-         ((find-tab-by-cname
-           (cname)
-           (cl-loop for tab in tabs
-                    if (equal (car tab) cname)
-                    return (cdr tab)))
-
-          (mogrify-highlighting
-           (hitab unhitab)
-
-           ;; Hack to reduce the number of
-           ;; round-trips to mozilla
-           (let (cmds)
-             (cond
-              ;; Highlighting tab
-              ((cl-fourth hitab)
-               (push '(js! ((cl-fourth hitab) "setAttribute")
-                       "style"
-                       "color: red; font-weight: bold")
-                     cmds)
-
-               ;; Highlight window proper
-               (push '(js! ((cl-third hitab)
-                            "setAttribute")
-                       "style"
-                       "border: 8px solid red")
-                     cmds)
-
-               ;; Select tab, when appropriate
-               (when js-js-switch-tabs
-                 (push
-                  '(js> ((cl-fifth hitab) "selectedTab") (cl-fourth hitab))
-                  cmds)))
-
-              ;; Highlighting whole window
-              ((cl-third hitab)
-               (push '(js! ((cl-third hitab) "document"
-                            "documentElement" "setAttribute")
-                       "style"
-                       (concat "-moz-appearance: none;"
-                               "border: 8px solid red;"))
-                     cmds)))
-
-             (cond
-              ;; Unhighlighting tab
-              ((cl-fourth unhitab)
-               (push '(js! ((cl-fourth unhitab) "setAttribute") "style" "")
-                     cmds)
-               (push '(js! ((cl-third unhitab) "setAttribute") "style" "")
-                     cmds))
-
-              ;; Unhighlighting window
-              ((cl-third unhitab)
-               (push '(js! ((cl-third unhitab) "document"
-                            "documentElement" "setAttribute")
-                       "style" "")
-                     cmds)))
-
-             (eval `(with-js
-                        (js-list ,@(nreverse cmds)))
-                   t)))
-
-          (command-hook
-           ()
-           (let* ((tab (find-tab-by-cname (car ido-matches))))
-             (mogrify-highlighting tab prev-hitab)
-             (setq prev-hitab tab)))
-
-          (setup-hook
-           ()
-           ;; Fiddle with the match list a bit: if our first match
-           ;; is a tabbrowser window, rotate the match list until
-           ;; the active tab comes up
-           (let ((matched-tab (find-tab-by-cname (car ido-matches))))
-             (when (and matched-tab
-                        (null (cl-fourth matched-tab))
-                        (equal "navigator:browser"
-                               (js! ((cl-third matched-tab)
-                                     "document"
-                                     "documentElement"
-                                     "getAttribute")
-                                    "windowtype")))
-
-               (cl-loop with tab-to-match = (js< (cl-third matched-tab)
-                                                 "gBrowser"
-                                                 "selectedTab")
-
-                        for match in ido-matches
-                        for candidate-tab = (find-tab-by-cname match)
-                        if (eq (cl-fourth candidate-tab) tab-to-match)
-                        do (setq ido-cur-list
-                                 (ido-chop ido-cur-list match))
-                        and return t)))
-
-           (add-hook 'post-command-hook #'command-hook t t)))
-
-
-       (unwind-protect
-           ;; FIXME: Don't impose IDO on the user.
-           (setq selected-tab-cname
-                 (let ((ido-minibuffer-setup-hook
-                        (cons #'setup-hook ido-minibuffer-setup-hook)))
-                   (ido-completing-read
-                    prompt
-                    (mapcar #'car tabs)
-                    nil t nil
-                    'js-read-tab-history)))
-
-         (when prev-hitab
-           (mogrify-highlighting nil prev-hitab)
-           (setq prev-hitab nil)))
-
-       (add-to-history 'js-read-tab-history selected-tab-cname)
-
-       (setq selected-tab (cl-loop for tab in tabs
-                                   if (equal (car tab) selected-tab-cname)
-                                   return (cdr tab)))
-
-       (cons (if (cl-fourth selected-tab) 'browser 'window)
-             (cl-third selected-tab))))))
-
-(defun js--guess-eval-defun-info (pstate)
-  "Helper function for `js-eval-defun'.
-Return a list (NAME . CLASSPARTS), where CLASSPARTS is a list of
-strings making up the class name and NAME is the name of the
-function part."
-  (cond ((and (= (length pstate) 3)
-              (eq (js--pitem-type (cl-first pstate)) 'function)
-              (= (length (js--pitem-name (cl-first pstate))) 1)
-              (consp (js--pitem-type (cl-second pstate))))
-
-         (append (js--pitem-name (cl-second pstate))
-                 (list (cl-first (js--pitem-name (cl-first pstate))))))
-
-        ((and (= (length pstate) 2)
-              (eq (js--pitem-type (cl-first pstate)) 'function))
-
-         (append
-          (butlast (js--pitem-name (cl-first pstate)))
-          (list (car (last (js--pitem-name (cl-first pstate)))))))
-
-        (t (error "Function not a toplevel defun or class member"))))
-
-(defvar js--js-context nil
-  "The current JavaScript context.
-This is a cons like the one returned from `js--read-tab'.
-Change with `js-set-js-context'.")
-
-(defconst js--js-inserter
-  "(function(func_info,func) {
-    func_info.unshift('window');
-    var obj = window;
-    for(var i = 1; i < func_info.length - 1; ++i) {
-      var next = obj[func_info[i]];
-      if(typeof next !== 'object' && typeof next !== 'function') {
-        next = obj.prototype && obj.prototype[func_info[i]];
-        if(typeof next !== 'object' && typeof next !== 'function') {
-          alert('Could not find ' + func_info.slice(0, i+1).join('.') +
-                ' or ' + func_info.slice(0, i+1).join('.') + '.prototype');
-          return;
-        }
-
-        func_info.splice(i+1, 0, 'prototype');
-        ++i;
-      }
-    }
-
-    obj[func_info[i]] = func;
-    alert('Successfully updated '+func_info.join('.'));
-  })")
-
-(defun js-set-js-context (context)
-  "Set the JavaScript context to CONTEXT.
-When called interactively, prompt for CONTEXT."
-  (interactive (list (js--read-tab "JavaScript Context: ")))
-  (setq js--js-context context))
-
-(defun js--get-js-context ()
-  "Return a valid JavaScript context.
-If one hasn't been set, or if it's stale, prompt for a new one."
-  (with-js
-   (when (or (null js--js-context)
-             (js--js-handle-expired-p (cdr js--js-context))
-             (pcase (car js--js-context)
-               ('window (js? (js< (cdr js--js-context) "closed")))
-               ('browser (not (js? (js< (cdr js--js-context)
-                                        "contentDocument"))))
-               (x (error "Unmatched case in js--get-js-context: %S" x))))
-     (setq js--js-context (js--read-tab "JavaScript Context: ")))
-   js--js-context))
-
-(defun js--js-content-window (context)
-  (with-js
-   (pcase (car context)
-     ('window (cdr context))
-     ('browser (js< (cdr context)
-                    "contentWindow" "wrappedJSObject"))
-     (x (error "Unmatched case in js--js-content-window: %S" x)))))
-
-(defun js--make-nsilocalfile (path)
-  (with-js
-   (let ((file (js-create-instance "@mozilla.org/file/local;1"
-                                   "nsILocalFile")))
-     (js! (file "initWithPath") path)
-     file)))
-
-(defun js--js-add-resource-alias (alias path)
-  (with-js
-   (let* ((io-service (js-get-service "@mozilla.org/network/io-service;1"
-                                                "nsIIOService"))
-          (res-prot (js! (io-service "getProtocolHandler") "resource"))
-          (res-prot (js-qi res-prot "nsIResProtocolHandler"))
-          (path-file (js--make-nsilocalfile path))
-          (path-uri (js! (io-service "newFileURI") path-file)))
-     (js! (res-prot "setSubstitution") alias path-uri))))
-
-(cl-defun js-eval-defun ()
-  "Update a Mozilla tab using the JavaScript defun at point."
-  (interactive)
-
-  ;; This function works by generating a temporary file that contains
-  ;; the function we'd like to insert. We then use the elisp-js bridge
-  ;; to command mozilla to load this file by inserting a script tag
-  ;; into the document we set. This way, debuggers and such will have
-  ;; a way to find the source of the just-inserted function.
-  ;;
-  ;; We delete the temporary file if there's an error, but otherwise
-  ;; we add an unload event listener on the Mozilla side to delete the
-  ;; file.
-
-  (save-excursion
-    (let (begin end pstate defun-info temp-name defun-body)
-      (js-end-of-defun)
-      (setq end (point))
-      (js--ensure-cache)
-      (js-beginning-of-defun)
-      (re-search-forward "\\_<function\\_>")
-      (setq begin (match-beginning 0))
-      (setq pstate (js--forward-pstate))
-
-      (when (or (null pstate)
-                (> (point) end))
-        (error "Could not locate function definition"))
-
-      (setq defun-info (js--guess-eval-defun-info pstate))
-
-      (let ((overlay (make-overlay begin end)))
-        (overlay-put overlay 'face 'highlight)
-        (unwind-protect
-            (unless (y-or-n-p (format "Send %s to Mozilla? "
-                                      (mapconcat #'identity defun-info ".")))
-              (message "") ; question message lingers until next command
-              (cl-return-from js-eval-defun))
-          (delete-overlay overlay)))
-
-      (setq defun-body (buffer-substring-no-properties begin end))
-
-      (make-directory js-js-tmpdir t)
-
-      ;; (Re)register a Mozilla resource URL to point to the
-      ;; temporary directory
-      (js--js-add-resource-alias "js" js-js-tmpdir)
-
-      (setq temp-name (make-temp-file (concat js-js-tmpdir
-                                             "/js-")
-                                      nil ".js"))
-      (unwind-protect
-          (with-js
-            (with-temp-buffer
-              (insert js--js-inserter)
-              (insert "(")
-              (let ((standard-output (current-buffer)))
-                (json--print-list defun-info))
-              (insert ",\n")
-              (insert defun-body)
-              (insert "\n)")
-              (write-region (point-min) (point-max) temp-name
-                            nil 1))
-
-            ;; Give Mozilla responsibility for deleting this file
-            (let* ((content-window (js--js-content-window
-                                    (js--get-js-context)))
-                   (content-document (js< content-window "document"))
-                   (head (if (js? (js< content-document "body"))
-                             ;; Regular content
-                             (js< (js! (content-document 
"getElementsByTagName")
-                                       "head")
-                                  0)
-                           ;; Chrome
-                           (js< content-document "documentElement")))
-                   (elem (js! (content-document "createElementNS")
-                              "http://www.w3.org/1999/xhtml"; "script")))
-
-              (js! (elem "setAttribute") "type" "text/javascript")
-              (js! (elem "setAttribute") "src"
-                   (format "resource://js/%s"
-                           (file-name-nondirectory temp-name)))
-
-              (js! (head "appendChild") elem)
-
-              (js! (content-window "addEventListener") "unload"
-                   (js! ((js-new
-                          "Function" "file"
-                          "return function() { file.remove(false) }"))
-                        (js--make-nsilocalfile temp-name))
-                   'false)
-              (setq temp-name nil)
-
-
-
-              ))
-
-        ;; temp-name is set to nil on success
-        (when temp-name
-          (delete-file temp-name))))))
-
 ;;; Syntax extensions
 
 (defvar js-syntactic-mode-name t
diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el
index 6bf070cf9e..79530f8167 100644
--- a/lisp/progmodes/octave.el
+++ b/lisp/progmodes/octave.el
@@ -1814,18 +1814,18 @@ If the environment variable OCTAVE_SRCDIR is set, it is 
searched first."
        (user-error "Aborted")))
     (_ name)))
 
-(defvar find-tag-marker-ring)
+(declare-function xref-push-marker-stack "xref" (&optional m))
 
 (defun octave-find-definition (fn)
   "Find the definition of FN.
 Functions implemented in C++ can be found if
 variable `octave-source-directories' is set correctly."
   (interactive (list (octave-completing-read)))
-  (require 'etags)
+  (require 'xref)
   (let ((orig (point)))
     (if (and (derived-mode-p 'octave-mode)
              (octave-goto-function-definition fn))
-        (ring-insert find-tag-marker-ring (copy-marker orig))
+        (xref-push-marker-stack (copy-marker orig))
       (inferior-octave-send-list-and-digest
        ;; help NAME is more verbose
        (list (format "\
@@ -1840,7 +1840,7 @@ if iskeyword('%s') disp('`%s'' is a keyword') else 
which('%s') endif\n"
             (setq file (match-string 1 line))))
         (if (not file)
             (user-error "%s" (or line (format-message "`%s' not found" fn)))
-          (ring-insert find-tag-marker-ring (point-marker))
+          (xref-push-marker-stack)
           (setq file (funcall octave-find-definition-filename-function file))
           (when file
             (find-file file)
diff --git a/lisp/progmodes/opascal.el b/lisp/progmodes/opascal.el
index e55b09d8fc..495c77bbd9 100644
--- a/lisp/progmodes/opascal.el
+++ b/lisp/progmodes/opascal.el
@@ -1540,7 +1540,7 @@ If no extension is specified, .pas is assumed.  Creates a 
buffer for the unit."
 (defun opascal-find-current-def ()
   "Find the definition of the identifier under the current point."
   (interactive)
-  (error "opascal-find-current-def: not implemented yet"))
+  (error "opascal-find-current-def: Not implemented yet"))
 
 (defun opascal-find-current-xdef ()
   "Find the definition of the identifier under the current point, searching
@@ -1548,13 +1548,13 @@ in external units if necessary (as listed in the 
current unit's use clause).
 The set of directories to search for a unit is specified by the global variable
 `opascal-search-path'."
   (interactive)
-  (error "opascal-find-current-xdef: not implemented yet"))
+  (error "opascal-find-current-xdef: Not implemented yet"))
 
 (defun opascal-find-current-body ()
   "Find the body of the identifier under the current point, assuming
 it is a routine."
   (interactive)
-  (error "opascal-find-current-body: not implemented yet"))
+  (error "opascal-find-current-body: Not implemented yet"))
 
 (defun opascal-fill-comment ()
   "Fill the text of the current comment, according to `fill-column'.
diff --git a/lisp/progmodes/pascal.el b/lisp/progmodes/pascal.el
index e6e6e40aa1..5938da542a 100644
--- a/lisp/progmodes/pascal.el
+++ b/lisp/progmodes/pascal.el
@@ -1357,9 +1357,7 @@ The default is a name found in the buffer around point."
                      default ""))
         (label
           ;; Do completion with default.
-          (completing-read (if (not (string= default ""))
-                               (concat "Label (default " default "): ")
-                             "Label: ")
+          (completing-read (format-prompt "Label" default)
                            ;; Complete with the defuns found in the
                            ;; current-buffer.
                            (let ((buf (current-buffer)))
diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el
index 6c09dcf881..30b6edf0d9 100644
--- a/lisp/progmodes/prog-mode.el
+++ b/lisp/progmodes/prog-mode.el
@@ -49,9 +49,15 @@
   (define-key-after menu [prog-separator] menu-bar-separator
     'middle-separator)
 
+  (unless (xref-forward-history-empty-p)
+    (define-key-after menu [xref-forward]
+      '(menu-item "Go Forward" xref-go-forward
+                  :help "Forward to the position gone Back from")
+      'prog-separator))
+
   (unless (xref-marker-stack-empty-p)
     (define-key-after menu [xref-pop]
-      '(menu-item "Back Definition" xref-pop-marker-stack
+      '(menu-item "Go Back" xref-go-back
                   :help "Back to the position of the last search")
       'prog-separator))
 
@@ -68,6 +74,28 @@
         `(menu-item "Find Definition" xref-find-definitions-at-mouse
                     :help ,(format "Find definition of `%s'" identifier))
         'prog-separator)))
+
+  (when (thing-at-mouse click 'symbol)
+    (define-key-after menu [select-region mark-symbol]
+      `(menu-item "Symbol"
+                  ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'symbol))
+                  :help "Mark the symbol at click for a subsequent cut/copy")
+      'mark-whole-buffer))
+  (define-key-after menu [select-region mark-list]
+    `(menu-item "List"
+                ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 'list))
+                :help "Mark the list at click for a subsequent cut/copy")
+    'mark-whole-buffer)
+  (define-key-after menu [select-region mark-defun]
+    `(menu-item "Defun"
+                ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 'defun))
+                :help "Mark the defun at click for a subsequent cut/copy")
+    'mark-whole-buffer)
+
+  ;; Include text-mode select menu only in strings and comments.
+  (when (nth 8 (save-excursion (syntax-ppss (posn-point (event-end click)))))
+    (text-mode-context-menu menu click))
+
   menu)
 
 (defvar prog-mode-map
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 68beedad3d..f4fce44f26 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1,7 +1,7 @@
 ;;; project.el --- Operations on the current project  -*- lexical-binding: t; 
-*-
 
 ;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
-;; Version: 0.7.1
+;; Version: 0.8.1
 ;; Package-Requires: ((emacs "26.1") (xref "1.0.2"))
 
 ;; This is a GNU ELPA :core package.  Avoid using functionality that
@@ -338,16 +338,29 @@ The default implementation uses `find-program'."
                                       " "
                                       (shell-quote-argument ")"))
                             "")))
-         (output (with-output-to-string
-                   (with-current-buffer standard-output
-                     (let ((status
-                            (process-file-shell-command command nil t)))
-                       (unless (zerop status)
-                         (error "File listing failed: %s" 
(buffer-string))))))))
+         res)
+    (with-temp-buffer
+      (let ((status
+             (process-file-shell-command command nil t))
+            (pt (point-min)))
+        (unless (zerop status)
+          (goto-char (point-min))
+          (if (and
+               (not (eql status 127))
+               (search-forward "Permission denied\n" nil t))
+              (let ((end (1- (point))))
+                (re-search-backward "\\`\\|\0")
+                (error "File listing failed: %s"
+                       (buffer-substring (1+ (point)) end)))
+            (error "File listing failed: %s" (buffer-string))))
+        (goto-char pt)
+        (while (search-forward "\0" nil t)
+          (push (buffer-substring-no-properties (1+ pt) (1- (point)))
+                res)
+          (setq pt (point)))))
     (project--remote-file-names
-     (mapcar (lambda (s) (concat dfn (substring s 1)))
-             (sort (split-string output "\0" t)
-                   #'string<)))))
+     (mapcar (lambda (s) (concat dfn s))
+             (sort res #'string<)))))
 
 (defun project--remote-file-names (local-files)
   "Return LOCAL-FILES as if they were on the system of `default-directory'.
@@ -864,28 +877,36 @@ pattern to search for."
                  project-regexp-history-variable)))
 
 ;;;###autoload
-(defun project-find-file ()
+(defun project-find-file (&optional include-all)
   "Visit a file (with completion) in the current project.
 
 The filename at point (determined by `thing-at-point'), if any,
-is available as part of \"future history\"."
-  (interactive)
+is available as part of \"future history\".
+
+If INCLUDE-ALL is non-nil, or with prefix argument when called
+interactively, include all files under the project root, except
+for VCS directories listed in `vc-directory-exclusion-list'."
+  (interactive "P")
   (let* ((pr (project-current t))
          (dirs (list (project-root pr))))
-    (project-find-file-in (thing-at-point 'filename) dirs pr)))
+    (project-find-file-in (thing-at-point 'filename) dirs pr include-all)))
 
 ;;;###autoload
-(defun project-or-external-find-file ()
+(defun project-or-external-find-file (&optional include-all)
   "Visit a file (with completion) in the current project or external roots.
 
 The filename at point (determined by `thing-at-point'), if any,
-is available as part of \"future history\"."
-  (interactive)
+is available as part of \"future history\".
+
+If INCLUDE-ALL is non-nil, or with prefix argument when called
+interactively, include all files under the project root, except
+for VCS directories listed in `vc-directory-exclusion-list'."
+  (interactive "P")
   (let* ((pr (project-current t))
          (dirs (cons
                 (project-root pr)
                 (project-external-roots pr))))
-    (project-find-file-in (thing-at-point 'filename) dirs pr)))
+    (project-find-file-in (thing-at-point 'filename) dirs pr include-all)))
 
 (defcustom project-read-file-name-function #'project--read-file-cpd-relative
   "Function to call to read a file name from a list.
@@ -938,12 +959,25 @@ by the user at will."
                                    predicate
                                    hist mb-default))
 
-(defun project-find-file-in (suggested-filename dirs project)
+(defun project-find-file-in (suggested-filename dirs project &optional 
include-all)
   "Complete a file name in DIRS in PROJECT and visit the result.
 
 SUGGESTED-FILENAME is a relative file name, or part of it, which
-is used as part of \"future history\"."
-  (let* ((all-files (project-files project dirs))
+is used as part of \"future history\".
+
+If INCLUDE-ALL is non-nil, or with prefix argument when called
+interactively, include all files from DIRS, except for VCS
+directories listed in `vc-directory-exclusion-list'."
+  (let* ((vc-dirs-ignores (mapcar
+                           (lambda (dir)
+                             (concat dir "/"))
+                           vc-directory-exclusion-list))
+         (all-files
+          (if include-all
+              (mapcan
+               (lambda (dir) (project--files-in-directory dir vc-dirs-ignores))
+               dirs)
+            (project-files project dirs)))
          (completion-ignore-case read-file-name-completion-ignore-case)
          (file (funcall project-read-file-name-function
                         "Find file" all-files nil nil
diff --git a/lisp/progmodes/prolog.el b/lisp/progmodes/prolog.el
index 33ca01cc75..c36082bb6d 100644
--- a/lisp/progmodes/prolog.el
+++ b/lisp/progmodes/prolog.el
@@ -512,7 +512,7 @@ to automatically indent if-then-else constructs."
   :type 'boolean)
 
 (defcustom prolog-electric-colon-flag nil
-  "Makes `:' electric (inserts `:-' on a new line).
+  "Non-nil means make `:' electric (inserts `:-' on a new line).
 If non-nil, pressing `:' at the end of a line that starts in
 the first column (i.e., clause heads) inserts ` :-' and newline."
   :version "24.1"
@@ -520,7 +520,7 @@ the first column (i.e., clause heads) inserts ` :-' and 
newline."
   :type 'boolean)
 
 (defcustom prolog-electric-dash-flag nil
-  "Makes `-' electric (inserts a `-->' on a new line).
+  "Non-nil means make `-' electric (inserts a `-->' on a new line).
 If non-nil, pressing `-' at the end of a line that starts in
 the first column (i.e., DCG heads) inserts ` -->' and newline."
   :version "24.1"
@@ -2136,7 +2136,8 @@ A return value of N means N more left parentheses than 
right ones."
                              (line-end-position)))))
 
 (defun prolog-electric--if-then-else ()
-  "Insert spaces after the opening parenthesis, \"then\" (->) and \"else\" (;) 
branches.
+  "Insert spaces after the opening parenthesis.
+\"then\" (->) and \"else\" (;) branches.
 Spaces are inserted if all preceding objects on the line are
 whitespace characters, parentheses, or then/else branches."
   (when prolog-electric-if-then-else-flag
@@ -2483,11 +2484,8 @@ Interaction supports completion."
     (if (eq (try-completion default prolog-info-alist) nil)
         (setq default nil))
     ;; Read the PredSpec from the user
-    (completing-read
-     (if (zerop (length default))
-         "Help on predicate: "
-       (concat "Help on predicate (default " default "): "))
-     prolog-info-alist nil t nil nil default)))
+    (completing-read (format-prompt "Help on predicate" default)
+                     prolog-info-alist nil t nil nil default)))
 
 (defun prolog-build-info-alist (&optional verbose)
   "Build an alist of all builtins and library predicates.
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index c58ac6f637..b12f5ddc0d 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -4,8 +4,8 @@
 
 ;; Author: Fabián E. Gallina <fgallina@gnu.org>
 ;; URL: https://github.com/fgallina/python.el
-;; Version: 0.27.1
-;; Package-Requires: ((emacs "24.2") (cl-lib "1.0"))
+;; Version: 0.28
+;; Package-Requires: ((emacs "24.4") (cl-lib "1.0"))
 ;; Maintainer: emacs-devel@gnu.org
 ;; Created: Jul 2010
 ;; Keywords: languages
@@ -555,9 +555,6 @@ class declarations.")
           "assert" "else" "if" "pass" "yield" "break" "except" "import" "class"
           "in" "raise" "continue" "finally" "is" "return" "def" "for" "lambda"
           "try"
-          ;; Python 2:
-          "print" "exec"
-          ;; Python 3:
           ;; False, None, and True are listed as keywords on the Python 3
           ;; documentation, but since they also qualify as constants they are
           ;; fontified like that in order to keep font-lock consistent between
@@ -1521,7 +1518,10 @@ Returns nil if point is not in a def or class."
       (python-util-forward-comment -1)
       (forward-line 1)
       ;; Ensure point moves forward.
-      (and (> beg-pos (point)) (goto-char beg-pos)))))
+      (and (> beg-pos (point)) (goto-char beg-pos))
+      ;; Return non-nil if we did something (because then we were in a
+      ;; def/class).
+      (/= beg-pos (point)))))
 
 (defun python-nav--syntactically (fn poscompfn &optional contextfn)
   "Move point using FN avoiding places with specific context.
@@ -2727,20 +2727,12 @@ goes wrong and syntax highlighting in the shell gets 
messed up."
              (deactivate-mark nil)
              (start-pos prompt-end)
              (buffer-undo-list t)
-             (font-lock-buffer-pos nil)
              (replacement
               (python-shell-font-lock-with-font-lock-buffer
-                (delete-region (line-beginning-position)
-                               (point-max))
-                (setq font-lock-buffer-pos (point))
+                (delete-region (point-min) (point-max))
                 (insert input)
-                ;; Ensure buffer is fontified, keeping it
-                ;; compatible with Emacs < 24.4.
-                (if (fboundp 'font-lock-ensure)
-                    (funcall 'font-lock-ensure)
-                  (font-lock-default-fontify-buffer))
-                (buffer-substring font-lock-buffer-pos
-                                  (point-max))))
+                (font-lock-ensure)
+                (buffer-string)))
              (replacement-length (length replacement))
              (i 0))
         ;; Inject text properties to get input fontified.
@@ -3714,6 +3706,8 @@ def __PYTHON_EL_native_completion_setup():
             readline.parse_and_bind('tab: complete')
             # Require just one tab to send output.
             readline.parse_and_bind('set show-all-if-ambiguous on')
+            # Avoid replacing common prefix with ellipsis.
+            readline.parse_and_bind('set completion-prefix-display-length 0')
 
         print ('python.el: native completion setup loaded')
     except:
@@ -3811,7 +3805,7 @@ With argument MSG show activation/deactivation message."
                   (comint-redirect-perform-sanity-check nil)
                   (comint-redirect-insert-matching-regexp t)
                   (comint-redirect-finished-regexp
-                   "1__dummy_completion__[[:space:]]*\n")
+                   "1__dummy_completion__.*\n")
                   (comint-redirect-output-buffer redirect-buffer))
               ;; Compatibility with Emacs 24.x.  Comint changed and
               ;; now `comint-redirect-filter' gets 3 args.  This
@@ -4671,7 +4665,10 @@ See `python-check-command' for the default."
                 target = obj
                 objtype = 'def'
             if target:
-                args = inspect.formatargspec(*argspec_function(target))
+                if hasattr(inspect, 'signature'):
+                    args = str(inspect.signature(target))
+                else:
+                    args = inspect.formatargspec(*argspec_function(target))
                 name = obj.__name__
                 doc = '{objtype} {name}{args}'.format(
                     objtype=objtype, name=name, args=args
@@ -4770,10 +4767,14 @@ Interactively, prompt for symbol."
   (interactive
    (let ((symbol (python-eldoc--get-symbol-at-point))
          (enable-recursive-minibuffers t))
-     (list (read-string (if symbol
-                            (format "Describe symbol (default %s): " symbol)
-                          "Describe symbol: ")
-                        nil nil symbol))))
+     (list (read-string
+            ;; `format-prompt' is new in Emacs 28.1.
+            (if (fboundp 'format-prompt)
+                (format-prompt "Describe symbol" symbol)
+              (if symbol
+                  (format "Describe symbol (default %s): " symbol)
+                "Describe symbol: "))
+            nil nil symbol))))
   (message (python-eldoc--get-doc-at-point symbol)))
 
 (defun python-describe-at-point (symbol process)
diff --git a/lisp/progmodes/scheme.el b/lisp/progmodes/scheme.el
index 57351a7308..abcdcb3349 100644
--- a/lisp/progmodes/scheme.el
+++ b/lisp/progmodes/scheme.el
@@ -143,7 +143,6 @@
   (setq-local comment-start-skip ";+[ \t]*")
   (setq-local comment-use-syntax t)
   (setq-local comment-column 40)
-  (setq-local parse-sexp-ignore-comments t)
   (setq-local lisp-indent-function 'scheme-indent-function)
   (setq mode-line-process '("" scheme-mode-line-process))
   (setq-local imenu-case-fold-search t)
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index cccd70f06c..c6b6f83471 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -628,7 +628,8 @@ removed when closing the here document."
     (wksh sh-append ksh88)
 
     (zsh sh-append ksh88
-        "autoload" "bindkey" "builtin" "chdir" "compctl" "declare" "dirs"
+        "autoload" "always"
+         "bindkey" "builtin" "chdir" "compctl" "declare" "dirs"
         "disable" "disown" "echotc" "enable" "functions" "getln" "hash"
         "history" "integer" "limit" "local" "log" "popd" "pushd" "r"
         "readonly" "rehash" "sched" "setopt" "source" "suspend" "true"
@@ -1396,8 +1397,15 @@ If FORCE is non-nil and no process found, create one."
             (or found
                 (and force
                      (get-buffer-process
-                      (let ((explicit-shell-file-name sh-shell-file))
-                        (shell)))))))))
+                      (let ((explicit-shell-file-name sh-shell-file)
+                            (display-buffer-overriding-action
+                             '(nil . ((inhibit-same-window . t)))))
+                        ;; We must prevent this `(shell)' call from
+                        ;; switching buffers, so that the variable
+                        ;; `sh-shell-process' is set locally in the
+                        ;; correct buffer.
+                        (save-current-buffer
+                          (shell))))))))))
 
 (defun sh-show-shell ()
   "Pop the shell interaction buffer."
@@ -2515,7 +2523,7 @@ overwritten if
                      sh-styles-alist nil t)))
   (let ((sl (assoc name  sh-styles-alist)))
     (if (null sl)
-       (error "sh-load-style - style %s not known" name)
+        (error "sh-load-style: Style %s not known" name)
       (dolist (var (cdr sl))
        (set (car var) (cdr var))))))
 
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index 02eccb3301..f5888a0ce7 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -481,9 +481,9 @@ file.  Since that is a plaintext file, this could be 
dangerous."
      :list-all ("\\d+" . "\\dS+")
      :list-table ("\\d+ %s" . "\\dS+ %s")
      :completion-object sql-postgres-completion-object
-     :prompt-regexp "^[[:alnum:]_]*=[#>] "
+     :prompt-regexp "^[-[:alnum:]_]*[-=][#>] "
      :prompt-length 5
-     :prompt-cont-regexp "^[[:alnum:]_]*[-(][#>] "
+     :prompt-cont-regexp "^[-[:alnum:]_]*[-'(][#>] "
      :statement sql-postgres-statement-starters
      :input-filter sql-remove-tabs-filter
      :terminator ("\\(^\\s-*\\\\g\\|;\\)" . "\\g"))
@@ -700,8 +700,17 @@ making new SQLi sessions."
                                (sexp   :tag "Value Expression")))))
   :version "24.1")
 
-(defvaralias 'sql-dialect 'sql-product)
+(defun sql-add-connection (connection params)
+  "Add a new connection to `sql-connection-alist'.
 
+If CONNECTION already exists, it is replaced with PARAMS."
+  (setq sql-connection-alist
+        (assoc-delete-all connection sql-connection-alist))
+  (push
+   (cons connection params)
+   sql-connection-alist))
+
+(defvaralias 'sql-dialect 'sql-product)
 (defcustom sql-product 'ansi
   "Select the SQL database product used.
 This allows highlighting buffers properly when you open them."
@@ -963,12 +972,7 @@ If set to \"\\n\", each line in the history file will be 
interpreted as
 one command.  Multi-line commands are split into several commands when
 the input ring is initialized from a history file.
 
-This variable used to initialize `comint-input-ring-separator'.
-`comint-input-ring-separator' is part of Emacs 21; if your Emacs
-does not have it, setting `sql-input-ring-separator' will have no
-effect.  In that case multiline commands will be split into several
-commands when the input history is read, as if you had set
-`sql-input-ring-separator' to \"\\n\"."
+This variable used to initialize `comint-input-ring-separator'."
   :type 'string)
 
 ;; The usual hooks
@@ -1357,8 +1361,6 @@ specified, it's `sql-product' or `sql-connection' must 
match."
 (defvar sql-interactive-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map comint-mode-map)
-    (if (fboundp 'set-keymap-name)
-       (set-keymap-name map 'sql-interactive-mode-map)); XEmacs
     (define-key map (kbd "C-j") 'sql-accumulate-and-indent)
     (define-key map (kbd "C-c C-w") 'sql-copy-column)
     (define-key map (kbd "O") 'sql-magic-go)
@@ -2832,16 +2834,6 @@ configured."
       (font-lock-mode-internal nil)
       (font-lock-mode-internal t))
 
-    (add-hook 'font-lock-mode-hook
-              (lambda ()
-                  ;; Provide defaults for new font-lock faces.
-                  (defvar font-lock-builtin-face
-                    (if (boundp 'font-lock-preprocessor-face)
-                        font-lock-preprocessor-face
-                      font-lock-keyword-face))
-                  (defvar font-lock-doc-face font-lock-string-face))
-             nil t)
-
     ;; Setup imenu; it needs the same syntax-alist.
     (when imenu
       (setq imenu-syntax-alist syntax-alist))))
@@ -3219,14 +3211,7 @@ For both `:file' and `:completion', there can also be a
    symbol
    (let* ((default (plist-get plist :default))
           (last-value (sql-default-value symbol))
-          (prompt-def
-           (if default
-               (if (string-match "\\(\\):[ \t]*\\'" prompt)
-                   (replace-match (format " (default \"%s\")" default) t t 
prompt 1)
-                 (replace-regexp-in-string "[ \t]*\\'"
-                                           (format " (default \"%s\") " 
default)
-                                           prompt t t))
-             prompt))
+          (prompt-def (format-prompt prompt default))
           (use-dialog-box nil))
      (cond
       ((plist-member plist :file)
@@ -3311,7 +3296,7 @@ function like this: (sql-get-login \\='user \\='password 
\\='database)."
     (let ((plist (cdr-safe w)))
       (pcase (or (car-safe w) w)
         ('user
-         (sql-get-login-ext 'sql-user "User: " 'sql-user-history plist))
+         (sql-get-login-ext 'sql-user "User" 'sql-user-history plist))
 
         ('password
          (setq-default sql-password
@@ -3330,14 +3315,14 @@ function like this: (sql-get-login \\='user 
\\='password \\='database)."
                          (read-passwd "Password: " nil (sql-default-value 
'sql-password)))))
 
         ('server
-         (sql-get-login-ext 'sql-server "Server: " 'sql-server-history plist))
+         (sql-get-login-ext 'sql-server "Server" 'sql-server-history plist))
 
         ('database
-         (sql-get-login-ext 'sql-database "Database: "
+         (sql-get-login-ext 'sql-database "Database"
                             'sql-database-history plist))
 
         ('port
-         (sql-get-login-ext 'sql-port "Port: "
+         (sql-get-login-ext 'sql-port "Port"
                             nil (append '(:number t) plist)))))))
 
 (defun sql-find-sqli-buffer (&optional product connection)
@@ -3976,13 +3961,13 @@ for each match."
                        (cond
                         ((numberp c) (match-string c))
                         ((stringp c) (match-substitute-replacement c))
-                        (t (error "sql-redirect-value: unknown REGEXP-GROUPS 
value - %s" c))))
+                        (t (error "sql-redirect-value: Unknown REGEXP-GROUPS 
value - %s" c))))
                    regexp-groups))
           ;; String is specified; return replacement string
           ((stringp regexp-groups)
            (match-substitute-replacement regexp-groups))
           (t
-           (error "sql-redirect-value: unknown REGEXP-GROUPS value - %s"
+           (error "sql-redirect-value: Unknown REGEXP-GROUPS value - %s"
                   regexp-groups)))
          results)))
 
@@ -4182,10 +4167,6 @@ must tell Emacs.  Here's how to do that in your init 
file:
            (modify-syntax-entry ?\\\\ \"\\\\\" sql-mode-syntax-table)))"
   :abbrev-table sql-mode-abbrev-table
 
-  (when (and (featurep 'xemacs)
-             sql-mode-menu)
-      (easy-menu-add sql-mode-menu))
-
   ;; (smie-setup sql-smie-grammar #'sql-smie-rules)
   (setq-local comment-start "--")
   ;; Make each buffer in sql-mode remember the "current" SQLi buffer.
@@ -4308,9 +4289,6 @@ you entered, right above the output it created.
   (setq mode-name
         (concat "SQLi[" (or (sql-get-product-feature sql-product :name)
                             (symbol-name sql-product)) "]"))
-  (when (and (featurep 'xemacs)
-             sql-interactive-mode-menu)
-    (easy-menu-add sql-interactive-mode-menu))
 
   ;; Note that making KEYWORDS-ONLY nil will cause havoc if you try
   ;; SELECT 'x' FROM DUAL with SQL*Plus, because the title of the column
@@ -4681,6 +4659,14 @@ the call to \\[sql-product-interactive] with
               (get-buffer new-sqli-buffer)))))
     (user-error "No default SQL product defined: set `sql-product'")))
 
+(defun sql-comint-automatic-password (_)
+  "Intercept password prompts when we know the password.
+This must also do the job of detecting password prompts."
+  (when (and
+         sql-password
+         (not (string= "" sql-password)))
+    sql-password))
+
 (defun sql-comint (product params &optional buf-name)
   "Set up a comint buffer to run the SQL processor.
 
@@ -4705,6 +4691,13 @@ buffer.  If nil, a name is chosen for it."
       (setq buf-name (sql-generate-unique-sqli-buffer-name product nil)))
     (set-text-properties 0 (length buf-name) nil buf-name)
 
+    ;; Create the buffer first, because we want to set it up before
+    ;; comint starts to run.
+    (set-buffer (get-buffer-create buf-name))
+    ;; Set up the automatic population of passwords, if supported.
+    (when (sql-get-product-feature product :password-in-comint)
+      (setq comint-password-function #'sql-comint-automatic-password))
+
     ;; Start the command interpreter in the buffer
     ;;   PROC-NAME is BUF-NAME without enclosing asterisks
     (let ((proc-name (replace-regexp-in-string "\\`[*]\\(.*\\)[*]\\'" "\\1" 
buf-name)))
diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el
index ac6a8fbbcb..14f252b42d 100644
--- a/lisp/progmodes/verilog-mode.el
+++ b/lisp/progmodes/verilog-mode.el
@@ -9,7 +9,7 @@
 ;; Keywords: languages
 ;; The "Version" is the date followed by the decimal rendition of the Git
 ;;     commit hex.
-;; Version: 2021.09.23.089128420
+;; Version: 2021.10.14.127365406
 
 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this
 ;; file on 19/3/2008, and the maintainer agreed that when a bug is
@@ -87,7 +87,7 @@
 ;;
 ;; If you want to customize Verilog mode to fit your needs better,
 ;; you may add the below lines (the values of the variables presented
-;; here are the defaults). Note also that if you use an Emacs that
+;; here are the defaults).  Note also that if you use an Emacs that
 ;; supports custom, it's probably better to use the custom menu to
 ;; edit these.  If working as a member of a large team these settings
 ;; should be common across all users (in a site-start file), or set
@@ -124,7 +124,7 @@
 ;;
 
 ;; This variable will always hold the version number of the mode
-(defconst verilog-mode-version "2021-09-23-54ffde4-vpo-GNU"
+(defconst verilog-mode-version "2021-10-14-797711e-vpo-GNU"
   "Version of this Verilog mode.")
 (defconst verilog-mode-release-emacs t
   "If non-nil, this version of Verilog mode was released with Emacs itself.")
@@ -1264,7 +1264,9 @@ See `verilog-auto-inst-param-value'."
 Also affects AUTOINSTPARAM.  Declaration order is the default for
 backward compatibility, and as some teams prefer signals that are
 declared together to remain together.  Sorted order reduces
-changes when declarations are moved around in a file.
+changes when declarations are moved around in a file. Sorting is
+within input/output/inout groupings, there is intentionally no
+option to intermix between input/output/inouts.
 
 See also `verilog-auto-arg-sort'."
   :version "24.1"  ; rev688
@@ -4038,9 +4040,12 @@ Some other functions are:
     \\[verilog-sk-repeat]  Insert a repeat (..) begin .. end block.
     \\[verilog-sk-specify]  Insert a specify .. endspecify block.
     \\[verilog-sk-task]  Insert a task .. begin .. end endtask block.
-    \\[verilog-sk-while]  Insert a while (...) begin .. end block, prompting 
for details.
-    \\[verilog-sk-casex]  Insert a casex (...) item: begin.. end endcase 
block, prompting for details.
-    \\[verilog-sk-casez]  Insert a casez (...) item: begin.. end endcase 
block, prompting for details.
+    \\[verilog-sk-while]  Insert a while (...) begin .. end block,
+                       prompting for details.
+    \\[verilog-sk-casex]  Insert a casex (...) item: begin.. end endcase block,
+                       prompting for details.
+    \\[verilog-sk-casez]  Insert a casez (...) item: begin.. end endcase block,
+                       prompting for details.
     \\[verilog-sk-if]  Insert an if (..) begin .. end block.
     \\[verilog-sk-else-if]  Insert an else if (..) begin .. end block.
     \\[verilog-sk-comment]  Insert a comment block.
@@ -4824,7 +4829,7 @@ Limit search to point LIM."
              ((match-end 1)  ; [
              (setq colon (1+ colon))
              (if (>= colon 0)
-                 (error "%s: unbalanced [" (verilog-point-text))))
+                  (error "%s: Unbalanced [" (verilog-point-text))))
              ((match-end 2)  ; ]
              (setq colon (1- colon)))
 
@@ -5475,8 +5480,11 @@ becomes:
                     (let* ((pop-up-windows t))
                       (let ((name (expand-file-name
                                    (read-file-name
-                                    (format "Find this error in: (default %s) "
-                                            file)
+                                    ;; `format-prompt' is new in Emacs 28.1.
+                                    (if (fboundp 'format-prompt)
+                                        (format-prompt "Find this error in" 
file)
+                                      (format "Find this error in (default 
%s): "
+                                              file))
                                     nil ;; dir
                                     file t))))
                         (setq buffer
@@ -6580,7 +6588,8 @@ Return >0 for nested struct."
          nil))))
 
 (defun verilog-at-constraint-p ()
-  "If at the { of a constraint or coverpoint definition, return true, moving 
point to constraint."
+  "If at the { of a constraint or coverpoint definition, return true.
+Also move point to constraint."
   (if (save-excursion
        (let ((p (point)))
           (and
@@ -6594,7 +6603,8 @@ Return >0 for nested struct."
                        (equal (char-before) ?\;)
                        (equal (char-before) ?\}))
                    ;; skip what looks like bus repetition operator {#{
-                   (not (string-match "^{\\s-*[\\(\\)0-9a-zA-Z_]*\\s-*{" 
(buffer-substring p (point)))))))))
+                   (not (string-match "^{\\s-*[()0-9a-zA-Z_\\]*\\s-*{"
+                                      (buffer-substring p (point)))))))))
       (progn
         (let ( (pt (point)) (pass 0))
           (verilog-backward-ws&directives)
@@ -7859,14 +7869,14 @@ If search fails, other files are checked based on
   (let* ((default (verilog-get-default-symbol))
         ;; The following variable is used in verilog-comp-function
         (verilog-buffer-to-use (current-buffer))
-        (label (if (not (string= default ""))
-                   ;; Do completion with default
-                   (completing-read (concat "Goto-Label: (default "
-                                            default ") ")
-                                    #'verilog-comp-defun nil nil "")
-                 ;; There is no default value. Complete without it
-                 (completing-read "Goto-Label: "
-                                  #'verilog-comp-defun nil nil "")))
+         (label
+          (completing-read (cond ((fboundp 'format-prompt)
+                                  ;; `format-prompt' is new in Emacs 28.1.
+                                  (format-prompt "Goto-Label" default))
+                                 ((not (string= default ""))
+                                  (concat "Goto-Label (default " default "): 
"))
+                                 (t "Goto-Label: "))
+                           #'verilog-comp-defun nil nil ""))
         pt)
     ;; Make sure library paths are correct, in case need to resolve module
     (verilog-auto-reeval-locals)
@@ -14985,7 +14995,9 @@ but instead, [[Fill in here]] happens!.
 
 (provide 'verilog-mode)
 
+;;TODO: Could `byte-compile-docstring-max-column' be decreased?
 ;; Local Variables:
+;; byte-compile-docstring-max-column: 90
 ;; checkdoc-permit-comma-termination-flag:t
 ;; checkdoc-force-docstrings-flag:nil
 ;; indent-tabs-mode:nil
diff --git a/lisp/progmodes/vhdl-mode.el b/lisp/progmodes/vhdl-mode.el
index fc0d406f73..3a9185b334 100644
--- a/lisp/progmodes/vhdl-mode.el
+++ b/lisp/progmodes/vhdl-mode.el
@@ -5917,16 +5917,16 @@ Skip backwards if DIRECTION is negative, skip forward 
otherwise."
 ;; Functions to help finding the correct indentation column:
 
 (defun vhdl-first-word (point)
-  "If the keyword at POINT is at boi, then return (current-column) at
-that point, else nil."
+  "If the keyword at POINT is at boi, return (current-column) at that point.
+Otherwise return nil."
   (save-excursion
     (and (goto-char point)
         (eq (point) (vhdl-point 'boi))
         (current-column))))
 
 (defun vhdl-last-word (point)
-  "If the keyword at POINT is at eoi, then return (current-column) at
-that point, else nil."
+  "If keyword at POINT is at eoi, then return (current-column) at that point.
+Otherwise, return nil."
   (save-excursion
     (and (goto-char point)
         (save-excursion (or (eq (progn (forward-sexp) (point))
@@ -6266,13 +6266,11 @@ of an identifier that just happens to contain an 
\"end\" keyword."
 
 (defconst vhdl-statement-fwd-re
   "\\b\\(if\\|for\\|while\\|loop\\)\\b\\([^_]\\|\\'\\)"
-  "A regular expression for searching forward that matches all known
-\"statement\" keywords.")
+  "Regexp for searching forward that matches all known \"statement\" 
keywords.")
 
 (defconst vhdl-statement-bwd-re
   "\\b\\(if\\|for\\|while\\|loop\\)\\b[^_]"
-  "A regular expression for searching backward that matches all known
-\"statement\" keywords.")
+  "Regexp for searching backward that matches all known \"statement\" 
keywords.")
 
 (defun vhdl-statement-p (&optional _lim)
   "Return t if we are looking at a real \"statement\" keyword.
@@ -6723,8 +6721,9 @@ search, and an argument indicating an interactive call."
          vhdl-begin-bwd-re "\\|" vhdl-statement-bwd-re))
 
 (defun vhdl-beginning-of-statement-1 (&optional lim)
-  "Move to the start of the current statement, or the previous
-statement if already at the beginning of one."
+  "Move to the start of the current statement.
+If already at the beginning of a statement, move to the start of
+the previous statement instead."
   (let ((lim (or lim (point-min)))
        (here (point))
        (pos (point))
diff --git a/lisp/progmodes/which-func.el b/lisp/progmodes/which-func.el
index 8946e2c3f4..176f599649 100644
--- a/lisp/progmodes/which-func.el
+++ b/lisp/progmodes/which-func.el
@@ -185,7 +185,8 @@ and you want to simplify them for the mode line
 
 (defvar-local which-func-mode nil
   "Non-nil means display current function name in mode line.
-This makes a difference only if `which-function-mode' is non-nil.")
+This makes a difference only if variable `which-function-mode' is
+non-nil.")
 
 (add-hook 'after-change-major-mode-hook #'which-func-ff-hook t)
 
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index fb8090cfb7..26188bbdda 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -1,7 +1,7 @@
 ;;; xref.el --- Cross-referencing commands              -*-lexical-binding:t-*-
 
 ;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
-;; Version: 1.2.2
+;; Version: 1.3.2
 ;; Package-Requires: ((emacs "26.1"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -46,9 +46,9 @@
 ;;
 ;; One would usually call `make-xref' and `xref-make-file-location',
 ;; `xref-make-buffer-location' or `xref-make-bogus-location' to create
-;; them.  More generally, a location must be an instance of an EIEIO
-;; class inheriting from `xref-location' and implementing
-;; `xref-location-group' and `xref-location-marker'.
+;; them.  More generally, a location must be an instance of a type for
+;; which methods `xref-location-group' and `xref-location-marker' are
+;; implemented.
 ;;
 ;; There's a special kind of xrefs we call "match xrefs", which
 ;; correspond to search results.  For these values,
@@ -62,15 +62,32 @@
 ;; distinct, because the user can't see the properties when making the
 ;; choice.
 ;;
+;; Older versions of Xref used EIEIO for implementation of the
+;; built-in types, and included a class called `xref-location' which
+;; was supposed to be inherited from.  Neither is true anymore.
+;;
 ;; See the etags and elisp-mode implementations for full examples.
 
 ;;; Code:
 
 (require 'cl-lib)
-(require 'eieio)
 (require 'ring)
 (require 'project)
 
+(eval-and-compile
+  (when (version< emacs-version "28.0.60")
+    ;; etags.el in Emacs 26 and 27 uses EIEIO, and its location type
+    ;; inherits from `xref-location'.
+    (require 'eieio)
+
+    ;; Suppressing byte-compilation warnings (in Emacs 28+) about
+    ;; `defclass' not being defined, which happens because the
+    ;; `require' statement above is not evaluated either.
+    ;; FIXME: Use `with-suppressed-warnings' when we stop supporting Emacs 26.
+    (with-no-warnings
+      (defclass xref-location () ()
+        :documentation "(Obsolete) location represents a position in a file or 
buffer."))))
+
 (defgroup xref nil "Cross-referencing commands."
   :version "25.1"
   :group 'tools)
@@ -78,9 +95,6 @@
 
 ;;; Locations
 
-(defclass xref-location () ()
-  :documentation "A location represents a position in a file or buffer.")
-
 (cl-defgeneric xref-location-marker (location)
   "Return the marker for LOCATION.")
 
@@ -99,7 +113,7 @@ When it is a file name, it should be the \"expanded\" 
version.")
   "Return the length of the match."
   nil)
 
-;;;; Commonly needed location classes are defined here:
+;;;; Commonly needed location types are defined here:
 
 (defcustom xref-file-name-display 'project-relative
   "Style of file name display in *xref* buffers.
@@ -121,19 +135,20 @@ in its full absolute form."
 
 ;; FIXME: might be useful to have an optional "hint" i.e. a string to
 ;; search for in case the line number is slightly out of date.
-(defclass xref-file-location (xref-location)
-  ((file :type string :initarg :file :reader xref-location-group)
-   (line :type fixnum :initarg :line :reader xref-location-line)
-   (column :type fixnum :initarg :column :reader xref-file-location-column))
-  :documentation "A file location is a file/line/column triple.
-Line numbers start from 1 and columns from 0.")
+(cl-defstruct (xref-file-location
+               (:constructor xref-make-file-location (file line column)))
+  "A file location is a file/line/column triple.
+Line numbers start from 1 and columns from 0."
+  file line column)
+
+(cl-defmethod xref-location-group ((l xref-file-location))
+  (xref-file-location-file l))
 
-(defun xref-make-file-location (file line column)
-  "Create and return a new `xref-file-location'."
-  (make-instance 'xref-file-location :file file :line line :column column))
+(cl-defmethod xref-location-line ((l xref-file-location))
+  (xref-file-location-line l))
 
 (cl-defmethod xref-location-marker ((l xref-file-location))
-  (with-slots (file line column) l
+  (pcase-let (((cl-struct xref-file-location file line column) l))
     (with-current-buffer
         (or (get-file-buffer file)
             (let ((find-file-suppress-same-file-warnings t))
@@ -151,77 +166,58 @@ Line numbers start from 1 and columns from 0.")
             (forward-char column))
           (point-marker))))))
 
-(defclass xref-buffer-location (xref-location)
-  ((buffer :type buffer :initarg :buffer)
-   (position :type fixnum :initarg :position)))
-
-(defun xref-make-buffer-location (buffer position)
-  "Create and return a new `xref-buffer-location'."
-  (make-instance 'xref-buffer-location :buffer buffer :position position))
+(cl-defstruct (xref-buffer-location
+               (:constructor xref-make-buffer-location (buffer position)))
+  buffer position)
 
 (cl-defmethod xref-location-marker ((l xref-buffer-location))
-  (with-slots (buffer position) l
+  (pcase-let (((cl-struct xref-buffer-location buffer position) l))
     (let ((m (make-marker)))
       (move-marker m position buffer))))
 
 (cl-defmethod xref-location-group ((l xref-buffer-location))
-  (with-slots (buffer) l
+  (pcase-let (((cl-struct xref-buffer-location buffer) l))
     (or (buffer-file-name buffer)
         (format "(buffer %s)" (buffer-name buffer)))))
 
-(defclass xref-bogus-location (xref-location)
-  ((message :type string :initarg :message
-            :reader xref-bogus-location-message))
-  :documentation "Bogus locations are sometimes useful to
-indicate errors, e.g. when we know that a function exists but the
-actual location is not known.")
-
-(defun xref-make-bogus-location (message)
-  "Create and return a new `xref-bogus-location'."
-  (make-instance 'xref-bogus-location :message message))
+(cl-defstruct (xref-bogus-location
+               (:constructor xref-make-bogus-location (message)))
+  "Bogus locations are sometimes useful to indicate errors,
+e.g. when we know that a function exists but the actual location
+is not known."
+  message)
 
 (cl-defmethod xref-location-marker ((l xref-bogus-location))
-  (user-error "%s" (oref l message)))
+  (user-error "%s" (xref-bogus-location-message l)))
 
 (cl-defmethod xref-location-group ((_ xref-bogus-location)) "(No location)")
 
 
 ;;; Cross-reference
 
-(defclass xref-item ()
-  ((summary :type string :initarg :summary
-            :reader xref-item-summary
-            :documentation "One line which will be displayed for
-this item in the output buffer.")
-   (location :initarg :location
-             :reader xref-item-location
-             :documentation "An object describing how to navigate
-to the reference's target."))
-  :comment "An xref item describes a reference to a location
-somewhere.")
-
-(defun xref-make (summary location)
-  "Create and return a new `xref-item'.
-SUMMARY is a short string to describe the xref.
-LOCATION is an `xref-location'."
-  (make-instance 'xref-item :summary summary :location location))
-
-(defclass xref-match-item ()
-  ((summary :type string :initarg :summary
-            :reader xref-item-summary)
-   (location :initarg :location
-             :type xref-location
-             :reader xref-item-location)
-   (length :initarg :length :reader xref-match-length))
-  :comment "A match xref item describes a search result.")
-
-(defun xref-make-match (summary location length)
-  "Create and return a new `xref-match-item'.
-SUMMARY is a short string to describe the xref.
-LOCATION is an `xref-location'.
-LENGTH is the match length, in characters."
-  (make-instance 'xref-match-item :summary summary
-                 :location location :length length))
+(defmacro xref--defstruct (name &rest fields)
+  (declare (indent 1))
+  `(cl-defstruct ,(if (>= emacs-major-version 27)
+                      name
+                    (remq (assq :noinline name) name))
+     ,@fields))
+
+(xref--defstruct (xref-item
+                  (:constructor xref-make (summary location))
+                  (:noinline t))
+  "An xref item describes a reference to a location somewhere."
+  summary location)
+
+(xref--defstruct (xref-match-item
+                  (:include xref-item)
+                  (:constructor xref-make-match (summary location length))
+                  (:noinline t))
+  "A match xref item describes a search result."
+  length)
+
+(cl-defgeneric xref-match-length ((item xref-match-item))
+  "Return the length of the match."
+  (xref-match-item-length item))
 
 
 ;;; API
@@ -345,15 +341,9 @@ backward."
           (t (goto-char start) nil))))
 
 
-;;; Marker stack  (M-. pushes, M-, pops)
-
-(defcustom xref-marker-ring-length 16
-  "Length of the xref marker ring.
-If this variable is not set through Customize, you must call
-`xref-set-marker-ring-length' for changes to take effect."
-  :type 'integer
-  :initialize #'custom-initialize-default
-  :set #'xref-set-marker-ring-length)
+;; Dummy variable retained for compatibility.
+(defvar xref-marker-ring-length 16)
+(make-obsolete-variable 'xref-marker-ring-length nil "29.1")
 
 (defcustom xref-prompt-for-identifier '(not xref-find-definitions
                                             xref-find-definitions-other-window
@@ -424,29 +414,49 @@ or earlier: it can break 
`dired-do-find-regexp-and-replace'."
   :version "28.1"
   :package-version '(xref . "1.2.0"))
 
-(defvar xref--marker-ring (make-ring xref-marker-ring-length)
-  "Ring of markers to implement the marker stack.")
+(defvar xref--history (cons nil nil)
+  "(BACKWARD-STACK . FORWARD-STACK) of markers to visited Xref locations.")
 
-(defun xref-set-marker-ring-length (var val)
-  "Set `xref-marker-ring-length'.
-VAR is the symbol `xref-marker-ring-length' and VAL is the new
-value."
-  (set-default var val)
-  (if (ring-p xref--marker-ring)
-      (ring-resize xref--marker-ring val)))
+(make-obsolete-variable 'xref-marker-ring nil "29.1")
+
+(defun xref-set-marker-ring-length (_var _val)
+  (declare (obsolete nil "29.1"))
+  nil)
 
 (defun xref-push-marker-stack (&optional m)
-  "Add point M (defaults to `point-marker') to the marker stack."
-  (ring-insert xref--marker-ring (or m (point-marker))))
+  "Add point M (defaults to `point-marker') to the marker stack.
+The future stack is erased."
+  (push (or m (point-marker)) (car xref--history))
+  (dolist (mk (cdr xref--history))
+    (set-marker mk nil nil))
+  (setcdr xref--history nil))
+
+;;;###autoload
+(define-obsolete-function-alias 'xref-pop-marker-stack #'xref-go-back "29.1")
 
 ;;;###autoload
-(defun xref-pop-marker-stack ()
-  "Pop back to where \\[xref-find-definitions] was last invoked."
+(defun xref-go-back ()
+  "Go back to the previous position in xref history.
+To undo, use \\[xref-go-forward]."
   (interactive)
-  (let ((ring xref--marker-ring))
-    (when (ring-empty-p ring)
-      (user-error "Marker stack is empty"))
-    (let ((marker (ring-remove ring 0)))
+  (if (null (car xref--history))
+      (user-error "At start of xref history")
+    (let ((marker (pop (car xref--history))))
+      (push (point-marker) (cdr xref--history))
+      (switch-to-buffer (or (marker-buffer marker)
+                            (user-error "The marked buffer has been deleted")))
+      (goto-char (marker-position marker))
+      (set-marker marker nil nil)
+      (run-hooks 'xref-after-return-hook))))
+
+;;;###autoload
+(defun xref-go-forward ()
+  "Got to the point where a previous \\[xref-go-back] was invoked."
+  (interactive)
+  (if (null (cdr xref--history))
+      (user-error "At end of xref history")
+    (let ((marker (pop (cdr xref--history))))
+      (push (point-marker) (car xref--history))
       (switch-to-buffer (or (marker-buffer marker)
                             (user-error "The marked buffer has been deleted")))
       (goto-char (marker-position marker))
@@ -469,17 +479,23 @@ value."
 
 ;; etags.el needs this
 (defun xref-clear-marker-stack ()
-  "Discard all markers from the marker stack."
-  (let ((ring xref--marker-ring))
-    (while (not (ring-empty-p ring))
-      (let ((marker (ring-remove ring)))
-        (set-marker marker nil nil)))))
+  "Discard all markers from the xref history."
+  (dolist (l (list (car xref--history) (cdr xref--history)))
+    (dolist (m l)
+      (set-marker m nil nil)))
+  (setq xref--history (cons nil nil))
+  nil)
 
 ;;;###autoload
 (defun xref-marker-stack-empty-p ()
-  "Return t if the marker stack is empty; nil otherwise."
-  (ring-empty-p xref--marker-ring))
+  "Whether the xref back-history is empty."
+  (null (car xref--history)))
+;; FIXME: rename this to `xref-back-history-empty-p'.
 
+;;;###autoload
+(defun xref-forward-history-empty-p ()
+  "Whether the xref forward-history is empty."
+  (null (cdr xref--history)))
 
 
 (defun xref--goto-char (pos)
@@ -694,7 +710,7 @@ quit the *xref* buffer."
   "Quit *xref* buffer, then pop the xref marker stack."
   (interactive)
   (quit-window)
-  (xref-pop-marker-stack))
+  (xref-go-back))
 
 (defun xref-query-replace-in-results (from to)
   "Perform interactive replacement of FROM with TO in all displayed xrefs.
@@ -967,13 +983,11 @@ GROUP is a string for decoration purposes and XREF is an
 `xref-item' object."
   (require 'compile) ; For the compilation faces.
   (cl-loop for (group . xrefs) in xref-alist
-           for max-line-width =
-           (cl-loop for xref in xrefs
-                    maximize (let ((line (xref-location-line
-                                          (oref xref location))))
-                               (and line (1+ (floor (log line 10))))))
-           for line-format = (and max-line-width
-                                  (format "%%%dd: " max-line-width))
+           for max-line = (cl-loop for xref in xrefs
+                                   maximize (xref-location-line
+                                             (xref-item-location xref)))
+           for line-format = (and max-line
+                                  (format "%%%dd: " (1+ (floor (log max-line 
10)))))
            with item-text-props = (list 'mouse-face 'highlight
                                         'keymap xref--button-map
                                         'help-echo
@@ -984,27 +998,27 @@ GROUP is a string for decoration purposes and XREF is an
            do
            (xref--insert-propertized '(face xref-file-header xref-group t)
                                      group "\n")
-           (cl-loop for xref in xrefs do
-                    (with-slots (summary location) xref
-                      (let* ((line (xref-location-line location))
-                             (prefix
-                              (cond
-                               ((not line) "  ")
-                               ((and (equal line prev-line)
-                                     (equal prev-group group))
-                                "")
-                               (t (propertize (format line-format line)
-                                              'face 'xref-line-number)))))
-                        ;; Render multiple matches on the same line, together.
-                        (when (and (equal prev-group group)
-                                   (or (null line)
-                                       (not (equal prev-line line))))
-                          (insert "\n"))
-                        (xref--insert-propertized (nconc (list 'xref-item xref)
-                                                         item-text-props)
-                                                  prefix summary)
-                        (setq prev-line line
-                              prev-group group))))
+           (dolist (xref xrefs)
+             (pcase-let (((cl-struct xref-item summary location) xref))
+               (let* ((line (xref-location-line location))
+                      (prefix
+                       (cond
+                        ((not line) "  ")
+                        ((and (equal line prev-line)
+                              (equal prev-group group))
+                         "")
+                        (t (propertize (format line-format line)
+                                       'face 'xref-line-number)))))
+                 ;; Render multiple matches on the same line, together.
+                 (when (and (equal prev-group group)
+                            (or (null line)
+                                (not (equal prev-line line))))
+                   (insert "\n"))
+                 (xref--insert-propertized (nconc (list 'xref-item xref)
+                                                  item-text-props)
+                                           prefix summary)
+                 (setq prev-line line
+                       prev-group group))))
            (insert "\n"))
   (add-to-invisibility-spec '(ellipsis . t))
   (save-excursion
@@ -1018,13 +1032,13 @@ GROUP is a string for decoration purposes and XREF is an
 
 The style is determined by the value of `xref-file-name-display'.
 If GROUP looks like a file name, its value is formatted according
-to that style.  Otherwise it it returned unchanged."
+to that style.  Otherwise it is returned unchanged."
   ;; XXX: The way we verify that it's indeed a file name and not some
   ;; other kind of string, e.g. Java package name or TITLE from
   ;; `tags-apropos-additional-actions', is pretty lax.  But we don't
   ;; want to use `file-exists-p' for performance reasons.  If this
   ;; ever turns out to be a problem, some other alternatives are to
-  ;; either have every location class which uses file names format the
+  ;; either have every location type which uses file names format the
   ;; values themselves (e.g. by piping through some public function),
   ;; or adding a new accessor to locations, like GROUP-TYPE.
   (cl-ecase xref-file-name-display
@@ -1050,7 +1064,7 @@ Return an alist of the form ((GROUP . (XREF ...)) ...)."
                    (eq xref-file-name-display 'project-relative)
                    (project-current)))
          (project-root (and project
-                            (expand-file-name (project-root project)))))
+                            (expand-file-name (xref--project-root project)))))
     (mapcar
      (lambda (pair)
        (cons (xref--group-name-for-display (car pair) project-root)
@@ -1206,22 +1220,23 @@ between them by typing in the minibuffer with 
completion."
     (cl-loop for ((group . xrefs) . more1) on xref-alist
              do
              (cl-loop for (xref . more2) on xrefs do
-                      (with-slots (summary location) xref
-                        (let* ((line (xref-location-line location))
-                               (line-fmt
-                                (if line
-                                    (format #("%d:" 0 2 (face 
xref-line-number))
-                                            line)
-                                  ""))
-                               (group-prefix
-                                (substring group group-prefix-length))
-                               (group-fmt
-                                (propertize group-prefix
-                                            'face 'xref-file-header
-                                            'xref--group group-prefix))
-                               (candidate
-                                (format "%s:%s%s" group-fmt line-fmt summary)))
-                          (push (cons candidate xref) 
xref-alist-with-line-info)))))
+                      (let* ((summary (xref-item-summary xref))
+                             (location (xref-item-location xref))
+                             (line (xref-location-line location))
+                             (line-fmt
+                              (if line
+                                  (format #("%d:" 0 2 (face xref-line-number))
+                                          line)
+                                ""))
+                             (group-prefix
+                              (substring group group-prefix-length))
+                             (group-fmt
+                              (propertize group-prefix
+                                          'face 'xref-file-header
+                                          'xref--group group-prefix))
+                             (candidate
+                              (format "%s:%s%s" group-fmt line-fmt summary)))
+                        (push (cons candidate xref) 
xref-alist-with-line-info))))
 
     (setq xref (if (not (cdr xrefs))
                    (car xrefs)
@@ -1334,12 +1349,17 @@ definitions."
                (xref--prompt-p this-command))
            (let ((id
                   (completing-read
-                   (if def
-                       (format "%s (default %s): "
-                               (substring prompt 0 (string-match
-                                                    "[ :]+\\'" prompt))
-                               def)
-                     prompt)
+                   ;; `format-prompt' is new in Emacs 28.1
+                   (if (fboundp 'format-prompt)
+                       (format-prompt (substring prompt 0 (string-match
+                                                           "[ :]+\\'" prompt))
+                                      def)
+                     (if def
+                         (format "%s (default %s): "
+                                 (substring prompt 0 (string-match
+                                                      "[ :]+\\'" prompt))
+                                 def)
+                       prompt))
                    (xref-backend-identifier-completion-table backend)
                    nil nil nil
                    'xref--read-identifier-history def)))
@@ -1400,7 +1420,7 @@ definition for IDENTIFIER, display it in the selected 
window.
 Otherwise, display the list of the possible definitions in a
 buffer where the user can select from the list.
 
-Use \\[xref-pop-marker-stack] to return back to where you invoked this 
command."
+Use \\[xref-go-back] to return back to where you invoked this command."
   (interactive (list (xref--read-identifier "Find definitions of: ")))
   (xref--find-definitions identifier nil))
 
@@ -1491,7 +1511,8 @@ output of this command when the backend is etags."
 ;;; Key bindings
 
 ;;;###autoload (define-key esc-map "." #'xref-find-definitions)
-;;;###autoload (define-key esc-map "," #'xref-pop-marker-stack)
+;;;###autoload (define-key esc-map "," #'xref-go-back)
+;;;###autoload (define-key esc-map [?\C-,] #'xref-go-forward)
 ;;;###autoload (define-key esc-map "?" #'xref-find-references)
 ;;;###autoload (define-key esc-map [?\C-.] #'xref-find-apropos)
 ;;;###autoload (define-key ctl-x-4-map "." 
#'xref-find-definitions-other-window)
@@ -1648,7 +1669,11 @@ The template should have the following fields:
 (defcustom xref-search-program 'grep
   "The program to use for regexp search inside files.
 
-This must reference a corresponding entry in `xref-search-program-alist'."
+This must reference a corresponding entry in `xref-search-program-alist'.
+
+This variable is used in `xref-matches-in-files', which is the
+utility function used by commands like `dired-do-find-regexp' and
+`project-find-regexp'."
   :type '(choice
           (const :tag "Use Grep" grep)
           (const :tag "Use ripgrep" ripgrep)
@@ -1660,7 +1685,10 @@ This must reference a corresponding entry in 
`xref-search-program-alist'."
 (defun xref-matches-in-files (regexp files)
   "Find all matches for REGEXP in FILES.
 Return a list of xref values.
-FILES must be a list of absolute file names."
+FILES must be a list of absolute file names.
+
+See `xref-search-program' and `xref-search-program-alist' for how
+to control which program to use when looking for matches."
   (cl-assert (consp files))
   (require 'grep)
   (defvar grep-highlight-matches)
@@ -1881,34 +1909,36 @@ Such as the current syntax table and the applied syntax 
properties."
                                  syntax-needed)))))
 
 (defun xref--collect-matches-1 (regexp file line line-beg line-end 
syntax-needed)
-  (let (match-pairs matches)
+  (let (matches
+        stop beg end
+        last-beg last-end
+        summary-end)
     (when syntax-needed
       (syntax-propertize line-end))
-    (while (and
-            ;; REGEXP might match an empty string.  Or line.
-            (or (null match-pairs)
-                (> (point) line-beg))
-            (re-search-forward regexp line-end t))
-      (push (cons (match-beginning 0)
-                  (match-end 0))
-            match-pairs))
-    (setq match-pairs (nreverse match-pairs))
-    (while match-pairs
-      (let* ((beg-end (pop match-pairs))
-             (beg-column (- (car beg-end) line-beg))
-             (end-column (- (cdr beg-end) line-beg))
-             (loc (xref-make-file-location file line beg-column))
-             (summary (buffer-substring (if matches (car beg-end) line-beg)
-                                        (if match-pairs
-                                            (caar match-pairs)
-                                          line-end))))
-        (when matches
-          (cl-decf beg-column (- (car beg-end) line-beg))
-          (cl-decf end-column (- (car beg-end) line-beg)))
-        (add-face-text-property beg-column end-column 'xref-match
-                                t summary)
-        (push (xref-make-match summary loc (- end-column beg-column))
-              matches)))
+    (while (not stop)
+      (if (and
+           ;; REGEXP might match an empty string.  Or line.
+           (not (and last-beg (eql end line-beg)))
+           (re-search-forward regexp line-end t))
+          (setq beg (match-beginning 0)
+                end (match-end 0)
+                summary-end beg)
+        (setq stop t
+              summary-end line-end))
+      (when last-beg
+        (let* ((beg-column (- last-beg line-beg))
+               (end-column (- last-end line-beg))
+               (summary-start (if matches last-beg line-beg))
+               (summary (buffer-substring summary-start
+                                          summary-end))
+               (loc (xref-make-file-location file line beg-column)))
+          (add-face-text-property (- last-beg summary-start)
+                                  (- last-end summary-start)
+                                  'xref-match t summary)
+          (push (xref-make-match summary loc (- end-column beg-column))
+                matches)))
+      (setq last-beg beg
+            last-end end))
     (nreverse matches)))
 
 (defun xref--find-file-buffer (file)
diff --git a/lisp/progmodes/xscheme.el b/lisp/progmodes/xscheme.el
index 7076331984..26ffe33b83 100644
--- a/lisp/progmodes/xscheme.el
+++ b/lisp/progmodes/xscheme.el
@@ -562,7 +562,7 @@ The strings are concatenated and terminated by a newline."
 
 (defun xscheme-yank (&optional arg)
   "Insert the most recent expression at point.
-With just C-U as argument, same but put point in front (and mark at end).
+With just \\[universal-argument] as argument, same but put point in front (and 
mark at end).
 With argument n, reinsert the nth most recently sent expression.
 See also the commands \\[xscheme-yank-pop] and \\[xscheme-yank-push]."
   (interactive "*P")
@@ -908,8 +908,8 @@ the remaining input.")
               xscheme-signal-death-message)
          (progn
            (beep)
-           (message
-"The Scheme process has died!  Do M-x reset-scheme to restart it"))))))
+            (message (substitute-command-keys
+"The Scheme process has died!  Type \\[reset-scheme] to restart it")))))))
 
 (defun xscheme-process-filter-initialize (running-p)
   (setq xscheme-process-filter-state 'idle)
diff --git a/lisp/ps-mule.el b/lisp/ps-mule.el
index ab8af40628..2d1dcd2b68 100644
--- a/lisp/ps-mule.el
+++ b/lisp/ps-mule.el
@@ -1209,8 +1209,8 @@ V%s 0 /%s-latin1 /%s Latin1Encoding put\n"
          (ps-output-prologue (format "ETOP%d %d %d put\n" i (car font) index))
          (setq index (1+ index))))
       (ps-output-prologue (format "/VTOP%d [%s] def\n" i
-                                 (mapconcat #'(lambda (x)
-                                                (format "F%02X" (cdr x)))
+                                  (mapconcat (lambda (x)
+                                               (format "F%02X" (cdr x)))
                                             font-list " ")))))
 
   ;; Redefine fonts f0, f1, f2, f3, h0, h1, H0.
diff --git a/lisp/ps-print.el b/lisp/ps-print.el
index 38671b58e2..0fc9554679 100644
--- a/lisp/ps-print.el
+++ b/lisp/ps-print.el
@@ -2788,7 +2788,7 @@ Each element comprises: font family (the key), name, 
bold, italic, bold-italic,
 reference size, line height, space width, average character width.
 To get the info for another specific font (say Helvetica), do the following:
 - create a new buffer
-- generate the PostScript image to a file (C-u M-x ps-print-buffer)
+- generate the PostScript image to a file (\\[universal-argument] 
\\[ps-print-buffer])
 - open this file and delete the leading `%' (which is the PostScript comment
   character) from the line
           `% 3 cm 20 cm moveto  10/Courier ReportFontInfo  showpage'
@@ -3855,7 +3855,7 @@ It can be retrieved with `(ps-get ALIST-SYM KEY)'."
 
 (defun ps-color-scale (color)
   ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
-  (mapcar #'(lambda (value) (/ value ps-print-color-scale))
+  (mapcar (lambda (value) (/ value ps-print-color-scale))
          (color-values color)))
 
 
@@ -3878,7 +3878,7 @@ Note: No major/minor-mode is activated and no local 
variables are evaluated for
        (with-temp-buffer
          (insert-file-contents filename)
          (buffer-string))
-      (error "ps-print PostScript prologue `%s' file was not found"
+      (error "ps-print: PostScript prologue `%s' file was not found"
             filename))))
 
 
@@ -4747,11 +4747,11 @@ page-height == ((floor print-height ((th + ls) * zh)) * 
((th + ls) * zh)) - th
 (defun ps-background-pages (page-list func)
   (if page-list
       (mapcar
-       #'(lambda (pages)
-          (let ((start (if (consp pages) (car pages) pages))
-                (end   (if (consp pages) (cdr pages) pages)))
-            (and (integerp start) (integerp end) (<= start end)
-                 (add-to-list 'ps-background-pages (vector start end func)))))
+       (lambda (pages)
+         (let ((start (if (consp pages) (car pages) pages))
+               (end   (if (consp pages) (cdr pages) pages)))
+           (and (integerp start) (integerp end) (<= start end)
+                (add-to-list 'ps-background-pages (vector start end func)))))
        page-list)
     (setq ps-background-all-pages (cons func ps-background-all-pages))))
 
@@ -4789,76 +4789,76 @@ page-height == ((floor print-height ((th + ls) * zh)) * 
((th + ls) * zh)) - th
 
 (defun ps-background-text ()
   (mapcar
-   #'(lambda (text)
-       (setq ps-background-text-count (1+ ps-background-text-count))
-       (ps-output (format "/ShowBackText-%d{\n" ps-background-text-count))
-       (ps-output-string (nth 0 text)) ; text
-       (ps-output
-       "\n"
-       (ps-float-format (nth 4 text) 200.0) ; font size
-       (format "/%s " (or (nth 3 text) "Times-Roman")) ; font name
-       (ps-float-format (nth 6 text)
-                        "PrintHeight PrintPageWidth atan") ; rotation
-       (ps-float-format (nth 5 text) 0.85) ; gray
-       (ps-float-format (nth 1 text) "0") ; x position
-       (ps-float-format (nth 2 text) "0") ; y position
-       "\nShowBackText}def\n")
-       (ps-background-pages (nthcdr 7 text) ; page list
-                           (format "ShowBackText-%d\n"
-                                   ps-background-text-count)))
+   (lambda (text)
+     (setq ps-background-text-count (1+ ps-background-text-count))
+     (ps-output (format "/ShowBackText-%d{\n" ps-background-text-count))
+     (ps-output-string (nth 0 text))   ; text
+     (ps-output
+      "\n"
+      (ps-float-format (nth 4 text) 200.0) ; font size
+      (format "/%s " (or (nth 3 text) "Times-Roman")) ; font name
+      (ps-float-format (nth 6 text)
+                       "PrintHeight PrintPageWidth atan") ; rotation
+      (ps-float-format (nth 5 text) 0.85) ; gray
+      (ps-float-format (nth 1 text) "0") ; x position
+      (ps-float-format (nth 2 text) "0") ; y position
+      "\nShowBackText}def\n")
+     (ps-background-pages (nthcdr 7 text) ; page list
+                          (format "ShowBackText-%d\n"
+                                  ps-background-text-count)))
    ps-print-background-text))
 
 
 (defun ps-background-image ()
   (mapcar
-   #'(lambda (image)
-       (let ((image-file (expand-file-name (nth 0 image))))
-        (when (file-readable-p image-file)
-          (setq ps-background-image-count (1+ ps-background-image-count))
-          (ps-output
-           (format "/ShowBackImage-%d{\n--back-- "
-                   ps-background-image-count)
-           (ps-float-format (nth 5 image) 0.0) ; rotation
-           (ps-float-format (nth 3 image) 1.0) ; x scale
-           (ps-float-format (nth 4 image) 1.0) ; y scale
-           (ps-float-format (nth 1 image) ; x position
-                            "PrintPageWidth 2 div")
-           (ps-float-format (nth 2 image) ; y position
-                            "PrintHeight 2 div BottomMargin add")
-           "\nBeginBackImage\n")
-          (ps-insert-file image-file)
-          ;; coordinate adjustment to center image
-          ;; around x and y position
-          (let ((box (ps-get-boundingbox)))
-            (with-current-buffer ps-spool-buffer
-              (save-excursion
-                (if (re-search-backward "^--back--" nil t)
-                    (replace-match
-                     (format "%s %s"
-                             (ps-float-format
-                              (- (+ (/ (- (aref box 2) (aref box 0)) 2.0)
-                                    (aref box 0))))
-                             (ps-float-format
-                              (- (+ (/ (- (aref box 3) (aref box 1)) 2.0)
-                                    (aref box 1)))))
-                     t)))))
-          (ps-output "\nEndBackImage}def\n")
-          (ps-background-pages (nthcdr 6 image) ; page list
-                               (format "ShowBackImage-%d\n"
-                                       ps-background-image-count)))))
+   (lambda (image)
+     (let ((image-file (expand-file-name (nth 0 image))))
+       (when (file-readable-p image-file)
+         (setq ps-background-image-count (1+ ps-background-image-count))
+         (ps-output
+          (format "/ShowBackImage-%d{\n--back-- "
+                  ps-background-image-count)
+          (ps-float-format (nth 5 image) 0.0) ; rotation
+          (ps-float-format (nth 3 image) 1.0) ; x scale
+          (ps-float-format (nth 4 image) 1.0) ; y scale
+          (ps-float-format (nth 1 image) ; x position
+                           "PrintPageWidth 2 div")
+          (ps-float-format (nth 2 image) ; y position
+                           "PrintHeight 2 div BottomMargin add")
+          "\nBeginBackImage\n")
+         (ps-insert-file image-file)
+         ;; coordinate adjustment to center image
+         ;; around x and y position
+         (let ((box (ps-get-boundingbox)))
+           (with-current-buffer ps-spool-buffer
+             (save-excursion
+               (if (re-search-backward "^--back--" nil t)
+                   (replace-match
+                    (format "%s %s"
+                            (ps-float-format
+                             (- (+ (/ (- (aref box 2) (aref box 0)) 2.0)
+                                   (aref box 0))))
+                            (ps-float-format
+                             (- (+ (/ (- (aref box 3) (aref box 1)) 2.0)
+                                   (aref box 1)))))
+                    t)))))
+         (ps-output "\nEndBackImage}def\n")
+         (ps-background-pages (nthcdr 6 image) ; page list
+                              (format "ShowBackImage-%d\n"
+                                      ps-background-image-count)))))
    ps-print-background-image))
 
 
 (defun ps-background (page-number)
   (let (has-local-background)
-    (mapc #'(lambda (range)
-             (and (<= (aref range 0) page-number)
-                  (<= page-number (aref range 1))
-                  (if has-local-background
-                      (ps-output (aref range 2))
-                    (setq has-local-background t)
-                    (ps-output "/printLocalBackground{\n"
-                               (aref range 2)))))
+    (mapc (lambda (range)
+            (and (<= (aref range 0) page-number)
+                 (<= page-number (aref range 1))
+                 (if has-local-background
+                     (ps-output (aref range 2))
+                   (setq has-local-background t)
+                   (ps-output "/printLocalBackground{\n"
+                              (aref range 2)))))
          ps-background-pages)
     (and has-local-background (ps-output "}def\n"))))
 
@@ -5697,8 +5697,8 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
                  (> (car page) 0)
                  (<= (car page) (cdr page))
                  (setq new (cons page new))))))
-    (setq ps-selected-pages      (sort new #'(lambda (one other)
-                                              (< (car one) (car other))))
+    (setq ps-selected-pages      (sort new (lambda (one other)
+                                             (< (car one) (car other))))
          ps-last-selected-pages ps-selected-pages
          ps-first-page          nil
          ps-last-page           nil))
@@ -5782,8 +5782,8 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
                               "unspecified-fg"
                               0.0)
        ps-foreground-list    (mapcar
-                              #'(lambda (arg)
-                                  (ps-rgb-color arg "unspecified-fg" 0.0))
+                               (lambda (arg)
+                                 (ps-rgb-color arg "unspecified-fg" 0.0))
                               (append (and (not (member ps-print-color-p
                                                         '(nil black-white)))
                                            ps-fg-list)
@@ -6012,9 +6012,9 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
     (if (and (boundp 'ucs-mule-8859-to-mule-unicode)
           (char-table-p ucs-mule-8859-to-mule-unicode))
        (map-char-table
-        #'(lambda (k v)
-            (if (and v (eq (char-charset v) 'latin-iso8859-1) (/= k v))
-                (aset tbl k v)))
+         (lambda (k v)
+           (if (and v (eq (char-charset v) 'latin-iso8859-1) (/= k v))
+               (aset tbl k v)))
         ucs-mule-8859-to-mule-unicode))
     tbl)
   "Translation table for PostScript printing.
diff --git a/lisp/recentf.el b/lisp/recentf.el
index 9ae059a70d..6b5a47c66f 100644
--- a/lisp/recentf.el
+++ b/lisp/recentf.el
@@ -674,55 +674,55 @@ Return nil if file NAME is not one of the ten more 
recent."
   "Sort the list of menu elements L in ascending order.
 The MENU-ITEM part of each menu element is compared."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-string-lessp
-             (recentf-menu-element-item e1)
-             (recentf-menu-element-item e2)))))
+        (lambda (e1 e2)
+          (recentf-string-lessp
+           (recentf-menu-element-item e1)
+           (recentf-menu-element-item e2)))))
 
 (defsubst recentf-sort-descending (l)
   "Sort the list of menu elements L in descending order.
 The MENU-ITEM part of each menu element is compared."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-string-lessp
-             (recentf-menu-element-item e2)
-             (recentf-menu-element-item e1)))))
+        (lambda (e1 e2)
+          (recentf-string-lessp
+           (recentf-menu-element-item e2)
+           (recentf-menu-element-item e1)))))
 
 (defsubst recentf-sort-basenames-ascending (l)
   "Sort the list of menu elements L in ascending order.
 Only filenames sans directory are compared."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-string-lessp
-             (file-name-nondirectory (recentf-menu-element-value e1))
-             (file-name-nondirectory (recentf-menu-element-value e2))))))
+        (lambda (e1 e2)
+          (recentf-string-lessp
+           (file-name-nondirectory (recentf-menu-element-value e1))
+           (file-name-nondirectory (recentf-menu-element-value e2))))))
 
 (defsubst recentf-sort-basenames-descending (l)
   "Sort the list of menu elements L in descending order.
 Only filenames sans directory are compared."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-string-lessp
-             (file-name-nondirectory (recentf-menu-element-value e2))
-             (file-name-nondirectory (recentf-menu-element-value e1))))))
+        (lambda (e1 e2)
+          (recentf-string-lessp
+           (file-name-nondirectory (recentf-menu-element-value e2))
+           (file-name-nondirectory (recentf-menu-element-value e1))))))
 
 (defsubst recentf-sort-directories-ascending (l)
   "Sort the list of menu elements L in ascending order.
 Compares directories then filenames to order the list."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-directory-compare
-             (recentf-menu-element-value e1)
-             (recentf-menu-element-value e2)))))
+        (lambda (e1 e2)
+          (recentf-directory-compare
+           (recentf-menu-element-value e1)
+           (recentf-menu-element-value e2)))))
 
 (defsubst recentf-sort-directories-descending (l)
   "Sort the list of menu elements L in descending order.
 Compares directories then filenames to order the list."
   (sort (copy-sequence l)
-        #'(lambda (e1 e2)
-            (recentf-directory-compare
-             (recentf-menu-element-value e2)
-             (recentf-menu-element-value e1)))))
+        (lambda (e1 e2)
+          (recentf-directory-compare
+           (recentf-menu-element-value e2)
+           (recentf-menu-element-value e1)))))
 
 (defun recentf-show-basenames (l &optional no-dir)
   "Filter the list of menu elements L to show filenames sans directory.
@@ -1122,8 +1122,9 @@ IGNORE arguments."
     (setq-local recentf-edit-list nil)
     (widget-insert
      (format-message
-      "Click on OK to delete selected files from the recent list.
-Click on Cancel or type `q' to cancel.\n"))
+      (substitute-command-keys
+       "Click on OK to delete selected files from the recent list.
+Click on Cancel or type \\[recentf-cancel-dialog] to cancel.\n")))
     ;; Insert the list of files as checkboxes
     (dolist (item recentf-list)
       (widget-create 'checkbox
@@ -1221,7 +1222,8 @@ use for the dialog.  It defaults to 
\"*`recentf-menu-title'*\"."
                        ", or type the corresponding digit key,"
                      "")
                    " to open it.\n"
-                   (format-message "Click on Cancel or type `q' to cancel.\n"))
+                   (substitute-command-keys
+                    "Click on Cancel or type \\[recentf-cancel-dialog] to 
cancel.\n"))
     ;; Use a L&F that looks like the recentf menu.
     (tree-widget-set-theme "folder")
     (apply #'widget-create
@@ -1380,5 +1382,5 @@ buffers you switch to a lot, you can say something like 
the following:
 (provide 'recentf)
 
 (run-hooks 'recentf-load-hook)
-
+
 ;;; recentf.el ends here
diff --git a/lisp/repeat.el b/lisp/repeat.el
index ee9e14b515..ac08952eaa 100644
--- a/lisp/repeat.el
+++ b/lisp/repeat.el
@@ -344,8 +344,8 @@ For example, you can set it to <return> like 
`isearch-exit'."
 
 (defcustom repeat-exit-timeout nil
   "Break the repetition chain of keys after specified timeout.
-When a number, exit the repeat mode after idle time of the specified
-number of seconds."
+When a number, exit the transient repeating mode after idle time
+of the specified number of seconds."
   :type '(choice (const :tag "No timeout to exit repeating sequence" nil)
                  (number :tag "Timeout in seconds to exit repeating"))
   :group 'convenience
@@ -355,7 +355,7 @@ number of seconds."
   "Timer activated after the last key typed in the repeating key sequence.")
 
 (defcustom repeat-keep-prefix t
-  "Keep the prefix arg of the previous command."
+  "Whether to keep the prefix arg of the previous command when repeating."
   :type 'boolean
   :group 'convenience
   :version "28.1")
@@ -363,7 +363,7 @@ number of seconds."
 (defcustom repeat-echo-function #'repeat-echo-message
   "Function to display a hint about available keys.
 Function is called after every repeatable command with one argument:
-a repeating map, or nil after deactivating the repeat mode."
+a repeating map, or nil after deactivating the transient repeating mode."
   :type '(choice (const :tag "Show hints in the echo area"
                         repeat-echo-message)
                  (const :tag "Show indicator in the mode line"
@@ -374,11 +374,11 @@ a repeating map, or nil after deactivating the repeat 
mode."
   :version "28.1")
 
 (defvar repeat-in-progress nil
-  "Non-nil when the repeating map is active.")
+  "Non-nil when the repeating transient map is active.")
 
 ;;;###autoload
 (defvar repeat-map nil
-  "The value of the repeating map for the next command.
+  "The value of the repeating transient map for the next command.
 A command called from the map can set it again to the same map when
 the map can't be set on the command symbol property `repeat-map'.")
 
@@ -387,7 +387,7 @@ the map can't be set on the command symbol property 
`repeat-map'.")
   "Toggle Repeat mode.
 When Repeat mode is enabled, and the command symbol has the property named
 `repeat-map', this map is activated temporarily for the next command.
-See `describe-repeat-maps' for a list of all repeatable command."
+See `describe-repeat-maps' for a list of all repeatable commands."
   :global t :group 'convenience
   (if (not repeat-mode)
       (remove-hook 'post-command-hook 'repeat-post-hook)
diff --git a/lisp/replace.el b/lisp/replace.el
index 84ec042f45..5287be2c52 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -2263,11 +2263,11 @@ See also `multi-occur'."
 
 (defun occur-engine-add-prefix (lines &optional prefix-face)
   (mapcar
-   #'(lambda (line)
-       (concat (if prefix-face
-                  (propertize "       :" 'font-lock-face prefix-face)
-                "       :")
-              line "\n"))
+   (lambda (line)
+     (concat (if prefix-face
+                 (propertize "       :" 'font-lock-face prefix-face)
+               "       :")
+             line "\n"))
    lines))
 
 (defun occur-accumulate-lines (count &optional keep-props pt)
diff --git a/lisp/select.el b/lisp/select.el
index 15e171c13f..3c9f961f6d 100644
--- a/lisp/select.el
+++ b/lisp/select.el
@@ -440,13 +440,13 @@ two markers or an overlay.  Otherwise, it is nil."
              (setq type 'C_STRING))
             (t
              (let (non-latin-1 non-unicode eight-bit)
-               (mapc #'(lambda (x)
-                         (if (>= x #x100)
-                             (if (< x #x110000)
-                                 (setq non-latin-1 t)
-                               (if (< x #x3FFF80)
-                                   (setq non-unicode t)
-                                 (setq eight-bit t)))))
+                (mapc (lambda (x)
+                        (if (>= x #x100)
+                            (if (< x #x110000)
+                                (setq non-latin-1 t)
+                              (if (< x #x3FFF80)
+                                  (setq non-unicode t)
+                                (setq eight-bit t)))))
                      str)
                (setq type (if (or non-unicode
                                   (and
diff --git a/lisp/server.el b/lisp/server.el
index 6359a76199..d998656237 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -90,12 +90,12 @@
 
 (defcustom server-use-tcp nil
   "If non-nil, use TCP sockets instead of local sockets."
-  :set #'(lambda (sym val)
-           (unless (featurep 'make-network-process '(:family local))
-             (setq val t)
-             (unless load-in-progress
-               (message "Local sockets unsupported, using TCP sockets")))
-           (set-default sym val))
+  :set (lambda (sym val)
+         (unless (featurep 'make-network-process '(:family local))
+           (setq val t)
+           (unless load-in-progress
+             (message "Local sockets unsupported, using TCP sockets")))
+         (set-default sym val))
   :type 'boolean
   :version "22.1")
 
@@ -485,11 +485,11 @@ If CLIENT is non-nil, add a description of it to the 
logged message."
     (when (and (frame-live-p frame)
               proc
               ;; See if this is the last frame for this client.
-              (>= 1 (let ((frame-num 0))
-                      (dolist (f (frame-list))
-                        (when (eq proc (frame-parameter f 'client))
-                          (setq frame-num (1+ frame-num))))
-                      frame-num)))
+               (not (seq-some
+                     (lambda (f)
+                       (and (not (eq frame f))
+                            (eq proc (frame-parameter f 'client))))
+                     (frame-list))))
       (server-log (format "server-handle-delete-frame, frame %s" frame) proc)
       (server-delete-client proc 'noframe)))) ; Let delete-frame delete the 
frame later.
 
@@ -1580,13 +1580,13 @@ specifically for the clients and did not exist before 
their request for it."
     (server-buffer-done (current-buffer))))
 
 (defun server-kill-emacs-query-function ()
-  "Ask before exiting Emacs if it has live clients."
-  (or (not (let (live-client)
-             (dolist (proc server-clients)
-               (when (memq t (mapcar #'buffer-live-p
-                                     (process-get proc 'buffers)))
-                 (setq live-client t)))
-             live-client))
+  "Ask before exiting Emacs if it has live clients.
+A \"live client\" is a client with at least one live buffer
+associated with it."
+  (or (not (seq-some (lambda (proc)
+                       (seq-some #'buffer-live-p
+                                 (process-get proc 'buffers)))
+                     server-clients))
       (yes-or-no-p "This Emacs session has clients; exit anyway? ")))
 
 (defun server-kill-buffer ()
diff --git a/lisp/ses.el b/lisp/ses.el
index ea966295b1..5e2d254881 100644
--- a/lisp/ses.el
+++ b/lisp/ses.el
@@ -3554,7 +3554,7 @@ With prefix, sorts in REVERSE order."
        (push (cons (buffer-substring-no-properties (point) end)
                    (+ minrow x))
              keys))
-      (setq keys (sort keys #'(lambda (x y) (string< (car x) (car y)))))
+      (setq keys (sort keys (lambda (x y) (string< (car x) (car y)))))
       ;;Extract the lines in reverse sorted order
       (or reverse
          (setq keys (nreverse keys)))
@@ -3774,7 +3774,9 @@ function is redefined."
      (setq name (intern name))
      (let* ((cur-printer (gethash name ses--local-printer-hashmap))
             (default (and cur-printer (ses--locprn-def cur-printer))))
-            (setq def (ses-read-printer (format "Enter definition of printer 
%S" name)
+            (setq def (ses-read-printer (format-prompt
+                                         "Enter definition of printer %S"
+                                         default name)
                                         default)))
             (list name def)))
 
diff --git a/lisp/shell.el b/lisp/shell.el
index b575024e01..370532ea46 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -766,12 +766,16 @@ Make the shell buffer the current buffer, and return it.
               (called-interactively-p 'any)
               (null explicit-shell-file-name)
               (null (getenv "ESHELL")))
+     ;; `expand-file-name' shall not add the MS Windows volume letter
+     ;; (Bug#49229).
      (setq-local explicit-shell-file-name
-                 (file-local-name
-                  (expand-file-name
-                   (read-file-name "Remote shell path: " default-directory
-                                   shell-file-name t shell-file-name
-                                   #'file-remote-p)))))
+                 (replace-regexp-in-string
+                  "^[[:alpha:]]:" ""
+                  (file-local-name
+                   (expand-file-name
+                    (read-file-name "Remote shell path: " default-directory
+                                    shell-file-name t shell-file-name
+                                    #'file-remote-p))))))
 
    ;; Rain or shine, BUFFER must be current by now.
    (unless (comint-check-proc buffer)
@@ -781,7 +785,8 @@ Make the shell buffer the current buffer, and return it.
             (startfile (concat "~/.emacs_" name))
             (xargs-name (intern-soft (concat "explicit-" name "-args"))))
        (unless (file-exists-p startfile)
-         (setq startfile (concat user-emacs-directory "init_" name ".sh")))
+         (setq startfile (locate-user-emacs-file
+                          (concat "init_" name ".sh"))))
        (setq-local shell--start-prog (file-name-nondirectory prog))
        (apply #'make-comint-in-buffer "shell" buffer prog
               (if (file-exists-p startfile) startfile)
diff --git a/lisp/simple.el b/lisp/simple.el
index 298e3ea5ee..82e373be9e 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -527,21 +527,28 @@ Other major modes are defined by comparison with this 
one."
   (kill-all-local-variables)
   (run-mode-hooks))
 
+(define-derived-mode clean-mode fundamental-mode "Clean"
+  "A mode that removes all overlays and text properties."
+  (kill-all-local-variables t)
+  (let ((inhibit-read-only t))
+    (dolist (overlay (overlays-in (point-min) (point-max)))
+      (delete-overlay overlay))
+    (set-text-properties (point-min) (point-max) nil)
+    (setq-local yank-excluded-properties t)))
+
 ;; Special major modes to view specially formatted data rather than files.
 
-(defvar special-mode-map
-  (let ((map (make-sparse-keymap)))
-    (suppress-keymap map)
-    (define-key map "q" 'quit-window)
-    (define-key map " " 'scroll-up-command)
-    (define-key map [?\S-\ ] 'scroll-down-command)
-    (define-key map "\C-?" 'scroll-down-command)
-    (define-key map "?" 'describe-mode)
-    (define-key map "h" 'describe-mode)
-    (define-key map ">" 'end-of-buffer)
-    (define-key map "<" 'beginning-of-buffer)
-    (define-key map "g" 'revert-buffer)
-    map))
+(defvar-keymap special-mode-map
+  :suppress t
+  "q" #'quit-window
+  " " #'scroll-up-command
+  [?\S-\ ] #'scroll-down-command
+  "\C-?" #'scroll-down-command
+  "?" #'describe-mode
+  "h" #'describe-mode
+  ">" #'end-of-buffer
+  "<" #'beginning-of-buffer
+  "g" #'revert-buffer)
 
 (put 'special-mode 'mode-class 'special)
 (define-derived-mode special-mode nil "Special"
@@ -589,6 +596,9 @@ text-property `hard'.
 A non-nil INTERACTIVE argument means to run the `post-self-insert-hook'."
   (interactive "*P\np")
   (barf-if-buffer-read-only)
+  (when (and arg
+             (< (prefix-numeric-value arg) 0))
+    (error "Repetition argument has to be non-negative"))
   ;; Call self-insert so that auto-fill, abbrev expansion etc. happen.
   ;; Set last-command-event to tell self-insert what to insert.
   (let* ((was-page-start (and (bolp) (looking-at page-delimiter)))
@@ -700,9 +710,10 @@ When called from Lisp code, ARG may be a prefix string to 
copy."
      :height 0.1 :background "#505050")
     (((type graphic) (background light))
      :height 0.1 :background "#a0a0a0")
-    (t :foreground "ForestGreen"))
+    (t
+     :foreground "ForestGreen" :underline t))
   "Face for separator lines."
-  :version "28.1"
+  :version "29.1"
   :group 'text)
 
 (defun make-separator-line (&optional length)
@@ -710,11 +721,13 @@ When called from Lisp code, ARG may be a prefix string to 
copy."
 This uses the `separator-line' face.
 
 If LENGTH is nil, use the window width."
-  (if (display-graphic-p)
+  (if (or (display-graphic-p)
+          (display-supports-face-attributes-p '(:underline t)))
       (if length
           (concat (propertize (make-string length ?\s) 'face 'separator-line)
                   "\n")
         (propertize "\n" 'face '(:inherit separator-line :extend t)))
+    ;; In terminals (that don't support underline), use a line of dashes.
     (concat (propertize (make-string (or length (1- (window-width))) ?-)
                         'face 'separator-line)
             "\n")))
@@ -2144,7 +2157,7 @@ Equivalent key-bindings are also shown in the completion 
list of
 \\[execute-extended-command] for all commands that have them."
   :group 'keyboard
   :type '(choice (const :tag "off" nil)
-                 (integer :tag "time" 2)
+                 (natnum :tag "time" 2)
                  (other :tag "on")))
 
 (defcustom extended-command-suggest-shorter t
@@ -2942,8 +2955,9 @@ undo record: if we undo from 4, `pending-undo-list' will 
be at 3,
 (defvar undo-in-region nil
   "Non-nil if `pending-undo-list' is not just a tail of `buffer-undo-list'.")
 
-(defvar undo-no-redo nil
-  "If t, `undo' doesn't go through redo entries.")
+(defcustom undo-no-redo nil
+  "If t, `undo' doesn't go through redo entries."
+  :type 'boolean)
 
 (defvar pending-undo-list nil
   "Within a run of consecutive undo commands, list remaining to be undone.
@@ -5065,10 +5079,11 @@ interact nicely with `interprogram-cut-function' and
 interaction; you may want to use them instead of manipulating the kill
 ring directly.")
 
-(defcustom kill-ring-max 60
+(defcustom kill-ring-max 120
   "Maximum length of kill ring before oldest elements are thrown away."
   :type 'integer
-  :group 'killing)
+  :group 'killing
+  :version "29.1")
 
 (defvar kill-ring-yank-pointer nil
   "The tail of the kill ring whose car is the last thing yanked.")
@@ -5281,12 +5296,16 @@ Lisp programs should use this function for killing text.
 Supply two arguments, character positions BEG and END indicating the
  stretch of text to be killed.  If the optional argument REGION is
  non-nil, the function ignores BEG and END, and kills the current
- region instead."
+ region instead.  Interactively, REGION is always non-nil, and so
+ this command always kills the current region."
   ;; Pass mark first, then point, because the order matters when
   ;; calling `kill-append'.
-  (interactive (list (mark) (point) 'region))
-  (unless (and beg end)
-    (user-error "The mark is not set now, so there is no region"))
+  (interactive (progn
+                 (let ((beg (mark))
+                       (end (point)))
+                   (unless (and beg end)
+                     (user-error "The mark is not set now, so there is no 
region"))
+                   (list beg end 'region))))
   (condition-case nil
       (let ((string (if region
                         (funcall region-extract-function 'delete)
@@ -8415,16 +8434,29 @@ presented."
 
 (defcustom blink-matching-paren t
   "Non-nil means show matching open-paren when close-paren is inserted.
-If t, highlight the paren.  If `jump', briefly move cursor to its
-position.  If `jump-offscreen', move cursor there even if the
-position is off screen.  With any other non-nil value, the
-off-screen position of the opening paren will be shown in the
-echo area."
+If this is non-nil, then when you type a closing delimiter, such as a
+closing parenthesis or brace, Emacs briefly indicates the location
+of the matching opening delimiter.
+
+The valid values are:
+
+  t                 Highlight the matching open-paren if it is visible
+                    in the window, otherwise show the text with matching
+                    open-paren in the echo area.  This is the default.
+  `jump'            If the matching open-paren is visible in the window,
+                    briefly move cursor to its position; otherwise show
+                    the text with matching open-paren in the echo area.
+  `jump-offscreen'  Briefly move cursor to the matching open-paren
+                    even if it is not visible in the window.
+  nil               Don't show the matching open-paren.
+
+Any other non-nil value is handled the same as t."
+
   :type '(choice
           (const :tag "Disable" nil)
-          (const :tag "Highlight" t)
-          (const :tag "Move cursor" jump)
-          (const :tag "Move cursor, even if off screen" jump-offscreen))
+          (const :tag "Highlight open-paren if visible" t)
+          (const :tag "Move cursor to open-paren if visible" jump)
+          (const :tag "Move cursor even if it's off screen" jump-offscreen))
   :group 'paren-blinking)
 
 (defcustom blink-matching-paren-on-screen t
@@ -8552,40 +8584,43 @@ The function should return non-nil if the two tokens do 
not match.")
                                    (current-buffer))
                      (sit-for blink-matching-delay))
                  (delete-overlay blink-matching--overlay)))))
-       (t
-        (let ((open-paren-line-string
-               (save-excursion
-                 (goto-char blinkpos)
-                 ;; Show what precedes the open in its line, if anything.
-                 (cond
-                  ((save-excursion (skip-chars-backward " \t") (not (bolp)))
-                   (buffer-substring (line-beginning-position)
-                                     (1+ blinkpos)))
-                  ;; Show what follows the open in its line, if anything.
-                  ((save-excursion
-                     (forward-char 1)
-                     (skip-chars-forward " \t")
-                     (not (eolp)))
-                   (buffer-substring blinkpos
-                                     (line-end-position)))
-                  ;; Otherwise show the previous nonblank line,
-                  ;; if there is one.
-                  ((save-excursion (skip-chars-backward "\n \t") (not (bobp)))
-                   (concat
-                    (buffer-substring (progn
-                                        (skip-chars-backward "\n \t")
-                                        (line-beginning-position))
-                                      (progn (end-of-line)
-                                             (skip-chars-backward " \t")
-                                             (point)))
-                    ;; Replace the newline and other whitespace with `...'.
-                    "..."
-                    (buffer-substring blinkpos (1+ blinkpos))))
-                  ;; There is nothing to show except the char itself.
-                  (t (buffer-substring blinkpos (1+ blinkpos)))))))
-          (minibuffer-message
-           "Matches %s"
-           (substring-no-properties open-paren-line-string))))))))
+       ((not show-paren-context-when-offscreen)
+        (minibuffer-message
+         "Matches %s"
+         (substring-no-properties
+          (blink-paren-open-paren-line-string blinkpos))))))))
+
+(defun blink-paren-open-paren-line-string (pos)
+  "Return the line string that contains the openparen at POS."
+  (save-excursion
+    (goto-char pos)
+    ;; Show what precedes the open in its line, if anything.
+    (cond
+     ((save-excursion (skip-chars-backward " \t") (not (bolp)))
+      (buffer-substring (line-beginning-position)
+                        (1+ pos)))
+     ;; Show what follows the open in its line, if anything.
+     ((save-excursion
+        (forward-char 1)
+        (skip-chars-forward " \t")
+        (not (eolp)))
+      (buffer-substring pos
+                        (line-end-position)))
+     ;; Otherwise show the previous nonblank line,
+     ;; if there is one.
+     ((save-excursion (skip-chars-backward "\n \t") (not (bobp)))
+      (concat
+       (buffer-substring (progn
+                           (skip-chars-backward "\n \t")
+                           (line-beginning-position))
+                         (progn (end-of-line)
+                                (skip-chars-backward " \t")
+                                (point)))
+       ;; Replace the newline and other whitespace with `...'.
+       "..."
+       (buffer-substring pos (1+ pos))))
+     ;; There is nothing to show except the char itself.
+     (t (buffer-substring pos (1+ pos))))))
 
 (defvar blink-paren-function 'blink-matching-open
   "Function called, if non-nil, whenever a close parenthesis is inserted.
@@ -9835,6 +9870,7 @@ does not have any effect until this variable is set.
 CUSTOMIZATIONS, if non-nil, should be composed of alternating
 `defcustom' keywords and values to add to the declaration of
 `COMMAND-alternatives' (typically :group and :version)."
+  (declare (indent defun))
   (let* ((command-name (symbol-name command))
          (varalt-name (concat command-name "-alternatives"))
          (varalt-sym (intern varalt-name))
diff --git a/lisp/skeleton.el b/lisp/skeleton.el
index c363fb2c48..2b183996d8 100644
--- a/lisp/skeleton.el
+++ b/lisp/skeleton.el
@@ -113,7 +113,8 @@ are integer buffer positions in the reverse order of the 
insertion order.")
   "Define a user-configurable COMMAND that enters a statement skeleton.
 DOCUMENTATION is that of the command.
 SKELETON is as defined under `skeleton-insert'."
-  (declare (doc-string 2) (debug (&define name stringp skeleton-edebug-spec)))
+  (declare (doc-string 2) (debug (&define name stringp skeleton-edebug-spec))
+           (indent defun))
   (if skeleton-debug
       (set command skeleton))
   `(progn
diff --git a/lisp/sort.el b/lisp/sort.el
index d6767ed509..0925980541 100644
--- a/lisp/sort.el
+++ b/lisp/sort.el
@@ -540,8 +540,8 @@ Use \\[untabify] to convert tabs to spaces before sorting."
            (narrow-to-region beg1 end1)
            (goto-char beg1)
            (sort-subr reverse 'forward-line 'end-of-line
-                      #'(lambda () (move-to-column col-start) nil)
-                      #'(lambda () (move-to-column col-end) nil))))))))
+                       (lambda () (move-to-column col-start) nil)
+                       (lambda () (move-to-column col-end) nil))))))))
 
 ;;;###autoload
 (defun reverse-region (beg end)
diff --git a/lisp/subr.el b/lisp/subr.el
index 2d2794cfd1..5a5842d428 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -193,7 +193,7 @@ set earlier in the `setq-local'.  The return value of the
   "Define VAR as a buffer-local variable with default value VAL.
 Like `defvar' but additionally marks the variable as being automatically
 buffer-local wherever it is set."
-  (declare (debug defvar) (doc-string 3))
+  (declare (debug defvar) (doc-string 3) (indent 2))
   ;; Can't use backquote here, it's too early in the bootstrap.
   (list 'progn (list 'defvar var val docstring)
         (list 'make-variable-buffer-local (list 'quote var))))
@@ -696,7 +696,7 @@ If N is omitted or nil, remove the last element."
   "Destructively remove `equal' duplicates from LIST.
 Store the result in LIST and return it.  LIST must be a proper list.
 Of several `equal' occurrences of an element in LIST, the first
-one is kept."
+one is kept.  See `seq-uniq' for non-destructive operation."
   (let ((l (length list)))
     (if (> l 100)
         (let ((hash (make-hash-table :test #'equal :size l))
@@ -925,19 +925,191 @@ side-effects, and the argument LIST is not modified."
 
 ;;;; Keymap support.
 
+(defun kbd-valid-p (keys)
+  "Say whether KEYS is a valid `kbd' sequence.
+A `kbd' sequence is a string consisting of one and more key
+strokes.  The key strokes are separated by a space character.
+
+Each key stroke is either a single character, or the name of an
+event, surrounded by angle brackets.  In addition, any key stroke
+may be preceded by one or more modifier keys.  Finally, a limited
+number of characters have a special shorthand syntax.
+
+Here's some example key sequences.
+
+  \"f\"           (the key 'f')
+  \"S o m\"       (a three key sequence of the keys 'S', 'o' and 'm')
+  \"C-c o\"       (a two key sequence of the keys 'c' with the control modifier
+                 and then the key 'o')
+  \"H-<left>\"    (the key named \"left\" with the hyper modifier)
+  \"M-RET\"       (the \"return\" key with a meta modifier)
+  \"C-M-<space>\" (the \"space\" key with both the control and meta modifiers)
+
+These are the characters that have shorthand syntax:
+NUL, RET, TAB, LFD, ESC, SPC, DEL.
+
+Modifiers have to be specified in this order:
+
+   A-C-H-M-S-s
+
+which is
+
+   Alt-Control-Hyper-Meta-Shift-super"
+  (declare (pure t) (side-effect-free t))
+  (and (stringp keys)
+       (string-match-p "\\`[^ ]+\\( [^ ]+\\)*\\'" keys)
+       (save-match-data
+         (catch 'exit
+           (let ((prefixes
+                  "\\(A-\\)?\\(C-\\)?\\(H-\\)?\\(M-\\)?\\(S-\\)?\\(s-\\)?")
+                 (case-fold-search nil))
+             (dolist (key (split-string keys " "))
+               ;; Every key might have these modifiers, and they should be
+               ;; in this order.
+               (when (string-match (concat "\\`" prefixes) key)
+                 (setq key (substring key (match-end 0))))
+               (unless (or (and (= (length key) 1)
+                                ;; Don't accept control characters as keys.
+                                (not (< (aref key 0) ?\s))
+                                ;; Don't accept Meta'd characters as keys.
+                                (or (multibyte-string-p key)
+                                    (not (<= 127 (aref key 0) 255))))
+                           (and (string-match-p "\\`<[-_A-Za-z0-9]+>\\'" key)
+                                ;; Don't allow <M-C-down>.
+                                (= (progn
+                                     (string-match
+                                      (concat "\\`<" prefixes) key)
+                                     (match-end 0))
+                                   1))
+                           (string-match-p
+                            
"\\`\\(NUL\\|RET\\|TAB\\|LFD\\|ESC\\|SPC\\|DEL\\)\\'"
+                            key))
+                 ;; Invalid.
+                 (throw 'exit nil)))
+             t)))))
+
 (defun kbd (keys)
   "Convert KEYS to the internal Emacs key representation.
 KEYS should be a string in the format returned by commands such
 as `C-h k' (`describe-key').
+
 This is the same format used for saving keyboard macros (see
 `edmacro-mode').
 
+Here's some example key sequences:
+
+    \"f\"
+    \"C-c C-c\"
+    \"H-<left>\"
+    \"M-RET\"
+    \"C-M-<return>\"
+
 For an approximate inverse of this, see `key-description'."
-  ;; Don't use a defalias, since the `pure' property is true only for
-  ;; the calling convention of `kbd'.
   (declare (pure t) (side-effect-free t))
   ;; A pure function is expected to preserve the match data.
-  (save-match-data (read-kbd-macro keys)))
+  (save-match-data
+    (let ((case-fold-search nil)
+          (len (length keys)) ; We won't alter keys in the loop below.
+          (pos 0)
+          (res []))
+      (while (and (< pos len)
+                  (string-match "[^ \t\n\f]+" keys pos))
+        (let* ((word-beg (match-beginning 0))
+               (word-end (match-end 0))
+               (word (substring keys word-beg len))
+               (times 1)
+               key)
+          ;; Try to catch events of the form "<as df>".
+          (if (string-match "\\`<[^ <>\t\n\f][^>\t\n\f]*>" word)
+              (setq word (match-string 0 word)
+                    pos (+ word-beg (match-end 0)))
+            (setq word (substring keys word-beg word-end)
+                  pos word-end))
+          (when (string-match "\\([0-9]+\\)\\*." word)
+            (setq times (string-to-number (substring word 0 (match-end 1))))
+            (setq word (substring word (1+ (match-end 1)))))
+          (cond ((string-match "^<<.+>>$" word)
+                 (setq key (vconcat (if (eq (key-binding [?\M-x])
+                                            'execute-extended-command)
+                                        [?\M-x]
+                                      (or (car (where-is-internal
+                                                'execute-extended-command))
+                                          [?\M-x]))
+                                    (substring word 2 -2) "\r")))
+                ((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
+                      (progn
+                        (setq word (concat (match-string 1 word)
+                                           (match-string 3 word)))
+                        (not (string-match
+                              "\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
+                              word))))
+                 (setq key (list (intern word))))
+                ((or (equal word "REM") (string-match "^;;" word))
+                 (setq pos (string-match "$" keys pos)))
+                (t
+                 (let ((orig-word word) (prefix 0) (bits 0))
+                   (while (string-match "^[ACHMsS]-." word)
+                     (setq bits (+ bits (cdr (assq (aref word 0)
+                                                   '((?A . ?\A-\^@) (?C . 
?\C-\^@)
+                                                     (?H . ?\H-\^@) (?M . 
?\M-\^@)
+                                                     (?s . ?\s-\^@) (?S . 
?\S-\^@))))))
+                     (setq prefix (+ prefix 2))
+                     (setq word (substring word 2)))
+                   (when (string-match "^\\^.$" word)
+                     (setq bits (+ bits ?\C-\^@))
+                     (setq prefix (1+ prefix))
+                     (setq word (substring word 1)))
+                   (let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
+                                              ("LFD" . "\n") ("TAB" . "\t")
+                                              ("ESC" . "\e") ("SPC" . " ")
+                                              ("DEL" . "\177")))))
+                     (when found (setq word (cdr found))))
+                   (when (string-match "^\\\\[0-7]+$" word)
+                     (let ((n 0))
+                       (dolist (ch (cdr (string-to-list word)))
+                         (setq n (+ (* n 8) ch -48)))
+                       (setq word (vector n))))
+                   (cond ((= bits 0)
+                          (setq key word))
+                         ((and (= bits ?\M-\^@) (stringp word)
+                               (string-match "^-?[0-9]+$" word))
+                          (setq key (mapcar (lambda (x) (+ x bits))
+                                            (append word nil))))
+                         ((/= (length word) 1)
+                          (error "%s must prefix a single character, not %s"
+                                 (substring orig-word 0 prefix) word))
+                         ((and (/= (logand bits ?\C-\^@) 0) (stringp word)
+                               ;; We used to accept . and ? here,
+                               ;; but . is simply wrong,
+                               ;; and C-? is not used (we use DEL instead).
+                               (string-match "[@-_a-z]" word))
+                          (setq key (list (+ bits (- ?\C-\^@)
+                                             (logand (aref word 0) 31)))))
+                         (t
+                          (setq key (list (+ bits (aref word 0)))))))))
+          (when key
+            (dolist (_ (number-sequence 1 times))
+              (setq res (vconcat res key))))))
+      (when (and (>= (length res) 4)
+                 (eq (aref res 0) ?\C-x)
+                 (eq (aref res 1) ?\()
+                 (eq (aref res (- (length res) 2)) ?\C-x)
+                 (eq (aref res (- (length res) 1)) ?\)))
+        (setq res (apply #'vector (let ((lres (append res nil)))
+                                    ;; Remove the first and last two elements.
+                                    (setq lres (cdr (cdr lres)))
+                                    (nreverse lres)
+                                    (setq lres (cdr (cdr lres)))
+                                    (nreverse lres)
+                                    lres))))
+      (if (not (memq nil (mapcar (lambda (ch)
+                                   (and (numberp ch)
+                                        (<= 0 ch 127)))
+                                 res)))
+          ;; Return a string.
+          (concat (mapcar #'identity res))
+        ;; Return a vector.
+        res))))
 
 (defun undefined ()
   "Beep to tell the user this binding is undefined."
@@ -1000,6 +1172,7 @@ Bindings are always added before any inherited map.
 
 The order of bindings in a keymap matters only when it is used as
 a menu, so this function is not useful for non-menu keymaps."
+  (declare (indent defun))
   (unless after (setq after t))
   (or (keymapp keymap)
       (signal 'wrong-type-argument (list 'keymapp keymap)))
@@ -1752,6 +1925,7 @@ be a list of the form returned by `event-start' and 
`event-end'."
 (make-obsolete 'window-redisplay-end-trigger nil "23.1")
 (make-obsolete 'set-window-redisplay-end-trigger nil "23.1")
 (make-obsolete-variable 'operating-system-release nil "28.1")
+(make-obsolete-variable 'inhibit-changing-match-data 'save-match-data "29.1")
 
 (make-obsolete 'run-window-configuration-change-hook nil "27.1")
 
@@ -3035,6 +3209,7 @@ If there is a natural number at point, use it as default."
     (set-keymap-parent map minibuffer-local-map)
 
     (define-key map [remap self-insert-command] 
#'read-char-from-minibuffer-insert-char)
+    (define-key map [remap exit-minibuffer] 
#'read-char-from-minibuffer-insert-other)
 
     (define-key map [remap recenter-top-bottom] 
#'minibuffer-recenter-top-bottom)
     (define-key map [remap scroll-up-command] #'minibuffer-scroll-up-command)
@@ -3152,9 +3327,10 @@ There is no need to explicitly add `help-char' to CHARS;
     (define-key map [remap scroll-other-window] 
#'minibuffer-scroll-other-window)
     (define-key map [remap scroll-other-window-down] 
#'minibuffer-scroll-other-window-down)
 
-    (define-key map [escape] #'abort-recursive-edit)
-    (dolist (symbol '(quit exit exit-prefix))
+    (define-key map [remap exit] #'y-or-n-p-insert-other)
+    (dolist (symbol '(exit-prefix quit))
       (define-key map (vector 'remap symbol) #'abort-recursive-edit))
+    (define-key map [escape] #'abort-recursive-edit)
 
     ;; FIXME: try catch-all instead of explicit bindings:
     ;; (define-key map [remap t] #'y-or-n-p-insert-other)
@@ -3366,6 +3542,29 @@ user can undo the change normally."
             (accept-change-group ,handle)
           (cancel-change-group ,handle))))))
 
+(defmacro with-undo-amalgamate (&rest body)
+  "Like `progn' but perform BODY with amalgamated undo barriers.
+
+This allows multiple operations to be undone in a single step.
+When undo is disabled this behaves like `progn'."
+  (declare (indent 0) (debug t))
+  (let ((handle (make-symbol "--change-group-handle--")))
+    `(let ((,handle (prepare-change-group))
+           ;; Don't truncate any undo data in the middle of this,
+           ;; otherwise Emacs might truncate part of the resulting
+           ;; undo step: we want to mimic the behavior we'd get if the
+           ;; undo-boundaries were never added in the first place.
+           (undo-outer-limit nil)
+           (undo-limit most-positive-fixnum)
+           (undo-strong-limit most-positive-fixnum))
+       (unwind-protect
+           (progn
+             (activate-change-group ,handle)
+             ,@body)
+         (progn
+           (accept-change-group ,handle)
+           (undo-amalgamate-change-group ,handle))))))
+
 (defun prepare-change-group (&optional buffer)
   "Return a handle for the current buffer's state, for a change group.
 If you specify BUFFER, make a handle for BUFFER's state instead.
@@ -3565,6 +3764,9 @@ If either NAME or VAL are specified, both should be 
specified."
 (defvar suspend-resume-hook nil
   "Normal hook run by `suspend-emacs', after Emacs is continued.")
 
+(defvar after-pdump-load-hook nil
+  "Normal hook run after loading the .pdmp file.")
+
 (defvar temp-buffer-show-hook nil
   "Normal hook run by `with-output-to-temp-buffer' after displaying the buffer.
 When the hook runs, the temporary buffer is current, and the window it
@@ -4384,11 +4586,6 @@ is allowed once again.  (Immediately, if `inhibit-quit' 
is nil.)"
           ;; that intends to handle the quit signal next time.
           (eval '(ignore nil)))))
 
-;; Don't throw `throw-on-input' on those events by default.
-(setq while-no-input-ignore-events
-      '(focus-in focus-out help-echo iconify-frame
-        make-frame-visible selection-request))
-
 (defmacro while-no-input (&rest body)
   "Execute BODY only as long as there's no pending input.
 If input arrives, that ends the execution of BODY,
@@ -4636,6 +4833,7 @@ If `default-directory' is already an existing directory, 
it's not changed."
                                              (file-exists-p dir)))
                                       (list default-directory
                                             (expand-file-name "~/")
+                                            temporary-file-directory
                                             (getenv "TMPDIR")
                                             "/tmp/")
                                       "/")))
@@ -4760,14 +4958,12 @@ wherever possible, since it is slow."
 (defsubst looking-at-p (regexp)
   "\
 Same as `looking-at' except this function does not change the match data."
-  (let ((inhibit-changing-match-data t))
-    (looking-at regexp)))
+  (looking-at regexp t))
 
 (defsubst string-match-p (regexp string &optional start)
   "\
 Same as `string-match' except this function does not change the match data."
-  (let ((inhibit-changing-match-data t))
-    (string-match regexp string start)))
+  (string-match regexp string start t))
 
 (defun subregexp-context-p (regexp pos &optional start)
   "Return non-nil if POS is in a normal subregexp context in REGEXP.
@@ -5572,6 +5768,7 @@ If HOOKVAR is nil, `mail-send-hook' is used.
 
 The properties used on SYMBOL are `composefunc', `sendfunc',
 `abortfunc', and `hookvar'."
+  (declare (indent defun))
   (put symbol 'composefunc composefunc)
   (put symbol 'sendfunc sendfunc)
   (put symbol 'abortfunc (or abortfunc #'kill-buffer))
@@ -6418,17 +6615,29 @@ seconds."
 This is intended for very simple filling while bootstrapping
 Emacs itself, and does not support all the customization options
 of fill.el (for example `fill-region')."
-  (if (< (string-width str) fill-column)
+  (if (< (length str) fill-column)
       str
-    (let ((fst (substring str 0 fill-column))
-          (lst (substring str fill-column)))
-      (if (string-match ".*\\( \\(.+\\)\\)$" fst)
-          (setq fst (replace-match "\n\\2" nil nil fst 1)))
+    (let* ((limit (min fill-column (length str)))
+           (fst (substring str 0 limit))
+           (lst (substring str limit)))
+      (cond ((string-match "\\( \\)$" fst)
+             (setq fst (replace-match "\n" nil nil fst 1)))
+            ((string-match "^ \\(.*\\)" lst)
+             (setq fst (concat fst "\n"))
+             (setq lst (match-string 1 lst)))
+            ((string-match ".*\\( \\(.+\\)\\)$" fst)
+             (setq lst (concat (match-string 2 fst) lst))
+             (setq fst (replace-match "\n" nil nil fst 1))))
       (concat fst (internal--fill-string-single-line lst)))))
 
 (defun internal--format-docstring-line (string &rest objects)
-  "Format a documentation string out of STRING and OBJECTS.
-This is intended for internal use only."
+  "Format a single line from a documentation string out of STRING and OBJECTS.
+Signal an error if STRING contains a newline.
+This is intended for internal use only.  Avoid using this for the
+first line of a docstring; the first line should be a complete
+sentence (see Info node `(elisp) Documentation Tips')."
+  (when (string-match "\n" string)
+    (error "Unable to fill string containing newline: %S" string))
   (internal--fill-string-single-line (apply #'format string objects)))
 
 (defun json-available-p ()
@@ -6447,4 +6656,125 @@ not a list, return a one-element list containing 
OBJECT."
       object
     (list object)))
 
+(defun define-keymap (&rest definitions)
+  "Create a new keymap and define KEY/DEFEFINITION pairs as key sequences.
+The new keymap is returned.
+
+Options can be given as keywords before the KEY/DEFEFINITION
+pairs.  Available keywords are:
+
+:full      If non-nil, create a chartable alist (see `make-keymap').
+             If nil (i.e., the default), create a sparse keymap (see
+             `make-sparse-keymap').
+
+:suppress  If non-nil, the keymap will be suppressed (see `suppress-keymap').
+             If `nodigits', treat digits like other chars.
+
+:parent    If non-nil, this should be a keymap to use as the parent
+             (see `set-keymap-parent').
+
+:keymap    If non-nil, instead of creating a new keymap, the given keymap
+             will be destructively modified instead.
+
+:name      If non-nil, this should be a string to use as the menu for
+             the keymap in case you use it as a menu with `x-popup-menu'.
+
+:prefix    If non-nil, this should be a symbol to be used as a prefix
+             command (see `define-prefix-command').  If this is the case,
+             this symbol is returned instead of the map itself.
+
+KEY/DEFINITION pairs are as KEY and DEF in `define-key'.  KEY can
+also be the special symbol `:menu', in which case DEFINITION
+should be a MENU form as accepted by `easy-menu-define'.
+
+\(fn &key FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)"
+  (declare (indent defun))
+  (define-keymap--define definitions))
+
+(defun define-keymap--define (definitions)
+  (let (full suppress parent name prefix keymap)
+    ;; Handle keywords.
+    (while (and definitions
+                (keywordp (car definitions))
+                (not (eq (car definitions) :menu)))
+      (let ((keyword (pop definitions)))
+        (unless definitions
+          (error "Missing keyword value for %s" keyword))
+        (let ((value (pop definitions)))
+          (pcase keyword
+            (:full (setq full value))
+            (:keymap (setq keymap value))
+            (:parent (setq parent value))
+            (:suppress (setq suppress value))
+            (:name (setq name value))
+            (:prefix (setq prefix value))
+            (_ (error "Invalid keyword: %s" keyword))))))
+
+    (when (and prefix
+               (or full parent suppress keymap))
+      (error "A prefix keymap can't be defined with 
:full/:parent/:suppress/:keymap keywords"))
+
+    (when (and keymap full)
+      (error "Invalid combination: :keymap with :full"))
+
+    (let ((keymap (cond
+                   (keymap keymap)
+                   (prefix (define-prefix-command prefix nil name))
+                   (full (make-keymap name))
+                   (t (make-sparse-keymap name)))))
+      (when suppress
+        (suppress-keymap keymap (eq suppress 'nodigits)))
+      (when parent
+        (set-keymap-parent keymap parent))
+
+      ;; Do the bindings.
+      (while definitions
+        (let ((key (pop definitions)))
+          (unless definitions
+            (error "Uneven number of key/definition pairs"))
+          (let ((def (pop definitions)))
+            (if (eq key :menu)
+                (easy-menu-define nil keymap "" def)
+              (define-key keymap key def)))))
+      keymap)))
+
+(defmacro defvar-keymap (variable-name &rest defs)
+  "Define VARIABLE-NAME as a variable with a keymap definition.
+See `define-keymap' for an explanation of the keywords and KEY/DEFINITION.
+
+In addition to the keywords accepted by `define-keymap', this
+macro also accepts a `:doc' keyword, which (if present) is used
+as the variable documentation string.
+
+\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY 
DEFINITION]...)"
+  (declare (indent 1))
+  (let ((opts nil)
+        doc)
+    (while (and defs
+                (keywordp (car defs))
+                (not (eq (car defs) :menu)))
+      (let ((keyword (pop defs)))
+        (unless defs
+          (error "Uneven number of keywords"))
+        (if (eq keyword :doc)
+            (setq doc (pop defs))
+          (push keyword opts)
+          (push (pop defs) opts))))
+    (unless (zerop (% (length defs) 2))
+      (error "Uneven number of key/definition pairs: %s" defs))
+    `(defvar ,variable-name
+       (define-keymap--define (list ,@(nreverse opts) ,@defs))
+       ,@(and doc (list doc)))))
+
+(defmacro with-delayed-message (args &rest body)
+  "Like `progn', but display MESSAGE if BODY takes longer than TIMEOUT seconds.
+The MESSAGE form will be evaluated immediately, but the resulting
+string will be displayed only if BODY takes longer than TIMEOUT seconds.
+
+\(fn (timeout message) &rest body)"
+  (declare (indent 1))
+  `(funcall-with-delayed-message ,(car args) ,(cadr args)
+                                 (lambda ()
+                                   ,@body)))
+
 ;;; subr.el ends here
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index d0a1b3b70b..10f26875db 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -227,6 +227,10 @@ a list of frames to update."
 ;;; Key bindings
 
 (defun tab-bar--key-to-number (key)
+  "Return the tab number represented by KEY.
+If KEY is a symbol 'tab-N', where N is a tab number, the value is N.
+If KEY is \\='current-tab, the value is nil.
+For any other value of KEY, the value is t."
   (cond
    ((null key) t)
    ((eq key 'current-tab) nil)
@@ -235,7 +239,16 @@ a list of frames to update."
         (string-to-number (string-replace "tab-" "" key-name)))))
    (t t)))
 
+(defvar tab-bar--dragging-in-progress)
+
 (defun tab-bar--event-to-item (posn)
+  "This function extracts extra info from the mouse event at position POSN.
+It returns a list of the form (KEY KEY-BINDING CLOSE-P), where:
+ KEY is a symbol representing a tab, such as \\='tab-1 or \\='current-tab;
+ KEY-BINDING is the binding of KEY;
+ CLOSE-P is non-nil if the mouse event was a click on the close button \"x\",
+   nil otherwise."
+  (setq tab-bar--dragging-in-progress nil)
   (if (posn-window posn)
       (let ((caption (car (posn-string posn))))
         (when caption
@@ -259,31 +272,40 @@ a list of frames to update."
                (setq column (+ column (length (nth 1 binding))))))
            keymap))))))
 
-(defun tab-bar-mouse-select-tab (event)
+(defun tab-bar-mouse-down-1 (event)
+  "Select the tab at mouse click, or add a new tab on the tab bar.
+Whether this command adds a new tab or selects an existing tab
+depends on whether the click is on the \"+\" button or on an
+existing tab."
   (interactive "e")
   (let* ((item (tab-bar--event-to-item (event-start event)))
          (tab-number (tab-bar--key-to-number (nth 0 item))))
-    ;; Don't close the tab when clicked on the close button.
-    ;; Let `tab-bar-mouse-close-tab-from-button' do this.
-    (unless (nth 2 item)
+    (setq tab-bar--dragging-in-progress t)
+    ;; Don't close the tab when clicked on the close button.  Also
+    ;; don't add new tab on down-mouse.  Let `tab-bar-mouse-1' do this.
+    (unless (or (eq (car item) 'add-tab) (nth 2 item))
       (if (functionp (nth 1 item))
           (call-interactively (nth 1 item))
         (unless (eq tab-number t)
           (tab-bar-select-tab tab-number))))))
 
-(defun tab-bar-mouse-close-tab-from-button (event)
-  "Close the tab only when clicked on the close button."
+(defun tab-bar-mouse-1 (event)
+  "Close the tab whose \"x\" close button you click.
+See also `tab-bar-mouse-close-tab', which closes the tab
+regardless of where you click on it.  Also add a new tab."
   (interactive "e")
   (let* ((item (tab-bar--event-to-item (event-start event)))
          (tab-number (tab-bar--key-to-number (nth 0 item))))
-    (when (nth 2 item)
-      (unless (eq tab-number t)
-        (tab-bar-close-tab tab-number)))))
+    (cond
+     ((and (eq (car item) 'add-tab) (functionp (nth 1 item)))
+      (call-interactively (nth 1 item)))
+     ((and (nth 2 item) (not (eq tab-number t)))
+      (tab-bar-close-tab tab-number)))))
 
 (defun tab-bar-mouse-close-tab (event)
-  "Close the tab when clicked anywhere on the tab.
-This is in contrast with `tab-bar-mouse-close-tab-from-button'
-that closes only when clicked on the close button."
+  "Close the tab you click on.
+This is in contrast with `tab-bar-mouse-1' that closes a tab
+only when you click on its \"x\" close button."
   (interactive "e")
   (let* ((item (tab-bar--event-to-item (event-start event)))
          (tab-number (tab-bar--key-to-number (nth 0 item))))
@@ -291,6 +313,7 @@ that closes only when clicked on the close button."
       (tab-bar-close-tab tab-number))))
 
 (defun tab-bar-mouse-context-menu (event)
+  "Pop up the context menu for the tab on which you click."
   (interactive "e")
   (let* ((item (tab-bar--event-to-item (event-start event)))
          (tab-number (tab-bar--key-to-number (nth 0 item)))
@@ -311,7 +334,12 @@ that closes only when clicked on the close button."
         `(menu-item "Duplicate" (lambda () (interactive)
                                   (tab-bar-duplicate-tab
                                    nil ,tab-number))
-                    :help "Duplicate the tab"))
+                    :help "Clone the tab"))
+      (define-key-after menu [detach-tab]
+        `(menu-item "Detach" (lambda () (interactive)
+                               (tab-bar-detach-tab
+                                ,tab-number))
+                    :help "Move the tab to new frame"))
       (define-key-after menu [close]
         `(menu-item "Close" (lambda () (interactive)
                               (tab-bar-close-tab ,tab-number))
@@ -325,23 +353,28 @@ that closes only when clicked on the close button."
     (popup-menu menu event)))
 
 (defun tab-bar-mouse-move-tab (event)
+  "Move a tab to a different position on the tab bar.
+This command should be bound to a drag event.  It moves the tab
+at the mouse-down event to the position at mouse-up event."
   (interactive "e")
+  (setq tab-bar--dragging-in-progress nil)
   (let ((from (tab-bar--key-to-number
                (nth 0 (tab-bar--event-to-item
                        (event-start event)))))
         (to (tab-bar--key-to-number
              (nth 0 (tab-bar--event-to-item
                      (event-end event))))))
-    (unless (or (eq from t) (eq to t))
-      (tab-bar-move-tab-to to from))))
+    (unless (or (eq from to) (eq from t) (eq to t))
+      (tab-bar-move-tab-to
+       (if (null to) (1+ (tab-bar--current-tab-index)) to) from))))
 
 (defvar tab-bar-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [down-mouse-1] 'tab-bar-mouse-select-tab)
+    (define-key map [down-mouse-1] 'tab-bar-mouse-down-1)
     (define-key map [drag-mouse-1] 'tab-bar-mouse-move-tab)
-    (define-key map [mouse-1] 'tab-bar-mouse-close-tab-from-button)
+    (define-key map [mouse-1]      'tab-bar-mouse-1)
     (define-key map [down-mouse-2] 'tab-bar-mouse-close-tab)
-    (define-key map [mouse-2] 'ignore)
+    (define-key map [mouse-2]      'ignore)
     (define-key map [down-mouse-3] 'tab-bar-mouse-context-menu)
 
     (define-key map [mouse-4]     'tab-previous)
@@ -672,14 +705,22 @@ the formatted tab name to display in the tab bar."
   "Template for displaying tab bar items.
 Every item in the list is a function that returns
 a string, or a list of menu-item elements, or nil.
-When you add more items `tab-bar-format-align-right' and
-`tab-bar-format-global' to the end, then after enabling
-`display-time-mode' (or any other mode that uses `global-mode-string')
-it will display time aligned to the right on the tab bar instead of
-the mode line.  Replacing `tab-bar-format-tabs' with
+Adding a function to the list causes the tab bar to show
+that string, or display a tab button which, when clicked,
+will invoke the command that is the binding of the menu item.
+The menu-item binding of nil will produce a tab clicking
+on which will select that tab.  The menu-item's title is
+displayed as the label of the tab.
+If a function returns nil, it doesn't directly affect the
+tab bar appearance, but can do that by some side-effect.
+If the list ends with `tab-bar-format-align-right' and
+`tab-bar-format-global', then after enabling `display-time-mode'
+(or any other mode that uses `global-mode-string'),
+it will display time aligned to the right on the tab bar instead
+of the mode line.  Replacing `tab-bar-format-tabs' with
 `tab-bar-format-tabs-groups' will group tabs on the tab bar."
   :type 'hook
-  :options '(tab-bar-format-menu-global
+  :options '(tab-bar-format-menu-bar
              tab-bar-format-history
              tab-bar-format-tabs
              tab-bar-format-tabs-groups
@@ -694,25 +735,27 @@ the mode line.  Replacing `tab-bar-format-tabs' with
   :group 'tab-bar
   :version "28.1")
 
-(defun tab-bar-format-menu-global ()
-  "Show global menu on clicking the Menu button."
-  `((add-tab menu-item (propertize "Menu" 'face 'tab-bar-tab-inactive)
-             (lambda (event) (interactive "e")
-               (let ((menu (make-sparse-keymap
-                            (propertize "Global Menu" 'hide t))))
-
-                 (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
-                 (map-keymap (lambda (key binding)
-                               (when (consp binding)
-                                 (define-key-after menu (vector key)
-                                   (copy-sequence binding))))
-                             (lookup-key global-map [menu-bar]))
+(defun tab-bar-menu-bar (event)
+  "Pop up the same menu as displayed by the menu bar.
+Used by `tab-bar-format-menu-bar'."
+  (interactive "e")
+  (let ((menu (make-sparse-keymap (propertize "Menu Bar" 'hide t))))
+    (run-hooks 'activate-menubar-hook 'menu-bar-update-hook)
+    (map-keymap (lambda (key binding)
+                  (when (consp binding)
+                    (define-key-after menu (vector key)
+                      (copy-sequence binding))))
+                (menu-bar-keymap))
+    (popup-menu menu event)))
 
-                 (popup-menu menu event)))
-             :help "Global Menu")))
+(defun tab-bar-format-menu-bar ()
+  "Produce the Menu button for the tab bar that shows the menu bar."
+  `((menu-bar menu-item (propertize "Menu" 'face 'tab-bar-tab-inactive)
+     tab-bar-menu-bar :help "Menu Bar")))
 
 (defun tab-bar-format-history ()
-  "Show back and forward buttons when `tab-bar-history-mode' is enabled.
+  "Produce back and forward buttons for the tab bar.
+These buttons will be shown when `tab-bar-history-mode' is enabled.
 You can hide these buttons by customizing `tab-bar-format' and removing
 `tab-bar-format-history' from it."
   (when tab-bar-history-mode
@@ -726,7 +769,7 @@ You can hide these buttons by customizing `tab-bar-format' 
and removing
        :help "Click to go forward in tab history"))))
 
 (defun tab-bar--format-tab (tab i)
-  "Format TAB using its index I and return the result as a string."
+  "Format TAB using its index I and return the result as a keymap."
   (append
    `((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore))
    (cond
@@ -748,7 +791,7 @@ You can hide these buttons by customizing `tab-bar-format' 
and removing
         ,(alist-get 'close-binding tab))))))
 
 (defun tab-bar-format-tabs ()
-  "Show all tabs."
+  "Produce all the tabs for the tab bar."
   (let ((i 0))
     (mapcan
      (lambda (tab)
@@ -802,6 +845,9 @@ Function gets one argument: a tab."
     (tab-bar-tab-face-default tab)))
 
 (defun tab-bar--format-tab-group (tab i &optional current-p)
+  "Format TAB as a tab that represents a group of tabs.
+The argument I is the tab index, and CURRENT-P is non-nil
+when the tab is current.  Return the result as a keymap."
   (append
    `((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore))
    `((,(intern (format "group-%i" i))
@@ -819,7 +865,7 @@ Function gets one argument: a tab."
       :help "Click to visit group"))))
 
 (defun tab-bar-format-tabs-groups ()
-  "Show tabs with their groups."
+  "Produce tabs for the tab bar grouped according to their groups."
   (let* ((tabs (funcall tab-bar-tabs-function))
          (current-group (funcall tab-bar-tab-group-function
                                  (tab-bar--current-tab-find tabs)))
@@ -863,7 +909,7 @@ Function gets one argument: a tab."
     `((align-right menu-item ,str ignore))))
 
 (defun tab-bar-format-global ()
-  "Format `global-mode-string' to display it in the tab bar.
+  "Produce display of `global-mode-string' in the tab bar.
 When `tab-bar-format-global' is added to `tab-bar-format'
 (possibly appended after `tab-bar-format-align-right'),
 then modes that display information on the mode line
@@ -912,6 +958,7 @@ on the tab bar instead."
 (push '(tabs . frameset-filter-tabs) frameset-filter-alist)
 
 (defun tab-bar--tab (&optional frame)
+  "Make a new tab data structure that can be added to tabs on the FRAME."
   (let* ((tab (tab-bar--current-tab-find nil frame))
          (tab-explicit-name (alist-get 'explicit-name tab))
          (tab-group (alist-get 'group tab))
@@ -946,12 +993,15 @@ on the tab bar instead."
                 (cdr tab)))))
 
 (defun tab-bar--current-tab (&optional tab frame)
+  "Make the current tab data structure from TAB on FRAME."
   (tab-bar--current-tab-make (or tab (tab-bar--current-tab-find nil frame))))
 
 (defun tab-bar--current-tab-make (&optional tab)
-  ;; `tab' here is an argument meaning "use tab as template".  This is
-  ;; necessary when switching tabs, otherwise the destination tab
-  ;; inherits the current tab's `explicit-name' parameter.
+  "Make the current tab data structure from TAB.
+TAB here is an argument meaning \"use tab as template\",
+i.e. the tab is created using data from TAB.  This is
+necessary when switching tabs, otherwise the destination tab
+inherits the current tab's `explicit-name' parameter."
   (let* ((tab-explicit-name (alist-get 'explicit-name tab))
          (tab-group (if tab
                         (alist-get 'group tab)
@@ -974,27 +1024,33 @@ on the tab bar instead."
                 (cdr tab)))))
 
 (defun tab-bar--current-tab-find (&optional tabs frame)
+  ;; Find the current tab as a pointer to its data structure.
   (assq 'current-tab (or tabs (funcall tab-bar-tabs-function frame))))
 
 (defun tab-bar--current-tab-index (&optional tabs frame)
+  ;; Return the index of the current tab.
   (seq-position (or tabs (funcall tab-bar-tabs-function frame))
                 'current-tab (lambda (a b) (eq (car a) b))))
 
 (defun tab-bar--tab-index (tab &optional tabs frame)
+  ;; Return the index of TAB.
   (seq-position (or tabs (funcall tab-bar-tabs-function frame))
                 tab #'eq))
 
 (defun tab-bar--tab-index-by-name (name &optional tabs frame)
+  ;; Return the index of TAB by the its NAME.
   (seq-position (or tabs (funcall tab-bar-tabs-function frame))
                 name (lambda (a b) (equal (alist-get 'name a) b))))
 
 (defun tab-bar--tab-index-recent (nth &optional tabs frame)
+  ;; Return the index of NTH recent tab.
   (let* ((tabs (or tabs (funcall tab-bar-tabs-function frame)))
          (sorted-tabs (tab-bar--tabs-recent tabs frame))
          (tab (nth (1- nth) sorted-tabs)))
     (tab-bar--tab-index tab tabs)))
 
 (defun tab-bar--tabs-recent (&optional tabs frame)
+  ;; Return the list of tabs sorted by recency.
   (let* ((tabs (or tabs (funcall tab-bar-tabs-function frame))))
     (seq-sort-by (lambda (tab) (alist-get 'time tab)) #'>
                  (seq-remove (lambda (tab)
@@ -1007,7 +1063,8 @@ on the tab bar instead."
 When this command is bound to a numeric key (with a prefix or modifier key
 using `tab-bar-select-tab-modifiers'), calling it without an argument
 will translate its bound numeric key to the numeric argument.
-TAB-NUMBER counts from 1.  Negative TAB-NUMBER counts tabs from the end of the 
tab bar."
+TAB-NUMBER counts from 1.  Negative TAB-NUMBER counts tabs from the end of
+the tab bar."
   (interactive "P")
   (unless (integerp tab-number)
     (let ((key (event-basic-type last-command-event)))
@@ -1083,7 +1140,8 @@ TAB-NUMBER counts from 1.  Negative TAB-NUMBER counts 
tabs from the end of the t
       (force-mode-line-update))))
 
 (defun tab-bar-switch-to-next-tab (&optional arg)
-  "Switch to ARGth next tab."
+  "Switch to ARGth next tab.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (unless (integerp arg)
     (setq arg 1))
@@ -1093,20 +1151,24 @@ TAB-NUMBER counts from 1.  Negative TAB-NUMBER counts 
tabs from the end of the t
     (tab-bar-select-tab (1+ to-index))))
 
 (defun tab-bar-switch-to-prev-tab (&optional arg)
-  "Switch to ARGth previous tab."
+  "Switch to ARGth previous tab.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (unless (integerp arg)
     (setq arg 1))
   (tab-bar-switch-to-next-tab (- arg)))
 
 (defun tab-bar-switch-to-last-tab (&optional arg)
-  "Switch to the last tab or ARGth tab from the end of the tab bar."
+  "Switch to the last tab or ARGth tab from the end of the tab bar.
+Interactively, ARG is the prefix numeric argument; it defaults to 1,
+which means the last tab on the tab bar."
   (interactive "p")
   (tab-bar-select-tab (- (length (funcall tab-bar-tabs-function))
                          (1- (or arg 1)))))
 
 (defun tab-bar-switch-to-recent-tab (&optional arg)
-  "Switch to ARGth most recently visited tab."
+  "Switch to ARGth most recently visited tab.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (unless (integerp arg)
     (setq arg 1))
@@ -1154,8 +1216,9 @@ where argument addressing is relative."
 
 (defun tab-bar-move-tab (&optional arg)
   "Move the current tab ARG positions to the right.
-If a negative ARG, move the current tab ARG positions to the left.
-Argument addressing is relative in contrast to `tab-bar-move-tab-to'
+Interactively, ARG is the prefix numeric argument and defaults to 1.
+If ARG is negative, move the current tab ARG positions to the left.
+Argument addressing is relative in contrast to `tab-bar-move-tab-to',
 where argument addressing is absolute."
   (interactive "p")
   (let* ((tabs (funcall tab-bar-tabs-function))
@@ -1165,6 +1228,7 @@ where argument addressing is absolute."
 
 (defun tab-bar-move-tab-backward (&optional arg)
   "Move the current tab ARG positions to the left.
+Interactively, ARG is the prefix numeric argument and defaults to 1.
 Like `tab-bar-move-tab', but moves in the opposite direction."
   (interactive "p")
   (tab-bar-move-tab (- (or arg 1))))
@@ -1175,7 +1239,8 @@ FROM-NUMBER defaults to the current tab number.
 FROM-NUMBER and TO-NUMBER count from 1.
 FROM-FRAME specifies the source frame and defaults to the selected frame.
 TO-FRAME specifies the target frame and defaults the next frame.
-Interactively, ARG selects the ARGth different frame to move to."
+Interactively, ARG selects the ARGth next frame on the same terminal,
+to which to move the tab; ARG defaults to 1."
   (interactive "P")
   (unless from-frame
     (setq from-frame (selected-frame)))
@@ -1195,24 +1260,52 @@ Interactively, ARG selects the ARGth different frame to 
move to."
                   (nthcdr to-index to-tabs))
       (with-selected-frame from-frame
         (let ((inhibit-message t) ; avoid message about deleted tab
+              (tab-bar-close-last-tab-choice 'delete-frame)
               tab-bar-closed-tabs)
           (tab-bar-close-tab from-number)))
       (tab-bar-tabs-set to-tabs to-frame)
       (force-mode-line-update t))))
 
+(defun tab-bar-detach-tab (&optional from-number)
+  "Move tab number FROM-NUMBER to a new frame.
+FROM-NUMBER defaults to the current tab (which happens interactively)."
+  (interactive (list (1+ (tab-bar--current-tab-index))))
+  (let* ((tabs (funcall tab-bar-tabs-function))
+         (tab-index (1- (or from-number (1+ (tab-bar--current-tab-index 
tabs)))))
+         (tab-name (alist-get 'name (nth tab-index tabs)))
+         ;; On some window managers, `make-frame' selects the new frame,
+         ;; so previously selected frame is saved to `from-frame'.
+         (from-frame (selected-frame))
+         (new-frame (make-frame `((name . ,tab-name)))))
+    (tab-bar-move-tab-to-frame nil from-frame from-number new-frame nil)
+    (with-selected-frame new-frame
+      (tab-bar-close-tab))))
+
+(defun tab-bar-move-window-to-tab ()
+  "Move the selected window to a new tab.
+This command removes the selected window from the configuration stored
+on the current tab, and makes a new tab with that window in its
+configuration."
+  (interactive)
+  (let ((tab-bar-new-tab-choice 'window))
+    (tab-bar-new-tab))
+  (tab-bar-switch-to-recent-tab)
+  (delete-window)
+  (tab-bar-switch-to-recent-tab))
+
 
 (defcustom tab-bar-new-tab-to 'right
-  "Defines where to create a new tab.
+  "Where to create a new tab.
 If `leftmost', create as the first tab.
-If `left', create to the left from the current tab.
-If `right', create to the right from the current tab.
+If `left', create to the left of the current tab.
+If `right', create to the right of the current tab.
 If `rightmost', create as the last tab.
 If the value is a function, it should return a number as a position
-on the tab bar specifying where to insert a new tab."
-  :type '(choice (const :tag "First tab" leftmost)
-                 (const :tag "To the left" left)
-                 (const :tag "To the right" right)
-                 (const :tag "Last tab" rightmost)
+on the tab bar specifying where to add a new tab."
+  :type '(choice (const :tag "Add as First" leftmost)
+                 (const :tag "Add to Left" left)
+                 (const :tag "Add to Right" right)
+                 (const :tag "Add as Last" rightmost)
                  (function :tag "Function"))
   :group 'tab-bar
   :version "27.1")
@@ -1231,7 +1324,7 @@ TAB-NUMBER counts from 1.  If no TAB-NUMBER is specified, 
then add
 a new tab at the position specified by `tab-bar-new-tab-to'.
 Negative TAB-NUMBER counts tabs from the end of the tab bar,
 and -1 means the new tab will become the last one.
-Argument addressing is absolute in contrast to `tab-bar-new-tab'
+Argument addressing is absolute in contrast to `tab-bar-new-tab',
 where argument addressing is relative.
 After the tab is created, the hooks in
 `tab-bar-tab-post-open-functions' are run."
@@ -1244,10 +1337,12 @@ After the tab is created, the hooks in
       ;; Handle the case when it's called in the active minibuffer.
       (when (minibuffer-selected-window)
         (select-window (minibuffer-selected-window)))
-      (delete-other-windows)
-      ;; Create a new window to get rid of old window parameters
-      ;; (e.g. prev/next buffers) of old window.
-      (split-window) (delete-window)
+      (let ((ignore-window-parameters t))
+        (delete-other-windows))
+      (unless (eq tab-bar-new-tab-choice 'window)
+        ;; Create a new window to get rid of old window parameters
+        ;; (e.g. prev/next buffers) of old window.
+        (split-window) (delete-window))
       (let ((buffer
              (if (functionp tab-bar-new-tab-choice)
                  (funcall tab-bar-new-tab-choice)
@@ -1302,7 +1397,7 @@ If a negative ARG, create a new tab ARG positions to the 
left.
 If ARG is zero, create a new tab in place of the current tab.
 If no ARG is specified, then add a new tab at the position
 specified by `tab-bar-new-tab-to'.
-Argument addressing is relative in contrast to `tab-bar-new-tab-to'
+Argument addressing is relative in contrast to `tab-bar-new-tab-to',
 where argument addressing is absolute.
 If FROM-NUMBER is a tab number, a new tab is created from that tab."
   (interactive "P")
@@ -1317,7 +1412,7 @@ If FROM-NUMBER is a tab number, a new tab is created from 
that tab."
     (tab-bar-new-tab-to)))
 
 (defun tab-bar-duplicate-tab (&optional arg from-number)
-  "Duplicate the current tab to ARG positions to the right.
+  "Clone the current tab to ARG positions to the right.
 ARG and FROM-NUMBER have the same meaning as in `tab-bar-new-tab'."
   (interactive "P")
   (let ((tab-bar-new-tab-choice nil)
@@ -1329,7 +1424,7 @@ ARG and FROM-NUMBER have the same meaning as in 
`tab-bar-new-tab'."
   "A list of closed tabs to be able to undo their closing.")
 
 (defcustom tab-bar-close-tab-select 'recent
-  "Defines what tab to select after closing the specified tab.
+  "Which tab to make current after closing the specified tab.
 If `left', select the adjacent left tab.
 If `right', select the adjacent right tab.
 If `recent', select the most recently visited tab."
@@ -1340,7 +1435,7 @@ If `recent', select the most recently visited tab."
   :version "27.1")
 
 (defcustom tab-bar-close-last-tab-choice nil
-  "Defines what to do when the last tab is closed.
+  "What to do when the last tab is closed.
 If nil, do nothing and show a message, like closing the last window or frame.
 If `delete-frame', delete the containing frame, as a web browser would do.
 If `tab-bar-mode-disable', disable `tab-bar-mode' so that tabs no longer show
@@ -1365,9 +1460,8 @@ function returns a non-nil value, the tab will not be 
closed."
 
 (defcustom tab-bar-tab-pre-close-functions nil
   "List of functions to call before closing a tab.
-The tab to be closed and a boolean indicating whether or not it
-is the only tab in the frame are supplied as arguments,
-respectively."
+Each function is called with two arguments: the tab to be closed
+and a boolean indicating whether or not it is the only tab on its frame."
   :type '(repeat function)
   :group 'tab-bar
   :version "27.1")
@@ -1376,6 +1470,7 @@ respectively."
   "Close the tab specified by its absolute position TAB-NUMBER.
 If no TAB-NUMBER is specified, then close the current tab and switch
 to the tab specified by `tab-bar-close-tab-select'.
+Interactively, TAB-NUMBER is the prefix numeric argument, and defaults to 1.
 TAB-NUMBER counts from 1.
 Optional TO-NUMBER could be specified to override the value of
 `tab-bar-close-tab-select' programmatically with a position
@@ -1449,7 +1544,8 @@ for the last tab on a frame is determined by
           (message "Deleted tab and switched to %s" 
tab-bar-close-tab-select))))))
 
 (defun tab-bar-close-tab-by-name (name)
-  "Close the tab by NAME."
+  "Close the tab given its NAME.
+Interactively, prompt for NAME."
   (interactive
    (list (completing-read "Close tab by name: "
                           (mapcar (lambda (tab)
@@ -1458,8 +1554,9 @@ for the last tab on a frame is determined by
   (tab-bar-close-tab (1+ (tab-bar--tab-index-by-name name))))
 
 (defun tab-bar-close-other-tabs (&optional tab-number)
-  "Close all tabs on the selected frame, except TAB-NUMBER.
-TAB-NUMBER counts from 1 and defaults to the current tab."
+  "Close all tabs on the selected frame, except the tab TAB-NUMBER.
+TAB-NUMBER counts from 1 and defaults to the current tab (which
+happens interactively)."
   (interactive)
   (let* ((tabs (funcall tab-bar-tabs-function))
          (current-index (tab-bar--current-tab-index tabs))
@@ -1525,9 +1622,12 @@ TAB-NUMBER counts from 1 and defaults to the current 
tab."
 
 
 (defun tab-bar-rename-tab (name &optional tab-number)
-  "Rename the tab specified by its absolute position TAB-NUMBER.
+  "Give the tab specified by its absolute position TAB-NUMBER a new NAME.
 If no TAB-NUMBER is specified, then rename the current tab.
+Interactively, TAB-NUMBER is the prefix numeric argument, and defaults
+to the current tab.
 TAB-NUMBER counts from 1.
+Interactively, prompt for the new NAME.
 If NAME is the empty string, then use the automatic name
 function `tab-bar-tab-name-function'."
   (interactive
@@ -1555,7 +1655,8 @@ function `tab-bar-tab-name-function'."
       (message "Renamed tab to '%s'" tab-new-name))))
 
 (defun tab-bar-rename-tab-by-name (tab-name new-name)
-  "Rename the tab named TAB-NAME.
+  "Rename the tab named TAB-NAME to NEW-NAME.
+Interactively, prompt for TAB-NAME and NEW-NAME.
 If NEW-NAME is the empty string, then use the automatic name
 function `tab-bar-tab-name-function'."
   (interactive
@@ -1572,7 +1673,7 @@ function `tab-bar-tab-name-function'."
 ;;; Tab groups
 
 (defun tab-bar-move-tab-to-group (&optional tab)
-  "Relocate TAB (or the current tab) closer to its group."
+  "Relocate TAB (by default, the current tab) closer to its group."
   (interactive)
   (let* ((tabs (funcall tab-bar-tabs-function))
          (tab (or tab (tab-bar--current-tab-find tabs)))
@@ -1610,6 +1711,8 @@ The current tab is supplied as an argument."
 (defun tab-bar-change-tab-group (group-name &optional tab-number)
   "Add the tab specified by its absolute position TAB-NUMBER to GROUP-NAME.
 If no TAB-NUMBER is specified, then set the GROUP-NAME for the current tab.
+Interactively, TAB-NUMBER is the prefix numeric argument, and the command
+prompts for GROUP-NAME.
 TAB-NUMBER counts from 1.
 If GROUP-NAME is the empty string, then remove the tab from any group.
 While using this command, you might also want to replace
@@ -1647,7 +1750,8 @@ While using this command, you might also want to replace
       (message "Set tab group to '%s'" group-new-name))))
 
 (defun tab-bar-close-group-tabs (group-name)
-  "Close all tabs that belong to GROUP-NAME on the selected frame."
+  "Close all tabs that belong to GROUP-NAME on the selected frame.
+Interactively, prompt for GROUP-NAME."
   (interactive
    (let ((group-name (funcall tab-bar-tab-group-function
                               (tab-bar--current-tab-find))))
@@ -1694,7 +1798,7 @@ While using this command, you might also want to replace
 
 (defun tab-bar--history-pre-change ()
   (setq tab-bar-history-old-minibuffer-depth (minibuffer-depth))
-  ;; Store wc before possibly entering the minibuffer
+  ;; Store window-configuration before possibly entering the minibuffer.
   (when (zerop tab-bar-history-old-minibuffer-depth)
     (setq tab-bar-history-old
           `((wc . ,(current-window-configuration))
@@ -1703,7 +1807,8 @@ While using this command, you might also want to replace
 (defun tab-bar--history-change ()
   (when (and (not tab-bar-history-omit)
              tab-bar-history-old
-             ;; Store wc before possibly entering the minibuffer
+             ;; Store window-configuration before possibly entering
+             ;; the minibuffer.
              (zerop tab-bar-history-old-minibuffer-depth))
     (puthash (selected-frame)
              (seq-take (cons tab-bar-history-old
@@ -1895,20 +2000,24 @@ Letters do not insert themselves; instead, they are 
commands.
           nil))))
 
 (defun tab-switcher-next-line (&optional arg)
+  "Move to ARGth next line in the list of tabs.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (forward-line arg)
   (beginning-of-line)
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-prev-line (&optional arg)
+  "Move to ARGth previous line in the list of tabs.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (forward-line (- arg))
   (beginning-of-line)
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-unmark (&optional backup)
-  "Cancel all requested operations on window configuration on this line and 
move down.
-Optional prefix arg means move up."
+  "Cancel requested operations on window configuration on this line and move 
down.
+With prefix arg, move up instead."
   (interactive "P")
   (beginning-of-line)
   (move-to-column tab-switcher-column)
@@ -1919,7 +2028,7 @@ Optional prefix arg means move up."
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-backup-unmark ()
-  "Move up and cancel all requested operations on window configuration on line 
above."
+  "Move up one line and cancel requested operations on window configuration 
there."
   (interactive)
   (forward-line -1)
   (tab-switcher-unmark)
@@ -1928,7 +2037,7 @@ Optional prefix arg means move up."
 
 (defun tab-switcher-delete (&optional arg)
   "Mark window configuration on this line to be deleted by 
\\<tab-switcher-mode-map>\\[tab-switcher-execute] command.
-Prefix arg is how many window configurations to delete.
+Prefix arg says how many window configurations to delete.
 Negative arg means delete backwards."
   (interactive "p")
   (let ((buffer-read-only nil))
@@ -1953,7 +2062,7 @@ Then move up one line.  Prefix arg means move that many 
lines."
   (tab-switcher-delete (- (or arg 1))))
 
 (defun tab-switcher-delete-from-list (tab)
-  "Delete the window configuration from both lists."
+  "Delete the window configuration from the list of tabs."
   (push `((frame . ,(selected-frame))
           (index . ,(tab-bar--tab-index tab))
           (tab . ,tab))
@@ -1981,8 +2090,8 @@ Then move up one line.  Prefix arg means move that many 
lines."
 
 (defun tab-switcher-select ()
   "Select this line's window configuration.
-This command deletes and replaces all the previously existing windows
-in the selected frame."
+This command replaces all the existing windows in the selected frame
+with those specified by the selected window configuration."
   (interactive)
   (let* ((to-tab (tab-switcher-current-tab t)))
     (kill-buffer (current-buffer))
@@ -2008,8 +2117,8 @@ in the selected frame."
    (t (list (selected-frame)))))
 
 (defun tab-bar-get-buffer-tab (buffer-or-name &optional all-frames 
ignore-current-tab)
-  "Return a tab owning a window whose buffer is BUFFER-OR-NAME.
-BUFFER-OR-NAME may be a buffer or a buffer name and defaults to
+  "Return the tab that owns the window whose buffer is BUFFER-OR-NAME.
+BUFFER-OR-NAME may be a buffer or a buffer name, and defaults to
 the current buffer.
 
 The optional argument ALL-FRAMES specifies the frames to consider:
@@ -2057,7 +2166,7 @@ Otherwise, prefer buffers of the current tab."
        (tab-bar--reusable-frames all-frames)))))
 
 (defun display-buffer-in-tab (buffer alist)
-  "Display BUFFER in a tab.
+  "Display BUFFER in a tab using display actions in ALIST.
 ALIST is an association list of action symbols and values.  See
 Info node `(elisp) Buffer Display Action Alists' for details of
 such alists.
@@ -2065,8 +2174,8 @@ such alists.
 If ALIST contains a `tab-name' entry, it creates a new tab with that name and
 displays BUFFER in a new tab.  If a tab with this name already exists, it
 switches to that tab before displaying BUFFER.  The `tab-name' entry can be
-a function, then it is called with two arguments: BUFFER and ALIST, and
-should return the tab name.  When a `tab-name' entry is omitted, create
+a function, in which case it is called with two arguments: BUFFER and ALIST,
+and should return the tab name.  When a `tab-name' entry is omitted, create
 a new tab without an explicit name.
 
 The ALIST entry `tab-group' (string or function) defines the tab group.
@@ -2116,7 +2225,7 @@ indirectly called by the latter."
           (display-buffer-in-new-tab buffer alist))))))
 
 (defun display-buffer-in-new-tab (buffer alist)
-  "Display BUFFER in a new tab.
+  "Display BUFFER in a new tab using display actions in ALIST.
 ALIST is an association list of action symbols and values.  See
 Info node `(elisp) Buffer Display Action Alists' for details of
 such alists.
@@ -2126,9 +2235,9 @@ without checking if a suitable tab already exists.
 
 If ALIST contains a `tab-name' entry, it creates a new tab with that name
 and displays BUFFER in a new tab.  The `tab-name' entry can be a function,
-then it is called with two arguments: BUFFER and ALIST, and should return
-the tab name.  When a `tab-name' entry is omitted, create a new tab without
-an explicit name.
+in which case it is called with two arguments: BUFFER and ALIST, and should
+return the tab name.  When a `tab-name' entry is omitted, create a new tab
+without an explicit name.
 
 The ALIST entry `tab-group' (string or function) defines the tab group.
 
@@ -2150,19 +2259,23 @@ indirectly called by the latter."
         (tab-bar-change-tab-group tab-group)))
     (window--display-buffer buffer (selected-window) 'tab alist)))
 
-(defun switch-to-buffer-other-tab (buffer-or-name &optional norecord)
+(defun switch-to-buffer-other-tab (buffer-or-name &optional _norecord)
   "Switch to buffer BUFFER-OR-NAME in another tab.
-Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab."
+Like \\[switch-to-buffer-other-frame] (which see), but creates a new tab.
+Interactively, prompt for the buffer to switch to."
+  (declare (advertised-calling-convention (buffer-or-name) "28.1"))
   (interactive
    (list (read-buffer-to-switch "Switch to buffer in other tab: ")))
   (display-buffer (window-normalize-buffer-to-switch-to buffer-or-name)
                   '((display-buffer-in-tab)
-                    (inhibit-same-window . nil))
-                  norecord))
+                    (inhibit-same-window . nil))))
 
 (defun find-file-other-tab (filename &optional wildcards)
   "Edit file FILENAME, in another tab.
-Like \\[find-file-other-frame] (which see), but creates a new tab."
+Like \\[find-file-other-frame] (which see), but creates a new tab.
+Interactively, prompt for FILENAME.
+If WILDCARDS is non-nil, FILENAME can include widcards, and all matching
+files will be visited."
   (interactive
    (find-file-read-args "Find file in other tab: "
                         (confirm-nonexistent-file-or-buffer)))
@@ -2179,7 +2292,10 @@ Like \\[find-file-other-frame] (which see), but creates 
a new tab."
   "Edit file FILENAME, in another tab, but don't allow changes.
 Like \\[find-file-other-frame] (which see), but creates a new tab.
 Like \\[find-file-other-tab], but marks buffer as read-only.
-Use \\[read-only-mode] to permit editing."
+Use \\[read-only-mode] to permit editing.
+Interactively, prompt for FILENAME.
+If WILDCARDS is non-nil, FILENAME can include widcards, and all matching
+files will be visited."
   (interactive
    (find-file-read-args "Find file read-only in other tab: "
                         (confirm-nonexistent-file-or-buffer)))
@@ -2210,24 +2326,26 @@ When `switch-to-buffer-obey-display-actions' is non-nil,
 
 ;;; Short aliases and keybindings
 
-(defalias 'tab-new         'tab-bar-new-tab)
-(defalias 'tab-new-to      'tab-bar-new-tab-to)
-(defalias 'tab-duplicate   'tab-bar-duplicate-tab)
-(defalias 'tab-close       'tab-bar-close-tab)
-(defalias 'tab-close-other 'tab-bar-close-other-tabs)
-(defalias 'tab-close-group 'tab-bar-close-group-tabs)
-(defalias 'tab-undo        'tab-bar-undo-close-tab)
-(defalias 'tab-select      'tab-bar-select-tab)
-(defalias 'tab-switch      'tab-bar-switch-to-tab)
-(defalias 'tab-next        'tab-bar-switch-to-next-tab)
-(defalias 'tab-previous    'tab-bar-switch-to-prev-tab)
-(defalias 'tab-last        'tab-bar-switch-to-last-tab)
-(defalias 'tab-recent      'tab-bar-switch-to-recent-tab)
-(defalias 'tab-move        'tab-bar-move-tab)
-(defalias 'tab-move-to     'tab-bar-move-tab-to)
-(defalias 'tab-rename      'tab-bar-rename-tab)
-(defalias 'tab-group       'tab-bar-change-tab-group)
-(defalias 'tab-list        'tab-switcher)
+(defalias 'tab-new             'tab-bar-new-tab)
+(defalias 'tab-new-to          'tab-bar-new-tab-to)
+(defalias 'tab-duplicate       'tab-bar-duplicate-tab)
+(defalias 'tab-detach          'tab-bar-detach-tab)
+(defalias 'tab-window-detach   'tab-bar-move-window-to-tab)
+(defalias 'tab-close           'tab-bar-close-tab)
+(defalias 'tab-close-other     'tab-bar-close-other-tabs)
+(defalias 'tab-close-group     'tab-bar-close-group-tabs)
+(defalias 'tab-undo            'tab-bar-undo-close-tab)
+(defalias 'tab-select          'tab-bar-select-tab)
+(defalias 'tab-switch          'tab-bar-switch-to-tab)
+(defalias 'tab-next            'tab-bar-switch-to-next-tab)
+(defalias 'tab-previous        'tab-bar-switch-to-prev-tab)
+(defalias 'tab-last            'tab-bar-switch-to-last-tab)
+(defalias 'tab-recent          'tab-bar-switch-to-recent-tab)
+(defalias 'tab-move            'tab-bar-move-tab)
+(defalias 'tab-move-to         'tab-bar-move-tab-to)
+(defalias 'tab-rename          'tab-bar-rename-tab)
+(defalias 'tab-group           'tab-bar-change-tab-group)
+(defalias 'tab-list            'tab-switcher)
 
 (define-key tab-prefix-map "n" 'tab-duplicate)
 (define-key tab-prefix-map "N" 'tab-new-to)
@@ -2260,12 +2378,13 @@ Used in `repeat-mode'.")
 
 (defvar tab-bar-move-repeat-map
   (let ((map (make-sparse-keymap)))
-    (define-key map "m" 'tab-bar-move-tab)
+    (define-key map "m" 'tab-move)
     (define-key map "M" 'tab-bar-move-tab-backward)
     map)
   "Keymap to repeat tab move key sequences `C-x t m m M'.
 Used in `repeat-mode'.")
 (put 'tab-move 'repeat-map 'tab-bar-move-repeat-map)
+(put 'tab-bar-move-tab-backward 'repeat-map 'tab-bar-move-repeat-map)
 
 
 (provide 'tab-bar)
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index 1f7af9e9a9..5affae7913 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -36,13 +36,15 @@
   :group 'convenience
   :version "27.1")
 
-(defcustom tab-line-tab-face-functions '(tab-line-tab-face-special)
+(defcustom tab-line-tab-face-functions
+  '(tab-line-tab-face-modified tab-line-tab-face-special)
   "Functions called to modify tab faces.
 Each function is called with five arguments: the tab, a list of
 all tabs, the face returned by the previously called modifier,
 whether the tab is a buffer, and whether the tab is selected."
   :type '(repeat
           (choice (function-item tab-line-tab-face-special)
+                  (function-item tab-line-tab-face-modified)
                   (function-item tab-line-tab-face-inactive-alternating)
                   (function-item tab-line-tab-face-group)
                   (function :tag "Custom function")))
@@ -92,6 +94,14 @@ function `tab-line-tab-face-special'."
   :version "28.1"
   :group 'tab-line-faces)
 
+(defface tab-line-tab-modified
+  '((t :inherit font-lock-doc-face))
+  "Face for modified tabs.
+Applied when option `tab-line-tab-face-functions' includes
+function `tab-line-tab-face-modified'."
+  :version "28.1"
+  :group 'tab-line-faces)
+
 (defface tab-line-tab-group
   '((t :inherit tab-line :box nil))
   "Face for group tabs.
@@ -109,7 +119,11 @@ function `tab-line-tab-face-group'."
   :group 'tab-line-faces)
 
 (defface tab-line-highlight
-  '((t :inherit tab-line-tab))
+  '((((class color) (min-colors 88))
+     :box (:line-width 1 :style released-button)
+     :background "grey85"
+     :foreground "black")
+    (t :inverse-video nil))
   "Tab line face for highlighting."
   :version "27.1"
   :group 'tab-line-faces)
@@ -248,13 +262,14 @@ If nil, don't show it at all."
 
 (defcustom tab-line-tab-name-function #'tab-line-tab-name-buffer
   "Function to get a tab name.
-Function gets two arguments: tab to get name for and a list of tabs
-to display.  By default, use function `tab-line-tab-name'."
+The function is called with one or two arguments: the buffer or
+another object whose tab's name is requested, and, optionally,
+the list of all tabs."
   :type '(choice (const :tag "Buffer name"
                         tab-line-tab-name-buffer)
                  (const :tag "Truncated buffer name"
                         tab-line-tab-name-truncated-buffer)
-                 (function  :tag "Function"))
+                 (function :tag "Function"))
   :initialize 'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
@@ -280,9 +295,9 @@ to `tab-line-tab-name-truncated-buffer'."
 (defvar tab-line-tab-name-ellipsis t)
 
 (defun tab-line-tab-name-truncated-buffer (buffer &optional _buffers)
-  "Generate tab name from BUFFER.
+  "Generate tab name from BUFFER, truncating it as needed.
 Truncate it to the length specified by `tab-line-tab-name-truncated-max'.
-Append ellipsis `tab-line-tab-name-ellipsis' in this case."
+If truncated, append ellipsis per `tab-line-tab-name-ellipsis'."
   (let ((tab-name (buffer-name buffer)))
     (if (< (length tab-name) tab-line-tab-name-truncated-max)
         tab-name
@@ -329,7 +344,7 @@ Used only for `tab-line-tabs-mode-buffers' and 
`tab-line-tabs-buffer-groups'.")
                                 (buffer-list)))))
 
 (defun tab-line-tabs-mode-buffers ()
-  "Return a list of buffers with the same major mode with current buffer."
+  "Return a list of buffers with the same major mode as the current buffer."
   (let ((mode major-mode))
     (seq-sort-by #'buffer-name #'string<
                  (seq-filter (lambda (b) (with-current-buffer b
@@ -337,12 +352,12 @@ Used only for `tab-line-tabs-mode-buffers' and 
`tab-line-tabs-buffer-groups'.")
                              (funcall tab-line-tabs-buffer-list-function)))))
 
 (defvar tab-line-tabs-buffer-group-function nil
-  "Function to put a buffer to the group.
-Takes a buffer as arg and should return a group name as string.
-When the return value is nil, filter out the buffer.")
+  "Function to add a buffer to the appropriate group of tabs.
+Takes a buffer as arg and should return a group name as a string.
+If the return value is nil, the buffer should be filtered out.")
 
 (defvar tab-line-tabs-buffer-group-sort-function nil
-  "Function to sort buffers in group.")
+  "Function to sort buffers in a group.")
 
 (defvar tab-line-tabs-buffer-groups-sort-function #'string<
   "Function to sort group names.")
@@ -350,7 +365,9 @@ When the return value is nil, filter out the buffer.")
 (defvar tab-line-tabs-buffer-groups mouse-buffer-menu-mode-groups
   "How to group various major modes together in the tab line.
 Each element has the form (REGEXP . GROUPNAME).
-If the major mode's name string matches REGEXP, use GROUPNAME instead.")
+If the major mode's name matches REGEXP, it belongs to GROUPNAME.
+The default is for each major mode to have a separate group
+named the same as the mode.")
 
 (defun tab-line-tabs-buffer-group-name (&optional buffer)
   (if (functionp tab-line-tabs-buffer-group-function)
@@ -446,8 +463,11 @@ variable `tab-line-tabs-function'."
 
 (defcustom tab-line-tab-name-format-function #'tab-line-tab-name-format-default
   "Function to format a tab name.
-Function gets two arguments: the tab and a list of all tabs, and
-should return the formatted tab name to display in the tab line."
+The function will be called two arguments: the tab whose name to format,
+and the list of all the tabs; it should return the formatted tab name
+to display in the tab line.
+The first argument could also be a different object, for example the buffer
+which the tab will represent."
   :type 'function
   :initialize 'custom-initialize-default
   :set (lambda (sym val)
@@ -457,6 +477,7 @@ should return the formatted tab name to display in the tab 
line."
   :version "28.1")
 
 (defun tab-line-tab-name-format-default (tab tabs)
+  "Default function to use as `tab-line-tab-name-format-function', which see."
   (let* ((buffer-p (bufferp tab))
          (selected-p (if buffer-p
                          (eq tab (window-buffer))
@@ -489,7 +510,8 @@ should return the formatted tab name to display in the tab 
line."
              mouse-face tab-line-highlight))))
 
 (defun tab-line-format-template (tabs)
-  "Template for displaying tab line for selected window."
+  "Template of the format for displaying tab line for selected window.
+This is used by `tab-line-format'."
   (let* ((separator (or tab-line-separator (if window-system " " "|")))
          (hscroll (window-parameter nil 'tab-line-hscroll))
          (strings
@@ -521,7 +543,8 @@ should return the formatted tab name to display in the tab 
line."
 
 (defun tab-line-tab-face-inactive-alternating (tab tabs face _buffer-p 
selected-p)
   "Return FACE for TAB in TABS with alternation.
-When TAB is an inactive buffer and is even-numbered, make FACE
+SELECTED-P nil means TAB is not the selected tab.
+When TAB is not selected and is even-numbered, make FACE
 inherit from `tab-line-tab-inactive-alternate'.  For use in
 `tab-line-tab-face-functions'."
   (when (and (not selected-p) (cl-evenp (cl-position tab tabs)))
@@ -529,14 +552,23 @@ inherit from `tab-line-tab-inactive-alternate'.  For use 
in
   face)
 
 (defun tab-line-tab-face-special (tab _tabs face buffer-p _selected-p)
-  "Return FACE for TAB according to whether it's special.
-When TAB is a non-file-backed buffer, make FACE inherit from
+  "Return FACE for TAB according to whether its buffer is special.
+When TAB is a non-file-visiting buffer, make FACE inherit from
 `tab-line-tab-special'.  For use in
 `tab-line-tab-face-functions'."
   (when (and buffer-p (not (buffer-file-name tab)))
     (setf face `(:inherit (tab-line-tab-special ,face))))
   face)
 
+(defun tab-line-tab-face-modified (tab _tabs face buffer-p _selected-p)
+  "Return FACE for TAB according to whether its buffer is modified.
+When TAB is a modified, file-backed buffer, make FACE inherit
+from `tab-line-tab-modified'.  For use in
+`tab-line-tab-face-functions'."
+  (when (and buffer-p (buffer-file-name tab) (buffer-modified-p tab))
+    (setf face `(:inherit (tab-line-tab-modified ,face))))
+  face)
+
 (defun tab-line-tab-face-group (tab _tabs face _buffer-p _selected-p)
   "Return FACE for TAB according to whether it's a group tab.
 For use in `tab-line-tab-face-functions'."
@@ -547,7 +579,7 @@ For use in `tab-line-tab-face-functions'."
 (defvar tab-line-auto-hscroll)
 
 (defun tab-line-format ()
-  "Template for displaying tab line for selected window."
+  "Format for displaying the tab line of the selected window."
   (let* ((tabs (funcall tab-line-tabs-function))
          (cache-key (list tabs
                           ;; handle buffer renames
@@ -555,7 +587,10 @@ For use in `tab-line-tab-face-functions'."
                           ;; handle tab-line scrolling
                           (window-parameter nil 'tab-line-hscroll)
                           ;; for setting face 'tab-line-tab-current'
-                          (eq (selected-window) (old-selected-window))))
+                          (eq (selected-window) (old-selected-window))
+                          (and (memq 'tab-line-tab-face-modified
+                                     tab-line-tab-face-functions)
+                               (buffer-file-name) (buffer-modified-p))))
          (cache (window-parameter nil 'tab-line-cache)))
     ;; Enable auto-hscroll again after it was disabled on manual scrolling.
     ;; The moment to enable it is when the window-buffer was updated.
@@ -572,7 +607,7 @@ For use in `tab-line-tab-face-functions'."
 
 (defcustom tab-line-auto-hscroll t
   "Allow or disallow automatic horizontal scrolling of the tab line.
-Non-nil means the tab line are automatically scrolled horizontally to make
+Non-nil means the tab lines are automatically scrolled horizontally to make
 the selected tab visible."
   :type 'boolean
   :group 'tab-line
@@ -668,12 +703,16 @@ the selected tab visible."
       (force-mode-line-update t))))
 
 (defun tab-line-hscroll-right (&optional arg event)
+  "Scroll the tab line ARG positions to the right.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive (list current-prefix-arg last-nonmenu-event))
   (let ((window (and (listp event) (posn-window (event-start event)))))
     (tab-line-hscroll arg window)
     (force-mode-line-update window)))
 
 (defun tab-line-hscroll-left (&optional arg event)
+  "Scroll the tab line ARG positions to the left.
+Interactively, ARG is the prefix numeric argument and defaults to 1."
   (interactive (list current-prefix-arg last-nonmenu-event))
   (let ((window (and (listp event) (posn-window (event-start event)))))
     (tab-line-hscroll (- (or arg 1)) window)
@@ -681,10 +720,10 @@ the selected tab visible."
 
 
 (defun tab-line-new-tab (&optional event)
-  "Add a new tab to the tab line.
-Usually is invoked by clicking on the plus-shaped button.
-But any switching to other buffer also adds a new tab
-corresponding to the switched buffer."
+  "Add a new tab to the selected-window's tab line.
+This command is usually invoked by clicking on the plus-shaped button
+on the tab line.  Switching to another buffer also adds a new tab
+corresponding to the new buffer shown in the window."
   (interactive (list last-nonmenu-event))
   (if (functionp tab-line-new-tab-choice)
       (funcall tab-line-new-tab-choice)
@@ -697,9 +736,9 @@ corresponding to the switched buffer."
         (tmm-prompt (mouse-buffer-menu-keymap))))))
 
 (defun tab-line-select-tab (&optional event)
-  "Switch to the selected tab.
+  "Switch to the buffer specified by the tab on which you click.
 This command maintains the original order of prev/next buffers.
-So for example, switching to a previous tab is equivalent to
+So, for example, switching to a previous tab is equivalent to
 using the `previous-buffer' command."
   (interactive "e")
   (let* ((posnp (event-start event))
@@ -745,7 +784,7 @@ when `tab-line-tabs-function' is 
`tab-line-tabs-window-buffers'."
   :version "28.1")
 
 (defun tab-line-switch-to-prev-tab (&optional event)
-  "Switch to the previous tab.
+  "Switch to the previous tab's buffer.
 Its effect is the same as using the `previous-buffer' command
 (\\[previous-buffer])."
   (interactive (list last-nonmenu-event))
@@ -769,7 +808,7 @@ Its effect is the same as using the `previous-buffer' 
command
             (switch-to-buffer buffer)))))))
 
 (defun tab-line-switch-to-next-tab (&optional event)
-  "Switch to the next tab.
+  "Switch to the next tab's buffer.
 Its effect is the same as using the `next-buffer' command
 (\\[next-buffer])."
   (interactive (list last-nonmenu-event))
@@ -794,9 +833,9 @@ Its effect is the same as using the `next-buffer' command
 
 
 (defcustom tab-line-close-tab-function 'bury-buffer
-  "Defines what to do on closing the tab.
+  "What to do upon closing a tab on the tab line.
 If `bury-buffer', put the tab's buffer at the end of the list of all
-buffers that effectively hides the buffer's tab from the tab line.
+buffers, which effectively hides the buffer's tab from the tab line.
 If `kill-buffer', kills the tab's buffer.
 When a function, it is called with the tab as its argument.
 This option is useful when `tab-line-tabs-function' has the value
@@ -809,9 +848,9 @@ This option is useful when `tab-line-tabs-function' has the 
value
 
 (defun tab-line-close-tab (&optional event)
   "Close the selected tab.
-Usually is invoked by clicking on the close button on the right side
-of the tab.  This command buries the buffer, so it goes out of sight
-from the tab line."
+This command is usually invoked by clicking on the close button on the
+right side of the tab.  This command buries the buffer, so it goes out of
+sight of the tab line."
   (interactive (list last-nonmenu-event))
   (let* ((posnp (and (listp event) (event-start event)))
          (window (and posnp (posn-window posnp)))
@@ -834,7 +873,7 @@ from the tab line."
       (force-mode-line-update))))
 
 (defun tab-line-tab-context-menu (&optional event)
-  "Pop up context menu for the tab."
+  "Pop up the context menu for a tab-line tab."
   (interactive "e")
   (let ((menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
     (define-key-after menu [close]
@@ -842,7 +881,7 @@ from the tab line."
     (popup-menu menu event)))
 
 (defun tab-line-context-menu (&optional event)
-  "Pop up context menu for the tab line."
+  "Pop up the context menu for the tab line."
   (interactive "e")
   (let ((menu (make-sparse-keymap (propertize "Context Menu" 'hide t))))
     (define-key-after menu [close]
@@ -852,13 +891,15 @@ from the tab line."
 
 ;;;###autoload
 (define-minor-mode tab-line-mode
-  "Toggle display of window tab line in the buffer."
+  "Toggle display of tab line in the windows displaying the current buffer."
   :lighter nil
   (setq tab-line-format (when tab-line-mode '(:eval (tab-line-format)))))
 
 (defcustom tab-line-exclude-modes
   '(completion-list-mode)
-  "List of major modes in which the tab line is not enabled."
+  "List of major modes for which the tab-line display is not enabled.
+Buffers under any of these major modes will not show the tab line in
+their windows, even if `global-tab-line-mode' is enabled."
   :type '(repeat symbol)
   :group 'tab-line
   :version "27.1")
@@ -867,7 +908,12 @@ from the tab line."
 (defvar-local tab-line-exclude nil)
 
 (defun tab-line-mode--turn-on ()
-  "Turn on `tab-line-mode'."
+  "Turn on `tab-line-mode' in all pertinent buffers.
+Temporary buffers, buffers whose names begin with a space, buffers
+under major modes that are either mentioned in `tab-line-exclude-mode'
+or have a non-nil `tab-line-exclude' property on their symbol,
+and buffers that have a non-nil buffer-local value
+of `tab-line-exclude', are exempt from `tab-line-mode'."
   (unless (or (minibufferp)
               (string-match-p "\\` " (buffer-name))
               (memq major-mode tab-line-exclude-modes)
diff --git a/lisp/term.el b/lisp/term.el
index af93089104..698bef08b2 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -303,6 +303,7 @@
   (require 'ange-ftp)
   (require 'cl-lib))
 (require 'comint) ; Password regexp.
+(require 'ansi-color)
 (require 'ehelp)
 (require 'ring)
 (require 'shell)
@@ -710,13 +711,20 @@ Buffer local variable.")
 (defvar term-ansi-at-save-pwd nil)
 (defvar term-ansi-at-save-anon nil)
 (defvar term-ansi-current-bold nil)
+(defvar term-ansi-current-faint nil)
+(defvar term-ansi-current-italic nil)
+(defvar term-ansi-current-underline nil)
+(defvar term-ansi-current-slow-blink nil)
+(defvar term-ansi-current-fast-blink nil)
 (defvar term-ansi-current-color 0)
 (defvar term-ansi-face-already-done nil)
 (defvar term-ansi-current-bg-color 0)
-(defvar term-ansi-current-underline nil)
 (defvar term-ansi-current-reverse nil)
 (defvar term-ansi-current-invisible nil)
 
+(make-obsolete-variable 'term-ansi-face-already-done
+                        "it doesn't have any effect." "29.1")
+
 ;;; Faces
 (defvar ansi-term-color-vector
   [term
@@ -727,7 +735,15 @@ Buffer local variable.")
    term-color-blue
    term-color-magenta
    term-color-cyan
-   term-color-white])
+   term-color-white
+   term-color-bright-black
+   term-color-bright-red
+   term-color-bright-green
+   term-color-bright-yellow
+   term-color-bright-blue
+   term-color-bright-magenta
+   term-color-bright-cyan
+   term-color-bright-white])
 
 (defcustom term-default-fg-color nil
   "If non-nil, default color for foreground in Term mode."
@@ -752,54 +768,136 @@ Buffer local variable.")
   :group 'term)
 
 (defface term-bold
-  '((t :bold t))
+  '((t :inherit ansi-color-bold))
   "Default face to use for bold text."
-  :group 'term)
+  :group 'term
+  :version "28.1")
+
+(defface term-faint
+  '((t :inherit ansi-color-faint))
+  "Default face to use for faint text."
+  :group 'term
+  :version "29.1")
+
+(defface term-italic
+  '((t :inherit ansi-color-italic))
+  "Default face to use for italic text."
+  :group 'term
+  :version "29.1")
 
 (defface term-underline
-  '((t :underline t))
+  '((t :inherit ansi-color-underline))
   "Default face to use for underlined text."
-  :group 'term)
+  :group 'term
+  :version "28.1")
+
+(defface term-slow-blink
+  '((t :inherit ansi-color-slow-blink))
+  "Default face to use for slowly blinking text."
+  :group 'term
+  :version "29.1")
+
+(defface term-fast-blink
+  '((t :inherit ansi-color-fast-blink))
+  "Default face to use for rapidly blinking text."
+  :group 'term
+  :version "29.1")
 
 (defface term-color-black
-  '((t :foreground "black" :background "black"))
+  '((t :inherit ansi-color-black))
   "Face used to render black color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-red
-  '((t :foreground "red3" :background "red3"))
+  '((t :inherit ansi-color-red))
   "Face used to render red color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-green
-  '((t :foreground "green3" :background "green3"))
+  '((t :inherit ansi-color-green))
   "Face used to render green color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-yellow
-  '((t :foreground "yellow3" :background "yellow3"))
+  '((t :inherit ansi-color-yellow))
   "Face used to render yellow color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-blue
-  '((t :foreground "blue2" :background "blue2"))
+  '((t :inherit ansi-color-blue))
   "Face used to render blue color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-magenta
-  '((t :foreground "magenta3" :background "magenta3"))
+  '((t :inherit ansi-color-magenta))
   "Face used to render magenta color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-cyan
-  '((t :foreground "cyan3" :background "cyan3"))
+  '((t :inherit ansi-color-cyan))
   "Face used to render cyan color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
 
 (defface term-color-white
-  '((t :foreground "white" :background "white"))
+  '((t :inherit ansi-color-white))
   "Face used to render white color code."
-  :group 'term)
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-black
+  '((t :inherit ansi-color-bright-black))
+  "Face used to render bright black color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-red
+  '((t :inherit ansi-color-bright-red))
+  "Face used to render bright red color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-green
+  '((t :inherit ansi-color-bright-green))
+  "Face used to render bright green color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-yellow
+  '((t :inherit ansi-color-bright-yellow))
+  "Face used to render bright yellow color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-blue
+  '((t :inherit ansi-color-bright-blue))
+  "Face used to render bright blue color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-magenta
+  '((t :inherit ansi-color-bright-magenta))
+  "Face used to render bright magenta color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-cyan
+  '((t :inherit ansi-color-bright-cyan))
+  "Face used to render bright cyan color code."
+  :group 'term
+  :version "28.1")
+
+(defface term-color-bright-white
+  '((t :inherit ansi-color-bright-white))
+  "Face used to render bright white color code."
+  :group 'term
+  :version "28.1")
 
 (defcustom term-buffer-maximum-size 8192
   "The maximum size in lines for term buffers.
@@ -968,15 +1066,15 @@ is buffer-local."
 
 (defun term-ansi-reset ()
   (setq term-current-face 'term)
-  (setq term-ansi-current-underline nil)
   (setq term-ansi-current-bold nil)
+  (setq term-ansi-current-faint nil)
+  (setq term-ansi-current-italic nil)
+  (setq term-ansi-current-underline nil)
+  (setq term-ansi-current-slow-blink nil)
+  (setq term-ansi-current-fast-blink nil)
   (setq term-ansi-current-reverse nil)
   (setq term-ansi-current-color 0)
   (setq term-ansi-current-invisible nil)
-  ;; Stefan thought this should be t, but could not remember why.
-  ;; Setting it to t seems to cause bug#11785.  Setting it to nil
-  ;; again to see if there are other consequences...
-  (setq term-ansi-face-already-done nil)
   (setq term-ansi-current-bg-color 0))
 
 (define-derived-mode term-mode fundamental-mode "Term"
@@ -1433,7 +1531,6 @@ commands to use in that buffer.
                                             (getenv "ESHELL")
                                             shell-file-name))))
   (set-buffer (make-term "terminal" program))
-  (term-mode)
   (term-char-mode)
   (switch-to-buffer "*terminal*"))
 
@@ -1515,10 +1612,12 @@ Using \"emacs\" loses, because bash disables editing if 
$TERM == emacs.")
 :nd=\\E[C:up=\\E[A:ce=\\E[K:ho=\\E[H:pt\
 :al=\\E[L:dl=\\E[M:DL=\\E[%%dM:AL=\\E[%%dL:cs=\\E[%%i%%d;%%dr:sf=^J\
 :dc=\\E[P:DC=\\E[%%dP:IC=\\E[%%d@:im=\\E[4h:ei=\\E[4l:mi:\
+:mb=\\E[5m:mh=\\E[2m:ZR=\\E[23m:ZH=\\E[3m\
 :so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:md=\\E[1m:mr=\\E[7m:me=\\E[m\
 :UP=\\E[%%dA:DO=\\E[%%dB:LE=\\E[%%dD:RI=\\E[%%dC\
 :kl=\\EOD:kd=\\EOB:kr=\\EOC:ku=\\EOA:kN=\\E[6~:kP=\\E[5~:@7=\\E[4~:kh=\\E[1~\
-:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#8:pa#64:AB=\\E[4%%dm:AF=\\E[3%%dm:cr=^M\
+:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\
+:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\
 :bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\
 :kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:"
   ;; : -undefine ic
@@ -2309,7 +2408,14 @@ Checks if STRING contains a password prompt as defined by
   (when (term-in-line-mode)
     (when (let ((case-fold-search t))
             (string-match comint-password-prompt-regexp string))
-      (term-send-invisible (read-passwd string)))))
+      ;; Use `run-at-time' in order not to pause execution of the
+      ;; process filter with a minibuffer
+      (run-at-time
+       0 nil
+       (lambda (current-buf)
+         (with-current-buffer current-buf
+           (term-send-invisible (read-passwd string))))
+       (current-buffer)))))
 
 
 ;;; Low-level process communication
@@ -3038,30 +3144,34 @@ See `term-prompt-regexp'."
                                   (term-horizontal-column)
                                   term-ansi-current-bg-color
                                   term-ansi-current-bold
+                                  term-ansi-current-faint
+                                  term-ansi-current-italic
+                                  term-ansi-current-underline
+                                  term-ansi-current-slow-blink
+                                  term-ansi-current-fast-blink
                                   term-ansi-current-color
                                   term-ansi-current-invisible
                                   term-ansi-current-reverse
-                                  term-ansi-current-underline
                                   term-current-face)))
                      (?8 ;; Restore cursor (terminfo: rc, [ctlseqs]
                       ;; "DECRC").
                       (when term-saved-cursor
                         (term-goto (nth 0 term-saved-cursor)
                                    (nth 1 term-saved-cursor))
-                        (setq term-ansi-current-bg-color
-                              (nth 2 term-saved-cursor)
-                              term-ansi-current-bold
-                              (nth 3 term-saved-cursor)
-                              term-ansi-current-color
-                              (nth 4 term-saved-cursor)
-                              term-ansi-current-invisible
-                              (nth 5 term-saved-cursor)
-                              term-ansi-current-reverse
-                              (nth 6 term-saved-cursor)
-                              term-ansi-current-underline
-                              (nth 7 term-saved-cursor)
-                              term-current-face
-                              (nth 8 term-saved-cursor))))
+                        (pcase-setq
+                         `( ,_ ,_
+                            ,term-ansi-current-bg-color
+                            ,term-ansi-current-bold
+                            ,term-ansi-current-faint
+                            ,term-ansi-current-italic
+                            ,term-ansi-current-underline
+                            ,term-ansi-current-slow-blink
+                            ,term-ansi-current-fast-blink
+                            ,term-ansi-current-color
+                            ,term-ansi-current-invisible
+                            ,term-ansi-current-reverse
+                            ,term-current-face)
+                         term-saved-cursor)))
                      (?c ;; \Ec - Reset (terminfo: rs1, [ctlseqs] "RIS").
                       ;; This is used by the "clear" program.
                       (term-reset-terminal))
@@ -3219,110 +3329,141 @@ option is enabled.  See `term-set-goto-process-mark'."
   (setq term-current-row 0)
   (setq term-current-column 1)
   (term--reset-scroll-region)
-  (setq term-insert-mode nil)
-  ;; FIXME: No idea why this is here, it looks wrong.  --Stef
-  (setq term-ansi-face-already-done nil))
+  (setq term-insert-mode nil))
+
+(defun term--color-as-hex (for-foreground)
+  "Return the current ANSI color as a hexadecimal color string.
+Use the current background color if FOR-FOREGROUND is nil,
+otherwise use the current foreground color."
+  (let ((color (if for-foreground term-ansi-current-color
+                 term-ansi-current-bg-color)))
+    (or (ansi-color--code-as-hex (1- color))
+        (progn
+          (and ansi-color-bold-is-bright term-ansi-current-bold
+               (<= 1 color 8)
+               (setq color (+ color 8)))
+          (if for-foreground
+              (face-foreground (elt ansi-term-color-vector color)
+                               nil 'default)
+            (face-background (elt ansi-term-color-vector color)
+                             nil 'default))))))
 
 ;; New function to deal with ansi colorized output, as you can see you can
 ;; have any bold/underline/fg/bg/reverse combination. -mm
 
 (defun term-handle-colors-array (parameter)
-  (cond
-
-   ;; Bold  (terminfo: bold)
-   ((eq parameter 1)
-    (setq term-ansi-current-bold t))
-
-   ;; Underline
-   ((eq parameter 4)
-    (setq term-ansi-current-underline t))
-
-   ;; Blink (unsupported by Emacs), will be translated to bold.
-   ;; This may change in the future though.
-   ((eq parameter 5)
-    (setq term-ansi-current-bold t))
-
-   ;; Reverse (terminfo: smso)
-   ((eq parameter 7)
-    (setq term-ansi-current-reverse t))
-
-   ;; Invisible
-   ((eq parameter 8)
-    (setq term-ansi-current-invisible t))
-
-   ;; Reset underline (terminfo: rmul)
-   ((eq parameter 24)
-    (setq term-ansi-current-underline nil))
-
-   ;; Reset reverse (terminfo: rmso)
-   ((eq parameter 27)
-    (setq term-ansi-current-reverse nil))
-
-   ;; Foreground
-   ((and (>= parameter 30) (<= parameter 37))
-    (setq term-ansi-current-color (- parameter 29)))
-
-   ;; Reset foreground
-   ((eq parameter 39)
-    (setq term-ansi-current-color 0))
-
-   ;; Background
-   ((and (>= parameter 40) (<= parameter 47))
-    (setq term-ansi-current-bg-color (- parameter 39)))
-
-   ;; Reset background
-   ((eq parameter 49)
-    (setq term-ansi-current-bg-color 0))
-
-   ;; 0 (Reset) or unknown (reset anyway)
-   (t
-    (term-ansi-reset)))
-
-  ;; (message "Debug: U-%d R-%d B-%d I-%d D-%d F-%d B-%d"
-  ;;          term-ansi-current-underline
-  ;;          term-ansi-current-reverse
-  ;;          term-ansi-current-bold
-  ;;          term-ansi-current-invisible
-  ;;          term-ansi-face-already-done
-  ;;          term-ansi-current-color
-  ;;          term-ansi-current-bg-color)
-
-  (unless term-ansi-face-already-done
+  (declare (obsolete term--handle-colors-list "29.1"))
+  (term--handle-colors-list (list parameter)))
+
+(defun term--handle-colors-list (parameters)
+  (while parameters
+    (pcase (pop parameters)
+      (1 (setq term-ansi-current-bold t))       ; (terminfo: bold)
+      (2 (setq term-ansi-current-faint t))      ; (terminfo: dim)
+      (3 (setq term-ansi-current-italic t))     ; (terminfo: sitm)
+      (4 (setq term-ansi-current-underline t))  ; (terminfo: smul)
+      (5 (setq term-ansi-current-slow-blink t)) ; (terminfo: blink)
+      (6 (setq term-ansi-current-fast-blink t))
+      (7 (setq term-ansi-current-reverse t))    ; (terminfo: smso, rev)
+      (8 (setq term-ansi-current-invisible t))  ; (terminfo: invis)
+      (21 (setq term-ansi-current-bold nil))
+      (22 (setq term-ansi-current-bold nil)
+          (setq term-ansi-current-faint nil))
+      (23 (setq term-ansi-current-italic nil))    ; (terminfo: ritm)
+      (24 (setq term-ansi-current-underline nil)) ; (terminfo: rmul)
+      (25 (setq term-ansi-current-slow-blink nil)
+          (setq term-ansi-current-fast-blink nil))
+      (27 (setq term-ansi-current-reverse nil)) ; (terminfo: rmso)
+
+      ;; Foreground (terminfo: setaf)
+      ((and param (guard (<= 30 param 37)))
+       (setq term-ansi-current-color (- param 29)))
+
+      ;; Bright foreground (terminfo: setaf)
+      ((and param (guard (<= 90 param 97)))
+       (setq term-ansi-current-color (- param 81)))
+
+      ;; Extended foreground (terminfo: setaf)
+      (38
+       (pcase (pop parameters)
+         ;; 256 color
+         (5 (if (setq term-ansi-current-color (pop parameters))
+                (cl-incf term-ansi-current-color)
+              (term-ansi-reset)))
+         ;; Full 24-bit color
+         (2 (cl-loop with color = (1+ 256) ; Base
+                     for i from 16 downto 0 by 8
+                     if (pop parameters)
+                     do (setq color (+ color (ash it i)))
+                     else return (term-ansi-reset)
+                     finally
+                     (if (> color (+ 1 256 #xFFFFFF))
+                         (term-ansi-reset)
+                       (setq term-ansi-current-color color))))
+         (_ (term-ansi-reset))))
+
+      ;; Reset foreground (terminfo: op)
+      (39 (setq term-ansi-current-color 0))
+
+      ;; Background (terminfo: setab)
+      ((and param (guard (<= 40 param 47)))
+       (setq term-ansi-current-bg-color (- param 39)))
+
+      ;; Bright background (terminfo: setab)
+      ((and param (guard (<= 100 param 107)))
+       (setq term-ansi-current-bg-color (- param 91)))
+
+      ;; Extended background (terminfo: setab)
+      (48
+       (pcase (pop parameters)
+         ;; 256 color
+         (5 (if (setq term-ansi-current-bg-color (pop parameters))
+                (cl-incf term-ansi-current-bg-color)
+              (term-ansi-reset)))
+         ;; Full 24-bit color
+         (2 (cl-loop with color = (1+ 256) ; Base
+                     for i from 16 downto 0 by 8
+                     if (pop parameters)
+                     do (setq color (+ color (ash it i)))
+                     else return (term-ansi-reset)
+                     finally
+                     (if (> color (+ 1 256 #xFFFFFF))
+                         (term-ansi-reset)
+                       (setq term-ansi-current-bg-color color))))
+         (_ (term-ansi-reset))))
+
+      ;; Reset background (terminfo: op)
+      (49 (setq term-ansi-current-bg-color 0))
+
+      ;; 0 (Reset) (terminfo: sgr0) or unknown (reset anyway)
+      (_ (term-ansi-reset))))
+
+  (let (fg bg)
     (if term-ansi-current-invisible
-        (let ((color
-               (if term-ansi-current-reverse
-                   (face-foreground
-                    (elt ansi-term-color-vector term-ansi-current-color)
-                    nil 'default)
-                 (face-background
-                  (elt ansi-term-color-vector term-ansi-current-bg-color)
-                  nil 'default))))
-          (setq term-current-face
-                (list :background color
-                      :foreground color))
-          ) ;; No need to bother with anything else if it's invisible.
-      (setq term-current-face
-            (list :foreground
-                  (face-foreground
-                   (elt ansi-term-color-vector term-ansi-current-color)
-                   nil 'default)
-                  :background
-                  (face-background
-                   (elt ansi-term-color-vector term-ansi-current-bg-color)
-                   nil 'default)
-                  :inverse-video term-ansi-current-reverse))
-
-      (when term-ansi-current-bold
-        (setq term-current-face
-              `(,term-current-face :inherit term-bold)))
-
-      (when term-ansi-current-underline
-        (setq term-current-face
-              `(,term-current-face :inherit term-underline)))))
-
-  ;;   (message "Debug %S" term-current-face)
-  ;; FIXME: shouldn't we set term-ansi-face-already-done to t here?  --Stef
-  (setq term-ansi-face-already-done nil))
+        (setq bg (term--color-as-hex term-ansi-current-reverse)
+              fg bg)
+      (setq fg (term--color-as-hex t)
+            bg (term--color-as-hex nil)))
+    (setq term-current-face
+          `( :foreground ,fg
+             :background ,bg
+             ,@(unless term-ansi-current-invisible
+                 (list :inverse-video term-ansi-current-reverse)))))
+
+  (setq term-current-face
+        `(,term-current-face
+          ,@(when term-ansi-current-bold
+              '(term-bold))
+          ,@(when term-ansi-current-faint
+              '(term-faint))
+          ,@(when term-ansi-current-italic
+              '(term-italic))
+          ,@(when term-ansi-current-underline
+              '(term-underline))
+          ,@(when term-ansi-current-slow-blink
+              '(term-slow-blink))
+          ,@(when term-ansi-current-fast-blink
+              '(term-fast-blink)))))
 
 
 ;; Handle a character assuming (eq terminal-state 2) -
@@ -3408,9 +3549,9 @@ option is enabled.  See `term-set-goto-process-mark'."
 
    ;; Modified to allow ansi coloring -mm
    ;; \E[m - Set/reset modes, set bg/fg
-   ;;(terminfo: smso,rmso,smul,rmul,rev,bold,sgr0,invis,op,setab,setaf)
+   ;;(terminfo: 
smso,rmso,smul,rmul,rev,bold,dim,sitm,ritm,blink,sgr0,invis,op,setab,setaf)
    ((eq char ?m)
-    (mapc #'term-handle-colors-array params))
+    (term--handle-colors-list params))
 
    ;; \E[6n - Report cursor position (terminfo: u7)
    ((eq char ?n)
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index 1a3811a37c..67a417c116 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -867,10 +867,10 @@ See the documentation of 
`create-fontset-from-fontset-spec' for the format.")
   ;; For Darwin nothing except UTF-8 makes sense.
   (when (eq system-type 'darwin)
       (add-hook 'before-init-hook
-                #'(lambda ()
-                    (setq locale-coding-system 'utf-8-unix)
-                    (setq default-process-coding-system
-                          '(utf-8-unix . utf-8-unix)))))
+                (lambda ()
+                  (setq locale-coding-system 'utf-8-unix)
+                  (setq default-process-coding-system
+                        '(utf-8-unix . utf-8-unix)))))
 
   ;; Mac OS X Lion introduces PressAndHold, which is unsupported by this port.
   ;; See this thread for more details:
diff --git a/lisp/term/w32-win.el b/lisp/term/w32-win.el
index 80afcb3604..8b745c495d 100644
--- a/lisp/term/w32-win.el
+++ b/lisp/term/w32-win.el
@@ -274,6 +274,7 @@ See the documentation of `create-fontset-from-fontset-spec' 
for the format.")
             '(gif "libgif-6.dll" "giflib5.dll" "gif.dll")
         '(gif "libgif-5.dll" "giflib4.dll" "libungif4.dll" "libungif.dll")))
        '(svg "librsvg-2-2.dll")
+       '(webp "libwebp-7.dll" "libwebp.dll")
        '(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll")
        '(glib "libglib-2.0-0.dll")
        '(gio "libgio-2.0-0.dll")
@@ -532,7 +533,7 @@ characters from these blocks.")
   (let (val)
     (dolist (elt script-representative-chars)
       (let ((subranges w32-no-usb-subranges)
-            (chars (cdr elt))
+            (chars (append (cdr elt) nil)) ; handle vectors as well
             ch found subrange)
         (while (and (consp chars) (not found))
           (setq ch (car chars)
@@ -595,7 +596,11 @@ default font on FRAME, or its best approximation."
                                              0 nchars script-chars)
                           '[nil]))
                   ;; Does this font support ALL of the script's
-                  ;; representative characters?
+                  ;; representative characters?  Note that, when the
+                  ;; representative characters are specified as a
+                  ;; vector, this is a more stringent test than font
+                  ;; selection does, because supporting _any_
+                  ;; character from the vector is enough.
                   (setq idx 0)
                   (while (and (< idx nchars) (not (null (aref glyphs idx))))
                     (setq idx (1+ idx)))
diff --git a/lisp/textmodes/artist.el b/lisp/textmodes/artist.el
index c42286e5bc..25f0c35aa5 100644
--- a/lisp/textmodes/artist.el
+++ b/lisp/textmodes/artist.el
@@ -2840,9 +2840,8 @@ Returns a list of strings."
           (if (memq system-type '(windows-nt ms-dos))
               (artist-figlet-get-font-list-windows)
             (artist-figlet-get-font-list)))
-        (font (completing-read (concat "Select font (default "
-                                       artist-figlet-default-font
-                                       "): ")
+         (font (completing-read (format-prompt "Select font"
+                                               artist-figlet-default-font)
                                (mapcar
                                 (lambda (font) (cons font font))
                                 avail-fonts))))
diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el
index 237a1d9935..c06e8bfa1b 100644
--- a/lisp/textmodes/bibtex.el
+++ b/lisp/textmodes/bibtex.el
@@ -4317,8 +4317,6 @@ for a crossref key, t otherwise."
           (eqb (goto-char pos))
           (t (set-buffer buffer) (goto-char pos)))
     pos))
-;; backward compatibility
-(defalias 'bibtex-find-crossref 'bibtex-search-crossref)
 
 (defun bibtex-dist (pos beg end)
   "Return distance between POS and region delimited by BEG and END."
@@ -4381,8 +4379,6 @@ A prefix arg negates the value of 
`bibtex-search-entry-globally'."
              (if display (bibtex-reposition-window)))
             (display (message "Key `%s' not found" key)))
       pnt)))
-;; backward compatibility
-(defalias 'bibtex-find-entry 'bibtex-search-entry)
 
 (defun bibtex-prepare-new-entry (index)
   "Prepare a new BibTeX entry with index INDEX.
@@ -5608,5 +5604,8 @@ If APPEND is non-nil, append ENTRIES to those already 
displayed."
   (setq buffer-read-only t)
   (goto-char (point-min)))
 
+(define-obsolete-function-alias 'bibtex-find-crossref #'bibtex-search-crossref 
"29.1")
+(define-obsolete-function-alias 'bibtex-find-entry #'bibtex-search-entry 
"29.1")
+
 (provide 'bibtex)
 ;;; bibtex.el ends here
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 9f123dc816..e5017a68f7 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -305,14 +305,14 @@
     ;; CSS Box Alignment Module Level 3
     ;; (https://www.w3.org/TR/css-align-3/#property-index)
     ("align-content"
-     baseline-position content-distibution overflow-position content-position)
+     baseline-position content-distribution overflow-position content-position)
     ("align-items"
      "normal" "stretch" baseline-position overflow-position self-position)
     ("align-self"
      "auto" "normal" "stretch"
      baseline-position overflow-position self-position)
     ("justify-content" "normal"
-     content-distibution overflow-position content-position "left" "right")
+     content-distribution overflow-position content-position "left" "right")
     ("justify-items"
      "normal" "stretch" baseline-position overflow-position self-position
      "left" "right" "legacy")
diff --git a/lisp/textmodes/etc-authors-mode.el 
b/lisp/textmodes/etc-authors-mode.el
index a591b2db97..8b5fefd3b7 100644
--- a/lisp/textmodes/etc-authors-mode.el
+++ b/lisp/textmodes/etc-authors-mode.el
@@ -5,18 +5,20 @@
 ;; Author: Stefan Kangas <stefan@marxist.se>
 ;; Keywords: internal
 
-;; This program is free software; you can redistribute it and/or modify
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation, either version 3 of the License, or
 ;; (at your option) any later version.
 
-;; This program is distributed in the hope that it will be useful,
+;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/lisp/textmodes/fill.el b/lisp/textmodes/fill.el
index 81d908c95e..73d76a8ac6 100644
--- a/lisp/textmodes/fill.el
+++ b/lisp/textmodes/fill.el
@@ -396,12 +396,8 @@ and `fill-nobreak-invisible'."
          (save-excursion
            (skip-chars-backward " ")
            (and (eq (preceding-char) ?.)
-                (looking-at " \\([^ ]\\|$\\)"))))
-     ;; Another approach to the same problem.
-     (save-excursion
-       (skip-chars-backward " ")
-       (and (eq (preceding-char) ?.)
-           (not (progn (forward-char -1) (looking-at (sentence-end))))))
+                 ;; There's something more after the space.
+                (looking-at " [^ \n]"))))
      ;; Don't split a line if the rest would look like a new paragraph.
      (unless use-hard-newlines
        (save-excursion
@@ -768,7 +764,7 @@ space does not end a sentence, so don't break a line there."
               (setq first nil
                     linebeg (+ (point) (length actual-fill-prefix))))
            (move-to-column (current-fill-column))
-           (if (when (< (point) to)
+           (if (when (and (< (point) to) (< linebeg to))
                  ;; Find the position where we'll break the line.
                  ;; Use an immediately following space, if any.
                  ;; However, note that `move-to-column' may overshoot
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index b650ab3871..0a3a49d868 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -250,16 +250,15 @@ Always stores Fcc copy of message when nil."
 Should probably be \"-Ei\"."
   :type 'string)
 
-(defcustom ispell-look-command
-  (cond ((file-exists-p "/bin/look") "/bin/look")
-       ((file-exists-p "/usr/local/bin/look") "/usr/local/bin/look")
-       ((file-exists-p "/usr/bin/look") "/usr/bin/look")
-       (t "look"))
+(defcustom ispell-look-command (executable-find "look")
   "Name of the look command for search processes.
 This must be an absolute file name."
-  :type 'file)
+  :type '(choice (const :tag "None" nil)
+                 file)
+  :version "28.1")
 
-(defcustom ispell-look-p (file-exists-p ispell-look-command)
+(defcustom ispell-look-p (and ispell-look-command
+                              (file-exists-p ispell-look-command))
   "Non-nil means use `look' rather than `grep'.
 Default is based on whether `look' seems to be available."
   :type 'boolean)
@@ -398,6 +397,10 @@ re-start Emacs."
                               (const :tag "default" nil))
                        (coding-system :tag "Coding System"))))
 
+(defcustom ispell-help-timeout 5
+  "The number of seconds to display the help text."
+  :type 'number
+  :version "28.1")
 
 (defvar ispell-dictionary-base-alist
   '((nil                                ; default
@@ -2460,7 +2463,7 @@ SPC:   Accept word this time.
              (with-current-buffer buffer
                (insert (concat help-1 "\n" help-2 "\n" help-3)))
              (ispell-display-buffer buffer)
-             (sit-for 5)
+             (sit-for ispell-help-timeout)
              (kill-buffer "*Ispell Help*"))
          (unwind-protect
              (let ((resize-mini-windows 'grow-only))
@@ -2470,7 +2473,7 @@ SPC:   Accept word this time.
                ;;(set-minibuffer-window (selected-window))
                (enlarge-window 2)
                (insert (concat help-1 "\n" help-2 "\n" help-3))
-               (sit-for 5))
+               (sit-for ispell-help-timeout))
            (erase-buffer)))))))
 
 (define-obsolete-function-alias 'lookup-words 'ispell-lookup-words "24.4")
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index 8a54b1a301..e1475934dd 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -814,7 +814,7 @@ in order to only add another reference in the same cite 
command."
   (interactive)
   (reftex-citation nil ?t))
 
-(defvar reftex-select-bib-map)
+(defvar reftex-select-bib-mode-map)
 (defvar reftex--found-list)
 (defun reftex-offer-bib-menu ()
   "Offer bib menu and return list of selected items."
@@ -870,7 +870,7 @@ in order to only add another reference in the same cite 
command."
                     (reftex-select-item
                      reftex-citation-prompt
                      reftex-citation-help
-                     reftex-select-bib-map
+                     reftex-select-bib-mode-map
                      nil
                      'reftex-bibtex-selection-callback nil))
               (setq key (car rtn)
diff --git a/lisp/textmodes/reftex-global.el b/lisp/textmodes/reftex-global.el
index cc8b3244b9..b90c21339c 100644
--- a/lisp/textmodes/reftex-global.el
+++ b/lisp/textmodes/reftex-global.el
@@ -348,7 +348,7 @@ Also checks if buffers visiting the files are in read-only 
mode."
                  (with-current-buffer buf
                    buffer-read-only))
         (ding)
-        (or (y-or-n-p (format "Buffer %s is read-only. Continue?"
+        (or (y-or-n-p (format "Buffer %s is read-only.  Continue?"
                               (buffer-name buf)))
             (error "Abort"))))))
 
diff --git a/lisp/textmodes/reftex-parse.el b/lisp/textmodes/reftex-parse.el
index c521a07f19..b8c75cb21b 100644
--- a/lisp/textmodes/reftex-parse.el
+++ b/lisp/textmodes/reftex-parse.el
@@ -345,7 +345,17 @@ of master file."
 
              ;; Find external document specifications
              (goto-char 1)
-             (while (re-search-forward "[\n\r][ 
\t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
+             (while (re-search-forward
+                     (concat "[\n\r][ \t]*"
+                             ;; Support \externalcitedocument macro
+                             "\\\\external\\(?:cite\\)?document"
+                             ;; The optional prefix
+                             "\\(\\[\\([^]]*\\)\\]\\)?"
+                             ;; The 2nd opt. arg can only be nocite
+                             "\\(?:\\[nocite\\]\\)?"
+                             ;; Mandatory file argument
+                             "{\\([^}]+\\)}")
+                     nil t)
                (push (list 'xr-doc (reftex-match-string 2)
                            (reftex-match-string 3))
                      docstruct))
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index 9d5bc5a8f0..15d86b359c 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -230,7 +230,7 @@ This function is controlled by the settings of 
reftex-insert-label-flags."
                                  (symbol-value reftex-docstruct-symbol)))
               (ding)
               (if (y-or-n-p
-                   (format-message "Label `%s' exists. Use anyway? " label))
+                   (format-message "Label `%s' exists.  Use anyway?" label))
                   (setq valid t)))
 
              ;; Label is ok
@@ -533,7 +533,7 @@ When called with 2 \\[universal-argument] prefix args, 
disable magic word recogn
         (cons (cdr cell) (- (match-end 0) (match-end 1)))
       nil)))
 
-(defvar reftex-select-label-map)
+(defvar reftex-select-label-mode-map)
 (defun reftex-offer-label-menu (typekey)
   ;; Offer a menu with the appropriate labels.
   (let* ((buf (current-buffer))
@@ -605,7 +605,7 @@ When called with 2 \\[universal-argument] prefix args, 
disable magic word recogn
                     (reftex-select-item
                      reftex-select-label-prompt
                      reftex-select-label-help
-                     reftex-select-label-map
+                     reftex-select-label-mode-map
                      offset
                      'reftex-show-label-location follow))
               (setq key       (car rtn)
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index 7ca2fb827e..b5f53ba86e 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -856,10 +856,10 @@ label prefix determines the wording of a reference."
          (label (car toc)) newlabel)
     (if (not (stringp label))
         (error "This is not a label entry"))
-    (setq newlabel (read-string (format "Rename label \"%s\" to:" label)))
+    (setq newlabel (read-string (format "Rename label \"%s\" to: " label)))
     (if (assoc newlabel (symbol-value reftex-docstruct-symbol))
         (if (not (y-or-n-p
-                  (format-message "Label `%s' exists.  Use anyway? " label)))
+                  (format-message "Label `%s' exists.  Use anyway? " 
newlabel)))
             (error "Abort")))
     (save-excursion
       (save-window-excursion
diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el
index 7ef8161ab5..dedc388219 100644
--- a/lisp/textmodes/sgml-mode.el
+++ b/lisp/textmodes/sgml-mode.el
@@ -440,7 +440,8 @@ These have to be run via `sgml-syntax-propertize'"))
 
 ;; internal
 (defvar sgml-face-tag-alist ()
-  "Alist of face and tag name for facemenu.")
+  "Alist of face and tag name for facemenu.
+The tag name can be a string or a list of strings.")
 
 (defvar sgml-tag-face-alist ()
   "Tag names and face or list of faces to fontify with when invisible.
@@ -528,11 +529,13 @@ an optional alist of possible values."
     (comment-indent-new-line soft)))
 
 (defun sgml-mode-facemenu-add-face-function (face _end)
-  (let ((tag-face (cdr (assq face sgml-face-tag-alist))))
+  "Add \"face\" tags with `facemenu-keymap' commands."
+  (let ((tag-face (ensure-list (cdr (assq face sgml-face-tag-alist)))))
     (cond (tag-face
           (setq tag-face (funcall skeleton-transformation-function tag-face))
-          (setq facemenu-end-add-face (concat "</" tag-face ">"))
-          (concat "<" tag-face ">"))
+           (setq facemenu-end-add-face
+                 (mapconcat (lambda (f) (concat "</" f ">")) (reverse 
tag-face) ""))
+           (mapconcat (lambda (f) (concat "<" f ">")) tag-face ""))
          ((and (consp face)
                (consp (car face))
                (null  (cdr face))
@@ -1868,6 +1871,7 @@ This takes effect when first loading the library.")
 (defvar html-face-tag-alist
   '((bold . "strong")
     (italic . "em")
+    (bold-italic . ("strong" "em"))
     (underline . "u")
     (mode-line . "rev"))
   "Value of `sgml-face-tag-alist' for HTML mode.")
@@ -2411,6 +2415,8 @@ To work around that, do:
     (setq-local css-id-list-function #'html-current-buffer-ids))
 
   (setq imenu-create-index-function 'html-imenu-index)
+  (yank-media-handler 'text/html #'html-mode--html-yank-handler)
+  (yank-media-handler "image/.*" #'html-mode--image-yank-handler)
 
   (setq-local sgml-empty-tags
              ;; From HTML-4.01's loose.dtd, parsed with
@@ -2426,6 +2432,30 @@ To work around that, do:
   ;; (setq imenu-sort-function nil) ; sorting the menu defeats the purpose
   )
 
+(defun html-mode--html-yank-handler (_type html)
+  (save-restriction
+    (insert html)
+    (ignore-errors
+      (sgml-pretty-print (point-min) (point-max)))))
+
+(defun html-mode--image-yank-handler (type image)
+  (let ((file (read-file-name (format "Save %s image to: " type))))
+    (when (file-directory-p file)
+      (user-error "%s is a directory"))
+    (when (and (file-exists-p file)
+               (not (yes-or-no-p (format "%s exists; overwrite?" file))))
+      (user-error "%s exists"))
+    (with-temp-buffer
+      (set-buffer-multibyte nil)
+      (insert image)
+      (write-region (point-min) (point-max) file))
+    (insert (format "<img src=%S>\n" (file-relative-name file)))
+    (insert-image
+     (create-image file (mailcap-mime-type-to-extension type) nil
+                  :max-width 200
+                  :max-height 200)
+     " ")))
+
 (defvar html-imenu-regexp
   "\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)"
   "A regular expression matching a head line to be added to the menu.
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el
index 6fd66b2502..5fba93c76e 100644
--- a/lisp/textmodes/tex-mode.el
+++ b/lisp/textmodes/tex-mode.el
@@ -2457,7 +2457,7 @@ Only applies the FSPEC to the args part of FORMAT."
          (default (tex-compile-default fspec)))
      (list default-directory
           (completing-read
-           (format "Command [%s]: " (tex-summarize-command default))
+            (format-prompt "Command" (tex-summarize-command default))
            (mapcar (lambda (x)
                      (list (tex-format-cmd (eval (car x) t) fspec)))
                    tex-compile-commands)
diff --git a/lisp/textmodes/texinfo.el b/lisp/textmodes/texinfo.el
index 135a404731..71db33bae3 100644
--- a/lisp/textmodes/texinfo.el
+++ b/lisp/textmodes/texinfo.el
@@ -411,13 +411,13 @@ value of `texinfo-mode-hook'."
                      "\\)\\>"))
   (setq-local require-final-newline mode-require-final-newline)
   (setq-local indent-tabs-mode nil)
-  (setq-local paragraph-separate
-             (concat "@[a-zA-Z]*[ \n]\\|"
-                     paragraph-separate))
   (setq-local paragraph-start (concat "@[a-zA-Z]*[ \n]\\|"
                                      paragraph-start))
+  (setq-local fill-paragraph-function 'texinfo--fill-paragraph)
   (setq-local sentence-end-base "\\(@\\(end\\)?dots{}\\|[.?!]\\)[]\"'”)}]*")
   (setq-local fill-column 70)
+  (setq-local beginning-of-defun-function #'texinfo--beginning-of-defun)
+  (setq-local end-of-defun-function #'texinfo--end-of-defun)
   (setq-local comment-start "@c ")
   (setq-local comment-start-skip "@c +\\|@comment +")
   (setq-local words-include-escapes t)
@@ -457,6 +457,58 @@ value of `texinfo-mode-hook'."
                    prevent-filling
                  (concat auto-fill-inhibit-regexp "\\|" prevent-filling)))))
 
+(defvar texinfo-fillable-commands '("@noindent")
+  "A list of commands that can be filled.")
+
+(defun texinfo--fill-paragraph (justify)
+  "Function to fill a paragraph in `texinfo-mode'."
+  (let ((command-re "\\(@[a-zA-Z]+\\)[ \t\n]"))
+    (catch 'no-fill
+      (save-restriction
+        ;; First check whether we're on a command line that can be
+        ;; filled by itself.
+        (or
+         (save-excursion
+           (beginning-of-line)
+           (when (looking-at command-re)
+             (let ((command (match-string 1)))
+               (if (member command texinfo-fillable-commands)
+                   (progn
+                     (narrow-to-region (point) (progn (forward-line 1) 
(point)))
+                     t)
+                 (throw 'no-fill nil)))))
+         ;; We're not on such a line, so fill the region.
+         (save-excursion
+           (let ((regexp (concat command-re "\\|^[ \t]*$\\|\f")))
+             (narrow-to-region
+              (if (re-search-backward regexp nil t)
+                  (progn
+                    (forward-line 1)
+                    (point))
+                (point-min))
+              (if (re-search-forward regexp nil t)
+                  (match-beginning 0)
+                (point-max)))
+             (goto-char (point-min)))))
+        ;; We've now narrowed to the region we want to fill.
+        (let ((fill-paragraph-function nil)
+              (adaptive-fill-mode nil))
+          (fill-paragraph justify))))
+    t))
+
+(defun texinfo--beginning-of-defun (&optional arg)
+  "Go to the previous @node line."
+  (while (and (> arg 0)
+              (re-search-backward "^@node " nil t))
+    (setq arg (1- arg))))
+
+(defun texinfo--end-of-defun ()
+  "Go to the start of the next @node line."
+  (when (looking-at-p "@node")
+    (forward-line))
+  (if (re-search-forward "^@node " nil t)
+      (goto-char (match-beginning 0))
+    (goto-char (point-max))))
 
 
 ;;; Insert string commands
@@ -806,7 +858,8 @@ temporary file before the region itself.  The buffer's 
header is all lines
 between the strings defined by `tex-start-of-header' and `tex-end-of-header'
 inclusive.  The header must start in the first 100 lines.
 
-The value of `texinfo-tex-trailer' is appended to the temporary file after the 
region."
+The value of `texinfo-tex-trailer' is appended to the temporary
+file after the region."
   (interactive "r")
   (require 'tex-mode)
   (let ((tex-command texinfo-tex-command)
diff --git a/lisp/textmodes/texnfo-upd.el b/lisp/textmodes/texnfo-upd.el
index 843bbb2bca..6862da6046 100644
--- a/lisp/textmodes/texnfo-upd.el
+++ b/lisp/textmodes/texnfo-upd.el
@@ -1508,7 +1508,7 @@ will be at some level higher in the Texinfo file.  The 
fourth argument
               'normal
             'no-pointer))
          (t
-          (error "texinfo-find-pointer: lack proper arguments")))))
+           (error "texinfo-find-pointer: Lack proper arguments")))))
 
 (defun texinfo-pointer-name (kind)
   "Return the node name preceding the section command.
@@ -1676,7 +1676,7 @@ or `Up' pointer."
               'normal
             'no-pointer))
          (t
-          (error "texinfo-sequential-find-pointer: lack proper arguments")))))
+           (error "texinfo-sequential-find-pointer: Lack proper arguments")))))
 
 
 ;;; Inserting `@node' lines
diff --git a/lisp/textmodes/text-mode.el b/lisp/textmodes/text-mode.el
index 74c6d412a6..478cf62268 100644
--- a/lisp/textmodes/text-mode.el
+++ b/lisp/textmodes/text-mode.el
@@ -95,6 +95,28 @@ inherit all the commands defined in this map.")
      :style toggle
      :selected (memq 'turn-on-auto-fill text-mode-hook)]))
 
+(defun text-mode-context-menu (menu click)
+  "Populate MENU with text selection commands at CLICK."
+
+  (when (thing-at-mouse click 'word)
+    (define-key-after menu [select-region mark-word]
+      `(menu-item "Word"
+                  ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 'word))
+                  :help "Mark the word at click for a subsequent cut/copy")
+      'mark-whole-buffer))
+  (define-key-after menu [select-region mark-sentence]
+    `(menu-item "Sentence"
+                ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'sentence))
+                :help "Mark the sentence at click for a subsequent cut/copy")
+    'mark-whole-buffer)
+  (define-key-after menu [select-region mark-paragraph]
+    `(menu-item "Paragraph"
+                ,(lambda (e) (interactive "e") (mark-thing-at-mouse e 
'paragraph))
+                :help "Mark the paragraph at click for a subsequent cut/copy")
+    'mark-whole-buffer)
+
+  menu)
+
 
 (define-derived-mode text-mode nil "Text"
   "Major mode for editing text written for humans to read.
@@ -104,7 +126,8 @@ You can thus get the full benefit of adaptive filling
 \\{text-mode-map}
 Turning on Text mode runs the normal hook `text-mode-hook'."
   (setq-local text-mode-variant t)
-  (setq-local require-final-newline mode-require-final-newline))
+  (setq-local require-final-newline mode-require-final-newline)
+  (add-hook 'context-menu-functions 'text-mode-context-menu 10 t))
 
 (define-derived-mode paragraph-indent-text-mode text-mode "Parindent"
   "Major mode for editing text, with leading spaces starting a paragraph.
diff --git a/lisp/textmodes/tildify.el b/lisp/textmodes/tildify.el
index 01e2ad72d8..2a4c8cff8f 100644
--- a/lisp/textmodes/tildify.el
+++ b/lisp/textmodes/tildify.el
@@ -67,7 +67,7 @@ matching the white space).  The pattern is matched 
case-sensitive regardless of
 the value of `case-fold-search' setting."
   :version "25.1"
   :type 'regexp
-  :safe t)
+  :safe #'stringp)
 
 (defcustom tildify-pattern-alist ()
   "Alist specifying where to insert hard spaces.
@@ -112,7 +112,7 @@ If nil, current major mode has no way to represent a hard 
space."
                         " ")
                  (const :tag "No-break space (U+00A0)" "\u00A0")
                  (string :tag "Custom string"))
-  :safe t)
+  :safe #'string-or-null-p)
 
 (defcustom tildify-string-alist ()
   "Alist specifying what is a hard space in the current major mode.
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index efe33982c3..32e66184d7 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -231,7 +231,27 @@ The bounds of THING are determined by 
`bounds-of-thing-at-point'."
 (put 'line 'beginning-op
      (lambda () (if (bolp) (forward-line -1) (beginning-of-line))))
 
-;;  Sexps
+;;  Strings
+
+(put 'string 'bounds-of-thing-at-point 
'thing-at-point-bounds-of-string-at-point)
+
+(defun thing-at-point-bounds-of-string-at-point ()
+  "Return the bounds of the string at point.
+Prefer the enclosing string with fallback on sexp at point.
+\[Internal function used by `bounds-of-thing-at-point'.]"
+  (save-excursion
+    (let ((ppss (syntax-ppss)))
+      (if (nth 3 ppss)
+          ;; Inside the string
+          (ignore-errors
+            (goto-char (nth 8 ppss))
+            (cons (point) (progn (forward-sexp) (point))))
+        ;; At the beginning of the string
+        (if (eq (char-syntax (char-after)) ?\")
+            (let ((bound (bounds-of-thing-at-point 'sexp)))
+             (and bound
+                  (<= (car bound) (point)) (< (point) (cdr bound))
+                  bound)))))))
 
 (defun in-string-p ()
   "Return non-nil if point is in a string."
@@ -241,6 +261,8 @@ The bounds of THING are determined by 
`bounds-of-thing-at-point'."
       (beginning-of-defun)
       (nth 3 (parse-partial-sexp (point) orig)))))
 
+;;  Sexps
+
 (defun thing-at-point--end-of-sexp ()
   "Move point to the end of the current sexp."
   (let ((char-syntax (syntax-after (point))))
@@ -284,29 +306,18 @@ The bounds of THING are determined by 
`bounds-of-thing-at-point'."
 
 (put 'list 'bounds-of-thing-at-point 'thing-at-point-bounds-of-list-at-point)
 
-(defun thing-at-point-bounds-of-list-at-point (&optional escape-strings 
no-syntax-crossing)
+(defun thing-at-point-bounds-of-list-at-point ()
   "Return the bounds of the list at point.
 Prefer the enclosing list with fallback on sexp at point.
 \[Internal function used by `bounds-of-thing-at-point'.]"
   (save-excursion
-    (if (ignore-errors (up-list -1 escape-strings no-syntax-crossing))
+    (if (ignore-errors (up-list -1))
        (ignore-errors (cons (point) (progn (forward-sexp) (point))))
       (let ((bound (bounds-of-thing-at-point 'sexp)))
        (and bound
             (<= (car bound) (point)) (< (point) (cdr bound))
             bound)))))
 
-(put 'list-or-string 'bounds-of-thing-at-point
-     'thing-at-point-bounds-of-list-or-string-at-point)
-
-(defun thing-at-point-bounds-of-list-or-string-at-point ()
-  "Return the bounds of the list or string at point.
-Like `thing-at-point-bounds-of-list-at-point', but if
-point is inside a string that's enclosed in the list, this
-function will return the enclosed string and not the
-enclosing list."
-  (thing-at-point-bounds-of-list-at-point t t))
-
 ;; Defuns
 
 (put 'defun 'beginning-op 'beginning-of-defun)
diff --git a/lisp/thumbs.el b/lisp/thumbs.el
index 4c863883ba..001b2c8e77 100644
--- a/lisp/thumbs.el
+++ b/lisp/thumbs.el
@@ -91,7 +91,7 @@ When it reaches that size (in bytes), a warning is sent."
 (defcustom thumbs-conversion-program
   (if (eq system-type 'windows-nt)
       ;; FIXME is this necessary, or can a sane PATHEXE be assumed?
-      ;; Eg find-program does not do this.
+      ;; E.g. find-program does not do this.
       "convert.exe"
     "convert")
   "Name of conversion program for thumbnails generation.
@@ -292,22 +292,11 @@ smaller according to whether INCREMENT is 1 or -1."
        (thumbs-call-convert fn tn "sample" thumbs-geometry))
     tn))
 
-(defun thumbs-image-type (img)
-  "Return image type from filename IMG."
-  (cond ((string-match ".*\\.jpe?g\\'" img) 'jpeg)
-       ((string-match ".*\\.xpm\\'" img) 'xpm)
-       ((string-match ".*\\.xbm\\'" img) 'xbm)
-       ((string-match ".*\\.pbm\\'" img) 'pbm)
-       ((string-match ".*\\.gif\\'" img) 'gif)
-       ((string-match ".*\\.bmp\\'" img) 'bmp)
-       ((string-match ".*\\.png\\'" img) 'png)
-       ((string-match ".*\\.tiff?\\'" img) 'tiff)))
-
 (declare-function image-size "image.c" (spec &optional pixels frame))
 
 (defun thumbs-file-size (img)
   (let ((i (image-size
-           (find-image `((:type ,(thumbs-image-type img) :file ,img))) t)))
+            (find-image `((:type ,(image-type-from-file-name img) :file 
,img))) t)))
     (concat (number-to-string (round (car i))) "x"
            (number-to-string (round (cdr i))))))
 
@@ -410,7 +399,7 @@ and SAME-WINDOW to show thumbs in the same window."
            thumbs-image-num (or num 0))
       (delete-region (point-min)(point-max))
       (save-excursion
-       (thumbs-insert-image img (thumbs-image-type img) 0)))))
+        (thumbs-insert-image img (image-type-from-file-name img) 0)))))
 
 (defun thumbs-find-image-at-point (&optional img otherwin)
   "Display image IMG for thumbnail at point.
@@ -544,7 +533,7 @@ Open another window."
                      " - " (number-to-string num)))
        (let ((inhibit-read-only t))
          (erase-buffer)
-         (thumbs-insert-image img (thumbs-image-type img) 0)
+          (thumbs-insert-image img (image-type-from-file-name img) 0)
          (goto-char (point-min))))
       (setq thumbs-image-num num
            thumbs-current-image-filename img))))
@@ -775,6 +764,9 @@ ACTION and ARG should be a valid convert command."
 (define-key dired-mode-map "\C-tm" 'thumbs-dired-show-marked)
 (define-key dired-mode-map "\C-tw" 'thumbs-dired-setroot)
 
+(define-obsolete-function-alias 'thumbs-image-type
+  #'image-type-from-file-name "29.1")
+
 (provide 'thumbs)
 
 ;;; thumbs.el ends here
diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el
index 5258742845..178e490fb7 100644
--- a/lisp/time-stamp.el
+++ b/lisp/time-stamp.el
@@ -41,6 +41,7 @@
   :group 'data
   :group 'extensions)
 
+
 (defcustom time-stamp-format "%Y-%02m-%02d %02H:%02M:%02S %l"
   "Format of the string inserted by \\[time-stamp].
 This is a string, used verbatim except for character sequences beginning
@@ -58,7 +59,7 @@ with %, as follows.
 %#p  `am' or `pm'                       %P  gives uppercase: `AM' or `PM'
 %02S seconds
 %w   day number of week, Sunday is 0
-%02y 2-digit year: `03'                 %Y  4-digit year: `2003'
+%02y 2-digit year                       %Y  4-digit year
 %Z   time zone name: `EST'              %#Z gives lowercase: `est'
 %5z  time zone offset: `-0500' (since Emacs 27; see note below)
 
@@ -92,6 +93,7 @@ edited by older versions of Emacs also, do not use this 
format yet."
   :version "27.1")
 ;;;###autoload(put 'time-stamp-format 'safe-local-variable 'stringp)
 
+
 (defcustom time-stamp-active t
   "Non-nil to enable time-stamping of buffers by \\[time-stamp].
 Can be toggled by \\[time-stamp-toggle-active].
@@ -109,6 +111,7 @@ line to a local variables list near the end of the file:
 See also the variable `time-stamp-warn-inactive'."
   :type 'boolean)
 
+
 (defcustom time-stamp-warn-inactive t
   "Have \\[time-stamp] warn if a buffer did not get time-stamped.
 If non-nil, a warning is displayed if `time-stamp-active' has
@@ -117,6 +120,7 @@ otherwise would have been updated."
   :type 'boolean
   :version "19.29")
 
+
 (defcustom time-stamp-time-zone nil
   "The time zone to be used by \\[time-stamp].
 Its format is that of the ZONE argument of the `format-time-string' function."
@@ -131,9 +135,10 @@ Its format is that of the ZONE argument of the 
`format-time-string' function."
   :version "20.1")
 ;;;###autoload(put 'time-stamp-time-zone 'safe-local-variable 
'time-stamp-zone-type-p)
 
+
 ;;;###autoload
 (defun time-stamp-zone-type-p (zone)
-  "Return whether or not ZONE is of the correct type for a timezone rule.
+  "Return non-nil if ZONE is of the correct type for a timezone rule.
 Valid ZONE values are described in the documentation of `format-time-string'."
   (or (memq zone '(nil t wall))
       (stringp zone)
@@ -143,6 +148,7 @@ Valid ZONE values are described in the documentation of 
`format-time-string'."
            (stringp (cadr zone)))
       (integerp zone)))
 
+
 ;;; Do not change time-stamp-line-limit, time-stamp-start,
 ;;; time-stamp-end, time-stamp-pattern, time-stamp-inserts-lines,
 ;;; or time-stamp-count in your .emacs or you will be incompatible
@@ -167,6 +173,7 @@ If you were to change `time-stamp-line-limit', 
`time-stamp-start',
 would be incompatible with other people's files.")
 ;;;###autoload(put 'time-stamp-line-limit 'safe-local-variable 'integerp)
 
+
 (defvar time-stamp-start "Time-stamp:[ \t]+\\\\?[\"<]+"    ;Do not change!
   "Regexp after which the time stamp is written by \\[time-stamp].
 
@@ -180,6 +187,7 @@ If you were to change `time-stamp-line-limit', 
`time-stamp-start',
 would be incompatible with other people's files.")
 ;;;###autoload(put 'time-stamp-start 'safe-local-variable 'stringp)
 
+
 (defvar time-stamp-end "\\\\?[\">]"    ;Do not change!
   "Regexp marking the text after the time stamp.
 \\[time-stamp] deletes the text between the first match of `time-stamp-start'
@@ -192,8 +200,8 @@ or `time-stamp-format'.
 
 The end text normally starts on the same line as the start text ends,
 but if there are any newlines in `time-stamp-format', the same number
-of newlines must separate the start and end.  \\[time-stamp] tries
-to not change the number of lines in the buffer.  `time-stamp-inserts-lines'
+of newlines must separate the start and end.  Thus \\[time-stamp] tries
+to not change the number of lines in the buffer; `time-stamp-inserts-lines'
 controls this behavior.
 
 These variables are best changed with file-local variables.
@@ -305,7 +313,7 @@ this line to a local variables list near the end of the 
file:
 
 If the file has no time-stamp template, this function does nothing.
 
-You can set `time-stamp-pattern' in a files's local variables list
+You can set `time-stamp-pattern' in a file's local variables list
 to customize the information in the time stamp and where it is written.
 
 The time stamp is updated only if `time-stamp-active' is non-nil."
@@ -469,9 +477,8 @@ normally the current time is used."
 (defconst time-stamp-no-file "(no file)"
   "String to use when the buffer is not associated with a file.")
 
-;;; time-stamp is transitioning to be compatible with format-time-string.
-;;; During the process, this function implements
-;;; intermediate, compatible formats.
+;;; time-stamp is transitioning to be more compatible with format-time-string.
+;;; This function implements the differences.
 ;;;      At all times, all the formats recommended in the doc string
 ;;; of time-stamp-format will work not only in the current version of
 ;;; Emacs, but in all versions that have been released within the past
@@ -705,7 +712,7 @@ and all `time-stamp-format' compatibility."
 
 (defun time-stamp-do-number (format-char alt-form field-width time)
   "Handle compatible FORMAT-CHAR where only default width/padding will change.
-ALT-FORM is whether `#' specified.  FIELD-WIDTH is the string
+ALT-FORM is whether `#' was specified.  FIELD-WIDTH is the string
 width specification or \"\".  TIME is the time to convert.
 This is an internal helper for `time-stamp-string-preprocess'."
   (let ((format-string (concat "%" (char-to-string format-char))))
@@ -713,6 +720,7 @@ This is an internal helper for 
`time-stamp-string-preprocess'."
        ""                              ;discourage "%:2d" and the like
       (string-to-number (time-stamp--format format-string time)))))
 
+
 (defvar time-stamp-conversion-warn t
   "Enable warnings about soon-to-be-unsupported forms in `time-stamp-format'.
 If nil, these warnings are disabled, which would be a bad idea!
@@ -740,6 +748,7 @@ Suggests replacing OLD-FORM with NEW-FORM."
       (insert "\"" old-form "\" -- use " new-form "\n"))
     (display-buffer "*Time-stamp-compatibility*"))))
 
+
 ;;; A principled, expressive implementation of time zone offset
 ;;; formatting ("%z" and variants).
 
@@ -816,15 +825,13 @@ Suggests replacing OLD-FORM with NEW-FORM."
 
 ;;; * ABNF syntax of the offset string produced by %z
 
-;; offset = sign hours [minutes [seconds]] padding /
-;;          sign hours [colonminutes [colonseconds]] padding /
-;;          sign bighours colonminutes [colonseconds] padding
+;; offset = sign ( hours [minutes [seconds]] /
+;;                 hours [":" minutes [":" seconds]] /
+;;                 bighours ":" minutes [":" seconds] ) padding
 ;; sign = "+" / "-"
 ;; hours = digitpair
 ;; minutes = digitpair
 ;; seconds = digitpair
-;; colonminutes = ":" minutes
-;; colonseconds = ":" seconds
 ;; digitpair = digit digit
 ;; digit = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
 ;; bighours = 1*digit digitpair
@@ -837,8 +844,6 @@ Suggests replacing OLD-FORM with NEW-FORM."
                                                field-width
                                                offset-secs)
   "Formats a time offset according to a %z variation.
-The caller of this function must have already parsed the %z format
-string; this function accepts just the parts of the format.
 
 With no flags, the output includes hours and minutes: +-HHMM
 unless there is a non-zero seconds part, in which case the seconds
@@ -865,7 +870,14 @@ added on the right if necessary.  The added characters 
will be spaces
 unless FLAG-PAD-ZEROS-FIRST is non-nil.
 
 OFFSET-SECS is the time zone offset (in seconds east of UTC) to be
-formatted according to the preceding parameters."
+formatted according to the preceding parameters.
+
+This is an internal function used by `time-stamp'."
+  ;; The caller of this function must have already parsed the %z
+  ;; format string; this function accepts just the parts of the format.
+  ;; `time-stamp-string-preprocess' is the full-fledged parser normally
+  ;; used.  The unit test (in time-stamp-tests.el) defines the simpler
+  ;; parser `format-time-offset'.
   (let ((hrs (/ (abs offset-secs) 3600))
         (mins (/ (% (abs offset-secs) 3600) 60))
         (secs (% (abs offset-secs) 60))
diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el
index 6da401187b..f5d64aeb36 100644
--- a/lisp/tool-bar.el
+++ b/lisp/tool-bar.el
@@ -290,6 +290,8 @@ holds a keymap."
       "Specify on which side the tool bar shall be.
 Possible values are `top' (tool bar on top), `bottom' (tool bar at bottom),
 `left' (tool bar on left) and `right' (tool bar on right).
+This option has effect only on graphical frames and only
+if Emacs was built with GTK.
 Customize `tool-bar-mode' if you want to show or hide the tool bar."
       :version "24.1"
       :type '(choice (const top)
diff --git a/lisp/transient.el b/lisp/transient.el
index f3d3902a77..f80e6afb10 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -7,7 +7,7 @@
 ;; Keywords: bindings
 
 ;; Package-Requires: ((emacs "25.1"))
-;; Package-Version: 0.3.6
+;; Package-Version: 0.3.7
 
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 
@@ -54,6 +54,7 @@
 
 (require 'cl-lib)
 (require 'eieio)
+(require 'edmacro)
 (require 'format-spec)
 (require 'seq)
 
@@ -74,7 +75,7 @@
 (define-obsolete-function-alias 'define-infix-command
   'transient-define-infix "Transient 0.3.0")
 (define-obsolete-function-alias 'define-infix-argument
-  'transient-define-argument "Transient 0.3.0")
+  #'transient-define-argument "Transient 0.3.0")
 
 (define-obsolete-variable-alias 'current-transient-prefix
   'transient-current-prefix "Transient 0.3.0")
@@ -148,34 +149,46 @@ features are available:
 (defcustom transient-display-buffer-action
   '(display-buffer-in-side-window
     (side . bottom)
-    (inhibit-same-window . t))
+    (dedicated . t)
+    (inhibit-same-window . t)
+    (window-parameters (no-other-window . t)))
   "The action used to display the transient popup buffer.
 
 The transient popup buffer is displayed in a window using
 
-  \(display-buffer buf transient-display-buffer-action)
+  (display-buffer BUFFER transient-display-buffer-action)
 
 The value of this option has the form (FUNCTION . ALIST),
 where FUNCTION is a function or a list of functions.  Each such
-function should accept two arguments: a buffer to display and
-an alist of the same form as ALIST.  See `display-buffer' for
-details.
+function should accept two arguments: a buffer to display and an
+alist of the same form as ALIST.  See info node `(elisp)Choosing
+Window' for details.
 
 The default is:
 
   (display-buffer-in-side-window
     (side . bottom)
-    (inhibit-same-window . t))
+    (dedicated . t)
+    (inhibit-same-window . t)
+    (window-parameters (no-other-window . t)))
 
 This displays the window at the bottom of the selected frame.
-Another useful value is (display-buffer-below-selected).  This
-is what `magit-popup' used by default.  For more alternatives
-see info node `(elisp)Display Action Functions'.
+Another useful FUNCTION is `display-buffer-below-selected', which
+is what `magit-popup' used by default.  For more alternatives see
+info node `(elisp)Display Action Functions' and info node
+`(elisp)Buffer Display Action Alists'.
+
+Note that the buffer that was current before the transient buffer
+is shown should remain the current buffer.  Many suffix commands
+act on the thing at point, if appropriate, and if the transient
+buffer became the current buffer, then that would change what is
+at point.  To that effect `inhibit-same-window' ensures that the
+selected window is not used to show the transient buffer.
 
 It may be possible to display the window in another frame, but
 whether that works in practice depends on the window-manager.
 If the window manager selects the new window (Emacs frame),
-then it doesn't work.
+then that unfortunately changes which buffer is current.
 
 If you change the value of this option, then you might also
 want to change the value of `transient-mode-line-format'."
@@ -569,7 +582,7 @@ If `transient-save-history' is nil, then do nothing."
     (transient-save-history)))
 
 (unless noninteractive
-  (add-hook 'kill-emacs-hook 'transient-maybe-save-history))
+  (add-hook 'kill-emacs-hook #'transient-maybe-save-history))
 
 ;;; Classes
 ;;;; Prefix
@@ -585,12 +598,14 @@ If `transient-save-history' is nil, then do nothing."
    (history     :initarg :history     :initform nil)
    (history-pos :initarg :history-pos :initform 0)
    (history-key :initarg :history-key :initform nil)
-   (man-page    :initarg :man-page    :initform nil)
+   (show-help   :initarg :show-help   :initform nil)
    (info-manual :initarg :info-manual :initform nil)
+   (man-page    :initarg :man-page    :initform nil)
    (transient-suffix     :initarg :transient-suffix     :initform nil)
    (transient-non-suffix :initarg :transient-non-suffix :initform nil)
    (incompatible         :initarg :incompatible         :initform nil)
-   (suffix-description   :initarg :suffix-description))
+   (suffix-description   :initarg :suffix-description)
+   (variable-pitch       :initarg :variable-pitch       :initform nil))
   "Transient prefix command.
 
 Each transient prefix command consists of a command, which is
@@ -640,7 +655,7 @@ the prototype is stored in the clone's `prototype' slot.")
     :initarg :if-not-derived
     :initform nil
     :documentation "Enable if major-mode does not derive from value."))
-  "Abstract superclass for group and and suffix classes.
+  "Abstract superclass for group and suffix classes.
 
 It is undefined what happens if more than one `if*' predicate
 slot is non-nil."
@@ -652,6 +667,7 @@ slot is non-nil."
    (transient   :initarg :transient)
    (format      :initarg :format      :initform " %k %d")
    (description :initarg :description :initform nil)
+   (show-help   :initarg :show-help   :initform nil)
    (inapt                             :initform nil)
    (inapt-if
     :initarg :inapt-if
@@ -726,10 +742,14 @@ slot is non-nil."
    (argument-regexp  :initarg :argument-regexp))
   "Class used for sets of mutually exclusive command-line switches.")
 
-(defclass transient-files (transient-infix) ()
-  "Class used for the \"--\" argument.
+(defclass transient-files (transient-option) ()
+  ((key         :initform "--")
+   (argument    :initform "--")
+   (multi-value :initform rest)
+   (reader      :initform transient-read-files))
+  "Class used for the \"--\" argument or similar.
 All remaining arguments are treated as files.
-They become the value of this this argument.")
+They become the value of this argument.")
 
 ;;;; Group
 
@@ -910,7 +930,7 @@ keyword.
        (put ',name 'transient--suffix
             (,(or class 'transient-switch) :command ',name ,@slots)))))
 
-(defalias 'transient-define-argument 'define-infix-command
+(defalias 'transient-define-argument #'transient-define-infix
   "Define NAME as a transient infix command.
 
 Only use this alias to define an infix command that actually
@@ -1061,7 +1081,8 @@ example, sets a variable use `transient-define-infix' 
instead.
           (put cmd 'transient--infix-command
                (transient--default-infix-command))
         ;; This is not an anonymous infix argument.
-        (error "Suffix %s is not defined or autoloaded as a command" cmd)))))
+        (when (transient--use-suffix-p obj)
+          (error "Suffix %s is not defined or autoloaded as a command" 
cmd))))))
 
 (defun transient--derive-shortarg (arg)
   (save-match-data
@@ -1289,8 +1310,8 @@ variable instead.")
 
 (defvar transient--exitp nil "Whether to exit the transient.")
 (defvar transient--showp nil "Whether the transient is show in a popup 
buffer.")
-(defvar transient--helpp nil "Whether `help-mode' is active.")
-(defvar transient--editp nil "Whether `edit-mode' is active.")
+(defvar transient--helpp nil "Whether help-mode is active.")
+(defvar transient--editp nil "Whether edit-mode is active.")
 
 (defvar transient--active-infix nil "The active infix awaiting user input.")
 
@@ -1415,14 +1436,14 @@ then just return it.  Otherwise return the symbol whose
 
 (defvar transient-base-map
   (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "ESC ESC ESC") 'transient-quit-all)
-    (define-key map (kbd "C-g") 'transient-quit-one)
-    (define-key map (kbd "C-q") 'transient-quit-all)
-    (define-key map (kbd "C-z") 'transient-suspend)
-    (define-key map (kbd "C-v") 'transient-scroll-up)
-    (define-key map (kbd "C-M-v") 'transient-scroll-down)
-    (define-key map [next]      'transient-scroll-up)
-    (define-key map [prior]     'transient-scroll-down)
+    (define-key map (kbd "ESC ESC ESC") #'transient-quit-all)
+    (define-key map (kbd "C-g")   #'transient-quit-one)
+    (define-key map (kbd "C-q")   #'transient-quit-all)
+    (define-key map (kbd "C-z")   #'transient-suspend)
+    (define-key map (kbd "C-v")   #'transient-scroll-up)
+    (define-key map (kbd "C-M-v") #'transient-scroll-down)
+    (define-key map [next]        #'transient-scroll-up)
+    (define-key map [prior]       #'transient-scroll-down)
     map)
   "Parent of other keymaps used by Transient.
 
@@ -1442,14 +1463,14 @@ to `transient-predicate-map'.")
 (defvar transient-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map transient-base-map)
-    (define-key map (kbd "C-p") 'universal-argument)
-    (define-key map (kbd "C--") 'negative-argument)
-    (define-key map (kbd "C-t") 'transient-show)
-    (define-key map (kbd "?")   'transient-help)
-    (define-key map (kbd "C-h") 'transient-help)
+    (define-key map (kbd "C-u")   #'universal-argument)
+    (define-key map (kbd "C--")   #'negative-argument)
+    (define-key map (kbd "C-t")   #'transient-show)
+    (define-key map (kbd "?")     #'transient-help)
+    (define-key map (kbd "C-h")   #'transient-help)
     ;; Also bound to "C-x p" and "C-x n" in transient-common-commands.
-    (define-key map (kbd "C-M-p") 'transient-history-prev)
-    (define-key map (kbd "C-M-n") 'transient-history-next)
+    (define-key map (kbd "C-M-p") #'transient-history-prev)
+    (define-key map (kbd "C-M-n") #'transient-history-next)
     map)
   "Top-level keymap used by all transients.
 
@@ -1459,16 +1480,16 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
 (defvar transient-edit-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map transient-base-map)
-    (define-key map (kbd "?")     'transient-help)
-    (define-key map (kbd "C-h")   'transient-help)
-    (define-key map (kbd "C-x l") 'transient-set-level)
+    (define-key map (kbd "?")     #'transient-help)
+    (define-key map (kbd "C-h")   #'transient-help)
+    (define-key map (kbd "C-x l") #'transient-set-level)
     map)
   "Keymap that is active while a transient in is in \"edit mode\".")
 
 (defvar transient-sticky-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map transient-base-map)
-    (define-key map (kbd "C-g") 'transient-quit-seq)
+    (define-key map (kbd "C-g") #'transient-quit-seq)
     map)
   "Keymap that is active while an incomplete key sequence is active.")
 
@@ -1503,36 +1524,36 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'.")
 
 (defvar transient-predicate-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [handle-switch-frame]     'transient--do-suspend)
-    (define-key map [transient-suspend]       'transient--do-suspend)
-    (define-key map [transient-help]          'transient--do-stay)
-    (define-key map [transient-set-level]     'transient--do-stay)
-    (define-key map [transient-history-prev]  'transient--do-stay)
-    (define-key map [transient-history-next]  'transient--do-stay)
-    (define-key map [universal-argument]      'transient--do-stay)
-    (define-key map [negative-argument]       'transient--do-stay)
-    (define-key map [digit-argument]          'transient--do-stay)
-    (define-key map [transient-quit-all]      'transient--do-quit-all)
-    (define-key map [transient-quit-one]      'transient--do-quit-one)
-    (define-key map [transient-quit-seq]      'transient--do-stay)
-    (define-key map [transient-show]          'transient--do-stay)
-    (define-key map [transient-update]        'transient--do-stay)
-    (define-key map [transient-toggle-common] 'transient--do-stay)
-    (define-key map [transient-set]           'transient--do-call)
-    (define-key map [transient-save]          'transient--do-call)
-    (define-key map [describe-key-briefly]    'transient--do-stay)
-    (define-key map [describe-key]            'transient--do-stay)
-    (define-key map [transient-scroll-up]     'transient--do-stay)
-    (define-key map [transient-scroll-down]   'transient--do-stay)
-    (define-key map [mwheel-scroll]           'transient--do-stay)
-    (define-key map [scroll-bar-toolkit-scroll]   'transient--do-stay)
-    (define-key map [transient-noop]              'transient--do-noop)
-    (define-key map [transient-mouse-push-button] 'transient--do-move)
-    (define-key map [transient-push-button]       'transient--do-move)
-    (define-key map [transient-backward-button]   'transient--do-move)
-    (define-key map [transient-forward-button]    'transient--do-move)
-    (define-key map [transient-isearch-backward]  'transient--do-move)
-    (define-key map [transient-isearch-forward]   'transient--do-move)
+    (define-key map [handle-switch-frame]     #'transient--do-suspend)
+    (define-key map [transient-suspend]       #'transient--do-suspend)
+    (define-key map [transient-help]          #'transient--do-stay)
+    (define-key map [transient-set-level]     #'transient--do-stay)
+    (define-key map [transient-history-prev]  #'transient--do-stay)
+    (define-key map [transient-history-next]  #'transient--do-stay)
+    (define-key map [universal-argument]      #'transient--do-stay)
+    (define-key map [negative-argument]       #'transient--do-stay)
+    (define-key map [digit-argument]          #'transient--do-stay)
+    (define-key map [transient-quit-all]      #'transient--do-quit-all)
+    (define-key map [transient-quit-one]      #'transient--do-quit-one)
+    (define-key map [transient-quit-seq]      #'transient--do-stay)
+    (define-key map [transient-show]          #'transient--do-stay)
+    (define-key map [transient-update]        #'transient--do-stay)
+    (define-key map [transient-toggle-common] #'transient--do-stay)
+    (define-key map [transient-set]           #'transient--do-call)
+    (define-key map [transient-save]          #'transient--do-call)
+    (define-key map [describe-key-briefly]    #'transient--do-stay)
+    (define-key map [describe-key]            #'transient--do-stay)
+    (define-key map [transient-scroll-up]     #'transient--do-stay)
+    (define-key map [transient-scroll-down]   #'transient--do-stay)
+    (define-key map [mwheel-scroll]           #'transient--do-stay)
+    (define-key map [scroll-bar-toolkit-scroll]   #'transient--do-stay)
+    (define-key map [transient-noop]              #'transient--do-noop)
+    (define-key map [transient-mouse-push-button] #'transient--do-move)
+    (define-key map [transient-push-button]       #'transient--do-move)
+    (define-key map [transient-backward-button]   #'transient--do-move)
+    (define-key map [transient-forward-button]    #'transient--do-move)
+    (define-key map [transient-isearch-backward]  #'transient--do-move)
+    (define-key map [transient-isearch-forward]   #'transient--do-move)
     map)
   "Base keymap used to map common commands to their transient behavior.
 
@@ -1606,22 +1627,23 @@ of the corresponding object.")
              (sym (transient--suffix-symbol cmd)))
         (cond
          ((oref obj inapt)
-          (define-key map (vector sym) 'transient--do-warn-inapt))
+          (define-key map (vector sym) #'transient--do-warn-inapt))
          ((slot-boundp obj 'transient)
           (define-key map (vector sym)
             (let ((do (oref obj transient)))
               (pcase do
-                (`t (if sub-prefix
-                        'transient--do-replace
-                      'transient--do-stay))
+                (`t (cond (sub-prefix #'transient--do-replace)
+                          ((cl-typep obj 'transient-infix)
+                           #'transient--do-stay)
+                          (t #'transient--do-call)))
                 (`nil 'transient--do-exit)
                 (_ do)))))
          ((not (lookup-key transient-predicate-map (vector sym)))
           (define-key map (vector sym)
             (if sub-prefix
-                'transient--do-replace
+                #'transient--do-replace
               (or (oref transient--prefix transient-suffix)
-                  'transient--do-exit)))))))
+                  #'transient--do-exit)))))))
     map))
 
 (defun transient--make-redisplay-map ()
@@ -1649,7 +1671,7 @@ of the corresponding object.")
                   (listp def)
                   (keymapp def))
          (define-key topmap (vconcat transient--redisplay-key (list key))
-           'transient-update)))
+           #'transient-update)))
      (if transient--redisplay-key
          (lookup-key transient--transient-map (vconcat 
transient--redisplay-key))
        transient--transient-map))
@@ -1678,7 +1700,7 @@ EDIT may be non-nil."
       (transient--pop-keymap 'transient--redisplay-map)
       (setq name (oref transient--prefix command))
       (setq params (list :scope (oref transient--prefix scope))))
-     (transient--transient-map
+     (transient--prefix
       ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}"
       ;; of an outer prefix.  Unlike the usual `transient--do-replace',
       ;; these predicates fail to clean up after the outer prefix.
@@ -1953,8 +1975,10 @@ value.  Otherwise return CHILDREN as is."
 (defun transient--delete-window ()
   (when (window-live-p transient--window)
     (let ((buf (window-buffer transient--window)))
-      (with-demoted-errors "Error while exiting transient: %S"
-        (delete-window transient--window))
+      ;; Only delete the window if it never showed another buffer.
+      (unless (eq (car (window-parameter transient--window 'quit-restore)) 
'other)
+        (with-demoted-errors "Error while exiting transient: %S"
+          (delete-window transient--window)))
       (kill-buffer buf))))
 
 (defun transient--export ()
@@ -2093,8 +2117,8 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--emergency-exit ()
   "Exit the current transient command after an error occurred.
-When no transient is active (i.e. when `transient--prefix') is
-nil, then do nothing."
+When no transient is active (i.e. when `transient--prefix' is
+nil) then do nothing."
   (transient--debug 'emergency-exit)
   (when transient--prefix
     (setq transient--stack nil)
@@ -2171,17 +2195,17 @@ to `transient--do-warn'."
     (setq this-command 'transient-popup-navigation-help))
   transient--stay)
 
-(put 'transient--do-stay       'transient-color 'transient-blue)
-(put 'transient--do-noop       'transient-color 'transient-blue)
-(put 'transient--do-warn       'transient-color 'transient-blue)
-(put 'transient--do-warn-inapt 'transient-color 'transient-blue)
-(put 'transient--do-call       'transient-color 'transient-blue)
-(put 'transient--do-exit       'transient-color 'transient-red)
-(put 'transient--do-replace    'transient-color 'transient-red)
-(put 'transient--do-suspend    'transient-color 'transient-red)
-(put 'transient--do-quit-one   'transient-color 'transient-red)
-(put 'transient--do-quit-all   'transient-color 'transient-red)
-(put 'transient--do-move       'transient-color 'transient-blue)
+(put 'transient--do-stay       'transient-color 'transient-red)
+(put 'transient--do-noop       'transient-color 'transient-red)
+(put 'transient--do-warn       'transient-color 'transient-red)
+(put 'transient--do-warn-inapt 'transient-color 'transient-red)
+(put 'transient--do-call       'transient-color 'transient-red)
+(put 'transient--do-exit       'transient-color 'transient-blue)
+(put 'transient--do-replace    'transient-color 'transient-blue)
+(put 'transient--do-suspend    'transient-color 'transient-blue)
+(put 'transient--do-quit-one   'transient-color 'transient-blue)
+(put 'transient--do-quit-all   'transient-color 'transient-blue)
+(put 'transient--do-move       'transient-color 'transient-red)
 
 ;;; Commands
 
@@ -2209,7 +2233,18 @@ to `transient--do-warn'."
            (propertize "?"   'face 'transient-key)
            (propertize (symbol-name (transient--suffix-symbol
                                      this-original-command))
-                       'face 'font-lock-warning-face)))
+                       'face 'font-lock-warning-face))
+  (unless (and transient--transient-map
+               (memq transient--transient-map overriding-terminal-local-map))
+    (let ((transient--prefix (or transient--prefix 'sic)))
+      (transient--emergency-exit))
+    (view-lossage)
+    (other-window 1)
+    (display-warning 'transient "Inconsistent transient state detected.
+This should never happen.
+Please open an issue and post the shown command log.
+This is a heisenbug, so any additional details might help.
+Thanks!" :error)))
 
 (defun transient-toggle-common ()
   "Toggle whether common commands are always shown."
@@ -2407,14 +2442,14 @@ Non-infix suffix commands usually don't have a value."
 
 (cl-defmethod transient-init-value :around ((obj transient-prefix))
   "If bound, then call OBJ's `init-value' function.
-Otherwise call the primary method according to objects class."
+Otherwise call the primary method according to object's class."
   (if (slot-boundp obj 'init-value)
       (funcall (oref obj init-value) obj)
     (cl-call-next-method obj)))
 
 (cl-defmethod transient-init-value :around ((obj transient-infix))
   "If bound, then call OBJ's `init-value' function.
-Otherwise call the primary method according to objects class."
+Otherwise call the primary method according to object's class."
   (if (slot-boundp obj 'init-value)
       (funcall (oref obj init-value) obj)
     (cl-call-next-method obj)))
@@ -2432,30 +2467,30 @@ Otherwise call the primary method according to objects 
class."
                   default)
               nil)))))
 
+(cl-defmethod transient-init-value ((obj transient-argument))
+  (oset obj value
+        (let ((value (oref transient--prefix value))
+              (argument (and (slot-boundp obj 'argument)
+                             (oref obj argument)))
+              (multi-value (oref obj multi-value))
+              (regexp (if (slot-exists-p obj 'argument-regexp)
+                          (oref obj argument-regexp)
+                        (format "\\`%s\\(.*\\)" (oref obj argument)))))
+          (if (memq multi-value '(t rest))
+              (cdr (assoc argument value))
+            (let ((match (lambda (v)
+                           (and (stringp v)
+                                (string-match regexp v)
+                                (match-string 1 v)))))
+              (if multi-value
+                  (delq nil (mapcar match value))
+                (cl-some match value)))))))
+
 (cl-defmethod transient-init-value ((obj transient-switch))
   (oset obj value
         (car (member (oref obj argument)
                      (oref transient--prefix value)))))
 
-(cl-defmethod transient-init-value ((obj transient-option))
-  (oset obj value
-        (transient--value-match (format "\\`%s\\(.*\\)" (oref obj argument)))))
-
-(cl-defmethod transient-init-value ((obj transient-switches))
-  (oset obj value
-        (transient--value-match (oref obj argument-regexp))))
-
-(defun transient--value-match (re)
-  (when-let ((match (cl-find-if (lambda (v)
-                                  (and (stringp v)
-                                       (string-match re v)))
-                                (oref transient--prefix value))))
-    (match-string 1 match)))
-
-(cl-defmethod transient-init-value ((obj transient-files))
-  (oset obj value
-        (cdr (assoc "--" (oref transient--prefix value)))))
-
 ;;;; Read
 
 (cl-defgeneric transient-infix-read (obj)
@@ -2595,13 +2630,12 @@ stand-alone command."
     (cl-block nil
       (while t
         (let ((str (read-from-minibuffer prompt initial-input nil nil 
history)))
-          (cond ((string-equal str "")
-                 (cl-return nil))
-                ((string-match-p (if include-zero
-                                     "\\`\\(0\\|[1-9][0-9]*\\)\\'"
-                                   "\\`[1-9][0-9]*\\'")
-                                 str)
-                 (cl-return str))))
+          (when (or (string-equal str "")
+                    (string-match-p (if include-zero
+                                        "\\`\\(0\\|[1-9][0-9]*\\)\\'"
+                                      "\\`[1-9][0-9]*\\'")
+                                    str))
+            (cl-return str)))
         (message "Please enter a natural number (%s zero)."
                  (if include-zero "including" "excluding"))
         (sit-for 1)))))
@@ -2670,7 +2704,10 @@ prompt."
                (oref obj argument-regexp))))
     (if-let ((sic (and value arg transient--unset-incompatible))
              (spec (oref transient--prefix incompatible))
-             (incomp (remove arg (cl-find-if (lambda (elt) (member arg elt)) 
spec))))
+             (incomp (cl-mapcan (lambda (rule)
+                                  (and (member arg rule)
+                                       (remove arg rule)))
+                                spec)))
         (progn
           (cl-call-next-method obj value)
           (dolist (arg incomp)
@@ -2703,7 +2740,7 @@ If the current command was invoked from the transient 
prefix
 command PREFIX, then return the active infix arguments.  If
 the current command was not invoked from PREFIX, then return
 the set, saved or default value for PREFIX."
-  (delq nil (mapcar 'transient-infix-value (transient-suffixes prefix))))
+  (cl-mapcan #'transient--get-wrapped-value (transient-suffixes prefix)))
 
 (defun transient-suffixes (prefix)
   "Return the suffix objects of the transient prefix command PREFIX."
@@ -2714,11 +2751,20 @@ the set, saved or default value for PREFIX."
        (transient--init-suffixes prefix)))))
 
 (defun transient-get-value ()
-  (delq nil (mapcar (lambda (obj)
-                      (and (or (not (slot-exists-p obj 'unsavable))
-                               (not (oref obj unsavable)))
-                           (transient-infix-value obj)))
-                    transient-current-suffixes)))
+  (transient--with-emergency-exit
+    (cl-mapcan (lambda (obj)
+                 (and (or (not (slot-exists-p obj 'unsavable))
+                          (not (oref obj unsavable)))
+                      (transient--get-wrapped-value obj)))
+               transient-current-suffixes)))
+
+(defun transient--get-wrapped-value (obj)
+  (when-let ((value (transient-infix-value obj)))
+    (cl-ecase (and (slot-exists-p obj 'multi-value)
+                   (oref obj multi-value))
+      ((nil)    (list value))
+      ((t rest) (list value))
+      (repeat   value))))
 
 (cl-defgeneric transient-infix-value (obj)
   "Return the value of the suffix object OBJ.
@@ -2736,7 +2782,7 @@ Usually only infixes have a value, but see the method for
 (cl-defmethod transient-infix-value ((_   transient-suffix))
   "Return nil, which means \"no value\".
 
-Infix arguments contribute the the transient's value while suffix
+Infix arguments contribute the transient's value while suffix
 commands consume it.  This function is called for suffixes anyway
 because a command that both contributes to the transient's value
 and also consumes it is not completely unconceivable.
@@ -2750,13 +2796,13 @@ does nothing." nil)
   (oref obj value))
 
 (cl-defmethod transient-infix-value ((obj transient-option))
-  "Return (concat ARGUMENT VALUE) or nil.
-
-ARGUMENT and VALUE are the values of the respective slots of OBJ.
-If VALUE is nil, then return nil.  VALUE may be the empty string,
-which is not the same as nil."
+  "Return ARGUMENT and VALUE as a unit or nil if the latter is nil."
   (when-let ((value (oref obj value)))
-    (concat (oref obj argument) value)))
+    (let ((arg (oref obj argument)))
+      (cl-ecase (oref obj multi-value)
+        ((nil)    (concat arg value))
+        ((t rest) (cons arg value))
+        (repeat   (mapcar (lambda (v) (concat arg v)) value))))))
 
 (cl-defmethod transient-infix-value ((_   transient-variable))
   "Return nil, which means \"no value\".
@@ -2766,15 +2812,6 @@ value of the variable.  I.e. this is a side-effect and 
does not
 contribute to the value of the transient."
   nil)
 
-(cl-defmethod transient-infix-value ((obj transient-files))
-  "Return (cons ARGUMENT VALUE) or nil.
-
-ARGUMENT and VALUE are the values of the respective slots of OBJ.
-If VALUE is nil, then return nil.  VALUE may be the empty string,
-which is not the same as nil."
-  (when-let ((value (oref obj value)))
-    (cons (oref obj argument) value)))
-
 ;;;; Utilities
 
 (defun transient-arg-value (arg args)
@@ -2860,16 +2897,11 @@ have a history of their own.")
   (setq transient--showp t)
   (let ((buf (get-buffer-create transient--buffer-name))
         (focus nil))
-    (unless (window-live-p transient--window)
-      (setq transient--window
-            (display-buffer buf transient-display-buffer-action)))
-    (with-selected-window transient--window
+    (with-current-buffer buf
       (when transient-enable-popup-navigation
-        (setq focus (button-get (point) 'command)))
+        (setq focus (or (button-get (point) 'command)
+                        (transient--heading-at-point))))
       (erase-buffer)
-      (set-window-hscroll transient--window 0)
-      (set-window-dedicated-p transient--window t)
-      (set-window-parameter transient--window 'no-other-window t)
       (setq window-size-fixed t)
       (when (bound-and-true-p tab-line-format)
         (setq tab-line-format nil))
@@ -2896,14 +2928,26 @@ have a history of their own.")
                  'transient-separator)))
           (insert (propertize "__" 'face face 'display '(space :height (1))))
           (insert (propertize "\n" 'face face 'line-height t))))
-      (let ((window-resize-pixelwise t)
-            (window-size-fixed nil))
-        (fit-window-to-buffer nil nil 1))
-      (goto-char (point-min))
       (when transient-force-fixed-pitch
-        (transient--force-fixed-pitch))
-      (when transient-enable-popup-navigation
-        (transient--goto-button focus)))))
+        (transient--force-fixed-pitch)))
+    (unless (window-live-p transient--window)
+      (setq transient--window
+            (display-buffer buf transient-display-buffer-action)))
+    (when (window-live-p transient--window)
+      (with-selected-window transient--window
+        (goto-char (point-min))
+        (when transient-enable-popup-navigation
+          (transient--goto-button focus))
+        (magit--fit-window-to-buffer transient--window)))))
+
+(defun magit--fit-window-to-buffer (window)
+  (let ((window-resize-pixelwise t)
+        (window-size-fixed nil))
+    (if (eq (car (window-parameter window 'quit-restore)) 'other)
+        ;; Grow but never shrink window that previously displayed
+        ;; another buffer and is going to display that again.
+        (fit-window-to-buffer window nil (window-height window))
+      (fit-window-to-buffer window nil 1))))
 
 (defun transient--insert-groups ()
   (let ((groups (cl-mapcan (lambda (group)
@@ -2946,16 +2990,22 @@ have a history of their own.")
           (mapcar
            (lambda (column)
              (transient--maybe-pad-keys column group)
-             (let ((rows (mapcar 'transient-format (oref column suffixes))))
+             (let ((rows (mapcar #'transient-format (oref column suffixes))))
                (when-let ((desc (transient-format-description column)))
                  (push desc rows))
                rows))
            (oref group suffixes)))
+         (vp (oref transient--prefix variable-pitch))
          (rs (apply #'max (mapcar #'length columns)))
          (cs (length columns))
-         (cw (mapcar (lambda (col) (apply #'max (mapcar #'length col)))
+         (cw (mapcar (lambda (col)
+                       (apply #'max
+                              (mapcar (if vp #'transient--pixel-width #'length)
+                                      col)))
                      columns))
-         (cc (transient--seq-reductions-from (apply-partially #'+ 3) cw 0)))
+         (cc (transient--seq-reductions-from
+              (apply-partially #'+ (* 3 (if vp (transient--pixel-width " ") 
1)))
+              cw 0)))
     (if transient-force-single-column
         (dotimes (c cs)
           (dotimes (r rs)
@@ -2966,11 +3016,28 @@ have a history of their own.")
             (insert ?\n)))
       (dotimes (r rs)
         (dotimes (c cs)
-          (insert (make-string (- (nth c cc) (current-column)) ?\s))
-          (when-let ((cell (nth r (nth c columns))))
-            (insert cell))
-          (when (= c (1- cs))
-            (insert ?\n)))))))
+          (if vp
+              (progn
+                (when-let ((cell (nth r (nth c columns))))
+                  (insert cell))
+                (if (= c (1- cs))
+                    (insert ?\n)
+                  (insert (propertize " " 'display
+                                      `(space :align-to (,(nth (1+ c) cc)))))))
+            (insert (make-string (- (nth c cc) (current-column)) ?\s))
+            (when-let ((cell (nth r (nth c columns))))
+              (insert cell))
+            (when (= c (1- cs))
+              (insert ?\n))))))))
+
+(defun transient--pixel-width (string)
+  (save-window-excursion
+    (with-temp-buffer
+      (insert string)
+      (set-window-dedicated-p nil nil)
+      (set-window-buffer nil (current-buffer))
+      (car (window-text-pixel-size
+            nil (line-beginning-position) (point))))))
 
 (cl-defmethod transient--insert-group ((group transient-subgroups))
   (let* ((subgroups (oref group suffixes))
@@ -3064,18 +3131,18 @@ Optional support for popup buttons is also implemented 
here."
            ((equal (seq-take seq len) transient--redisplay-key)
             (let ((pre (key-description (vconcat (seq-take seq len))))
                   (suf (key-description (vconcat (seq-drop seq len)))))
-              (setq pre (string-replace "RET" "C-m" pre))
-              (setq pre (string-replace "TAB" "C-i" pre))
-              (setq suf (string-replace "RET" "C-m" suf))
-              (setq suf (string-replace "TAB" "C-i" suf))
+              (setq pre (replace-regexp-in-string "RET" "C-m" pre t))
+              (setq pre (replace-regexp-in-string "TAB" "C-i" pre t))
+              (setq suf (replace-regexp-in-string "RET" "C-m" suf t))
+              (setq suf (replace-regexp-in-string "TAB" "C-i" suf t))
               ;; We use e.g. "-k" instead of the more correct "- k",
               ;; because the former is prettier.  If we did that in
               ;; the definition, then we want to drop the space that
               ;; is reinserted above.  False-positives are possible
               ;; for silly bindings like "-C-c C-c".
-              (unless (string-search " " key)
-                (setq pre (string-replace " " "" pre))
-                (setq suf (string-replace " " "" suf)))
+              (unless (string-match-p " " key)
+                (setq pre (replace-regexp-in-string " " "" pre))
+                (setq suf (replace-regexp-in-string " " "" suf)))
               (concat (propertize pre 'face 'default)
                       (and (string-prefix-p (concat pre " ") key) " ")
                       (transient--colorize-key suf cmd)
@@ -3119,19 +3186,19 @@ and its value is returned to the caller."
       desc)))
 
 (cl-defmethod transient-format-description ((obj transient-group))
-  "Format the description by calling the next method.
-If the result doesn't use the `face' property at all, then apply
-the face `transient-heading' to the complete string."
+  "Format the description by calling the next method.  If the result
+doesn't use the `face' property at all, then apply the face
+`transient-heading' to the complete string."
   (when-let ((desc (cl-call-next-method obj)))
     (if (text-property-not-all 0 (length desc) 'face nil desc)
         desc
       (propertize desc 'face 'transient-heading))))
 
 (cl-defmethod transient-format-description :around ((obj transient-suffix))
-  "Format the description by calling the next method.
-If the result is nil, then use \"(BUG: no description)\" as the
-description.  If the OBJ's `key' is currently unreachable, then
-apply the face `transient-unreachable' to the complete string."
+  "Format the description by calling the next method.  If the result
+is nil, then use \"(BUG: no description)\" as the description.
+If the OBJ's `key' is currently unreachable, then apply the face
+`transient-unreachable' to the complete string."
   (let ((desc (or (cl-call-next-method obj)
                   (and (slot-boundp transient--prefix 'suffix-description)
                        (funcall (oref transient--prefix suffix-description)
@@ -3157,14 +3224,17 @@ apply the face `transient-unreachable' to the complete 
string."
                       'transient-inactive-argument)))
 
 (cl-defmethod transient-format-value ((obj transient-option))
-  (let ((value (oref obj value)))
-    (propertize (concat (oref obj argument)
-                        (if (listp value)
-                            (mapconcat #'identity value ",")
-                          value))
-                'face (if value
-                          'transient-value
-                        'transient-inactive-value))))
+  (let ((argument (oref obj argument)))
+    (if-let ((value (oref obj value)))
+        (propertize
+         (cl-ecase (oref obj multi-value)
+           ((nil)    (concat argument value))
+           ((t rest) (concat argument
+                             (and (not (string-suffix-p " " argument)) " ")
+                             (mapconcat #'prin1-to-string value " ")))
+           (repeat   (mapconcat (lambda (v) (concat argument v)) value " ")))
+         'face 'transient-value)
+      (propertize argument 'face 'transient-inactive-value))))
 
 (cl-defmethod transient-format-value ((obj transient-switches))
   (with-slots (value argument-format choices) obj
@@ -3184,15 +3254,6 @@ apply the face `transient-unreachable' to the complete 
string."
               (propertize "|" 'face 'transient-inactive-value))
              (propertize "]" 'face 'transient-inactive-value)))))
 
-(cl-defmethod transient-format-value ((obj transient-files))
-  (let ((argument (oref obj argument)))
-    (if-let ((value (oref obj value)))
-        (propertize (concat argument " "
-                            (mapconcat (lambda (f) (format "%S" f))
-                                       (oref obj value) " "))
-                    'face 'transient-argument)
-      (propertize argument 'face 'transient-inactive-argument))))
-
 (defun transient--key-unreachable-p (obj)
   (and transient--redisplay-key
        (let ((key (oref obj key)))
@@ -3236,41 +3297,58 @@ a prefix command, while porting a regular keymap to a 
transient."
 ;;; Help
 
 (cl-defgeneric transient-show-help (obj)
-  "Show help for OBJ's command.")
+  "Show documentation for the command represented by OBJ.")
 
 (cl-defmethod transient-show-help ((obj transient-prefix))
-  "Show the info manual, manpage or command doc-string.
-Show the first one that is specified."
-  (if-let ((manual (oref obj info-manual)))
-      (info manual)
-    (if-let ((manpage (oref obj man-page)))
-        (transient--show-manpage manpage)
-      (transient--describe-function (oref obj command)))))
+  "Call `show-help' if non-nil, else show `info-manual',
+if non-nil, else show the `man-page' if non-nil, else use
+`describe-function'."
+  (with-slots (show-help info-manual man-page command) obj
+    (cond (show-help (funcall show-help obj))
+          (info-manual (transient--show-manual info-manual))
+          (man-page (transient--show-manpage man-page))
+          (t (transient--describe-function command)))))
 
 (cl-defmethod transient-show-help ((obj transient-suffix))
-  "Show the command doc-string."
-  (if (eq this-original-command 'transient-help)
-      (if-let ((manpage (oref transient--prefix man-page)))
-          (transient--show-manpage manpage)
-        (transient--describe-function (oref transient--prefix command)))
-    (if-let ((prefix (get (transient--suffix-command obj) 'transient--prefix))
-             (manpage (oref prefix man-page)))
-        (transient--show-manpage manpage)
-      (transient--describe-function this-original-command))))
+  "Call `show-help' if non-nil, else use `describe-function'.
+Also used to dispatch showing documentation for the current
+prefix.  If the suffix is a sub-prefix, then also call the
+prefix method."
+  (cond
+   ((eq this-command 'transient-help)
+    (transient-show-help transient--prefix))
+   ((let ((prefix (get (transient--suffix-command obj)
+                       'transient--prefix)))
+      (and prefix (not (eq (oref transient--prefix command) this-command))
+           (prog1 t (transient-show-help prefix)))))
+   (t (if-let ((show-help (oref obj show-help)))
+          (funcall show-help obj)
+        (transient--describe-function this-command)))))
 
 (cl-defmethod transient-show-help ((obj transient-infix))
-  "Show the manpage if defined or the command doc-string.
-If the manpage is specified, then try to jump to the correct
-location."
-  (if-let ((manpage (oref transient--prefix man-page)))
-      (transient--show-manpage manpage (ignore-errors (oref obj argument)))
-    (transient--describe-function this-original-command)))
+  "Call `show-help' if non-nil, else show the `man-page'
+if non-nil, else use `describe-function'.  When showing the
+manpage, then try to jump to the correct location."
+  (if-let ((show-help (oref obj show-help)))
+      (funcall show-help obj)
+    (if-let ((man-page (oref transient--prefix man-page))
+             (argument (and (slot-boundp obj 'argument)
+                            (oref obj argument))))
+        (transient--show-manpage man-page argument)
+      (transient--describe-function this-command))))
 
 ;; `cl-generic-generalizers' doesn't support `command' et al.
 (cl-defmethod transient-show-help (cmd)
   "Show the command doc-string."
   (transient--describe-function cmd))
 
+(defun transient--describe-function (fn)
+  (describe-function fn)
+  (select-window (get-buffer-window (help-buffer))))
+
+(defun transient--show-manual (manual)
+  (info manual))
+
 (defun transient--show-manpage (manpage &optional argument)
   (require 'man)
   (let* ((Man-notify-method 'meek)
@@ -3282,10 +3360,6 @@ location."
     (when argument
       (transient--goto-argument-description argument))))
 
-(defun transient--describe-function (fn)
-  (describe-function fn)
-  (select-window (get-buffer-window (help-buffer))))
-
 (defun transient--goto-argument-description (arg)
   (goto-char (point-min))
   (let ((case-fold-search nil)
@@ -3366,9 +3440,9 @@ Suffixes on levels %s and %s are unavailable.\n"
 
 (defvar transient-resume-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [remap Man-quit]    'transient-resume)
-    (define-key map [remap Info-exit]   'transient-resume)
-    (define-key map [remap quit-window] 'transient-resume)
+    (define-key map [remap Man-quit]    #'transient-resume)
+    (define-key map [remap Info-exit]   #'transient-resume)
+    (define-key map [remap quit-window] #'transient-resume)
     map)
   "Keymap for `transient-resume-mode'.
 
@@ -3395,19 +3469,20 @@ resumes the suspended transient.")
               ;; Yes, I know that this is wrong(tm).
               ;; Unfortunately it is also necessary.
               (setq this-original-command command)
+              (transient--pre-command)
               (call-interactively command))))
 
 (defvar transient-popup-navigation-map
   (let ((map (make-sparse-keymap)))
-    (define-key map (kbd "<down-mouse-1>") 'transient-noop)
-    (define-key map (kbd "<mouse-1>") 'transient-mouse-push-button)
-    (define-key map (kbd "RET")       'transient-push-button)
-    (define-key map (kbd "<up>")      'transient-backward-button)
-    (define-key map (kbd "C-p")       'transient-backward-button)
-    (define-key map (kbd "<down>")    'transient-forward-button)
-    (define-key map (kbd "C-n")       'transient-forward-button)
-    (define-key map (kbd "C-r")       'transient-isearch-backward)
-    (define-key map (kbd "C-s")       'transient-isearch-forward)
+    (define-key map (kbd "<down-mouse-1>") #'transient-noop)
+    (define-key map (kbd "<mouse-1>") #'transient-mouse-push-button)
+    (define-key map (kbd "RET")       #'transient-push-button)
+    (define-key map (kbd "<up>")      #'transient-backward-button)
+    (define-key map (kbd "C-p")       #'transient-backward-button)
+    (define-key map (kbd "<down>")    #'transient-forward-button)
+    (define-key map (kbd "C-n")       #'transient-forward-button)
+    (define-key map (kbd "C-r")       #'transient-isearch-backward)
+    (define-key map (kbd "C-s")       #'transient-isearch-forward)
     map))
 
 (defun transient-mouse-push-button (&optional pos)
@@ -3436,22 +3511,32 @@ See `forward-button' for information about N."
     (forward-button n t)))
 
 (defun transient--goto-button (command)
-  (if (not command)
-      (forward-button 1)
+  (cond
+   ((stringp command)
+    (when (re-search-forward (concat "^" (regexp-quote command)) nil t)
+      (goto-char (match-beginning 0))))
+   (command
     (while (and (ignore-errors (forward-button 1))
                 (not (eq (button-get (button-at (point)) 'command) command))))
     (unless (eq (button-get (button-at (point)) 'command) command)
       (goto-char (point-min))
-      (forward-button 1))))
+      (forward-button 1)))))
+
+(defun transient--heading-at-point ()
+  (and (eq (get-text-property (point) 'face) 'transient-heading)
+       (let ((beg (line-beginning-position)))
+         (buffer-substring-no-properties
+          beg (next-single-property-change
+               beg 'face nil (line-end-position))))))
 
 ;;;; Popup Isearch
 
 (defvar transient--isearch-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map isearch-mode-map)
-    (define-key map [remap isearch-exit]   'transient-isearch-exit)
-    (define-key map [remap isearch-cancel] 'transient-isearch-cancel)
-    (define-key map [remap isearch-abort]  'transient-isearch-abort)
+    (define-key map [remap isearch-exit]   #'transient-isearch-exit)
+    (define-key map [remap isearch-cancel] #'transient-isearch-cancel)
+    (define-key map [remap isearch-abort]  #'transient-isearch-abort)
     map))
 
 (defun transient-isearch-backward (&optional regexp-p)
@@ -3537,14 +3622,14 @@ search instead."
     (funcall fn arg-mode)
     (transient--resume-override t)))
 
-(advice-add 'edebug--recursive-edit :around 'transient--edebug--recursive-edit)
+(advice-add 'edebug--recursive-edit :around 
#'transient--edebug--recursive-edit)
 
 (defun transient--abort-edebug ()
   (when (bound-and-true-p edebug-active)
     (transient--emergency-exit)))
 
-(advice-add 'abort-recursive-edit :before 'transient--abort-edebug)
-(advice-add 'top-level :before 'transient--abort-edebug)
+(advice-add 'abort-recursive-edit :before #'transient--abort-edebug)
+(advice-add 'top-level :before #'transient--abort-edebug)
 
 (defun transient--edebug-command-p ()
   (and (bound-and-true-p edebug-active)
@@ -3558,12 +3643,12 @@ search instead."
 (defun transient--suspend-which-key-mode ()
   (when (bound-and-true-p which-key-mode)
     (which-key-mode -1)
-    (add-hook 'transient-exit-hook 'transient--resume-which-key-mode)))
+    (add-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
 
 (defun transient--resume-which-key-mode ()
   (unless transient--prefix
     (which-key-mode 1)
-    (remove-hook 'transient-exit-hook 'transient--resume-which-key-mode)))
+    (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode)))
 
 (defun transient-bind-q-to-quit ()
   "Modify some keymaps to bind \"q\" to the appropriate quit command.
@@ -3583,10 +3668,10 @@ that does that.  Of course \"Q\" may already be bound 
to something
 else, so that function binds \"M-q\" to that command instead.
 Of course \"M-q\" may already be bound to something else, but
 we stop there."
-  (define-key transient-base-map   "q" 'transient-quit-one)
-  (define-key transient-sticky-map "q" 'transient-quit-seq)
+  (define-key transient-base-map   "q" #'transient-quit-one)
+  (define-key transient-sticky-map "q" #'transient-quit-seq)
   (setq transient-substitute-key-function
-        'transient-rebind-quit-commands))
+        #'transient-rebind-quit-commands))
 
 (defun transient-rebind-quit-commands (obj)
   "See `transient-bind-q-to-quit'."
@@ -3672,5 +3757,6 @@ we stop there."
 (provide 'transient)
 ;; Local Variables:
 ;; indent-tabs-mode: nil
+;; checkdoc-symbol-words: ("command-line" "edit-mode" "help-mode")
 ;; End:
 ;;; transient.el ends here
diff --git a/lisp/tree-widget.el b/lisp/tree-widget.el
index d40a628b99..8691f03f86 100644
--- a/lisp/tree-widget.el
+++ b/lisp/tree-widget.el
@@ -214,8 +214,8 @@ Give the image the specified properties PROPS."
 See also the option `widget-image-conversion'."
   (delq nil
         (mapcar
-         #'(lambda (fmt)
-             (and (image-type-available-p (car fmt)) fmt))
+         (lambda (fmt)
+           (and (image-type-available-p (car fmt)) fmt))
          widget-image-conversion)))
 
 ;; Buffer local cache of theme data.
diff --git a/lisp/url/url-tramp.el b/lisp/url/url-tramp.el
index 5b9dd8a268..5cf0d804d6 100644
--- a/lisp/url/url-tramp.el
+++ b/lisp/url/url-tramp.el
@@ -48,12 +48,14 @@ In case URL is not convertible, nil is returned."
       (when (url-password obj)
        (password-cache-add
         (tramp-make-tramp-file-name
-         (url-type obj) (url-user obj) nil
-          (url-host obj) port "")
+          (make-tramp-file-name
+          :method (url-type obj) :user (url-user obj)
+           :host (url-host obj)))
         (url-password obj)))
       (tramp-make-tramp-file-name
-       (url-type obj) (url-user obj) nil
-       (url-host obj) port (url-filename obj)))))
+       (make-tramp-file-name
+        :method (url-type obj) :user (url-user obj)
+        :host (url-host obj) :port port :localname (url-filename obj))))))
 
 (defun url-tramp-convert-tramp-to-url (file)
   "Convert FILE, a Tramp file name, to a URL.
diff --git a/lisp/userlock.el b/lisp/userlock.el
index a38f6ac422..348ccc6f8e 100644
--- a/lisp/userlock.el
+++ b/lisp/userlock.el
@@ -194,20 +194,19 @@ really edit the buffer? (%s, %s, %s or %s) "
                       (list "File reverted" filename)))
              ((eq answer ?n)
               (signal 'file-supersession
-                      (list "File changed on disk" filename)))))
+                      (list "File changed on disk" filename)))
+             ((eq answer ?y))
+             (t (setq answer nil))))
       (message
        "File on disk now will become a backup file if you save these changes.")
       (setq buffer-backed-up nil))))
 
 (defun ask-user-about-supersession-help ()
   (with-output-to-temp-buffer "*Help*"
-    (let ((revert-buffer-binding
-           ;; This takes place in the original buffer.
-           (substitute-command-keys "\\[revert-buffer]")))
-      (with-current-buffer standard-output
-        (insert
-         (format
-          "You want to modify a buffer whose disk file has changed
+    (with-current-buffer standard-output
+      (insert
+       (format
+        "You want to modify a buffer whose disk file has changed
 since you last read it in or saved it with this buffer.
 
 If you say %s to go ahead and modify this buffer,
@@ -216,14 +215,13 @@ If you say %s to revert, the contents of the buffer are 
refreshed
 from the file on disk.
 If you say %s, the change you started to make will be aborted.
 
-Usually, you should type %s and then %s,
-to get the latest version of the file, then make the change again."
-          (userlock--fontify-key "y")
-          (userlock--fontify-key "r")
-          (userlock--fontify-key "n")
-          (userlock--fontify-key "n")
-          revert-buffer-binding))
-        (help-mode)))))
+Usually, you should type %s to get the latest version of the
+file, then make the change again."
+        (userlock--fontify-key "y")
+        (userlock--fontify-key "r")
+        (userlock--fontify-key "n")
+        (userlock--fontify-key "r")))
+      (help-mode))))
 
 ;;;###autoload
 (defun userlock--handle-unlock-error (error)
diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el
index 2e20284951..1290d7e03a 100644
--- a/lisp/vc/add-log.el
+++ b/lisp/vc/add-log.el
@@ -930,8 +930,7 @@ non-nil, otherwise in local time."
                            (not (looking-at "[ \t]+.*<.*>$")))
                          (setq hit t)))))
             (forward-line 1)
-          (insert (nth (random (length new-entries))
-                       new-entries)
+          (insert (and new-entries (seq-random-elt new-entries))
                   (if use-hard-newlines hard-newline "\n")
                   (if use-hard-newlines hard-newline "\n"))
           (forward-line -1))))
diff --git a/lisp/vc/cvs-status.el b/lisp/vc/cvs-status.el
index 63b886362b..86b62eb1ce 100644
--- a/lisp/vc/cvs-status.el
+++ b/lisp/vc/cvs-status.el
@@ -29,23 +29,22 @@
 ;;; Code:
 
 (require 'cl-lib)
-(require 'pcvs-util)
+(require 'pcvs)
+(require 'easy-mmode)
 
 ;;;
 
-(easy-mmode-defmap cvs-status-mode-map
-  '(("n"       . next-line)
-    ("p"       . previous-line)
-    ("N"       . cvs-status-next)
-    ("P"       . cvs-status-prev)
-    ("\M-n"    . cvs-status-next)
-    ("\M-p"    . cvs-status-prev)
-    ("t"       . cvs-status-cvstrees)
-    ("T"       . cvs-status-trees)
-    (">"        . cvs-mode-checkout))
-  "CVS-Status' keymap."
-  :group 'cvs-status
-  :inherit 'cvs-mode-map)
+(defvar-keymap cvs-status-mode-map
+  :parent     'cvs-mode-map
+  "n"         #'next-line
+  "p"         #'previous-line
+  "N"         #'cvs-status-next
+  "P"         #'cvs-status-prev
+  ["M-n"]     #'cvs-status-next
+  ["M-p"]     #'cvs-status-prev
+  "t"         #'cvs-status-cvstrees
+  "T"         #'cvs-status-trees
+  ">"         #'cvs-mode-checkout)
 
 ;;(easy-menu-define cvs-status-menu cvs-status-mode-map
 ;;  "Menu for `cvs-status-mode'."
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index 0852f8790e..e68aa2257d 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -55,6 +55,7 @@
 ;;; Code:
 (eval-when-compile (require 'cl-lib))
 (eval-when-compile (require 'subr-x))
+(require 'easy-mmode)
 
 (autoload 'vc-find-revision "vc")
 (autoload 'vc-find-revision-no-save "vc")
@@ -162,57 +163,55 @@ and hunk-based syntax highlighting otherwise as a 
fallback."
 ;;;; keymap, menu, ...
 ;;;;
 
-(easy-mmode-defmap diff-mode-shared-map
-  '(("n" . diff-hunk-next)
-    ("N" . diff-file-next)
-    ("p" . diff-hunk-prev)
-    ("P" . diff-file-prev)
-    ("\t" . diff-hunk-next)
-    ([backtab] . diff-hunk-prev)
-    ("k" . diff-hunk-kill)
-    ("K" . diff-file-kill)
-    ("}" . diff-file-next)     ; From compilation-minor-mode.
-    ("{" . diff-file-prev)
-    ("\C-m" . diff-goto-source)
-    ([mouse-2] . diff-goto-source)
-    ("W" . widen)
-    ("o" . diff-goto-source)   ; other-window
-    ("A" . diff-ediff-patch)
-    ("r" . diff-restrict-view)
-    ("R" . diff-reverse-direction)
-    ([remap undo] . diff-undo))
-  "Basic keymap for `diff-mode', bound to various prefix keys."
-  :inherit special-mode-map)
-
-(easy-mmode-defmap diff-mode-map
-  `(("\e" . ,(let ((map (make-sparse-keymap)))
-               ;; We want to inherit most bindings from diff-mode-shared-map,
-               ;; but not all since they may hide useful M-<foo> global
-               ;; bindings when editing.
-               (set-keymap-parent map diff-mode-shared-map)
-               (dolist (key '("A" "r" "R" "g" "q" "W" "z"))
-                 (define-key map key nil))
-               map))
-    ;; From compilation-minor-mode.
-    ("\C-c\C-c" . diff-goto-source)
-    ;; By analogy with the global C-x 4 a binding.
-    ("\C-x4A" . diff-add-change-log-entries-other-window)
-    ;; Misc operations.
-    ("\C-c\C-a" . diff-apply-hunk)
-    ("\C-c\C-e" . diff-ediff-patch)
-    ("\C-c\C-n" . diff-restrict-view)
-    ("\C-c\C-s" . diff-split-hunk)
-    ("\C-c\C-t" . diff-test-hunk)
-    ("\C-c\C-r" . diff-reverse-direction)
-    ("\C-c\C-u" . diff-context->unified)
-    ;; `d' because it duplicates the context :-(  --Stef
-    ("\C-c\C-d" . diff-unified->context)
-    ("\C-c\C-w" . diff-ignore-whitespace-hunk)
-    ;; `l' because it "refreshes" the hunk like C-l refreshes the screen
-    ("\C-c\C-l" . diff-refresh-hunk)
-    ("\C-c\C-b" . diff-refine-hunk)  ;No reason for `b' :-(
-    ("\C-c\C-f" . next-error-follow-minor-mode))
-  "Keymap for `diff-mode'.  See also `diff-mode-shared-map'.")
+(defvar-keymap diff-mode-shared-map
+  :parent special-mode-map
+  "n" #'diff-hunk-next
+  "N" #'diff-file-next
+  "p" #'diff-hunk-prev
+  "P" #'diff-file-prev
+  ["TAB"] #'diff-hunk-next
+  [backtab] #'diff-hunk-prev
+  "k" #'diff-hunk-kill
+  "K" #'diff-file-kill
+  "}" #'diff-file-next                  ; From compilation-minor-mode.
+  "{" #'diff-file-prev
+  ["RET"] #'diff-goto-source
+  [mouse-2] #'diff-goto-source
+  "W" #'widen
+  "o" #'diff-goto-source                ; other-window
+  "A" #'diff-ediff-patch
+  "r" #'diff-restrict-view
+  "R" #'diff-reverse-direction
+  [remap undo] #'diff-undo)
+
+(defvar-keymap diff-mode-map
+  :doc "Keymap for `diff-mode'.  See also `diff-mode-shared-map'."
+  ["ESC"] (let ((map (define-keymap :parent diff-mode-shared-map)))
+            ;; We want to inherit most bindings from
+            ;; `diff-mode-shared-map', but not all since they may hide
+            ;; useful `M-<foo>' global bindings when editing.
+            (dolist (key '("A" "r" "R" "g" "q" "W" "z"))
+              (define-key map key nil))
+            map)
+  ;; From compilation-minor-mode.
+  ["C-c C-c"] #'diff-goto-source
+  ;; By analogy with the global C-x 4 a binding.
+  ["C-x 4 A"] #'diff-add-change-log-entries-other-window
+  ;; Misc operations.
+  ["C-c C-a"] #'diff-apply-hunk
+  ["C-c C-e"] #'diff-ediff-patch
+  ["C-c C-n"] #'diff-restrict-view
+  ["C-c C-s"] #'diff-split-hunk
+  ["C-c C-t"] #'diff-test-hunk
+  ["C-c C-r"] #'diff-reverse-direction
+  ["C-c C-u"] #'diff-context->unified
+  ;; `d' because it duplicates the context :-(  --Stef
+  ["C-c C-d"] #'diff-unified->context
+  ["C-c C-w"] #'diff-ignore-whitespace-hunk
+  ;; `l' because it "refreshes" the hunk like C-l refreshes the screen
+  ["C-c C-l"] #'diff-refresh-hunk
+  ["C-c C-b"] #'diff-refine-hunk        ;No reason for `b' :-(
+  ["C-c C-f"] #'next-error-follow-minor-mode)
 
 (easy-menu-define diff-mode-menu diff-mode-map
   "Menu for `diff-mode'."
@@ -269,9 +268,9 @@ and hunk-based syntax highlighting otherwise as a fallback."
   "Prefix key for `diff-minor-mode' commands."
   :type '(choice (string "\e") (string "C-c=") string))
 
-(easy-mmode-defmap diff-minor-mode-map
-  `((,diff-minor-mode-prefix . ,diff-mode-shared-map))
-  "Keymap for `diff-minor-mode'.  See also `diff-mode-shared-map'.")
+(defvar-keymap diff-minor-mode-map
+  :doc "Keymap for `diff-minor-mode'.  See also `diff-mode-shared-map'."
+  diff-minor-mode-prefix diff-mode-shared-map)
 
 (define-minor-mode diff-auto-refine-mode
   "Toggle automatic diff hunk finer highlighting (Diff Auto Refine mode).
@@ -894,6 +893,9 @@ data such as \"Index: ...\" and such."
       ;; Fix the original hunk-header.
       (diff-fixup-modifs start pos))))
 
+(defun diff--outline-level ()
+  (if (string-match-p diff-hunk-header-re (match-string 0))
+      2 1))
 
 ;;;;
 ;;;; jump to other buffers
@@ -1355,7 +1357,11 @@ else cover the whole buffer."
              (pcase (char-after)
                (?\s (cl-incf space))
                (?+ (cl-incf plus))
-               (?- (cl-incf minus))
+               (?- (unless ;; In git format-patch "^-- $" signifies
+                            ;; the end of the patch.
+                       (and (eq diff-buffer-type 'git)
+                            (looking-at "^-- $"))
+                     (cl-incf minus)))
                (?! (cl-incf bang))
                ((or ?\\ ?#) nil)
                (?\n (if diff-valid-unified-empty-line
@@ -1490,7 +1496,6 @@ a diff with \\[diff-reverse-direction].
 
   (setq-local font-lock-defaults diff-font-lock-defaults)
   (add-hook 'font-lock-mode-hook #'diff--font-lock-cleanup nil 'local)
-  (setq-local outline-regexp diff-outline-regexp)
   (setq-local imenu-generic-expression
               diff-imenu-generic-expression)
   ;; These are not perfect.  They would be better done separately for
@@ -1535,11 +1540,7 @@ a diff with \\[diff-reverse-direction].
                 #'diff--filter-substring)
   (unless buffer-file-name
     (hack-dir-local-variables-non-file-buffer))
-  (save-excursion
-    (setq-local diff-buffer-type
-                (if (re-search-forward "^diff --git" nil t)
-                    'git
-                  nil))))
+  (diff-setup-buffer-type))
 
 ;;;###autoload
 (define-minor-mode diff-minor-mode
@@ -1575,6 +1576,21 @@ modified lines of the diff."
                     "^[-+!] .*?\\([\t ]+\\)$"
                   "^[-+!<>].*?\\([\t ]+\\)$"))))
 
+(defun diff-setup-buffer-type ()
+  "Try to guess the `diff-buffer-type' from content of current Diff mode 
buffer.
+`outline-regexp' is updated accordingly."
+  (save-excursion
+    (goto-char (point-min))
+    (setq-local diff-buffer-type
+                (if (re-search-forward "^diff --git" nil t)
+                    'git
+                  nil)))
+  (when (eq diff-buffer-type 'git)
+    (setq diff-outline-regexp
+          (concat "\\(^diff --git.*\n\\|" diff-hunk-header-re "\\)"))
+    (setq-local outline-level #'diff--outline-level))
+  (setq-local outline-regexp diff-outline-regexp))
+
 (defun diff-delete-if-empty ()
   ;; An empty diff file means there's no more diffs to integrate, so we
   ;; can just remove the file altogether.  Very handy for .rej files if we
@@ -2599,13 +2615,15 @@ fixed, visit it in a buffer."
                            (or (match-beginning 2) (match-beginning 1))
                            'display (propertize
                                      (cond
-                                      ((null (match-beginning 1)) "new file  ")
-                                      ((null (match-beginning 2)) "deleted   ")
-                                      (t                          "modified  
"))
+                                      ((null (match-beginning 1))
+                                       (concat "new file  " (match-string 2)))
+                                      ((null (match-beginning 2))
+                                       (concat "deleted   " (match-string 1)))
+                                      (t
+                                       (concat "modified  " (match-string 1))))
                                      'face '(diff-file-header diff-header)))
-        (unless (match-beginning 2)
-          (put-text-property (match-end 1) (1- (match-end 0))
-                             'display "")))))
+        (put-text-property (match-end 1) (1- (match-end 0))
+                           'display ""))))
   nil)
 
 ;;; Syntax highlighting from font-lock
diff --git a/lisp/vc/diff.el b/lisp/vc/diff.el
index 352fa693ff..4061fedd57 100644
--- a/lisp/vc/diff.el
+++ b/lisp/vc/diff.el
@@ -96,15 +96,15 @@ Non-interactively, OLD and NEW may each be a file or a 
buffer."
   (interactive
    (let* ((newf (if (and buffer-file-name (file-exists-p buffer-file-name))
                    (read-file-name
-                    (concat "Diff new file (default "
-                            (file-name-nondirectory buffer-file-name) "): ")
+                     (format-prompt "Diff new file"
+                                    (file-name-nondirectory buffer-file-name))
                     nil buffer-file-name t)
                  (read-file-name "Diff new file: " nil nil t)))
           (oldf (file-newest-backup newf)))
      (setq oldf (if (and oldf (file-exists-p oldf))
                    (read-file-name
-                    (concat "Diff original file (default "
-                            (file-name-nondirectory oldf) "): ")
+                     (format-prompt "Diff original file"
+                                    (file-name-nondirectory oldf))
                     (file-name-directory oldf) oldf t)
                  (read-file-name "Diff original file: "
                                  (file-name-directory newf) nil t)))
diff --git a/lisp/vc/ediff-merg.el b/lisp/vc/ediff-merg.el
index 2bdce9e33c..d0ce9d326d 100644
--- a/lisp/vc/ediff-merg.el
+++ b/lisp/vc/ediff-merg.el
@@ -257,7 +257,8 @@ Buffer B."
 
 
 (defun ediff-re-merge ()
-  "Remerge unmodified diff regions using a new default.  Start with the 
current region."
+  "Remerge unmodified diff regions using a new default.
+Start with the current region."
   (interactive)
   (let* ((default-variant-alist
           (list '("default-A") '("default-B") '("combined")))
diff --git a/lisp/vc/ediff-mult.el b/lisp/vc/ediff-mult.el
index fa26b0b32f..bec0ec0120 100644
--- a/lisp/vc/ediff-mult.el
+++ b/lisp/vc/ediff-mult.el
@@ -1677,7 +1677,7 @@ With prefix arg UNHIDE, unhide instead."
                (setq custom-diff-buf ediff-custom-diff-buffer)))))
 
     (or (ediff-buffer-live-p meta-diff-buff)
-       (user-error "Ediff: something wrong--killed multiple diff's buffer"))
+        (user-error "Ediff: Something wrong--killed multiple diff's buffer"))
 
     (cond ((ediff-buffer-live-p custom-diff-buf)
           ;; for live session buffers we do them first because the user may
diff --git a/lisp/vc/ediff-ptch.el b/lisp/vc/ediff-ptch.el
index 4135e8b470..7622cf4c19 100644
--- a/lisp/vc/ediff-ptch.el
+++ b/lisp/vc/ediff-ptch.el
@@ -503,15 +503,11 @@ are two possible targets for this %spatch.  However, 
these files do not exist."
        patch-file-name)
     (setq patch-file-name
          (read-file-name
-          (format "Patch is in file%s: "
-                  (cond ((and buffer-file-name
-                              (equal (expand-file-name dir)
-                                     (file-name-directory buffer-file-name)))
-                         (concat
-                          " (default "
-                          (file-name-nondirectory buffer-file-name)
-                          ")"))
-                        (t "")))
+           (format-prompt "Patch is in file"
+                          (and buffer-file-name
+                               (equal (expand-file-name dir)
+                                      (file-name-directory buffer-file-name))
+                               (file-name-nondirectory buffer-file-name)))
           dir buffer-file-name 'must-match))
     (if (file-directory-p patch-file-name)
        (error "Patch file cannot be a directory: %s" patch-file-name)
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index 5646fd3d42..d4660a179e 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -2777,8 +2777,8 @@ up an appropriate window config."
   (interactive)
   (ediff-barf-if-not-control-buffer)
   (run-hooks 'ediff-suspend-hook)
-  (message
-   "To resume, type M-x eregistry and select the desired Ediff session"))
+  (message (substitute-command-keys
+            "To resume, type \\[eregistry] and select the desired Ediff 
session")))
 
 ;; ediff-barf-if-not-control-buffer ensures only called from ediff.
 (declare-function ediff-version "ediff" ())
@@ -3103,11 +3103,7 @@ Hit \\[ediff-recenter] to reset the windows afterward."
                (lambda () (when defaults
                             (setq minibuffer-default defaults)))
              (read-file-name
-              (format "%s%s "
-                      prompt
-                      (cond (default-file
-                              (concat " (default " default-file "):"))
-                            (t (concat " (default " default-dir "):"))))
+               (format-prompt prompt (or default-file default-dir))
               default-dir
               (or default-file default-dir)
               t                        ; must match, no-confirm
@@ -3220,7 +3216,7 @@ Hit \\[ediff-recenter] to reset the windows afterward."
       (if (buffer-modified-p)
          ;; If buffer is not obsolete and is modified, offer to save
          (if (yes-or-no-p
-              (format "Buffer %s has been modified. Save it in file %s? "
+               (format "Buffer %s has been modified.  Save it in file %s?"
                       (buffer-name)
                       buffer-file-name))
              (condition-case nil
diff --git a/lisp/vc/ediff.el b/lisp/vc/ediff.el
index 74ed1bd0ef..49fc60431f 100644
--- a/lisp/vc/ediff.el
+++ b/lisp/vc/ediff.el
@@ -680,7 +680,7 @@ MERGE-AUTOSTORE-DIR is the directory in which to store 
merged files."
 (defun ediff-merge-directories-with-ancestor (dir1 dir2 ancestor-dir regexp
                                                   &optional
                                                   merge-autostore-dir)
-  "Merge files in directories DIR1 and DIR2 using files in ANCESTOR-DIR as 
ancestors.
+  "Merge files in DIR1 and DIR2 using files in ANCESTOR-DIR as ancestors.
 Ediff merges files that have identical names in DIR1, DIR2.  If a pair of files
 in DIR1 and DIR2 doesn't have an ancestor in ANCESTOR-DIR, Ediff will merge
 without ancestor.  The fourth argument, REGEXP, is nil or a regular expression;
@@ -746,7 +746,7 @@ MERGE-AUTOSTORE-DIR is the directory in which to store 
merged files."
 (defun ediff-merge-directory-revisions-with-ancestor (dir1 regexp
                                                           &optional
                                                           merge-autostore-dir)
-  "Run Ediff on a directory, DIR1, merging its files with their revisions and 
ancestors.
+  "Run Ediff on DIR1 and merge its files with their revisions and ancestors.
 The second argument, REGEXP, is a regular expression that filters the file
 names.  Only the files that are under revision control are taken into account.
 MERGE-AUTOSTORE-DIR is the directory in which to store merged files."
@@ -1600,7 +1600,7 @@ With optional NODE, goes to that node."
 
 ;;;###autoload
 (defun ediff-merge-with-ancestor-command ()
-  "Call `ediff-merge-files-with-ancestor' with the next three command line 
arguments."
+  "Call `ediff-merge-files-with-ancestor' with next three command line 
arguments."
   (let ((file-a (nth 0 command-line-args-left))
        (file-b (nth 1 command-line-args-left))
        (ancestor (nth 2 command-line-args-left)))
@@ -1637,7 +1637,8 @@ With optional NODE, goes to that node."
 
 ;;;###autoload
 (defun ediff-merge-directories-with-ancestor-command ()
-  "Call `ediff-merge-directories-with-ancestor' with the next four command 
line arguments."
+  "Call `ediff-merge-directories-with-ancestor' with the next four command line
+arguments."
   (let ((file-a (nth 0 command-line-args-left))
        (file-b (nth 1 command-line-args-left))
        (ancestor (nth 2 command-line-args-left))
diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el
index e0a87ba941..c8d089e411 100644
--- a/lisp/vc/log-edit.el
+++ b/lisp/vc/log-edit.el
@@ -54,21 +54,19 @@
 (define-obsolete-variable-alias 'vc-log-mode-map 'log-edit-mode-map "28.1")
 (define-obsolete-variable-alias 'vc-log-entry-mode 'log-edit-mode-map "28.1")
 
-(easy-mmode-defmap log-edit-mode-map
-  '(("\C-c\C-c" . log-edit-done)
-    ("\C-c\C-a" . log-edit-insert-changelog)
-    ("\C-c\C-w" . log-edit-generate-changelog-from-diff)
-    ("\C-c\C-d" . log-edit-show-diff)
-    ("\C-c\C-f" . log-edit-show-files)
-    ("\C-c\C-k" . log-edit-kill-buffer)
-    ("\C-a"     . log-edit-beginning-of-line)
-    ("\M-n"    . log-edit-next-comment)
-    ("\M-p"    . log-edit-previous-comment)
-    ("\M-r"    . log-edit-comment-search-backward)
-    ("\M-s"    . log-edit-comment-search-forward)
-    ("\C-c?"   . log-edit-mode-help))
-  "Keymap for the `log-edit-mode' (to edit version control log messages)."
-  :group 'log-edit)
+(defvar-keymap log-edit-mode-map
+  (kbd "C-c C-c") #'log-edit-done
+  (kbd "C-c C-a") #'log-edit-insert-changelog
+  (kbd "C-c C-w") #'log-edit-generate-changelog-from-diff
+  (kbd "C-c C-d") #'log-edit-show-diff
+  (kbd "C-c C-f") #'log-edit-show-files
+  (kbd "C-c C-k") #'log-edit-kill-buffer
+  (kbd "C-a")     #'log-edit-beginning-of-line
+  (kbd "M-n")     #'log-edit-next-comment
+  (kbd "M-p")     #'log-edit-previous-comment
+  (kbd "M-r")     #'log-edit-comment-search-backward
+  (kbd "M-s")     #'log-edit-comment-search-forward
+  (kbd "C-c ?")   #'log-edit-mode-help)
 
 (easy-menu-define log-edit-menu log-edit-mode-map
   "Menu used for `log-edit-mode'."
@@ -891,7 +889,7 @@ name or time."
 Actually, the narrowed region doesn't include the date line.
 A \"page\" in a ChangeLog file is the area between two dates."
   (or (eq major-mode 'change-log-mode)
-      (error "log-edit-narrow-changelog: current buffer isn't a ChangeLog"))
+      (error "log-edit-narrow-changelog: Current buffer isn't a ChangeLog"))
 
   (goto-char (point-min))
 
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index c2f008fc47..2c78000e38 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -110,6 +110,7 @@
 ;;; Code:
 
 (require 'pcvs-util)
+(require 'easy-mmode)
 (autoload 'vc-find-revision "vc")
 (autoload 'vc-diff-internal "vc")
 
@@ -121,39 +122,23 @@
   :group 'pcl-cvs
   :prefix "log-view-")
 
-(easy-mmode-defmap log-view-mode-map
-  '(
-    ("-"       .       negative-argument)
-    ("0"       .       digit-argument)
-    ("1"       .       digit-argument)
-    ("2"       .       digit-argument)
-    ("3"       .       digit-argument)
-    ("4"       .       digit-argument)
-    ("5"       .       digit-argument)
-    ("6"       .       digit-argument)
-    ("7"       .       digit-argument)
-    ("8"       .       digit-argument)
-    ("9"       .       digit-argument)
-
-    ("\C-m" . log-view-toggle-entry-display)
-    ("m" . log-view-toggle-mark-entry)
-    ("e" . log-view-modify-change-comment)
-    ("d" . log-view-diff)
-    ("=" . log-view-diff)
-    ("D" . log-view-diff-changeset)
-    ("a" . log-view-annotate-version)
-    ("f" . log-view-find-revision)
-    ("n" . log-view-msg-next)
-    ("p" . log-view-msg-prev)
-    ("\t" . log-view-msg-next)
-    ([backtab] . log-view-msg-prev)
-    ("N" . log-view-file-next)
-    ("P" . log-view-file-prev)
-    ("\M-n" . log-view-file-next)
-    ("\M-p" . log-view-file-prev))
-  "Log-View's keymap."
-  :inherit special-mode-map
-  :group 'log-view)
+(defvar-keymap log-view-mode-map
+  (kbd "RET") #'log-view-toggle-entry-display
+  "m" #'log-view-toggle-mark-entry
+  "e" #'log-view-modify-change-comment
+  "d" #'log-view-diff
+  "=" #'log-view-diff
+  "D" #'log-view-diff-changeset
+  "a" #'log-view-annotate-version
+  "f" #'log-view-find-revision
+  "n" #'log-view-msg-next
+  "p" #'log-view-msg-prev
+  (kbd "TAB") #'log-view-msg-next
+  (kbd "<backtab>") #'log-view-msg-prev
+  "N" #'log-view-file-next
+  "P" #'log-view-file-prev
+  (kbd "M-n") #'log-view-file-next
+  (kbd "M-p") #'log-view-file-prev)
 
 (easy-menu-define log-view-mode-menu log-view-mode-map
   "Log-View Display Menu."
diff --git a/lisp/vc/pcvs-defs.el b/lisp/vc/pcvs-defs.el
index 54ef06960f..c3109f7e85 100644
--- a/lisp/vc/pcvs-defs.el
+++ b/lisp/vc/pcvs-defs.el
@@ -264,160 +264,6 @@ This variable is buffer local and only used in the *cvs* 
buffer.")
 (defconst cvs-vendor-branch "1.1.1"
   "The default branch used by CVS for vendor code.")
 
-(easy-mmode-defmap cvs-mode-diff-map
-  '(("E" "imerge" .    cvs-mode-imerge)
-    ("=" .             cvs-mode-diff)
-    ("e" "idiff" .     cvs-mode-idiff)
-    ("2" "other" .     cvs-mode-idiff-other)
-    ("d" "diff" .      cvs-mode-diff)
-    ("b" "backup" .    cvs-mode-diff-backup)
-    ("h" "head" .      cvs-mode-diff-head)
-    ("r" "repository" .        cvs-mode-diff-repository)
-    ("y" "yesterday" . cvs-mode-diff-yesterday)
-    ("v" "vendor" .    cvs-mode-diff-vendor))
-  "Keymap for diff-related operations in `cvs-mode'."
-  :name "Diff")
-;; This is necessary to allow correct handling of \\[cvs-mode-diff-map]
-;; in substitute-command-keys.
-(fset 'cvs-mode-diff-map cvs-mode-diff-map)
-
-(easy-mmode-defmap cvs-mode-map
-  ;;(define-prefix-command 'cvs-mode-map-diff-prefix)
-  ;;(define-prefix-command 'cvs-mode-map-control-c-prefix)
-  '(;; various
-    ;; (undo . cvs-mode-undo)
-    ("?" .     cvs-help)
-    ("h" .     cvs-help)
-    ("q" .     cvs-bury-buffer)
-    ("z" .     kill-this-buffer)
-    ("F" .     cvs-mode-set-flags)
-    ;; ("\M-f" .       cvs-mode-force-command)
-    ("!" .     cvs-mode-force-command)
-    ("\C-c\C-c" . cvs-mode-kill-process)
-    ;; marking
-    ("m" .     cvs-mode-mark)
-    ("M" .     cvs-mode-mark-all-files)
-    ("S" .     cvs-mode-mark-on-state)
-    ("u" .     cvs-mode-unmark)
-    ("\C-?".   cvs-mode-unmark-up)
-    ("%" .     cvs-mode-mark-matching-files)
-    ("T" .     cvs-mode-toggle-marks)
-    ("\M-\C-?" .       cvs-mode-unmark-all-files)
-    ;; navigation keys
-    (" " .     cvs-mode-next-line)
-    ("n" .     cvs-mode-next-line)
-    ("p" .     cvs-mode-previous-line)
-    ("\t" .    cvs-mode-next-line)
-    ([backtab] . cvs-mode-previous-line)
-    ;; M- keys are usually those that operate on modules
-    ;;("\M-C". cvs-mode-rcs2log) ; i.e. "Create a ChangeLog"
-    ;;("\M-t". cvs-rtag)
-    ;;("\M-l". cvs-rlog)
-    ("\M-c".   cvs-checkout)
-    ("\M-e".   cvs-examine)
-    ("g" .     cvs-mode-revert-buffer)
-    ("\M-u".   cvs-update)
-    ("\M-s".   cvs-status)
-    ;; diff commands
-    ("=" .     cvs-mode-diff)
-    ("d" .     cvs-mode-diff-map)
-    ;; keys that operate on individual files
-    ("\C-k" .  cvs-mode-acknowledge)
-    ("A" .     cvs-mode-add-change-log-entry-other-window)
-    ;;("B" .   cvs-mode-byte-compile-files)
-    ("C" .     cvs-mode-commit-setup)
-    ("O" .     cvs-mode-update)
-    ("U" .     cvs-mode-undo)
-    ("I" .     cvs-mode-insert)
-    ("a" .     cvs-mode-add)
-    ("b" .     cvs-set-branch-prefix)
-    ("B" .     cvs-set-secondary-branch-prefix)
-    ("c" .     cvs-mode-commit)
-    ("e" .     cvs-mode-examine)
-    ("f" .     cvs-mode-find-file)
-    ("\C-m" .  cvs-mode-find-file)
-    ("i" .     cvs-mode-ignore)
-    ("l" .     cvs-mode-log)
-    ("o" .     cvs-mode-find-file-other-window)
-    ("r" .     cvs-mode-remove)
-    ("s" .     cvs-mode-status)
-    ("t" .     cvs-mode-tag)
-    ("v" .     cvs-mode-view-file)
-    ("x" .     cvs-mode-remove-handled)
-    ;; cvstree bindings
-    ("+" .     cvs-mode-tree)
-    ;; mouse bindings
-    ([mouse-2] . cvs-mode-find-file)
-    ([follow-link] . (lambda (pos)
-                      (if (eq (get-char-property pos 'face) 'cvs-filename) t)))
-    ([(down-mouse-3)] . cvs-menu)
-    ;; dired-like bindings
-    ("\C-o" .   cvs-mode-display-file)
-    ;; Emacs-21 toolbar
-    ;;([tool-bar item1] . (menu-item "Examine" cvs-examine :image (image :file 
"/usr/share/icons/xpaint.xpm" :type xpm)))
-    ;;([tool-bar item2] . (menu-item "Update" cvs-update :image (image :file 
"/usr/share/icons/mail1.xpm" :type xpm)))
-    )
-  "Keymap for `cvs-mode'."
-  :dense t
-  :suppress t)
-
-(fset 'cvs-mode-map cvs-mode-map)
-
-(easy-menu-define cvs-menu cvs-mode-map "Menu used in `cvs-mode'."
-  '("CVS"
-    ["Open file"               cvs-mode-find-file      t]
-    ["Open in other window"    cvs-mode-find-file-other-window t]
-    ["Display in other window"  cvs-mode-display-file   t]
-    ["Interactive merge"       cvs-mode-imerge         t]
-    ("View diff"
-     ["Interactive diff"       cvs-mode-idiff          t]
-     ["Current diff"           cvs-mode-diff           t]
-     ["Diff with head"         cvs-mode-diff-head      t]
-     ["Diff with vendor"       cvs-mode-diff-vendor    t]
-     ["Diff against yesterday" cvs-mode-diff-yesterday t]
-     ["Diff with backup"       cvs-mode-diff-backup    t])
-    ["View log"                        cvs-mode-log            t]
-    ["View status"             cvs-mode-status         t]
-    ["View tag tree"           cvs-mode-tree           t]
-    "----"
-    ["Insert"                  cvs-mode-insert]
-    ["Update"                  cvs-mode-update         (cvs-enabledp 'update)]
-    ["Re-examine"              cvs-mode-examine        t]
-    ["Commit"                  cvs-mode-commit-setup   (cvs-enabledp 'commit)]
-    ["Tag"                     cvs-mode-tag            (cvs-enabledp (when 
cvs-force-dir-tag 'tag))]
-    ["Undo changes"            cvs-mode-undo           (cvs-enabledp 'undo)]
-    ["Add"                     cvs-mode-add            (cvs-enabledp 'add)]
-    ["Remove"                  cvs-mode-remove         (cvs-enabledp 'remove)]
-    ["Ignore"                  cvs-mode-ignore         (cvs-enabledp 'ignore)]
-    ["Add ChangeLog"           cvs-mode-add-change-log-entry-other-window t]
-    "----"
-    ["Mark"                     cvs-mode-mark t]
-    ["Mark all"                        cvs-mode-mark-all-files t]
-    ["Mark by regexp..."        cvs-mode-mark-matching-files t]
-    ["Mark by state..."         cvs-mode-mark-on-state t]
-    ["Unmark"                   cvs-mode-unmark        t]
-    ["Unmark all"              cvs-mode-unmark-all-files t]
-    ["Hide handled"            cvs-mode-remove-handled t]
-    "----"
-    ["PCL-CVS Manual"          (lambda () (interactive)
-                                 (info "(pcl-cvs)Top")) t]
-    "----"
-    ["Quit"                    cvs-mode-quit           t]))
-
-;;;;
-;;;; CVS-Minor mode
-;;;;
-
-(defcustom cvs-minor-mode-prefix "\C-xc"
-  "Prefix key for the `cvs-mode' bindings in `cvs-minor-mode'."
-  :type 'string)
-
-(easy-mmode-defmap cvs-minor-mode-map
-  `((,cvs-minor-mode-prefix . cvs-mode-map)
-    ("e" . (menu-item nil cvs-mode-edit-log
-           :filter (lambda (x) (if (derived-mode-p 'log-view-mode) x)))))
-  "Keymap for `cvs-minor-mode', used in buffers related to PCL-CVS.")
-
 (defvar cvs-buffer nil
   "(Buffer local) The *cvs* buffer associated with this buffer.")
 (put 'cvs-buffer 'permanent-local t)
diff --git a/lisp/vc/pcvs.el b/lisp/vc/pcvs.el
index 726fe4e283..2daa42fbf8 100644
--- a/lisp/vc/pcvs.el
+++ b/lisp/vc/pcvs.el
@@ -117,11 +117,11 @@
 
 (require 'cl-lib)
 (require 'ewoc)                                ;Ewoc was once cookie
-(require 'pcvs-defs)
 (require 'pcvs-util)
 (require 'pcvs-parse)
 (require 'pcvs-info)
 (require 'vc-cvs)
+(require 'easy-mmode)
 
 
 ;;;;
@@ -138,6 +138,147 @@
 
 (defvar cvs-from-vc nil "Bound to t inside VC advice.")
 
+(defvar-keymap cvs-mode-diff-map
+  :name "Diff"
+  "E" (cons "imerge" #'cvs-mode-imerge)
+  "=" #'cvs-mode-diff
+  "e" (cons "idiff" #'cvs-mode-idiff)
+  "2" (cons "other" #'cvs-mode-idiff-other)
+  "d" (cons "diff" #'cvs-mode-diff)
+  "b" (cons "backup" #'cvs-mode-diff-backup)
+  "h" (cons "head" #'cvs-mode-diff-head)
+  "r" (cons "repository" #'cvs-mode-diff-repository)
+  "y" (cons "yesterday" #'cvs-mode-diff-yesterday)
+  "v" (cons "vendor" #'cvs-mode-diff-vendor))
+;; This is necessary to allow correct handling of \\[cvs-mode-diff-map]
+;; in substitute-command-keys.
+(fset 'cvs-mode-diff-map cvs-mode-diff-map)
+
+(defvar-keymap cvs-mode-map
+  :full t
+  :suppress t
+  ;; various
+  "?"              #'cvs-help
+  "h"              #'cvs-help
+  "q"              #'cvs-bury-buffer
+  "z"              #'kill-this-buffer
+  "F"              #'cvs-mode-set-flags
+  "!"              #'cvs-mode-force-command
+  ["C-c C-c"]      #'cvs-mode-kill-process
+  ;; marking
+  "m"              #'cvs-mode-mark
+  "M"              #'cvs-mode-mark-all-files
+  "S"              #'cvs-mode-mark-on-state
+  "u"              #'cvs-mode-unmark
+  ["DEL"]          #'cvs-mode-unmark-up
+  "%"              #'cvs-mode-mark-matching-files
+  "T"              #'cvs-mode-toggle-marks
+  ["M-DEL"]        #'cvs-mode-unmark-all-files
+  ;; navigation keys
+  " "              #'cvs-mode-next-line
+  "n"              #'cvs-mode-next-line
+  "p"              #'cvs-mode-previous-line
+  "\t"             #'cvs-mode-next-line
+  [backtab]        #'cvs-mode-previous-line
+  ;; M- keys are usually those that operate on modules
+  ["M-c"]          #'cvs-checkout
+  ["M-e"]          #'cvs-examine
+  "g"              #'cvs-mode-revert-buffer
+  ["M-u"]          #'cvs-update
+  ["M-s"]          #'cvs-status
+  ;; diff commands
+  "="              #'cvs-mode-diff
+  "d"              cvs-mode-diff-map
+  ;; keys that operate on individual files
+  ["C-k"]          #'cvs-mode-acknowledge
+  "A"              #'cvs-mode-add-change-log-entry-other-window
+  "C"              #'cvs-mode-commit-setup
+  "O"              #'cvs-mode-update
+  "U"              #'cvs-mode-undo
+  "I"              #'cvs-mode-insert
+  "a"              #'cvs-mode-add
+  "b"              #'cvs-set-branch-prefix
+  "B"              #'cvs-set-secondary-branch-prefix
+  "c"              #'cvs-mode-commit
+  "e"              #'cvs-mode-examine
+  "f"              #'cvs-mode-find-file
+  ["RET"]          #'cvs-mode-find-file
+  "i"              #'cvs-mode-ignore
+  "l"              #'cvs-mode-log
+  "o"              #'cvs-mode-find-file-other-window
+  "r"              #'cvs-mode-remove
+  "s"              #'cvs-mode-status
+  "t"              #'cvs-mode-tag
+  "v"              #'cvs-mode-view-file
+  "x"              #'cvs-mode-remove-handled
+  ;; cvstree bindings
+  "+"              #'cvs-mode-tree
+  ;; mouse bindings
+  [mouse-2]        #'cvs-mode-find-file
+  [follow-link]    (lambda (pos)
+                     (eq (get-char-property pos 'face) 'cvs-filename))
+  [(down-mouse-3)] #'cvs-menu
+  ;; dired-like bindings
+  "\C-o"           #'cvs-mode-display-file)
+
+(easy-menu-define cvs-menu cvs-mode-map "Menu used in `cvs-mode'."
+  '("CVS"
+    ["Open file"               cvs-mode-find-file      t]
+    ["Open in other window"    cvs-mode-find-file-other-window t]
+    ["Display in other window"  cvs-mode-display-file   t]
+    ["Interactive merge"       cvs-mode-imerge         t]
+    ("View diff"
+     ["Interactive diff"       cvs-mode-idiff          t]
+     ["Current diff"           cvs-mode-diff           t]
+     ["Diff with head"         cvs-mode-diff-head      t]
+     ["Diff with vendor"       cvs-mode-diff-vendor    t]
+     ["Diff against yesterday" cvs-mode-diff-yesterday t]
+     ["Diff with backup"       cvs-mode-diff-backup    t])
+    ["View log"                        cvs-mode-log            t]
+    ["View status"             cvs-mode-status         t]
+    ["View tag tree"           cvs-mode-tree           t]
+    "----"
+    ["Insert"                  cvs-mode-insert]
+    ["Update"                  cvs-mode-update         (cvs-enabledp 'update)]
+    ["Re-examine"              cvs-mode-examine        t]
+    ["Commit"                  cvs-mode-commit-setup   (cvs-enabledp 'commit)]
+    ["Tag"                     cvs-mode-tag            (cvs-enabledp (when 
cvs-force-dir-tag 'tag))]
+    ["Undo changes"            cvs-mode-undo           (cvs-enabledp 'undo)]
+    ["Add"                     cvs-mode-add            (cvs-enabledp 'add)]
+    ["Remove"                  cvs-mode-remove         (cvs-enabledp 'remove)]
+    ["Ignore"                  cvs-mode-ignore         (cvs-enabledp 'ignore)]
+    ["Add ChangeLog"           cvs-mode-add-change-log-entry-other-window t]
+    "----"
+    ["Mark"                     cvs-mode-mark t]
+    ["Mark all"                        cvs-mode-mark-all-files t]
+    ["Mark by regexp..."        cvs-mode-mark-matching-files t]
+    ["Mark by state..."         cvs-mode-mark-on-state t]
+    ["Unmark"                   cvs-mode-unmark        t]
+    ["Unmark all"              cvs-mode-unmark-all-files t]
+    ["Hide handled"            cvs-mode-remove-handled t]
+    "----"
+    ["PCL-CVS Manual"          (lambda () (interactive)
+                                 (info "(pcl-cvs)Top")) t]
+    "----"
+    ["Quit"                    cvs-mode-quit           t]))
+
+;;;;
+;;;; CVS-Minor mode
+;;;;
+
+(defcustom cvs-minor-mode-prefix "\C-xc"
+  "Prefix key for the `cvs-mode' bindings in `cvs-minor-mode'."
+  :type 'string
+  :group 'pcl-cvs)
+
+(defvar-keymap cvs-minor-mode-map
+  cvs-minor-mode-prefix 'cvs-mode-map
+  "e" '(menu-item nil cvs-mode-edit-log
+                 :filter (lambda (x)
+                            (and (derived-mode-p 'log-view-mode) x))))
+
+(require 'pcvs-defs)
+
 ;;;;
 ;;;; flags variables
 ;;;;
@@ -758,6 +899,7 @@ clear what alternative to use.
 - `DOUBLE' is the generic case."
   (declare (debug (&define sexp lambda-list stringp
                            ("interactive" interactive) def-body))
+           (indent defun)
           (doc-string 3))
   (let ((style (cvs-cdr fun))
        (fun (cvs-car fun)))
@@ -1144,7 +1286,8 @@ Full documentation is in the Texinfo file."
                                      ("->" cvs-secondary-branch-prefix))))
          " " cvs-mode-line-process))
   (if buffer-file-name
-      (error "Use M-x cvs-quickdir to get a *cvs* buffer"))
+      (error (substitute-command-keys
+              "Use \\[cvs-quickdir] to get a *cvs* buffer")))
   (buffer-disable-undo)
   ;;(setq-local goal-column cvs-cursor-column)
   (setq-local revert-buffer-function 'cvs-mode-revert-buffer)
@@ -1283,8 +1426,7 @@ marked instead.  A directory can never be marked."
       (intern
        (upcase
        (completing-read
-        (concat
-         "Mark files in state" (if default (concat " [" default "]")) ": ")
+         (format-prompt "Mark files in state" default)
         (mapcar (lambda (x)
                   (list (downcase (symbol-name (car x)))))
                 cvs-states)
diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el
index b2a875c81f..2cc5ee739f 100644
--- a/lisp/vc/smerge-mode.el
+++ b/lisp/vc/smerge-mode.el
@@ -47,6 +47,7 @@
 (require 'diff)                                ;For diff-check-labels.
 (require 'diff-mode)                    ;For diff-refine.
 (require 'newcomment)
+(require 'easy-mmode)
 
 ;;; The real definition comes later.
 (defvar smerge-mode)
@@ -142,25 +143,24 @@ Used in `smerge-diff-base-upper' and related functions."
   "Face used for added characters shown by `smerge-refine'."
   :version "24.3")
 
-(easy-mmode-defmap smerge-basic-map
-  `(("n" . smerge-next)
-    ("p" . smerge-prev)
-    ("r" . smerge-resolve)
-    ("a" . smerge-keep-all)
-    ("b" . smerge-keep-base)
-    ("o" . smerge-keep-lower)           ; for the obsolete keep-other
-    ("l" . smerge-keep-lower)
-    ("m" . smerge-keep-upper)           ; for the obsolete keep-mine
-    ("u" . smerge-keep-upper)
-    ("E" . smerge-ediff)
-    ("C" . smerge-combine-with-next)
-    ("R" . smerge-refine)
-    ("\C-m" . smerge-keep-current)
-    ("=" . ,(make-sparse-keymap "Diff"))
-    ("=<" "base-upper" . smerge-diff-base-upper)
-    ("=>" "base-lower" . smerge-diff-base-lower)
-    ("==" "upper-lower" . smerge-diff-upper-lower))
-  "The base keymap for `smerge-mode'.")
+(defvar-keymap smerge-basic-map
+  "n" #'smerge-next
+  "p" #'smerge-prev
+  "r" #'smerge-resolve
+  "a" #'smerge-keep-all
+  "b" #'smerge-keep-base
+  "o" #'smerge-keep-lower               ; for the obsolete keep-other
+  "l" #'smerge-keep-lower
+  "m" #'smerge-keep-upper               ; for the obsolete keep-mine
+  "u" #'smerge-keep-upper
+  "E" #'smerge-ediff
+  "C" #'smerge-combine-with-next
+  "R" #'smerge-refine
+  ["C-m"] #'smerge-keep-current
+  "=" (define-keymap :name "Diff"
+        "<" (cons "base-upper" #'smerge-diff-base-upper)
+        ">" (cons "base-lower" #'smerge-diff-base-lower)
+        "=" (cons "upper-lower" #'smerge-diff-upper-lower)))
 
 (defcustom smerge-command-prefix "\C-c^"
   "Prefix for `smerge-mode' commands."
@@ -169,9 +169,8 @@ Used in `smerge-diff-base-upper' and related functions."
                 (const :tag "none"  "")
                 string))
 
-(easy-mmode-defmap smerge-mode-map
-  `((,smerge-command-prefix . ,smerge-basic-map))
-  "Keymap for `smerge-mode'.")
+(defvar-keymap smerge-mode-map
+  smerge-command-prefix smerge-basic-map)
 
 (defvar-local smerge-check-cache nil)
 (defun smerge-check (n)
diff --git a/lisp/vc/vc-annotate.el b/lisp/vc/vc-annotate.el
index 45bb17749b..def87db871 100644
--- a/lisp/vc/vc-annotate.el
+++ b/lisp/vc/vc-annotate.el
@@ -610,7 +610,8 @@ the file in question, search for the log entry required and 
move point."
   (vc-annotate-show-diff-revision-at-line-internal t))
 
 (defun vc-annotate-show-changeset-diff-revision-at-line ()
-  "Visit the diff of the revision at line from its previous revision for all 
files in the changeset."
+  "Show the diffs of revision at current line relative to previous revision.
+This is done for all files in changeset."
   (interactive)
   (when (eq 'file (vc-call-backend vc-annotate-backend 'revision-granularity))
     (error "The %s backend does not support changeset diffs" 
vc-annotate-backend))
diff --git a/lisp/vc/vc-bzr.el b/lisp/vc/vc-bzr.el
index bfe3293e45..48fedeca5a 100644
--- a/lisp/vc/vc-bzr.el
+++ b/lisp/vc/vc-bzr.el
@@ -1054,7 +1054,8 @@ stream.  Standard error output is discarded."
              (vc-bzr-command "info" t 0 dir)
              (buffer-string)))
        (shelve (vc-bzr-shelve-list))
-       (shelve-help-echo "Use M-x vc-bzr-shelve to create shelves")
+       (shelve-help-echo (substitute-command-keys
+                          "Use \\[vc-bzr-shelve] to create shelves"))
        (root-dir (vc-bzr-root dir))
        (pending-merge
        ;; FIXME: looking for .bzr/checkout/merge-hashes is not a
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index f8b87170af..8165d5e09f 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -1015,8 +1015,11 @@ child files."
     (nreverse result)))
 
 (defun vc-dir-child-files-and-states ()
-  "Return the list of conses (FILE . STATE) for child files of the current 
entry if it's a directory.
-If it is a file, return the corresponding cons for the file itself."
+  "Return the state of one or more files for the current entry.
+If the entry is a directory, return the list of states of its child
+files, where each file is described by a cons of the form (FILE . STATE).
+If the entry is a file, return a single cons cell (FILE . STATE) for
+that file."
   (let* ((crt (ewoc-locate vc-ewoc))
         (crt-data (ewoc-data crt))
          result)
diff --git a/lisp/vc/vc-dispatcher.el b/lisp/vc/vc-dispatcher.el
index cd23bcce94..346974bdba 100644
--- a/lisp/vc/vc-dispatcher.el
+++ b/lisp/vc/vc-dispatcher.el
@@ -404,7 +404,7 @@ Display the buffer in some window, but don't select it."
 (defvar compilation-error-regexp-alist)
 
 (defun vc-compilation-mode (backend)
-  "Setup `compilation-mode' after with the appropriate 
`compilation-error-regexp-alist'."
+  "Setup `compilation-mode' with the appropriate 
`compilation-error-regexp-alist'."
   (require 'compile)
   (let* ((error-regexp-alist
           (vc-make-backend-sym backend 'error-regexp-alist))
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index eca8d547a9..3f89fad235 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -242,15 +242,14 @@ included in the completions."
 ;;;###autoload         (load "vc-git" nil t)
 ;;;###autoload         (vc-git-registered file))))
 
+;; Good example of file name that needs this: "test[56].xx".
 (defun vc-git--literal-pathspec (file)
   "Prepend :(literal) path magic to FILE."
-  ;; Good example of file name that needs this: "test[56].xx".
   (when file
-    (let ((lname (file-local-name file)))
-      ;; Expand abbreviated file names.
-      (when (file-name-absolute-p lname)
-        (setq lname (expand-file-name lname)))
-      (concat ":(literal)" lname))))
+    ;; Expand abbreviated file names.
+    (when (file-name-absolute-p file)
+      (setq file (expand-file-name file)))
+    (concat ":(literal)" (file-local-name file))))
 
 (defun vc-git--literal-pathspecs (files)
   "Prepend :(literal) path magic to FILES."
@@ -1324,7 +1323,7 @@ or BRANCH^ (where \"^\" can be repeated)."
 
 (defun vc-git-expanded-log-entry (revision)
   (with-temp-buffer
-    (apply #'vc-git-command t nil nil (list "log" revision "-1" "--"))
+    (apply #'vc-git-command t nil nil (list "log" revision "-1"  "--no-color" 
"--"))
     (goto-char (point-min))
     (unless (eobp)
       ;; Indent the expanded log entry.
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 0ed9f7c31f..6bec9edbf3 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -672,7 +672,6 @@ Return the byte's value as an integer."
     (let* ((result nil)
            (flen (length fname))
            (case-fold-search nil)
-           (inhibit-changing-match-data t)
            ;; Find a conservative bound for the loop below by using
            ;; Boyer-Moore on the raw dirstate without parsing it; we
            ;; know we can't possibly find fname _after_ the last place
@@ -976,10 +975,9 @@ REPO must be the directory name of an hg repository."
   "Test whether the ignore pattern set HGIP says to ignore FILENAME.
 FILENAME must be the file's true absolute name."
   (let ((patterns (vc-hg--ignore-patterns-ignore-patterns hgip))
-        (inhibit-changing-match-data t)
         (ignored nil))
     (while (and patterns (not ignored))
-      (setf ignored (string-match (pop patterns) filename)))
+      (setf ignored (string-match-p (pop patterns) filename)))
     ignored))
 
 (defvar vc-hg--cached-ignore-patterns nil
@@ -1043,7 +1041,8 @@ Avoids the need to repeatedly scan dirstate on repeated 
calls to
              (equal size (pop cache))
              (equal ascii-fname (pop cache)))
         (pop cache)
-      (let ((result (vc-hg--raw-dirstate-search dirstate ascii-fname)))
+      (let ((result (save-match-data
+                      (vc-hg--raw-dirstate-search dirstate ascii-fname))))
         (setf vc-hg--dirstate-scan-cache
               (list dirstate mtime size ascii-fname result))
         result))))
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index b7760e3bba..cd5b11d840 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -864,7 +864,8 @@ In the latter case, VC mode is deactivated for this buffer."
 (defvar vc-prefix-map
   (let ((map (make-sparse-keymap)))
     (define-key map "a" #'vc-update-change-log)
-    (define-key map "b" #'vc-switch-backend)
+    (with-suppressed-warnings ((obsolete vc-switch-backend))
+      (define-key map "b" #'vc-switch-backend))
     (define-key map "d" #'vc-dir)
     (define-key map "g" #'vc-annotate)
     (define-key map "G" #'vc-ignore)
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 8767969163..4b56f1b795 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -739,6 +739,7 @@
 (require 'cl-lib)
 
 (declare-function diff-setup-whitespace "diff-mode" ())
+(declare-function diff-setup-buffer-type "diff-mode" ())
 
 (eval-when-compile
   (require 'dired))
@@ -937,11 +938,18 @@ repository, prompting for the directory and the VC 
backend to
 use."
   (catch 'found
     ;; First try: find a responsible backend, it must be a backend
-    ;; under which FILE is not yet registered.
-    (dolist (backend vc-handled-backends)
-      (and (not (vc-call-backend backend 'registered file))
-          (vc-call-backend backend 'responsible-p file)
-          (throw 'found backend)))
+    ;; under which FILE is not yet registered and with the most
+    ;; specific path to FILE.
+    (let ((max 0)
+          bk)
+      (dolist (backend vc-handled-backends)
+        (when (not (vc-call-backend backend 'registered file))
+          (let* ((path (vc-call-backend backend 'responsible-p file))
+                 (len (length path)))
+            (when (and len (> len max))
+              (setq max len bk backend)))))
+      (when bk
+        (throw 'found bk)))
     ;; no responsible backend
     (let* ((possible-backends
            (let (pos)
@@ -1188,7 +1196,11 @@ For old-style locking-based version control systems, 
like RCS:
    *vc-log* buffer to check in the changes.  Leave a
    read-only copy of each changed file after checking in.
   If every file is locked by you and unchanged, unlock them.
-  If every file is locked by someone else, offer to steal the lock."
+  If every file is locked by someone else, offer to steal the lock.
+
+When using this command to register a new file (or files), it
+will automatically deduce which VC repository to register it
+with, using the most specific one."
   (interactive "P")
   (let* ((vc-fileset (vc-deduce-fileset nil t 'state-model-only-files))
          (backend (car vc-fileset))
@@ -1216,7 +1228,11 @@ For old-style locking-based version control systems, 
like RCS:
      ((eq state 'ignored)
       (error "Fileset files are ignored by the version-control system"))
      ((or (null state) (eq state 'unregistered))
-      (vc-register vc-fileset))
+      (cond (verbose
+             (let ((backend (vc-read-backend "Backend to register to: ")))
+               (vc-register (cons backend (cdr vc-fileset)))))
+            (t
+             (vc-register vc-fileset))))
      ;; Files are up-to-date, or need a merge and user specified a revision
      ((or (eq state 'up-to-date) (and verbose (eq state 'needs-update)))
       (cond
@@ -1724,6 +1740,7 @@ to override the value of `vc-diff-switches' and 
`diff-switches'."
               (insert (cdr messages) ".\n")
               (message "%s" (cdr messages))))
        (diff-setup-whitespace)
+       (diff-setup-buffer-type)
        (goto-char (point-min))
        (when window
          (shrink-window-if-larger-than-buffer window)))
@@ -1859,13 +1876,10 @@ Return t if the buffer had changes, nil otherwise."
                                             (vc-working-revision first))))
       (when (string= rev1-default "") (setq rev1-default nil))))
     ;; construct argument list
-    (let* ((rev1-prompt (if rev1-default
-                            (concat "Older revision (default "
-                                    rev1-default "): ")
-                          "Older revision: "))
-           (rev2-prompt (concat "Newer revision (default "
-                                ;; (or rev2-default
-                                "current source): "))
+    (let* ((rev1-prompt (format-prompt "Older revision" rev1-default))
+           (rev2-prompt (format-prompt "Newer revision"
+                                       ;; (or rev2-default
+                                       "current source"))
            (rev1 (vc-read-revision rev1-prompt files backend rev1-default))
            (rev2 (vc-read-revision rev2-prompt files backend nil))) ;; 
rev2-default
       (when (string= rev1 "") (setq rev1 nil))
@@ -2078,7 +2092,7 @@ If `F.~REV~' already exists, use it instead of checking 
it out again."
    (with-current-buffer (or (buffer-base-buffer) (current-buffer))
      (vc-ensure-vc-buffer)
      (list
-      (vc-read-revision "Revision to visit (default is working revision): "
+      (vc-read-revision (format-prompt "Revision to visit" "working revision")
                         (list buffer-file-name)))))
   (set-buffer (or (buffer-base-buffer) (current-buffer)))
   (vc-ensure-vc-buffer)
@@ -2374,7 +2388,7 @@ This function runs the hook `vc-retrieve-tag-hook' when 
finished."
              (read-directory-name "Directory: " default-directory nil t))))
      (list
       dir
-      (vc-read-revision "Tag name to retrieve (default latest revisions): "
+      (vc-read-revision (format-prompt "Tag name to retrieve" "latest 
revisions")
                         (list dir)
                         (vc-responsible-backend dir)))))
   (let* ((backend (vc-responsible-backend dir))
@@ -2620,7 +2634,7 @@ with its diffs (if the underlying VCS supports that)."
 
 ;;;###autoload
 (defun vc-log-incoming (&optional remote-location)
-  "Show a log of changes that will be received with a pull operation from 
REMOTE-LOCATION.
+  "Show log of changes that will be received with pull from REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION."
   (interactive
    (when current-prefix-arg
@@ -2633,7 +2647,7 @@ When called interactively with a prefix argument, prompt 
for REMOTE-LOCATION."
 
 ;;;###autoload
 (defun vc-log-outgoing (&optional remote-location)
-  "Show a log of changes that will be sent with a push operation to 
REMOTE-LOCATION.
+  "Show log of changes that will be sent with a push operation to 
REMOTE-LOCATION.
 When called interactively with a prefix argument, prompt for REMOTE-LOCATION."
   (interactive
    (when current-prefix-arg
@@ -2860,6 +2874,7 @@ permanent, only for the current session.  This function 
only changes
 VC's perspective on FILE, it does not register or unregister it.
 By default, this command cycles through the registered backends.
 To get a prompt, use a prefix argument."
+  (declare (obsolete nil "28.1"))
   (interactive
    (list
     (or buffer-file-name
@@ -2914,7 +2929,8 @@ backend to NEW-BACKEND, and unregister FILE from the 
current backend.
     (if registered
        (set-file-modes file (logior (file-modes file) 128))
       ;; `registered' might have switched under us.
-      (vc-switch-backend file old-backend)
+      (with-suppressed-warnings ((obsolete vc-switch-backend))
+        (vc-switch-backend file old-backend))
       (let* ((rev (vc-working-revision file))
             (modified-file (and edited (make-temp-file file)))
             (unmodified-file (and modified-file (vc-version-backup-file 
file))))
@@ -2933,16 +2949,19 @@ backend to NEW-BACKEND, and unregister FILE from the 
current backend.
                    (vc-revert-file file))))
              (vc-call-backend new-backend 'receive-file file rev))
          (when modified-file
-           (vc-switch-backend file new-backend)
+            (with-suppressed-warnings ((obsolete vc-switch-backend))
+              (vc-switch-backend file new-backend))
            (unless (eq (vc-checkout-model new-backend (list file)) 'implicit)
              (vc-checkout file))
            (rename-file modified-file file 'ok-if-already-exists)
            (vc-file-setprop file 'vc-checkout-time nil)))))
     (when move
-      (vc-switch-backend file old-backend)
+      (with-suppressed-warnings ((obsolete vc-switch-backend))
+        (vc-switch-backend file old-backend))
       (setq comment (vc-call-backend old-backend 'comment-history file))
       (vc-call-backend old-backend 'unregister file))
-    (vc-switch-backend file new-backend)
+    (with-suppressed-warnings ((obsolete vc-switch-backend))
+      (vc-switch-backend file new-backend))
     (when (or move edited)
       (vc-file-setprop file 'vc-state 'edited)
       (vc-mode-line file new-backend)
diff --git a/lisp/whitespace.el b/lisp/whitespace.el
index d4f2b2890a..5a482c5253 100644
--- a/lisp/whitespace.el
+++ b/lisp/whitespace.el
@@ -1687,32 +1687,32 @@ cleaning up these problems."
                        (or whitespace-active-style whitespace-style)))
            (bogus-list
             (mapcar
-             #'(lambda (option)
-                 (when force
-                   (push (car option) style))
-                 (goto-char rstart)
-                 (let ((regexp
-                        (cond
-                         ((eq (car option) 'indentation)
-                          (whitespace-indentation-regexp))
-                         ((eq (car option) 'indentation::tab)
-                          (whitespace-indentation-regexp 'tab))
-                         ((eq (car option) 'indentation::space)
-                          (whitespace-indentation-regexp 'space))
-                         ((eq (car option) 'space-after-tab)
-                          (whitespace-space-after-tab-regexp))
-                         ((eq (car option) 'space-after-tab::tab)
-                          (whitespace-space-after-tab-regexp 'tab))
-                         ((eq (car option) 'space-after-tab::space)
-                          (whitespace-space-after-tab-regexp 'space))
-                         ((eq (car option) 'missing-newline-at-eof)
-                          "[^\n]\\'")
-                         (t
-                          (cdr option)))))
-                   (when (re-search-forward regexp rend t)
-                     (unless has-bogus
-                       (setq has-bogus (memq (car option) style)))
-                     t)))
+             (lambda (option)
+               (when force
+                 (push (car option) style))
+               (goto-char rstart)
+               (let ((regexp
+                      (cond
+                       ((eq (car option) 'indentation)
+                        (whitespace-indentation-regexp))
+                       ((eq (car option) 'indentation::tab)
+                        (whitespace-indentation-regexp 'tab))
+                       ((eq (car option) 'indentation::space)
+                        (whitespace-indentation-regexp 'space))
+                       ((eq (car option) 'space-after-tab)
+                        (whitespace-space-after-tab-regexp))
+                       ((eq (car option) 'space-after-tab::tab)
+                        (whitespace-space-after-tab-regexp 'tab))
+                       ((eq (car option) 'space-after-tab::space)
+                        (whitespace-space-after-tab-regexp 'space))
+                       ((eq (car option) 'missing-newline-at-eof)
+                        "[^\n]\\'")
+                       (t
+                        (cdr option)))))
+                 (when (re-search-forward regexp rend t)
+                   (unless has-bogus
+                     (setq has-bogus (memq (car option) style)))
+                   t)))
              whitespace-report-list)))
       (when (pcase report-if-bogus ('nil t) ('never nil) (_ has-bogus))
         (whitespace-kill-buffer whitespace-report-buffer-name)
@@ -2193,8 +2193,7 @@ resultant list will be returned."
    limit t))
 
 (defun whitespace-empty-at-bob-regexp (limit)
-  "Match spaces at beginning of buffer which do not contain the point at \
-beginning of buffer."
+  "Match spaces at beginning of buffer (BOB) which do not contain point at 
BOB."
   (let ((b (point))
        r)
     (cond
@@ -2464,5 +2463,4 @@ It should be added buffer-locally to 
`write-file-functions'."
                         "use `with-eval-after-load' instead." "28.1")
 (run-hooks 'whitespace-load-hook)
 
-
 ;;; whitespace.el ends here
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index ab358da7e3..fb06a95f51 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -3325,7 +3325,7 @@ It reads a file name from an editable text field."
 ;;;     (file (file-name-nondirectory value))
 ;;;     (menu-tag (widget-apply widget :menu-tag-get))
 ;;;     (must-match (widget-get widget :must-match))
-;;;     (answer (read-file-name (concat menu-tag " (default " value "): ")
+;;;     (answer (read-file-name (format-prompt menu-tag value)
 ;;;                             dir nil must-match file)))
 ;;;    (widget-value-set widget (abbreviate-file-name answer))
 ;;;    (widget-setup)
@@ -3644,6 +3644,13 @@ match-alternatives: %S"
   :type-error "This field should contain an integer"
   :match-alternatives '(integerp))
 
+(define-widget 'natnum 'restricted-sexp
+  "A nonnegative integer."
+  :tag "Integer (positive or zero)"
+  :value 0
+  :type-error "This field should contain a nonnegative integer"
+  :match-alternatives '(natnump))
+
 (define-widget 'number 'restricted-sexp
   "A number (floating point or integer)."
   :tag "Number"
diff --git a/lisp/widget.el b/lisp/widget.el
index 393fe6c21b..0232f6cf93 100644
--- a/lisp/widget.el
+++ b/lisp/widget.el
@@ -44,7 +44,7 @@
   ;;   (list 'or (list 'boundp (list 'car 'keywords))
   ;;     (list 'set (list 'car 'keywords) (list 'car 'keywords)))
   ;;   (list 'setq 'keywords (list 'cdr 'keywords)))))
-  (declare (obsolete nil "27.1"))
+  (declare (obsolete nil "27.1") (indent defun))
   nil)
 
 ;;(define-widget-keywords :documentation-indent
@@ -83,7 +83,7 @@ create identical widgets:
 * (apply #\\='widget-create CLASS ARGS)
 
 The third argument DOC is a documentation string for the widget."
-  (declare (doc-string 3))
+  (declare (doc-string 3) (indent defun))
   ;;
   (unless (or (null doc) (stringp doc))
     (error "Widget documentation must be nil or a string"))
diff --git a/lisp/window.el b/lisp/window.el
index b240b16f24..2582743679 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -108,11 +108,14 @@ Return the buffer."
       ;; Return the buffer.
       buffer)))
 
+;; Defined in help.el.
+(defvar resize-temp-buffer-window-inhibit)
+
 (defun temp-buffer-window-show (buffer &optional action)
   "Show temporary buffer BUFFER in a window.
 Return the window showing BUFFER.  Pass ACTION as action argument
 to `display-buffer'."
-  (let (window frame)
+  (let (resize-temp-buffer-window-inhibit window)
     (with-current-buffer buffer
       (set-buffer-modified-p nil)
       (setq buffer-read-only t)
@@ -130,9 +133,9 @@ to `display-buffer'."
                       t
                     window-combination-limit)))
              (setq window (display-buffer buffer action)))
-       (setq frame (window-frame window))
-       (unless (eq frame (selected-frame))
-         (raise-frame frame))
+        ;; We used to raise the window's frame here.  Do not do that
+        ;; since it would override an `inhibit-switch-frame' entry
+        ;; specified for the action alist used by `display-buffer'.
        (setq minibuffer-scroll-window window)
        (set-window-hscroll window 0)
        (with-selected-window window
@@ -1212,7 +1215,8 @@ it is found."
      ((setq state (frame-parameter frame 'window-state))
       ;; A window state was saved for FRAME.  Restore it and put the
       ;; current root window into its main window.
-      (let ((main-state (window-state-get (frame-root-window frame))))
+      (let ((window-combination-resize t)
+            (main-state (window-state-get (frame-root-window frame))))
         (window-state-put state (frame-root-window frame) t)
         (window-state-put main-state (window-main-window frame)))
       (window--sides-reverse-frame frame))
@@ -1406,9 +1410,12 @@ before writing to it."
                 (cadr fringes)
                 (window-scroll-bar-width window)
                 (window-right-divider-width window))
-        (format "height header-line: %s  mode-line: %s  divider: %s\n"
+        (format "height tab-line: %s header-line: %s  mode-line: %s\n"
+                (window-tab-line-height window)
                 (window-header-line-height window)
-                (window-mode-line-height window)
+                (window-mode-line-height window))
+        (format "height scroll-bar: %s divider: %s"
+                (window-scroll-bar-height window)
                 (window-bottom-divider-width window)))))
     (insert "\n")))
 
@@ -1510,21 +1517,11 @@ Emacs won't change the size of any window displaying 
that buffer,
 unless it has no other choice (like when deleting a neighboring
 window).")
 
-(defun window--preservable-size (window &optional horizontal)
-  "Return height of WINDOW as `window-preserve-size' would preserve it.
-Optional argument HORIZONTAL non-nil means to return the width of
-WINDOW as `window-preserve-size' would preserve it."
-  (if horizontal
-      (window-body-width window t)
-    (+ (window-body-height window t)
-       (window-header-line-height window)
-       (window-mode-line-height window))))
-
 (defun window-preserve-size (&optional window horizontal preserve)
-  "Preserve height of window WINDOW.
+  "Preserve height of specified WINDOW's body.
 WINDOW must be a live window and defaults to the selected one.
-Optional argument HORIZONTAL non-nil means preserve the width of
-WINDOW.
+Optional argument HORIZONTAL non-nil means to preserve the width
+of WINDOW's body.
 
 PRESERVE t means to preserve the current height/width of WINDOW's
 body in frame and window resizing operations whenever possible.
@@ -1541,21 +1538,15 @@ WINDOW as argument also removes the respective 
restraint.
 Other values of PRESERVE are reserved for future use."
   (setq window (window-normalize-window window t))
   (let* ((parameter (window-parameter window 'window-preserved-size))
-        (width (nth 1 parameter))
-        (height (nth 2 parameter)))
-    (if horizontal
-       (set-window-parameter
-        window 'window-preserved-size
-        (list
-         (window-buffer window)
-         (and preserve (window--preservable-size window t))
-         height))
-      (set-window-parameter
-       window 'window-preserved-size
-       (list
-       (window-buffer window)
-       width
-       (and preserve (window--preservable-size window)))))))
+        (width (if horizontal
+                     (and preserve (window-body-width window t))
+                   (nth 1 parameter)))
+        (height (if horizontal
+                      (nth 2 parameter)
+                    (and preserve (window-body-height window t)))))
+    (set-window-parameter
+     window 'window-preserved-size
+     (list (window-buffer window) width height))))
 
 (defun window-preserved-size (&optional window horizontal)
   "Return preserved height of window WINDOW.
@@ -1563,12 +1554,9 @@ WINDOW must be a live window and defaults to the 
selected one.
 Optional argument HORIZONTAL non-nil means to return preserved
 width of WINDOW."
   (setq window (window-normalize-window window t))
-  (let* ((parameter (window-parameter window 'window-preserved-size))
-        (buffer (nth 0 parameter))
-        (width (nth 1 parameter))
-        (height (nth 2 parameter)))
-    (when (eq buffer (window-buffer window))
-      (if horizontal width height))))
+  (let ((parameter (window-parameter window 'window-preserved-size)))
+    (when (eq (nth 0 parameter) (window-buffer window))
+      (nth (if horizontal 1 2) parameter))))
 
 (defun window--preserve-size (window horizontal)
   "Return non-nil when the height of WINDOW shall be preserved.
@@ -1576,7 +1564,7 @@ Optional argument HORIZONTAL non-nil means to return 
non-nil when
 the width of WINDOW shall be preserved."
   (let ((size (window-preserved-size window horizontal)))
     (and (numberp size)
-        (= size (window--preservable-size window horizontal)))))
+        (= size (window-body-size window horizontal t)))))
 
 (defun window-safe-min-size (&optional window horizontal pixelwise)
   "Return safe minimum size of WINDOW.
@@ -1690,6 +1678,7 @@ return the minimum pixel-size of WINDOW."
         ((let ((char-size (frame-char-size window))
                (pixel-height
                 (+ (window-safe-min-size window nil t)
+                   (window-tab-line-height window)
                    (window-header-line-height window)
                    (window-scroll-bar-height window)
                    (window-mode-line-height window)
@@ -7245,11 +7234,15 @@ Return WINDOW if BUFFER and WINDOW are live."
             (inhibit-modification-hooks t))
         (funcall (cdr (assq 'body-function alist)) window)))
 
-    (let ((quit-restore (window-parameter window 'quit-restore))
-         (height (cdr (assq 'window-height alist)))
-         (width (cdr (assq 'window-width alist)))
-         (size (cdr (assq 'window-size alist)))
-         (preserve-size (cdr (assq 'preserve-size alist))))
+    (let* ((frame (window-frame window))
+           (quit-restore (window-parameter window 'quit-restore))
+          (window-height (assq 'window-height alist))
+           (height (cdr window-height))
+          (window-width (assq 'window-width alist))
+           (width (cdr window-width))
+           (window-size (assq 'window-size alist))
+           (size (cdr window-size))
+          (preserve-size (cdr (assq 'preserve-size alist))))
       (cond
        ((or (eq type 'frame)
            (and (eq (car quit-restore) 'same)
@@ -7260,29 +7253,43 @@ Return WINDOW if BUFFER and WINDOW are live."
         ;; Adjust size of frame if asked for.  We probably should do
         ;; that only for a single window frame.
        (cond
-        ((not size))
+        ((not size)
+          (when window-size
+            (setq resize-temp-buffer-window-inhibit t)))
         ((consp size)
-         (let ((width (car size))
-               (height (cdr size))
-               (frame (window-frame window)))
-           (when (and (numberp width) (numberp height))
-             (set-frame-height
-              frame (+ (frame-height frame)
-                       (- height (window-total-height window))))
-             (set-frame-width
-              frame (+ (frame-width frame)
-                       (- width (window-total-width window)))))))
-        ((functionp size)
-         (ignore-errors (funcall size window)))))
+          ;; Modifying the parameters of a newly created frame might
+          ;; not work everywhere, but then `temp-buffer-resize-mode'
+          ;; will certainly fail in a similar fashion.
+          (if (eq (car size) 'body-chars)
+             (let ((width (+ (frame-text-width frame)
+                              (* (frame-char-width frame) (cadr size))
+                              (- (window-body-width window t))))
+                    (height (+ (frame-text-height frame)
+                               (* (frame-char-height frame) (cddr size))
+                               (- (window-body-height window t)))))
+               (modify-frame-parameters
+                frame `((height . (text-pixels . ,height))
+                         (width . (text-pixels . ,width)))))
+           (let ((width (- (+ (frame-width frame) (car size))
+                            (window-total-width window)))
+                  (height (- (+ (frame-height frame) (cdr size))
+                             (window-total-height window))))
+             (modify-frame-parameters
+              frame `((height . ,height) (width . ,width)))))
+          (setq resize-temp-buffer-window-inhibit t))
+         ((functionp size)
+         (ignore-errors (funcall size window))
+          (setq resize-temp-buffer-window-inhibit t))))
        ((or (eq type 'window)
            (and (eq (car quit-restore) 'same)
                 (eq (nth 1 quit-restore) 'window)))
        ;; A window that never showed another buffer but BUFFER ever
-        ;; since it was created on an existing frame.
-        ;;
-        ;; Adjust width and/or height of window if asked for.
+        ;; since it was created on an existing frame.  Adjust its width
+        ;; and/or height if asked for.
        (cond
-        ((not height))
+         ((not height)
+         (when window-height
+            (setq resize-temp-buffer-window-inhibit 'vertical)))
         ((numberp height)
          (let* ((new-height
                  (if (integerp height)
@@ -7293,12 +7300,23 @@ Return WINDOW if BUFFER and WINDOW are live."
                 (delta (- new-height (window-total-height window))))
            (when (and (window--resizable-p window delta nil 'safe)
                       (window-combined-p window))
-             (window-resize window delta nil 'safe))))
-        ((functionp height)
-         (ignore-errors (funcall height window))))
+             (window-resize window delta nil 'safe)))
+          (setq resize-temp-buffer-window-inhibit 'vertical))
+         ((and (consp height) (eq (car height) 'body-lines))
+         (let* ((delta (- (* (frame-char-height frame) (cdr height))
+                           (window-body-height window t))))
+           (and (window--resizable-p window delta nil 'safe nil nil nil t)
+                (window-combined-p window)
+                (window-resize window delta nil 'safe t)))
+          (setq resize-temp-buffer-window-inhibit 'vertical))
+         ((functionp height)
+         (ignore-errors (funcall height window))
+          (setq resize-temp-buffer-window-inhibit 'vertical)))
        ;; Adjust width of window if asked for.
        (cond
-        ((not width))
+        ((not width)
+          (when window-width
+            (setq resize-temp-buffer-window-inhibit 'horizontal)))
         ((numberp width)
          (let* ((new-width
                  (if (integerp width)
@@ -7309,13 +7327,24 @@ Return WINDOW if BUFFER and WINDOW are live."
                 (delta (- new-width (window-total-width window))))
            (when (and (window--resizable-p window delta t 'safe)
                       (window-combined-p window t))
-             (window-resize window delta t 'safe))))
+             (window-resize window delta t 'safe)))
+          (setq resize-temp-buffer-window-inhibit 'horizontal))
+         ((and (consp width) (eq (car width) 'body-columns))
+         (let* ((delta (- (* (frame-char-width frame) (cdr width))
+                           (window-body-width window t))))
+           (and (window--resizable-p window delta t 'safe nil nil nil t)
+                (window-combined-p window t)
+                (window-resize window delta t 'safe t)))
+          (setq resize-temp-buffer-window-inhibit 'horizontal))
         ((functionp width)
-         (ignore-errors (funcall width window))))
+         (ignore-errors (funcall width window))
+          (setq resize-temp-buffer-window-inhibit 'horizontal)))
+
        ;; Preserve window size if asked for.
        (when (consp preserve-size)
          (window-preserve-size window t (car preserve-size))
          (window-preserve-size window nil (cdr preserve-size)))))
+
       ;; Assign any window parameters specified.
       (let ((parameters (cdr (assq 'window-parameters alist))))
         (dolist (parameter parameters)
@@ -7558,6 +7587,9 @@ Action alist entries are:
     window from being used for display.
  `inhibit-switch-frame' -- A non-nil value prevents any frame
     used for showing the buffer from being raised or selected.
+    Note that a window manager may still raise a new frame and
+    give it focus, effectively overriding the value specified
+    here.
  `reusable-frames' -- The value specifies the set of frames to
     search for a window that already displays the buffer.
     Possible values are nil (the selected frame), t (any live
@@ -7567,20 +7599,33 @@ Action alist entries are:
     frame parameters to give a new frame, if one is created.
  `window-height' -- The value specifies the desired height of the
     window chosen and is either an integer (the total height of
-    the window), a floating point number (the fraction of its
-    total height with respect to the total height of the frame's
-    root window) or a function to be called with one argument -
-    the chosen window.  The function is supposed to adjust the
-    height of the window; its return value is ignored.  Suitable
-    functions are `shrink-window-if-larger-than-buffer' and
-    `fit-window-to-buffer'.
+    the window specified in frame lines), a floating point
+    number (the fraction of its total height with respect to the
+    total height of the frame's root window), a cons cell whose
+    car is 'body-lines' and whose cdr is an integer that
+    specifies the height of the window's body in frame lines, or
+    a function to be called with one argument - the chosen
+    window.  That function is supposed to adjust the height of
+    the window.  Suitable functions are `fit-window-to-buffer'
+    and `shrink-window-if-larger-than-buffer'.
  `window-width' -- The value specifies the desired width of the
     window chosen and is either an integer (the total width of
-    the window), a floating point number (the fraction of its
-    total width with respect to the width of the frame's root
-    window) or a function to be called with one argument - the
-    chosen window.  The function is supposed to adjust the width
-    of the window; its return value is ignored.
+    the window specified in frame lines), a floating point
+    number (the fraction of its total width with respect to the
+    width of the frame's root window), a cons cell whose car is
+    'body-columns' and whose cdr is an integer that specifies the
+    width of the window's body in frame columns, or a function to
+    be called with one argument - the chosen window.  That
+    function is supposed to adjust the width of the window.
+ `window-size' -- This entry is only useful for windows appearing
+    alone on their frame and specifies the desired size of that
+    window either as a cons of integers (the total width and
+    height of the window on that frame), a cons cell whose car is
+    'body-chars' and whose cdr is a cons of integers (the desired
+    width and height of the window's body in columns and lines of
+    its frame), or a function to be called with one argument -
+    the chosen window.  That function is supposed to adjust the
+    size of the frame.
  `preserve-size' -- The value should be either (t . nil) to
     preserve the width of the chosen window, (nil . t) to
     preserve its height or (t . t) to preserve its height and
@@ -7596,9 +7641,9 @@ Action alist entries are:
     to fill the window body with some contents that might depend
     on dimensions of the displayed window.
 
-The entries `window-height', `window-width' and `preserve-size'
-are applied only when the window used for displaying the buffer
-never showed another buffer before.
+The entries `window-height', `window-width', `window-size' and
+`preserve-size' are applied only when the window used for
+displaying the buffer never showed another buffer before.
 
 The ACTION argument can also have a non-nil and non-list value.
 This means to display the buffer in a window other than the
diff --git a/lisp/xdg.el b/lisp/xdg.el
index 1f9fa6795e..05fc3d711a 100644
--- a/lisp/xdg.el
+++ b/lisp/xdg.el
@@ -41,39 +41,108 @@
 ;; XDG Base Directory Specification
 ;; https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
 
-(defmacro xdg--dir-home (environ default-path)
-  (declare (debug (stringp stringp)))
-  (let ((env (make-symbol "env")))
-    `(let ((,env (getenv ,environ)))
-       (if (or (null ,env) (not (file-name-absolute-p ,env)))
-           (expand-file-name ,default-path)
-         ,env))))
+(defun xdg--dir-home (environ default-path)
+  (let ((env (getenv environ)))
+    (if (or (null env) (not (file-name-absolute-p env)))
+        (expand-file-name default-path)
+      env)))
 
 (defun xdg-config-home ()
-  "Return the base directory for user specific configuration files."
+  "Return the base directory for user specific configuration files.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_CONFIG_HOME defines the base directory relative to
+    which user-specific configuration files should be stored.
+    If $XDG_CONFIG_HOME is either not set or empty, a default
+    equal to $HOME/.config should be used.\""
   (xdg--dir-home "XDG_CONFIG_HOME" "~/.config"))
 
 (defun xdg-cache-home ()
-  "Return the base directory for user specific cache files."
+  "Return the base directory for user specific cache files.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_CACHE_HOME defines the base directory relative to
+    which user-specific non-essential data files should be
+    stored.  If $XDG_CACHE_HOME is either not set or empty, a
+    default equal to $HOME/.cache should be used.\""
   (xdg--dir-home "XDG_CACHE_HOME" "~/.cache"))
 
 (defun xdg-data-home ()
-  "Return the base directory for user specific data files."
+  "Return the base directory for user specific data files.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_DATA_HOME defines the base directory relative to which
+    user-specific data files should be stored.  If $XDG_DATA_HOME is
+    either not set or empty, a default equal to $HOME/.local/share
+    should be used.\""
   (xdg--dir-home "XDG_DATA_HOME" "~/.local/share"))
 
+(defun xdg-state-home ()
+  "Return the base directory for user-specific state data.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+  \"The $XDG_STATE_HOME contains state data that should persist
+  between (application) restarts, but that is not important or
+  portable enough to the user that it should be stored in
+  $XDG_DATA_HOME.  It may contain:
+
+  * actions history (logs, history, recently used files, …)
+
+  * current state of the application that can be reused on a
+    restart (view, layout, open files, undo history, …)\""
+  (xdg--dir-home "XDG_STATE_HOME" "~/.local/state"))
+
 (defun xdg-runtime-dir ()
-  "Return the value of $XDG_RUNTIME_DIR."
+  "Return the value of $XDG_RUNTIME_DIR.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_RUNTIME_DIR defines the base directory relative to
+    which user-specific non-essential runtime files and other
+    file objects (such as sockets, named pipes, ...) should be
+    stored.\""
   (getenv "XDG_RUNTIME_DIR"))
 
 (defun xdg-config-dirs ()
-  "Return the config directory search path as a list."
+  "Return the config directory search path as a list.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_CONFIG_DIRS defines the preference-ordered set of base
+    directories to search for configuration files in addition to
+    the $XDG_CONFIG_HOME base directory.  The directories in
+    $XDG_CONFIG_DIRS should be seperated with a colon ':'.
+
+    \"If $XDG_CONFIG_DIRS is either not set or empty, a value equal to
+    /etc/xdg should be used.\""
   (let ((env (getenv "XDG_CONFIG_DIRS")))
     (if (or (null env) (string= env ""))
         '("/etc/xdg")
       (parse-colon-path env))))
 
 (defun xdg-data-dirs ()
-  "Return the data directory search path as a list."
+  "Return the data directory search path as a list.
+
+According to the XDG Base Directory Specification version
+0.8 (8th May 2021):
+
+    \"$XDG_DATA_DIRS defines the preference-ordered set of base
+    directories to search for data files in addition to the
+    $XDG_DATA_HOME base directory.  The directories in
+    $XDG_DATA_DIRS should be seperated with a colon ':'.
+
+    \"If $XDG_DATA_DIRS is either not set or empty, a value equal
+    to /usr/local/share/:/usr/share/ should be used.\""
   (let ((env (getenv "XDG_DATA_DIRS")))
     (if (or (null env) (string= env ""))
         '("/usr/local/share/" "/usr/share/")
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 8c593abea8..905327083b 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -35,8 +35,9 @@
 (require 'bookmark)
 
 (declare-function make-xwidget "xwidget.c"
-                  (type title width height arguments &optional buffer))
+                  (type title width height arguments &optional buffer related))
 (declare-function xwidget-buffer "xwidget.c" (xwidget))
+(declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer))
 (declare-function xwidget-size-request "xwidget.c" (xwidget))
 (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height))
 (declare-function xwidget-webkit-execute-script "xwidget.c"
@@ -58,14 +59,14 @@
   "Displaying native widgets in Emacs buffers."
   :group 'widgets)
 
-(defun xwidget-insert (pos type title width height &optional args)
+(defun xwidget-insert (pos type title width height &optional args related)
   "Insert an xwidget at position POS.
-Supply the xwidget's TYPE, TITLE, WIDTH, and HEIGHT.
+Supply the xwidget's TYPE, TITLE, WIDTH, HEIGHT, and RELATED.
 See `make-xwidget' for the possible TYPE values.
 The usage of optional argument ARGS depends on the xwidget.
 This returns the result of `make-xwidget'."
   (goto-char pos)
-  (let ((id (make-xwidget type title width height args)))
+  (let ((id (make-xwidget type title width height args nil related)))
     (put-text-property (point) (+ 1 (point))
                        'display (list 'xwidget ':xwidget id))
     id))
@@ -88,6 +89,20 @@ This returns the result of `make-xwidget'."
 (require 'seq)
 (require 'url-handlers)
 
+(defgroup xwidget-webkit nil
+  "Displaying webkit xwidgets in Emacs buffers."
+  :version "29.1"
+  :group 'web
+  :prefix "xwidget-webkit-")
+
+(defcustom xwidget-webkit-buffer-name-prefix "*xwidget-webkit: "
+  "Buffer name prefix used by `xwidget-webkit' buffers."
+  :type 'string
+  :version "29.1")
+
+(defvar-local xwidget-webkit--title ""
+  "The title of the WebKit widget, used for the header line.")
+
 ;;;###autoload
 (defun xwidget-webkit-browse-url (url &optional new-session)
   "Ask xwidget-webkit to browse URL.
@@ -124,6 +139,14 @@ in `split-window-right' with a new xwidget webkit session."
     (with-selected-window (split-window-right)
       (xwidget-webkit-new-session url))))
 
+(declare-function xwidget-perform-lispy-event "xwidget.c")
+
+(defun xwidget-webkit-pass-command-event ()
+  "Pass `last-command-event' to the current buffer's WebKit widget."
+  (interactive)
+  (xwidget-perform-lispy-event (xwidget-webkit-current-session)
+                               last-command-event))
+
 ;;todo.
 ;; - check that the webkit support is compiled in
 (defvar xwidget-webkit-mode-map
@@ -138,6 +161,9 @@ in `split-window-right' with a new xwidget webkit session."
     (define-key map "w" 'xwidget-webkit-current-url)
     (define-key map "+" 'xwidget-webkit-zoom-in)
     (define-key map "-" 'xwidget-webkit-zoom-out)
+    (define-key map "e" 'xwidget-webkit-edit-mode)
+    (define-key map "\C-r" 'xwidget-webkit-isearch-mode)
+    (define-key map "\C-s" 'xwidget-webkit-isearch-mode)
 
     ;;similar to image mode bindings
     (define-key map (kbd "SPC")                 'xwidget-webkit-scroll-up)
@@ -164,6 +190,63 @@ in `split-window-right' with a new xwidget webkit session."
     map)
   "Keymap for `xwidget-webkit-mode'.")
 
+(easy-menu-define nil xwidget-webkit-mode-map "Xwidget WebKit menu."
+  (list "Xwidget WebKit"
+        ["Browse URL" xwidget-webkit-browse-url
+         :active t
+         :help "Prompt for a URL, then instruct WebKit to browse it"]
+        ["Back" xwidget-webkit-back t]
+        ["Forward" xwidget-webkit-forward t]
+        ["Reload" xwidget-webkit-reload t]
+        ["Insert String" xwidget-webkit-insert-string
+         :active t
+         :help "Insert a string into the currently active field"]
+        ["Zoom In" xwidget-webkit-zoom-in t]
+        ["Zoom Out" xwidget-webkit-zoom-out t]
+        ["Edit Mode" xwidget-webkit-edit-mode
+         :active t
+         :style toggle
+         :selected xwidget-webkit-edit-mode
+         :help "Send self inserting characters to the WebKit widget"]
+        ["Save Selection" xwidget-webkit-copy-selection-as-kill
+         :active t
+         :help "Save the browser's selection in the kill ring"]
+        ["Incremental Search" xwidget-webkit-isearch-mode
+         :active (not xwidget-webkit-isearch-mode)
+         :help "Perform incremental search inside the WebKit widget"]))
+
+(defvar xwidget-webkit-tool-bar-map
+  (let ((map (make-sparse-keymap)))
+    (prog1 map
+      (tool-bar-local-item-from-menu 'xwidget-webkit-back
+                                     "left-arrow"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-forward
+                                     "right-arrow"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-reload
+                                     "refresh"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-in
+                                     "zoom-in"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-out
+                                     "zoom-out"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-browse-url
+                                     "connect-to-url"
+                                     map
+                                     xwidget-webkit-mode-map)
+      (tool-bar-local-item-from-menu 'xwidget-webkit-isearch-mode
+                                     "search"
+                                     map
+                                     xwidget-webkit-mode-map))))
+
 (defun xwidget-webkit-zoom-in ()
   "Increase webkit view zoom factor."
   (interactive nil xwidget-webkit-mode)
@@ -265,7 +348,8 @@ If N is omitted or nil, scroll backwards by one char."
       ((xwidget-event-type (nth 1 last-input-event))
        (xwidget (nth 2 last-input-event))
        (xwidget-callback (xwidget-get xwidget 'callback)))
-    (funcall xwidget-callback xwidget xwidget-event-type)))
+    (when xwidget-callback
+      (funcall xwidget-callback xwidget xwidget-event-type))))
 
 (defun xwidget-webkit-callback (xwidget xwidget-event-type)
   "Callback for xwidgets.
@@ -273,30 +357,41 @@ XWIDGET instance, XWIDGET-EVENT-TYPE depends on the 
originating xwidget."
   (if (not (buffer-live-p (xwidget-buffer xwidget)))
       (xwidget-log
        "error: callback called for xwidget with dead buffer")
-    (with-current-buffer (xwidget-buffer xwidget)
-      (cond ((eq xwidget-event-type 'load-changed)
-             (let ((title (xwidget-webkit-title xwidget)))
-               (xwidget-log "webkit finished loading: %s" title)
-               ;; Do not adjust webkit size to window here, the selected window
-               ;; can be the mini-buffer window unwantedly.
-               (rename-buffer (format "*xwidget webkit: %s *" title) t)))
-            ((eq xwidget-event-type 'decide-policy)
-             (let ((strarg  (nth 3 last-input-event)))
-               (if (string-match ".*#\\(.*\\)" strarg)
-                   (xwidget-webkit-show-id-or-named-element
-                    xwidget
-                    (match-string 1 strarg)))))
-            ;; TODO: Response handling other than download.
-            ((eq xwidget-event-type 'download-callback)
-             (let ((url  (nth 3 last-input-event))
-                   (mime-type (nth 4 last-input-event))
-                   (file-name (nth 5 last-input-event)))
-               (xwidget-webkit-save-as-file url mime-type file-name)))
-            ((eq xwidget-event-type 'javascript-callback)
-             (let ((proc (nth 3 last-input-event))
-                   (arg  (nth 4 last-input-event)))
-               (funcall proc arg)))
-            (t (xwidget-log "unhandled event:%s" xwidget-event-type))))))
+    (cond ((eq xwidget-event-type 'load-changed)
+           (let ((title (xwidget-webkit-title xwidget)))
+             ;; This funciton will be called multi times, so only
+             ;; change buffer name when the load actually completes
+             ;; this can limit buffer-name flicker in mode-line.
+             (when (or (string-equal (nth 3 last-input-event)
+                                     "load-finished")
+                       (> (length title) 0))
+               (with-current-buffer (xwidget-buffer xwidget)
+                 (setq xwidget-webkit--title title)
+                 (force-mode-line-update)
+                 (xwidget-log "webkit finished loading: %s" title)
+                 ;; Do not adjust webkit size to window here, the
+                 ;; selected window can be the mini-buffer window
+                 ;; unwantedly.
+                 (rename-buffer (concat xwidget-webkit-buffer-name-prefix
+                                        title "*")
+                                t)))))
+          ((eq xwidget-event-type 'decide-policy)
+           (let ((strarg  (nth 3 last-input-event)))
+             (if (string-match ".*#\\(.*\\)" strarg)
+                 (xwidget-webkit-show-id-or-named-element
+                  xwidget
+                  (match-string 1 strarg)))))
+          ;; TODO: Response handling other than download.
+          ((eq xwidget-event-type 'download-callback)
+           (let ((url  (nth 3 last-input-event))
+                 (mime-type (nth 4 last-input-event))
+                 (file-name (nth 5 last-input-event)))
+             (xwidget-webkit-save-as-file url mime-type file-name)))
+          ((eq xwidget-event-type 'javascript-callback)
+           (let ((proc (nth 3 last-input-event))
+                 (arg  (nth 4 last-input-event)))
+             (funcall proc arg)))
+          (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
 
 (defvar bookmark-make-record-function)
 (when (memq window-system '(mac ns))
@@ -309,8 +404,10 @@ If non-nil, plugins are enabled.  Otherwise, disabled."
 (define-derived-mode xwidget-webkit-mode special-mode "xwidget-webkit"
   "Xwidget webkit view mode."
   (setq buffer-read-only t)
+  (setq-local tool-bar-map xwidget-webkit-tool-bar-map)
   (setq-local bookmark-make-record-function
               #'xwidget-webkit-bookmark-make-record)
+  (setq-local header-line-format 'xwidget-webkit--title)
   ;; Keep track of [vh]scroll when switching buffers
   (image-mode-setup-winprops))
 
@@ -606,10 +703,15 @@ For example, use this to display an anchor."
 
 (defun xwidget-webkit-new-session (url &optional callback)
   "Create a new webkit session buffer with URL."
-  (let*
-      ((bufname (generate-new-buffer-name "*xwidget-webkit*"))
-       (callback (or callback #'xwidget-webkit-callback))
-       xw)
+  (let* ((bufname
+          ;; Generate a temp-name based on current buffer name. it
+          ;; will be renamed by `xwidget-webkit-callback' in the
+          ;; future. This approach can limit flicker of buffer-name in
+          ;; mode-line.
+          (generate-new-buffer-name (buffer-name)))
+         (callback (or callback #'xwidget-webkit-callback))
+         (current-session (xwidget-webkit-current-session))
+         xw)
     (setq xwidget-webkit-last-session-buffer (switch-to-buffer
                                               (get-buffer-create bufname)))
     ;; The xwidget id is stored in a text property, so we need to have
@@ -621,11 +723,40 @@ For example, use this to display an anchor."
       (setq xw (xwidget-insert
                 start 'webkit bufname
                 (xwidget-window-inside-pixel-width (selected-window))
-                (xwidget-window-inside-pixel-height (selected-window)))))
+                (xwidget-window-inside-pixel-height (selected-window))
+                nil current-session)))
     (xwidget-put xw 'callback callback)
     (xwidget-webkit-mode)
     (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url)))
 
+(defun xwidget-webkit-import-widget (xwidget)
+  "Create a new webkit session buffer from XWIDGET, an existing xwidget.
+Return the buffer."
+  (let* ((bufname
+          ;; Generate a temp-name based on current buffer name. it
+          ;; will be renamed by `xwidget-webkit-callback' in the
+          ;; future. This approach can limit flicker of buffer-name in
+          ;; mode-line.
+          (generate-new-buffer-name (buffer-name)))
+         (callback #'xwidget-webkit-callback)
+         (buffer (get-buffer-create bufname)))
+    (with-current-buffer buffer
+      (save-excursion
+        (erase-buffer)
+        (insert ".")
+        (put-text-property (point-min) (point-max)
+                           'display (list 'xwidget :xwidget xwidget)))
+      (xwidget-put xwidget 'callback callback)
+      (set-xwidget-buffer xwidget buffer)
+      (xwidget-webkit-mode))
+    buffer))
+
+(defun xwidget-webkit-display-event (event)
+  "Import the xwidget inside EVENT and display it."
+  (interactive "e")
+  (display-buffer (xwidget-webkit-import-widget (nth 1 event))))
+
+(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event)
 
 (defun xwidget-webkit-goto-url (url)
   "Goto URL with xwidget webkit."
@@ -684,6 +815,165 @@ You can retrieve the value with `xwidget-get'."
   (set-xwidget-plist xwidget
                      (plist-put (xwidget-plist xwidget) propname value)))
 
+(defvar xwidget-webkit-edit-mode-map (make-keymap))
+
+(define-key xwidget-webkit-edit-mode-map [backspace] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [tab] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [left] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [right] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [up] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [down] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [return] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [C-left] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [C-right] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [C-up] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [C-down] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [C-return] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [S-left] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [S-right] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [S-up] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [S-down] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [S-return] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [M-left] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [M-right] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [M-up] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [M-down] 
'xwidget-webkit-pass-command-event)
+(define-key xwidget-webkit-edit-mode-map [M-return] 
'xwidget-webkit-pass-command-event)
+
+(define-minor-mode xwidget-webkit-edit-mode
+  "Minor mode for editing the content of WebKit buffers.
+
+This defines most self-inserting characters and some common
+keyboard shortcuts to `xwidget-webkit-pass-command-event', which
+will pass the key events corresponding to these characters to the
+WebKit widget."
+  :keymap xwidget-webkit-edit-mode-map)
+
+(substitute-key-definition 'self-insert-command
+                           'xwidget-webkit-pass-command-event
+                           xwidget-webkit-edit-mode-map
+                           global-map)
+
+(declare-function xwidget-webkit-search "xwidget.c")
+(declare-function xwidget-webkit-next-result "xwidget.c")
+(declare-function xwidget-webkit-previous-result "xwidget.c")
+(declare-function xwidget-webkit-finish-search "xwidget.c")
+
+(defvar-local xwidget-webkit-isearch--string ""
+  "The current search query.")
+(defvar-local xwidget-webkit-isearch--is-reverse nil
+  "Whether or not the current isearch should be reverse.")
+
+(defun xwidget-webkit-isearch--update (&optional only-message)
+  "Update the current buffer's WebKit widget's search query.
+If ONLY-MESSAGE is non-nil, the query will not be sent to the
+WebKit widget.  The query will be set to the contents of
+`xwidget-webkit-isearch--string'."
+  (unless only-message
+    (xwidget-webkit-search xwidget-webkit-isearch--string
+                           (xwidget-webkit-current-session)
+                           t xwidget-webkit-isearch--is-reverse t))
+  (message (concat (propertize "Search contents: " 'face 'minibuffer-prompt)
+                   xwidget-webkit-isearch--string)))
+
+(defun xwidget-webkit-isearch-erasing-char (count)
+  "Erase the last COUNT characters of the current query."
+  (interactive (list (prefix-numeric-value current-prefix-arg)))
+  (when (> (length xwidget-webkit-isearch--string) 0)
+    (setq xwidget-webkit-isearch--string
+          (substring xwidget-webkit-isearch--string 0
+                     (- (length xwidget-webkit-isearch--string) count))))
+  (xwidget-webkit-isearch--update))
+
+(defun xwidget-webkit-isearch-printing-char (char &optional count)
+  "Add ordinary character CHAR to the search string and search.
+With argument, add COUNT copies of CHAR."
+  (interactive (list last-command-event
+                     (prefix-numeric-value current-prefix-arg)))
+  (setq xwidget-webkit-isearch--string (concat xwidget-webkit-isearch--string
+                                               (make-string (or count 1) 
char)))
+  (xwidget-webkit-isearch--update))
+
+(defun xwidget-webkit-isearch-forward (count)
+  "Move to the next search result COUNT times."
+  (interactive (list (prefix-numeric-value current-prefix-arg)))
+  (let ((was-reverse xwidget-webkit-isearch--is-reverse))
+    (setq xwidget-webkit-isearch--is-reverse nil)
+    (when was-reverse
+      (xwidget-webkit-isearch--update)))
+  (let ((i 0))
+    (while (< i count)
+      (xwidget-webkit-next-result (xwidget-webkit-current-session))
+      (cl-incf i)))
+  (xwidget-webkit-isearch--update t))
+
+(defun xwidget-webkit-isearch-backward (count)
+  "Move to the previous search result COUNT times."
+  (interactive (list (prefix-numeric-value current-prefix-arg)))
+  (let ((was-reverse xwidget-webkit-isearch--is-reverse))
+    (setq xwidget-webkit-isearch--is-reverse t)
+    (unless was-reverse
+      (xwidget-webkit-isearch--update)))
+  (let ((i 0))
+    (while (< i count)
+      (xwidget-webkit-previous-result (xwidget-webkit-current-session))
+      (cl-incf i)))
+  (xwidget-webkit-isearch--update t))
+
+(defun xwidget-webkit-isearch-exit ()
+  "Exit incremental search of a WebKit buffer."
+  (interactive)
+  (xwidget-webkit-isearch-mode 0))
+
+(defvar xwidget-webkit-isearch-mode-map (make-keymap)
+  "The keymap used inside xwidget-webkit-isearch-mode.")
+
+(set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map)
+                      (cons 0 (max-char))
+                      'xwidget-webkit-isearch-exit)
+
+(substitute-key-definition 'self-insert-command
+                           'xwidget-webkit-isearch-printing-char
+                           xwidget-webkit-isearch-mode-map
+                           global-map)
+
+(define-key xwidget-webkit-isearch-mode-map (kbd "DEL")
+  'xwidget-webkit-isearch-erasing-char)
+(define-key xwidget-webkit-isearch-mode-map [backspace] 
'xwidget-webkit-isearch-erasing-char)
+(define-key xwidget-webkit-isearch-mode-map [return] 
'xwidget-webkit-isearch-exit)
+(define-key xwidget-webkit-isearch-mode-map "\r" 'xwidget-webkit-isearch-exit)
+(define-key xwidget-webkit-isearch-mode-map "\C-g" 
'xwidget-webkit-isearch-exit)
+(define-key xwidget-webkit-isearch-mode-map "\C-r" 
'xwidget-webkit-isearch-backward)
+(define-key xwidget-webkit-isearch-mode-map "\C-s" 
'xwidget-webkit-isearch-forward)
+(define-key xwidget-webkit-isearch-mode-map "\t" 
'xwidget-webkit-isearch-printing-char)
+
+(let ((meta-map (make-keymap)))
+  (set-char-table-range (nth 1 meta-map)
+                        (cons 0 (max-char))
+                        'xwidget-webkit-isearch-exit)
+  (define-key xwidget-webkit-isearch-mode-map (char-to-string 
meta-prefix-char) meta-map))
+
+(define-minor-mode xwidget-webkit-isearch-mode
+  "Minor mode for performing incremental search inside WebKit buffers.
+
+This resembles the regular incremental search, but it does not
+support recursive edits.
+
+If this mode is activated with 
`\\<xwidget-webkit-isearch-mode-map>\\[xwidget-webkit-isearch-backward]', then 
the search will by default
+start in the reverse direction.
+
+To navigate around the search results, type
+\\<xwidget-webkit-isearch-mode-map>\\[xwidget-webkit-isearch-forward] to move 
forward, and
+\\<xwidget-webkit-isearch-mode-map>\\[xwidget-webkit-isearch-backward] to move 
backward.
+
+Press \\<xwidget-webkit-isearch-mode-map>\\[xwidget-webkit-isearch-exit] to 
exit incremental search."
+  :keymap xwidget-webkit-isearch-mode-map
+  (if xwidget-webkit-isearch-mode
+      (progn
+        (setq xwidget-webkit-isearch--string "")
+        (setq xwidget-webkit-isearch--is-reverse (eq last-command-event ?\C-r))
+        (xwidget-webkit-isearch--update))
+    (xwidget-webkit-finish-search (xwidget-webkit-current-session))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
diff --git a/lisp/yank-media.el b/lisp/yank-media.el
new file mode 100644
index 0000000000..decab3b362
--- /dev/null
+++ b/lisp/yank-media.el
@@ -0,0 +1,194 @@
+;;; yank-media.el --- Yanking images and HTML  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@gnus.org>
+;; Keywords: utility
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'seq)
+
+(defvar yank-media--registered-handlers nil)
+
+;;;###autoload
+(defun yank-media ()
+  "Yank media (images, HTML and the like) from the clipboard.
+This command depends on the current major mode having support for
+accepting the media type.  The mode has to register itself using
+the `yank-media-handler' mechanism.
+
+Also see `yank-media-types' for a command that lets you explore
+all the different selection types."
+  (interactive)
+  (unless yank-media--registered-handlers
+    (user-error "The `%s' mode hasn't registered any handlers" major-mode))
+  (let ((all-types nil))
+    (pcase-dolist (`(,handled-type . ,handler)
+                   yank-media--registered-handlers)
+      (dolist (type (yank-media--find-matching-media handled-type))
+        (push (cons type handler) all-types)))
+    (unless all-types
+      (user-error
+       "No handler in the current buffer for anything on the clipboard"))
+    ;; We have a handler in the current buffer; if there's just
+    ;; matching type, just call the handler.
+    (if (length= all-types 1)
+        (funcall (cdar all-types) (caar all-types)
+                 (yank-media--get-selection (caar all-types)))
+      ;; More than one type the user for what type to insert.
+      (let ((type
+             (intern
+              (completing-read "Several types available, choose one: "
+                               (mapcar #'car all-types) nil t))))
+        (funcall (alist-get type all-types)
+                 type (yank-media--get-selection type))))))
+
+(defun yank-media--find-matching-media (handled-type)
+  (seq-filter
+   (lambda (type)
+     (pcase-let ((`(,major ,minor) (split-string (symbol-name type) "/")))
+       (if (and (equal major "image")
+                (not (image-type-available-p (intern minor))))
+           ;; Just filter out all the image types that Emacs doesn't
+           ;; support, because the clipboard is full of things like
+           ;; `image/x-win-bitmap'.
+           nil
+         ;; Check that the handler wants this type.
+         (and (if (symbolp handled-type)
+                  (eq handled-type type)
+                (string-match-p handled-type (symbol-name type)))
+              ;; An element may be in TARGETS but be empty.
+              (yank-media--get-selection type)))))
+   (gui-get-selection 'CLIPBOARD 'TARGETS)))
+
+(defun yank-media--get-selection (data-type)
+  (when-let ((data (gui-backend-get-selection 'CLIPBOARD data-type)))
+    (if (string-match-p "\\`text/" (symbol-name data-type))
+        (yank-media-types--format data-type data)
+      data)))
+
+;;;###autoload
+(defun yank-media-handler (types handler)
+  "Register HANDLER for dealing with `yank-media' actions for TYPES.
+TYPES should be a MIME media type symbol, a regexp, or a list
+that can contain both symbols and regexps.
+
+HANDLER is a function that will be called with two arguments: The
+MIME type (a symbol on the form `image/png') and the selection
+data (a string)."
+  (make-local-variable 'yank-media--registered-handlers)
+  (dolist (type (ensure-list types))
+    (setf (alist-get type yank-media--registered-handlers nil nil #'equal)
+          handler)))
+
+(defun yank-media-types (&optional all)
+  "Yank any element present in the primary selection or the clipboard.
+This is primarily meant as a debugging tool -- many of the
+elements (like images) will be inserted as raw data into the
+current buffer.  See `yank-media' instead for a command that
+inserts images as images.
+
+By default, data types that aren't supported by
+`gui-get-selection' (i.e., that returns nothing if you actually
+try to look at the selection) are not included by this command.
+If ALL (interactively, the prefix), also include these
+non-supported selection data types."
+  (interactive "P")
+  (let ((elements nil))
+    ;; First gather all the data.
+    (dolist (type '(PRIMARY CLIPBOARD))
+      (when-let ((data-types (gui-get-selection type 'TARGETS)))
+        (when (vectorp data-types)
+          (seq-do (lambda (data-type)
+                    (unless (memq data-type '( TARGETS MULTIPLE
+                                               DELETE SAVE_TARGETS))
+                      (let ((data (gui-get-selection type data-type)))
+                        (when (or data all)
+                          ;; Remove duplicates -- the data in PRIMARY and
+                          ;; CLIPBOARD are sometimes (mostly) identical,
+                          ;; and sometimes not.
+                          (let ((old (assq data-type elements)))
+                            (when (or (not old)
+                                      (not (equal (nth 2 old) data)))
+                              (push (list data-type type data)
+                                    elements)))))))
+                  data-types))))
+    ;; Then query the user.
+    (unless elements
+      (user-error "No elements in the primary selection or the clipboard"))
+    (let ((spec
+           (completing-read
+            "Yank type: "
+            (mapcar (lambda (e)
+                      (format "%s:%s" (downcase (symbol-name (cadr e)))
+                              (car e)))
+                    elements)
+            nil t)))
+      (dolist (elem elements)
+        (when (equal (format "%s:%s" (downcase (symbol-name (cadr elem)))
+                             (car elem))
+                     spec)
+          (insert (yank-media-types--format (car elem) (nth 2 elem))))))))
+
+(defun yank-media-types--format (data-type data)
+  (cond
+   ((not (stringp data))
+    (format "%s" data))
+   ((string-match-p "\\`text/" (symbol-name data-type))
+    ;; We may have utf-16, which Emacs won't detect automatically.
+    (let ((coding-system
+           (and (zerop (mod (length data) 2))
+                (let ((stats (vector 0 0)))
+                  (dotimes (i (length data))
+                    (when (zerop (elt data i))
+                      (setf (aref stats (mod i 2))
+                            (1+ (aref stats (mod i 2))))))
+                  ;; If we have more than 90% every-other nul, then it's
+                  ;; pretty likely to be utf-16.
+                  (cond
+                   ((> (if (zerop (elt stats 1))
+                           1
+                         (/ (float (elt stats 0))
+                            (float (elt stats 1))))
+                       0.9)
+                    ;; Big endian.
+                    'utf-16-be)
+                   ((> (if (zerop (elt stats 0))
+                           1
+                         (/ (float (elt stats 1))
+                            (float (elt stats 0))))
+                       0.9)
+                    ;; Little endian.
+                    'utf-16-le))))))
+      (if coding-system
+          (decode-coding-string data coding-system)
+        ;; Some programs add a nul character at the end of text/*
+        ;; selections.  Remove that.
+        (if (zerop (elt data (1- (length data))))
+            (substring data 0 (1- (length data)))
+          data))))
+   (t
+    data)))
+
+(provide 'yank-media)
+
+;;; yank-media.el ends here
diff --git a/m4/close-stream.m4 b/m4/close-stream.m4
deleted file mode 100644
index feeb4eae5d..0000000000
--- a/m4/close-stream.m4
+++ /dev/null
@@ -1,11 +0,0 @@
-#serial 4
-dnl Copyright (C) 2006-2007, 2009-2021 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-dnl Prerequisites of lib/close-stream.c.
-AC_DEFUN([gl_CLOSE_STREAM],
-[
-  :
-])
diff --git a/m4/dirent_h.m4 b/m4/dirent_h.m4
index 6d86142585..17e2a20c5d 100644
--- a/m4/dirent_h.m4
+++ b/m4/dirent_h.m4
@@ -1,4 +1,4 @@
-# dirent_h.m4 serial 16
+# dirent_h.m4 serial 19
 dnl Copyright (C) 2008-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,10 +6,10 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 dnl Written by Bruno Haible.
 
-AC_DEFUN([gl_DIRENT_H],
+AC_DEFUN_ONCE([gl_DIRENT_H],
 [
-  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
-  dnl once only, before all statements that occur in other macros.
+  dnl Ensure to expand the default settings once only, before all statements
+  dnl that occur in other macros.
   AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
 
   dnl <dirent.h> is always overridden, because of GNULIB_POSIXCHECK.
@@ -27,26 +27,41 @@ AC_DEFUN([gl_DIRENT_H],
     ]], [alphasort closedir dirfd fdopendir opendir readdir rewinddir scandir])
 ])
 
+# gl_DIRENT_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_DIRENT_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_DIRENT_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_DIRENT_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_DIRENT_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_UNISTD_H_REQUIRE_DEFAULTS dnl for REPLACE_FCHDIR
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REWINDDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CLOSEDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DIRFD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPENDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALPHASORT])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_DIRENT_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_DIRENT_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_DIRENT_H_DEFAULTS],
 [
-  AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR
-  GNULIB_OPENDIR=0;     AC_SUBST([GNULIB_OPENDIR])
-  GNULIB_READDIR=0;     AC_SUBST([GNULIB_READDIR])
-  GNULIB_REWINDDIR=0;   AC_SUBST([GNULIB_REWINDDIR])
-  GNULIB_CLOSEDIR=0;    AC_SUBST([GNULIB_CLOSEDIR])
-  GNULIB_DIRFD=0;       AC_SUBST([GNULIB_DIRFD])
-  GNULIB_FDOPENDIR=0;   AC_SUBST([GNULIB_FDOPENDIR])
-  GNULIB_SCANDIR=0;     AC_SUBST([GNULIB_SCANDIR])
-  GNULIB_ALPHASORT=0;   AC_SUBST([GNULIB_ALPHASORT])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_OPENDIR=1;       AC_SUBST([HAVE_OPENDIR])
   HAVE_READDIR=1;       AC_SUBST([HAVE_READDIR])
diff --git a/m4/environ.m4 b/m4/environ.m4
index d971770860..ae5329108e 100644
--- a/m4/environ.m4
+++ b/m4/environ.m4
@@ -1,4 +1,4 @@
-# environ.m4 serial 7
+# environ.m4 serial 8
 dnl Copyright (C) 2001-2004, 2006-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,7 +33,8 @@ AC_DEFUN([gt_CHECK_VAR_DECL],
     [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(
           [[$1
-            extern struct { int foo; } $2;]],
+            typedef struct { int foo; } foo_t;
+            extern foo_t $2;]],
           [[$2.foo = 1;]])],
        [gt_cv_var=no],
        [gt_cv_var=yes])])
diff --git a/m4/explicit_bzero.m4 b/m4/explicit_bzero.m4
index d77ec5a3a5..8c86d69e05 100644
--- a/m4/explicit_bzero.m4
+++ b/m4/explicit_bzero.m4
@@ -5,7 +5,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN([gl_FUNC_EXPLICIT_BZERO],
 [
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
 
   dnl Persuade glibc <string.h> to declare explicit_bzero.
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
diff --git a/m4/extern-inline.m4 b/m4/extern-inline.m4
index a2acf126c8..a4ac5ea532 100644
--- a/m4/extern-inline.m4
+++ b/m4/extern-inline.m4
@@ -17,7 +17,8 @@ AC_DEFUN([gl_EXTERN_INLINE],
    mishandles inline functions that call each other.  E.g., for 'inline void f
    (void) { } inline void g (void) { f (); }', c99 incorrectly complains
    'reference to static identifier "f" in extern inline function'.
-   This bug was observed with Sun C 5.12 SunOS_i386 2011/11/16.
+   This bug was observed with Oracle Developer Studio 12.6
+   (Sun C 5.15 SunOS_sparc 2017/05/30).
 
    Suppress extern inline (with or without __attribute__ ((__gnu_inline__)))
    on configurations that mistakenly use 'static inline' to implement
@@ -83,8 +84,8 @@ AC_DEFUN([gl_EXTERN_INLINE],
 # define _GL_EXTERN_INLINE extern
 # define _GL_EXTERN_INLINE_IN_USE
 #else
-# define _GL_INLINE static _GL_UNUSED
-# define _GL_EXTERN_INLINE static _GL_UNUSED
+# define _GL_INLINE _GL_UNUSED static
+# define _GL_EXTERN_INLINE _GL_UNUSED static
 #endif
 
 /* In GCC 4.6 (inclusive) to 5.1 (exclusive),
diff --git a/m4/fcntl_h.m4 b/m4/fcntl_h.m4
index e63a82f10a..aba44735d1 100644
--- a/m4/fcntl_h.m4
+++ b/m4/fcntl_h.m4
@@ -1,4 +1,4 @@
-# serial 17
+# serial 20
 # Configure fcntl.h.
 dnl Copyright (C) 2006-2007, 2009-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 dnl Written by Paul Eggert.
 
-AC_DEFUN([gl_FCNTL_H],
+AC_DEFUN_ONCE([gl_FCNTL_H],
 [
   AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
   AC_REQUIRE([gl_FCNTL_O_FLAGS])
@@ -26,25 +26,40 @@ AC_DEFUN([gl_FCNTL_H],
     ]], [fcntl openat])
 ])
 
+# gl_FCNTL_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_FCNTL_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_FCNTL_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_FCNTL_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CREAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCNTL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NONBLOCKING])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENAT])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CREAT], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_OPEN], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_FCNTL_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_FCNTL_H_DEFAULTS],
 [
-  GNULIB_CREAT=0;        AC_SUBST([GNULIB_CREAT])
-  GNULIB_FCNTL=0;        AC_SUBST([GNULIB_FCNTL])
-  GNULIB_NONBLOCKING=0;  AC_SUBST([GNULIB_NONBLOCKING])
-  GNULIB_OPEN=0;         AC_SUBST([GNULIB_OPEN])
-  GNULIB_OPENAT=0;       AC_SUBST([GNULIB_OPENAT])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_CREAT=1;    AC_SUBST([GNULIB_MDA_CREAT])
-  GNULIB_MDA_OPEN=1;     AC_SUBST([GNULIB_MDA_OPEN])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_FCNTL=1;          AC_SUBST([HAVE_FCNTL])
   HAVE_OPENAT=1;         AC_SUBST([HAVE_OPENAT])
diff --git a/m4/free.m4 b/m4/free.m4
index d671376b0b..a7923b9059 100644
--- a/m4/free.m4
+++ b/m4/free.m4
@@ -1,4 +1,4 @@
-# free.m4 serial 5
+# free.m4 serial 6
 # Copyright (C) 2003-2005, 2009-2021 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -40,7 +40,10 @@ AC_DEFUN([gl_FUNC_FREE],
     ])
 
   case $gl_cv_func_free_preserves_errno in
-   *yes) ;;
+   *yes)
+    AC_DEFINE([HAVE_FREE_POSIX], [1],
+      [Define if the 'free' function is guaranteed to preserve errno.])
+    ;;
    *) REPLACE_FREE=1 ;;
   esac
 ])
diff --git a/m4/gettimeofday.m4 b/m4/gettimeofday.m4
index 3c20081574..37c54404bb 100644
--- a/m4/gettimeofday.m4
+++ b/m4/gettimeofday.m4
@@ -1,4 +1,4 @@
-# serial 28
+# serial 29
 
 # Copyright (C) 2001-2003, 2005, 2007, 2009-2021 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -9,10 +9,10 @@ dnl From Jim Meyering.
 
 AC_DEFUN([gl_FUNC_GETTIMEOFDAY],
 [
-  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
+  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_C_RESTRICT])
   AC_REQUIRE([AC_CANONICAL_HOST])
-  AC_REQUIRE([gl_HEADER_SYS_TIME_H])
+  AC_REQUIRE([gl_SYS_TIME_H])
   AC_CHECK_FUNCS_ONCE([gettimeofday])
 
   gl_gettimeofday_timezone=void
diff --git a/m4/glibc21.m4 b/m4/glibc21.m4
deleted file mode 100644
index 74a781aa1c..0000000000
--- a/m4/glibc21.m4
+++ /dev/null
@@ -1,34 +0,0 @@
-# glibc21.m4 serial 5
-dnl Copyright (C) 2000-2002, 2004, 2008, 2010-2021 Free Software
-dnl Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-# Test for the GNU C Library, version 2.1 or newer, or uClibc.
-# From Bruno Haible.
-
-AC_DEFUN([gl_GLIBC21],
-  [
-    AC_CACHE_CHECK([whether we are using the GNU C Library >= 2.1 or uClibc],
-      [ac_cv_gnu_library_2_1],
-      [AC_EGREP_CPP([Lucky],
-        [
-#include <features.h>
-#ifdef __GNU_LIBRARY__
- #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2)
-  Lucky GNU user
- #endif
-#endif
-#ifdef __UCLIBC__
- Lucky user
-#endif
-        ],
-        [ac_cv_gnu_library_2_1=yes],
-        [ac_cv_gnu_library_2_1=no])
-      ]
-    )
-    AC_SUBST([GLIBC21])
-    GLIBC21="$ac_cv_gnu_library_2_1"
-  ]
-)
diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4
index f2eff10de6..12b19dbcb4 100644
--- a/m4/gnulib-common.m4
+++ b/m4/gnulib-common.m4
@@ -1,4 +1,4 @@
-# gnulib-common.m4 serial 63
+# gnulib-common.m4 serial 67
 dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -85,12 +85,12 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTR_fallthrough _GL_GNUC_PREREQ (7, 0)
 # define _GL_ATTR_format _GL_GNUC_PREREQ (2, 7)
 # define _GL_ATTR_leaf _GL_GNUC_PREREQ (4, 6)
+# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)
 # ifdef _ICC
 #  define _GL_ATTR_may_alias 0
 # else
 #  define _GL_ATTR_may_alias _GL_GNUC_PREREQ (3, 3)
 # endif
-# define _GL_ATTR_malloc _GL_GNUC_PREREQ (3, 0)
 # define _GL_ATTR_noinline _GL_GNUC_PREREQ (3, 1)
 # define _GL_ATTR_nonnull _GL_GNUC_PREREQ (3, 3)
 # define _GL_ATTR_nonstring _GL_GNUC_PREREQ (8, 0)
@@ -103,26 +103,47 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4)
 #endif
 
+#ifdef __has_c_attribute
+# define _GL_HAS_C_ATTRIBUTE(attr) __has_c_attribute (__##attr##__)
+#else
+# define _GL_HAS_C_ATTRIBUTE(attr) 0
+#endif
+
 ]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's _Alignas instead.
 [
+/* _GL_ATTRIBUTE_ALLOC_SIZE ((N)) declares that the Nth argument of the 
function
+   is the size of the returned memory block.
+   _GL_ATTRIBUTE_ALLOC_SIZE ((M, N)) declares that the Mth argument multiplied
+   by the Nth argument of the function is the size of the returned memory 
block.
+ */
+/* Applies to: function, pointer to function, function types.  */
 #if _GL_HAS_ATTRIBUTE (alloc_size)
 # define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))
 #else
 # define _GL_ATTRIBUTE_ALLOC_SIZE(args)
 #endif
 
+/* _GL_ATTRIBUTE_ALWAYS_INLINE tells that the compiler should always inline the
+   function and report an error if it cannot do so.  */
+/* Applies to: function.  */
 #if _GL_HAS_ATTRIBUTE (always_inline)
 # define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__))
 #else
 # define _GL_ATTRIBUTE_ALWAYS_INLINE
 #endif
 
+/* _GL_ATTRIBUTE_ARTIFICIAL declares that the function is not important to show
+    in stack traces when debugging.  The compiler should omit the function from
+    stack traces.  */
+/* Applies to: function.  */
 #if _GL_HAS_ATTRIBUTE (artificial)
 # define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__))
 #else
 # define _GL_ATTRIBUTE_ARTIFICIAL
 #endif
 
+/* _GL_ATTRIBUTE_COLD declares that the function is rarely executed.  */
+/* Applies to: functions.  */
 /* Avoid __attribute__ ((cold)) on MinGW; see thread starting at
    <https://lists.gnu.org/r/emacs-devel/2019-04/msg01152.html>.
    Also, Oracle Studio 12.6 requires 'cold' not '__cold__'.  */
@@ -136,13 +157,41 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_COLD
 #endif
 
+/* _GL_ATTRIBUTE_CONST declares that it is OK for a compiler to omit duplicate
+   calls to the function with the same arguments.
+   This attribute is safe for a function that neither depends on nor affects
+   observable state, and always returns exactly once - e.g., does not loop
+   forever, and does not call longjmp.
+   (This attribute is stricter than _GL_ATTRIBUTE_PURE.)  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (const)
 # define _GL_ATTRIBUTE_CONST __attribute__ ((__const__))
 #else
 # define _GL_ATTRIBUTE_CONST
 #endif
 
-#if 201710L < __STDC_VERSION__
+/* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
+   that can be freed by passing them as the Ith argument to the
+   function F.
+   _GL_ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that
+   can be freed via 'free'; it can be used only after declaring 'free'.  */
+/* Applies to: functions.  Cannot be used on inline functions.  */
+#if _GL_GNUC_PREREQ (11, 0)
+# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute__ ((__malloc__ (f, i)))
+#else
+# define _GL_ATTRIBUTE_DEALLOC(f, i)
+#endif
+#define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1)
+
+/* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated.
+   The compiler may warn if the entity is used.  */
+/* Applies to:
+     - function, variable,
+     - struct, union, struct/union member,
+     - enumeration, enumeration item,
+     - typedef,
+   in C++ also: namespace, class, template specialization.  */
+#if _GL_HAS_C_ATTRIBUTE (deprecated)
 # define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]]
 #elif _GL_HAS_ATTRIBUTE (deprecated)
 # define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))
@@ -150,6 +199,11 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_DEPRECATED
 #endif
 
+/* _GL_ATTRIBUTE_ERROR(msg) requests an error if a function is called and
+   the function call is not optimized away.
+   _GL_ATTRIBUTE_WARNING(msg) requests a warning if a function is called and
+   the function call is not optimized away.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (error)
 # define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg)))
 # define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg)))
@@ -161,14 +215,21 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_WARNING(msg)
 #endif
 
+/* _GL_ATTRIBUTE_EXTERNALLY_VISIBLE declares that the entity should remain
+   visible to debuggers etc., even with '-fwhole-program'.  */
+/* Applies to: functions, variables.  */
 #if _GL_HAS_ATTRIBUTE (externally_visible)
 # define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE __attribute__ ((externally_visible))
 #else
 # define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE
 #endif
 
-/* FALLTHROUGH is special, because it always expands to something.  */
-#if 201710L < __STDC_VERSION__
+/* _GL_ATTRIBUTE_FALLTHROUGH declares that it is not a programming mistake if
+   the control flow falls through to the immediately following 'case' or
+   'default' label.  The compiler should not warn in this case.  */
+/* Applies to: Empty statement (;), inside a 'switch' statement.  */
+/* Always expands to something.  */
+#if _GL_HAS_C_ATTRIBUTE (fallthrough)
 # define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]]
 #elif _GL_HAS_ATTRIBUTE (fallthrough)
 # define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))
@@ -176,18 +237,47 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_FALLTHROUGH ((void) 0)
 #endif
 
+/* _GL_ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK))
+   declares that the STRING-INDEXth function argument is a format string of
+   style ARCHETYPE, which is one of:
+     printf, gnu_printf
+     scanf, gnu_scanf,
+     strftime, gnu_strftime,
+     strfmon,
+   or the same thing prefixed and suffixed with '__'.
+   If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK
+   are suitable for the format string.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (format)
 # define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
 #else
 # define _GL_ATTRIBUTE_FORMAT(spec)
 #endif
 
+/* _GL_ATTRIBUTE_LEAF declares that if the function is called from some other
+   compilation unit, it executes code from that unit only by return or by
+   exception handling.  This declaration lets the compiler optimize that unit
+   more aggressively.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (leaf)
 # define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__))
 #else
 # define _GL_ATTRIBUTE_LEAF
 #endif
 
+/* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly
+   allocated memory.  */
+/* Applies to: functions.  */
+#if _GL_HAS_ATTRIBUTE (malloc)
+# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+#else
+# define _GL_ATTRIBUTE_MALLOC
+#endif
+
+/* _GL_ATTRIBUTE_MAY_ALIAS declares that pointers to the type may point to the
+   same storage as pointers to other types.  Thus this declaration disables
+   strict aliasing optimization.  */
+/* Applies to: types.  */
 /* Oracle Studio 12.6 mishandles may_alias despite __has_attribute OK.  */
 #if _GL_HAS_ATTRIBUTE (may_alias) && !defined __SUNPRO_C
 # define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__))
@@ -195,24 +285,33 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_MAY_ALIAS
 #endif
 
-#if 201710L < __STDC_VERSION__
+/* _GL_ATTRIBUTE_MAYBE_UNUSED declares that it is not a programming mistake if
+   the entity is not used.  The compiler should not warn if the entity is not
+   used.  */
+/* Applies to:
+     - function, variable,
+     - struct, union, struct/union member,
+     - enumeration, enumeration item,
+     - typedef,
+   in C++ also: class.  */
+/* In C++ and C2x, this is spelled [[__maybe_unused__]].
+   GCC's syntax is __attribute__ ((__unused__)).
+   clang supports both syntaxes.  */
+#if _GL_HAS_C_ATTRIBUTE (maybe_unused)
 # define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]]
-#elif _GL_HAS_ATTRIBUTE (unused)
-# define _GL_ATTRIBUTE_MAYBE_UNUSED __attribute__ ((__unused__))
 #else
-# define _GL_ATTRIBUTE_MAYBE_UNUSED
+# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED
 #endif
-/* Earlier spellings of this macro.  */
+/* Alternative spelling of this macro, for convenience.  */
 #define _GL_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED
+/* Earlier spellings of this macro.  */
 #define _UNUSED_PARAMETER_ _GL_ATTRIBUTE_MAYBE_UNUSED
 
-#if _GL_HAS_ATTRIBUTE (malloc)
-# define _GL_ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
-#else
-# define _GL_ATTRIBUTE_MALLOC
-#endif
-
-#if 201710L < __STDC_VERSION__
+/* _GL_ATTRIBUTE_NODISCARD declares that the caller of the function should not
+   discard the return value.  The compiler may warn if the caller does not use
+   the return value, unless the caller uses something like ignore_value.  */
+/* Applies to: function, enumeration, class.  */
+#if _GL_HAS_C_ATTRIBUTE (nodiscard)
 # define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]]
 #elif _GL_HAS_ATTRIBUTE (warn_unused_result)
 # define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__))
@@ -220,18 +319,30 @@ AC_DEFUN([gl_COMMON_BODY], [
 # define _GL_ATTRIBUTE_NODISCARD
 #endif
 
+/* _GL_ATTRIBUTE_NOINLINE tells that the compiler should not inline the
+   function.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (noinline)
 # define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__))
 #else
 # define _GL_ATTRIBUTE_NOINLINE
 #endif
 
+/* _GL_ATTRIBUTE_NONNULL ((N1, N2,...)) declares that the arguments N1, N2,...
+   must not be NULL.
+   _GL_ATTRIBUTE_NONNULL () declares that all pointer arguments must not be
+   null.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (nonnull)
 # define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args))
 #else
 # define _GL_ATTRIBUTE_NONNULL(args)
 #endif
 
+/* _GL_ATTRIBUTE_NONSTRING declares that the contents of a character array is
+   not meant to be NUL-terminated.  */
+/* Applies to: struct/union members and variables that are arrays of element
+   type '[[un]signed] char'.  */
 #if _GL_HAS_ATTRIBUTE (nonstring)
 # define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
 #else
@@ -240,41 +351,77 @@ AC_DEFUN([gl_COMMON_BODY], [
 
 /* There is no _GL_ATTRIBUTE_NORETURN; use _Noreturn instead.  */
 
+/* _GL_ATTRIBUTE_NOTHROW declares that the function does not throw exceptions.
+ */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (nothrow) && !defined __cplusplus
 # define _GL_ATTRIBUTE_NOTHROW __attribute__ ((__nothrow__))
 #else
 # define _GL_ATTRIBUTE_NOTHROW
 #endif
 
+/* _GL_ATTRIBUTE_PACKED declares:
+   For struct members: The member has the smallest possible alignment.
+   For struct, union, class: All members have the smallest possible alignment,
+   minimizing the memory required.  */
+/* Applies to: struct members, struct, union,
+   in C++ also: class.  */
 #if _GL_HAS_ATTRIBUTE (packed)
 # define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__))
 #else
 # define _GL_ATTRIBUTE_PACKED
 #endif
 
+/* _GL_ATTRIBUTE_PURE declares that It is OK for a compiler to omit duplicate
+   calls to the function with the same arguments if observable state is not
+   changed between calls.
+   This attribute is safe for a function that does not affect
+   observable state, and always returns exactly once.
+   (This attribute is looser than _GL_ATTRIBUTE_CONST.)  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (pure)
 # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
 #else
 # define _GL_ATTRIBUTE_PURE
 #endif
 
+/* _GL_ATTRIBUTE_RETURNS_NONNULL declares that the function's return value is
+   a non-NULL pointer.  */
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (returns_nonnull)
 # define _GL_ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
 #else
 # define _GL_ATTRIBUTE_RETURNS_NONNULL
 #endif
 
+/* _GL_ATTRIBUTE_SENTINEL(pos) declares that the variadic function expects a
+   trailing NULL argument.
+   _GL_ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99).
+   _GL_ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL.  
*/
+/* Applies to: functions.  */
 #if _GL_HAS_ATTRIBUTE (sentinel)
 # define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos))
 #else
 # define _GL_ATTRIBUTE_SENTINEL(pos)
 #endif
 
+/* A helper macro.  Don't use it directly.  */
+#if _GL_HAS_ATTRIBUTE (unused)
+# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#else
+# define _GL_ATTRIBUTE_UNUSED
+#endif
+
 ]dnl There is no _GL_ATTRIBUTE_VISIBILITY; see m4/visibility.m4 instead.
 [
-/* To support C++ as well as C, use _GL_UNUSED_LABEL with trailing ';'.  */
-#if !defined __cplusplus || _GL_GNUC_PREREQ (4, 5)
-# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_MAYBE_UNUSED
+/* _GL_UNUSED_LABEL; declares that it is not a programming mistake if the
+   immediately preceding label is not used.  The compiler should not warn
+   if the label is not used.  */
+/* Applies to: label (both in C and C++).  */
+/* Note that g++ < 4.5 does not support the '__attribute__ ((__unused__)) ;'
+   syntax.  But clang does.  */
+#if !(defined __cplusplus && !_GL_GNUC_PREREQ (4, 5)) || defined __clang__
+# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED
 #else
 # define _GL_UNUSED_LABEL
 #endif
@@ -357,6 +504,16 @@ AC_DEFUN([gl_COMMON_BODY], [
   export LIBC_FATAL_STDERR_
 ])
 
+# gl_MODULE_INDICATOR_INIT_VARIABLE([variablename])
+# gl_MODULE_INDICATOR_INIT_VARIABLE([variablename], [initialvalue])
+# initializes the shell variable that indicates the presence of the given 
module
+# as a C preprocessor expression.
+AC_DEFUN([gl_MODULE_INDICATOR_INIT_VARIABLE],
+[
+  GL_MODULE_INDICATOR_PREFIX[]_[$1]=m4_if([$2], , [0], [$2])
+  AC_SUBST(GL_MODULE_INDICATOR_PREFIX[]_[$1])
+])
+
 # gl_MODULE_INDICATOR_CONDITION
 # expands to a C preprocessor expression that evaluates to 1 or 0, depending
 # whether a gnulib module that has been requested shall be considered present
@@ -369,9 +526,9 @@ m4_define([gl_MODULE_INDICATOR_CONDITION], [1])
 AC_DEFUN([gl_MODULE_INDICATOR_SET_VARIABLE],
 [
   gl_MODULE_INDICATOR_SET_VARIABLE_AUX(
-    [GNULIB_[]m4_translit([[$1]],
-                          [abcdefghijklmnopqrstuvwxyz./-],
-                          [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])],
+    [GL_MODULE_INDICATOR_PREFIX[]_GNULIB_[]m4_translit([[$1]],
+                                                       
[abcdefghijklmnopqrstuvwxyz./-],
+                                                       
[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])],
     [gl_MODULE_INDICATOR_CONDITION])
 ])
 
@@ -656,6 +813,72 @@ AC_DEFUN([gl_CACHE_VAL_SILENT],
   ])
 ])
 
+# gl_CC_ALLOW_WARNINGS
+# sets and substitutes a variable GL_CFLAG_ALLOW_WARNINGS, to a $(CC) option
+# that reverts a preceding '-Werror' option, if available.
+# This is expected to be '-Wno-error' on gcc, clang (except clang/MSVC), 
xlclang
+# and empty otherwise.
+AC_DEFUN([gl_CC_ALLOW_WARNINGS],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_CACHE_CHECK([for C compiler option to allow warnings],
+    [gl_cv_cc_wallow],
+    [rm -f conftest*
+     echo 'int dummy;' > conftest.c
+     AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c conftest.c 
2>conftest1.err]) >/dev/null
+     AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -Wno-error -c conftest.c 
2>conftest2.err]) >/dev/null
+     dnl Test the number of error output lines, because AIX xlc accepts the
+     dnl option '-Wno-error', just to produce a warning
+     dnl "Option -Wno-error was incorrectly specified. The option will be 
ignored."
+     dnl afterwards.
+     if test $? = 0 && test `wc -l < conftest1.err` = `wc -l < conftest2.err`; 
then
+       gl_cv_cc_wallow='-Wno-error'
+     else
+       gl_cv_cc_wallow=none
+     fi
+     rm -f conftest*
+    ])
+  case "$gl_cv_cc_wallow" in
+    none) GL_CFLAG_ALLOW_WARNINGS='' ;;
+    *)    GL_CFLAG_ALLOW_WARNINGS="$gl_cv_cc_wallow" ;;
+  esac
+  AC_SUBST([GL_CFLAG_ALLOW_WARNINGS])
+])
+
+# gl_CXX_ALLOW_WARNINGS
+# sets and substitutes a variable GL_CXXFLAG_ALLOW_WARNINGS, to a $(CC) option
+# that reverts a preceding '-Werror' option, if available.
+AC_DEFUN([gl_CXX_ALLOW_WARNINGS],
+[
+  dnl Requires AC_PROG_CXX or gl_PROG_ANSI_CXX.
+  if test -n "$CXX" && test "$CXX" != no; then
+    AC_CACHE_CHECK([for C++ compiler option to allow warnings],
+      [gl_cv_cxx_wallow],
+      [rm -f conftest*
+       echo 'int dummy;' > conftest.cc
+       AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -c conftest.cc 
2>conftest1.err]) >/dev/null
+       AC_TRY_COMMAND([${CXX-c++} $CXXFLAGS $CPPFLAGS -Wno-error -c 
conftest.cc 2>conftest2.err]) >/dev/null
+       dnl Test the number of error output lines, because AIX xlC accepts the
+       dnl option '-Wno-error', just to produce a warning
+       dnl "Option -Wno-error was incorrectly specified. The option will be 
ignored."
+       dnl afterwards.
+       if test $? = 0 && test `wc -l < conftest1.err` = `wc -l < 
conftest2.err`; then
+         gl_cv_cxx_wallow='-Wno-error'
+       else
+         gl_cv_cxx_wallow=none
+       fi
+       rm -f conftest*
+      ])
+    case "$gl_cv_cxx_wallow" in
+      none) GL_CXXFLAG_ALLOW_WARNINGS='' ;;
+      *)    GL_CXXFLAG_ALLOW_WARNINGS="$gl_cv_cxx_wallow" ;;
+    esac
+  else
+    GL_CXXFLAG_ALLOW_WARNINGS=''
+  fi
+  AC_SUBST([GL_CXXFLAG_ALLOW_WARNINGS])
+])
+
 dnl Expands to some code for use in .c programs that, on native Windows, 
defines
 dnl the Microsoft deprecated alias function names to the underscore-prefixed
 dnl actual function names. With this macro, these function names are available
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 05e7faa993..e314edcfb5 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -63,6 +63,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module count-leading-zeros:
   # Code from module count-one-bits:
   # Code from module count-trailing-zeros:
+  # Code from module crypto/md5:
   # Code from module crypto/md5-buffer:
   # Code from module crypto/sha1-buffer:
   # Code from module crypto/sha256-buffer:
@@ -121,11 +122,13 @@ AC_DEFUN([gl_EARLY],
   # Code from module inttypes-incomplete:
   # Code from module largefile:
   AC_REQUIRE([AC_SYS_LARGEFILE])
+  AC_REQUIRE([gl_YEAR2038_EARLY])
   # Code from module lchmod:
   # Code from module libc-config:
   # Code from module libgmp:
   # Code from module limits-h:
   # Code from module lstat:
+  # Code from module malloc-posix:
   # Code from module manywarnings:
   # Code from module memmem-simple:
   # Code from module mempcpy:
@@ -136,6 +139,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module mktime-internal:
   # Code from module multiarch:
   # Code from module nocrash:
+  # Code from module nproc:
   # Code from module nstrftime:
   # Code from module open:
   # Code from module openat-h:
@@ -147,6 +151,8 @@ AC_DEFUN([gl_EARLY],
   # Code from module rawmemchr:
   # Code from module readlink:
   # Code from module readlinkat:
+  # Code from module realloc-gnu:
+  # Code from module realloc-posix:
   # Code from module regex:
   # Code from module root-uid:
   # Code from module scratch_buffer:
@@ -189,6 +195,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module u64:
   # Code from module unistd:
   # Code from module unlocked-io:
+  # Code from module unlocked-io-internal:
   # Code from module update-copyright:
   # Code from module utimens:
   # Code from module utimensat:
@@ -213,6 +220,8 @@ AC_DEFUN([gl_INIT],
   m4_pushdef([AC_LIBSOURCES], m4_defn([gl_LIBSOURCES]))
   m4_pushdef([gl_LIBSOURCES_LIST], [])
   m4_pushdef([gl_LIBSOURCES_DIR], [])
+  m4_pushdef([GL_MACRO_PREFIX], [gl])
+  m4_pushdef([GL_MODULE_INDICATOR_PREFIX], [GL])
   gl_COMMON
   gl_source_base='lib'
   gl_FUNC_ACL
@@ -245,6 +254,7 @@ AC_DEFUN([gl_INIT],
   gl_SHA512
   gl_CHECK_TYPE_STRUCT_DIRENT_D_TYPE
   gl_DIRENT_H
+  gl_DIRENT_H_REQUIRE_DEFAULTS
   gl_DOUBLE_SLASH_ROOT
   gl_FUNC_DUP2
   if test $REPLACE_DUP2 = 1; then
@@ -282,6 +292,7 @@ AC_DEFUN([gl_INIT],
   fi
   gl_FCNTL_MODULE_INDICATOR([fcntl])
   gl_FCNTL_H
+  gl_FCNTL_H_REQUIRE_DEFAULTS
   gl_FUNC_FDOPENDIR
   if test $HAVE_FDOPENDIR = 0 || test $REPLACE_FDOPENDIR = 1; then
     AC_LIBOBJ([fdopendir])
@@ -337,10 +348,10 @@ AC_DEFUN([gl_INIT],
   if test $REPLACE_GETOPT = 1; then
     AC_LIBOBJ([getopt])
     AC_LIBOBJ([getopt1])
-    dnl Arrange for unistd.h to include getopt.h.
-    GNULIB_GL_UNISTD_H_GETOPT=1
+    dnl Define the substituted variable GNULIB_UNISTD_H_GETOPT to 1.
+    gl_UNISTD_H_REQUIRE_DEFAULTS
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_GETOPT], [1])
   fi
-  AC_SUBST([GNULIB_GL_UNISTD_H_GETOPT])
   gl_UNISTD_MODULE_INDICATOR([getopt-posix])
   AC_REQUIRE([AC_CANONICAL_HOST])
   gl_FUNC_GETRANDOM
@@ -357,6 +368,7 @@ AC_DEFUN([gl_INIT],
   gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])
   gl_IEEE754_H
   gl_INTTYPES_INCOMPLETE
+  gl_INTTYPES_H_REQUIRE_DEFAULTS
   AC_REQUIRE([gl_LARGEFILE])
   gl___INLINE
   gl_LIBGMP
@@ -402,6 +414,7 @@ AC_DEFUN([gl_INIT],
   fi
   gl_TIME_MODULE_INDICATOR([mktime])
   gl_MULTIARCH
+  gl_NPROC
   gl_FUNC_GNU_STRFTIME
   gl_PATHMAX
   gl_FUNC_PIPE2
@@ -444,22 +457,50 @@ AC_DEFUN([gl_INIT],
   fi
   gl_STRING_MODULE_INDICATOR([sigdescr_np])
   gl_SIGNAL_H
+  gl_SIGNAL_H_REQUIRE_DEFAULTS
   gl_TYPE_SOCKLEN_T
   gt_TYPE_SSIZE_T
   gl_STAT_TIME
   gl_STAT_BIRTHTIME
   gl_STDALIGN_H
   gl_STDDEF_H
+  gl_STDDEF_H_REQUIRE_DEFAULTS
   gl_STDINT_H
   gl_STDIO_H
+  gl_STDIO_H_REQUIRE_DEFAULTS
+  dnl No need to create extra modules for these functions. Everyone who uses
+  dnl <stdio.h> likely needs them.
+  gl_STDIO_MODULE_INDICATOR([fscanf])
+  gl_MODULE_INDICATOR([fscanf])
+  gl_STDIO_MODULE_INDICATOR([scanf])
+  gl_MODULE_INDICATOR([scanf])
+  gl_STDIO_MODULE_INDICATOR([fgetc])
+  gl_STDIO_MODULE_INDICATOR([getc])
+  gl_STDIO_MODULE_INDICATOR([getchar])
+  gl_STDIO_MODULE_INDICATOR([fgets])
+  gl_STDIO_MODULE_INDICATOR([fread])
+  dnl No need to create extra modules for these functions. Everyone who uses
+  dnl <stdio.h> likely needs them.
+  gl_STDIO_MODULE_INDICATOR([fprintf])
+  gl_STDIO_MODULE_INDICATOR([printf])
+  gl_STDIO_MODULE_INDICATOR([vfprintf])
+  gl_STDIO_MODULE_INDICATOR([vprintf])
+  gl_STDIO_MODULE_INDICATOR([fputc])
+  gl_STDIO_MODULE_INDICATOR([putc])
+  gl_STDIO_MODULE_INDICATOR([putchar])
+  gl_STDIO_MODULE_INDICATOR([fputs])
+  gl_STDIO_MODULE_INDICATOR([puts])
+  gl_STDIO_MODULE_INDICATOR([fwrite])
   gl_STDLIB_H
+  gl_STDLIB_H_REQUIRE_DEFAULTS
   gl_FUNC_STPCPY
   if test $HAVE_STPCPY = 0; then
     AC_LIBOBJ([stpcpy])
     gl_PREREQ_STPCPY
   fi
   gl_STRING_MODULE_INDICATOR([stpcpy])
-  gl_HEADER_STRING_H
+  gl_STRING_H
+  gl_STRING_H_REQUIRE_DEFAULTS
   gl_FUNC_STRNLEN
   if test $HAVE_DECL_STRNLEN = 0 || test $REPLACE_STRNLEN = 1; then
     AC_LIBOBJ([strnlen])
@@ -477,19 +518,25 @@ AC_DEFUN([gl_INIT],
     AC_LIBOBJ([symlink])
   fi
   gl_UNISTD_MODULE_INDICATOR([symlink])
-  gl_HEADER_SYS_RANDOM
+  gl_SYS_RANDOM_H
+  gl_SYS_RANDOM_H_REQUIRE_DEFAULTS
   AC_PROG_MKDIR_P
-  AC_REQUIRE([gl_HEADER_SYS_SELECT])
+  gl_SYS_SELECT_H
+  gl_SYS_SELECT_H_REQUIRE_DEFAULTS
   AC_PROG_MKDIR_P
-  gl_HEADER_SYS_STAT_H
+  gl_SYS_STAT_H
+  gl_SYS_STAT_H_REQUIRE_DEFAULTS
   AC_PROG_MKDIR_P
-  gl_HEADER_SYS_TIME_H
+  gl_SYS_TIME_H
+  gl_SYS_TIME_H_REQUIRE_DEFAULTS
   AC_PROG_MKDIR_P
   gl_SYS_TYPES_H
+  gl_SYS_TYPES_H_REQUIRE_DEFAULTS
   AC_PROG_MKDIR_P
   gl_FUNC_GEN_TEMPNAME
   gl_MODULE_INDICATOR([tempname])
-  gl_HEADER_TIME_H
+  gl_TIME_H
+  gl_TIME_H_REQUIRE_DEFAULTS
   gl_TIME_R
   if test $HAVE_LOCALTIME_R = 0 || test $REPLACE_LOCALTIME_R = 1; then
     AC_LIBOBJ([time_r])
@@ -510,6 +557,17 @@ AC_DEFUN([gl_INIT],
   gl_TIMER_TIME
   gl_TIMESPEC
   gl_UNISTD_H
+  gl_UNISTD_H_REQUIRE_DEFAULTS
+  AC_DEFINE([GNULIB_STDIO_SINGLE_THREAD], [1],
+    [Define to 1 if you want the FILE stream functions getc, putc, etc.
+     to use unlocked I/O if available, throughout the package.
+     Unlocked I/O can improve performance, sometimes dramatically.
+     But unlocked I/O is safe only in single-threaded programs,
+     as well as in multithreaded programs for which you can guarantee that
+     every FILE stream, including stdin, stdout, stderr, is used only
+     in a single thread.])
+  AC_DEFINE([USE_UNLOCKED_IO], [GNULIB_STDIO_SINGLE_THREAD],
+    [An alias of GNULIB_STDIO_SINGLE_THREAD.])
   gl_FUNC_GLIBC_UNLOCKED_IO
   gl_FUNC_UTIMENSAT
   if test $HAVE_UTIMENSAT = 0 || test $REPLACE_UTIMENSAT = 1; then
@@ -527,12 +585,14 @@ AC_DEFUN([gl_INIT],
   gl_gnulib_enabled_getgroups=false
   gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
   gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
-  gl_gnulib_enabled_idx=false
   gl_gnulib_enabled_lchmod=false
+  gl_gnulib_enabled_ef455225c00f5049c808c2eda3e76866=false
   gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31=false
   gl_gnulib_enabled_open=false
   gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7=false
   gl_gnulib_enabled_rawmemchr=false
+  gl_gnulib_enabled_d3b2383720ee0e541357aa2aac598e2b=false
+  gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4=false
   gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false
   gl_gnulib_enabled_scratch_buffer=false
   gl_gnulib_enabled_strtoll=false
@@ -571,6 +631,7 @@ AC_DEFUN([gl_INIT],
   func_gl_gnulib_m4code_dynarray ()
   {
     if ! $gl_gnulib_enabled_dynarray; then
+      AC_PROG_MKDIR_P
       gl_gnulib_enabled_dynarray=true
     fi
   }
@@ -617,6 +678,9 @@ AC_DEFUN([gl_INIT],
       fi
       gl_UNISTD_MODULE_INDICATOR([getgroups])
       gl_gnulib_enabled_getgroups=true
+      if test $HAVE_GETGROUPS = 0 || test $REPLACE_GETGROUPS = 1; then
+        func_gl_gnulib_m4code_ef455225c00f5049c808c2eda3e76866
+      fi
     fi
   }
   func_gl_gnulib_m4code_be453cec5eecf5731a274f2de7f2db36 ()
@@ -641,16 +705,10 @@ AC_DEFUN([gl_INIT],
         func_gl_gnulib_m4code_getgroups
       fi
       if test $HAVE_GROUP_MEMBER = 0; then
-        func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec
+        func_gl_gnulib_m4code_d3b2383720ee0e541357aa2aac598e2b
       fi
     fi
   }
-  func_gl_gnulib_m4code_idx ()
-  {
-    if ! $gl_gnulib_enabled_idx; then
-      gl_gnulib_enabled_idx=true
-    fi
-  }
   func_gl_gnulib_m4code_lchmod ()
   {
     if ! $gl_gnulib_enabled_lchmod; then
@@ -663,6 +721,20 @@ AC_DEFUN([gl_INIT],
       gl_gnulib_enabled_lchmod=true
     fi
   }
+  func_gl_gnulib_m4code_ef455225c00f5049c808c2eda3e76866 ()
+  {
+    if ! $gl_gnulib_enabled_ef455225c00f5049c808c2eda3e76866; then
+      AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
+      if test $REPLACE_MALLOC = 1; then
+        AC_LIBOBJ([malloc])
+      fi
+      gl_STDLIB_MODULE_INDICATOR([malloc-posix])
+      gl_gnulib_enabled_ef455225c00f5049c808c2eda3e76866=true
+      if test $REPLACE_MALLOC = 1; then
+        func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec
+      fi
+    fi
+  }
   func_gl_gnulib_m4code_5264294aa0a5557541b53c8c741f7f31 ()
   {
     if ! $gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31; then
@@ -707,6 +779,34 @@ AC_DEFUN([gl_INIT],
       gl_gnulib_enabled_rawmemchr=true
     fi
   }
+  func_gl_gnulib_m4code_d3b2383720ee0e541357aa2aac598e2b ()
+  {
+    if ! $gl_gnulib_enabled_d3b2383720ee0e541357aa2aac598e2b; then
+      gl_FUNC_REALLOC_GNU
+      if test $REPLACE_REALLOC = 1; then
+        AC_LIBOBJ([realloc])
+      fi
+      gl_gnulib_enabled_d3b2383720ee0e541357aa2aac598e2b=true
+      func_gl_gnulib_m4code_61bcaca76b3e6f9ae55d57a1c3193bc4
+    fi
+  }
+  func_gl_gnulib_m4code_61bcaca76b3e6f9ae55d57a1c3193bc4 ()
+  {
+    if ! $gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4; then
+      gl_FUNC_REALLOC_POSIX
+      if test $REPLACE_REALLOC = 1; then
+        AC_LIBOBJ([realloc])
+      fi
+      gl_STDLIB_MODULE_INDICATOR([realloc-posix])
+      gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4=true
+      if test $REPLACE_REALLOC = 1; then
+        func_gl_gnulib_m4code_ef455225c00f5049c808c2eda3e76866
+      fi
+      if test $REPLACE_REALLOC = 1; then
+        func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec
+      fi
+    fi
+  }
   func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c ()
   {
     if ! $gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c; then
@@ -716,14 +816,17 @@ AC_DEFUN([gl_INIT],
   func_gl_gnulib_m4code_scratch_buffer ()
   {
     if ! $gl_gnulib_enabled_scratch_buffer; then
+      AC_PROG_MKDIR_P
       gl_gnulib_enabled_scratch_buffer=true
+      func_gl_gnulib_m4code_ef455225c00f5049c808c2eda3e76866
+      func_gl_gnulib_m4code_61bcaca76b3e6f9ae55d57a1c3193bc4
     fi
   }
   func_gl_gnulib_m4code_strtoll ()
   {
     if ! $gl_gnulib_enabled_strtoll; then
       gl_FUNC_STRTOLL
-      if test $HAVE_STRTOLL = 0; then
+      if test $HAVE_STRTOLL = 0 || test $REPLACE_STRTOLL = 1; then
         AC_LIBOBJ([strtoll])
         gl_PREREQ_STRTOLL
       fi
@@ -747,9 +850,6 @@ AC_DEFUN([gl_INIT],
   if test $HAVE_CANONICALIZE_FILE_NAME = 0 || test 
$REPLACE_CANONICALIZE_FILE_NAME = 1; then
     func_gl_gnulib_m4code_925677f0343de64b89a9f0c790b4104c
   fi
-  if test $HAVE_CANONICALIZE_FILE_NAME = 0 || test 
$REPLACE_CANONICALIZE_FILE_NAME = 1; then
-    func_gl_gnulib_m4code_idx
-  fi
   if test $HAVE_CANONICALIZE_FILE_NAME = 0 || test 
$REPLACE_CANONICALIZE_FILE_NAME = 1; then
     func_gl_gnulib_m4code_rawmemchr
   fi
@@ -813,9 +913,6 @@ AC_DEFUN([gl_INIT],
   if { test $HAVE_DECL_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test 
$ac_cv_type_long_long_int = yes; then
     func_gl_gnulib_m4code_strtoll
   fi
-  if test $HAVE_TIMEZONE_T = 0; then
-    func_gl_gnulib_m4code_idx
-  fi
   if test $HAVE_TIMEGM = 0 || test $REPLACE_TIMEGM = 1; then
     func_gl_gnulib_m4code_5264294aa0a5557541b53c8c741f7f31
   fi
@@ -839,12 +936,14 @@ AC_DEFUN([gl_INIT],
   AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], 
[$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], 
[$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
-  AM_CONDITIONAL([gl_GNULIB_ENABLED_idx], [$gl_gnulib_enabled_idx])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_lchmod], [$gl_gnulib_enabled_lchmod])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866], 
[$gl_gnulib_enabled_ef455225c00f5049c808c2eda3e76866])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31], 
[$gl_gnulib_enabled_5264294aa0a5557541b53c8c741f7f31])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_open], [$gl_gnulib_enabled_open])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_03e0aaad4cb89ca757653bd367a6ccb7], 
[$gl_gnulib_enabled_03e0aaad4cb89ca757653bd367a6ccb7])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_rawmemchr], [$gl_gnulib_enabled_rawmemchr])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b], 
[$gl_gnulib_enabled_d3b2383720ee0e541357aa2aac598e2b])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4], 
[$gl_gnulib_enabled_61bcaca76b3e6f9ae55d57a1c3193bc4])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], 
[$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_scratch_buffer], 
[$gl_gnulib_enabled_scratch_buffer])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
@@ -862,6 +961,8 @@ AC_DEFUN([gl_INIT],
       m4_if(m4_sysval, [0], [],
         [AC_FATAL([expected source file, required through AC_LIBSOURCES, not 
found])])
   ])
+  m4_popdef([GL_MODULE_INDICATOR_PREFIX])
+  m4_popdef([GL_MACRO_PREFIX])
   m4_popdef([gl_LIBSOURCES_DIR])
   m4_popdef([gl_LIBSOURCES_LIST])
   m4_popdef([AC_LIBSOURCES])
@@ -888,6 +989,8 @@ AC_DEFUN([gl_INIT],
   m4_pushdef([AC_LIBSOURCES], m4_defn([gltests_LIBSOURCES]))
   m4_pushdef([gltests_LIBSOURCES_LIST], [])
   m4_pushdef([gltests_LIBSOURCES_DIR], [])
+  m4_pushdef([GL_MACRO_PREFIX], [gltests])
+  m4_pushdef([GL_MODULE_INDICATOR_PREFIX], [GL])
   gl_COMMON
   gl_source_base='tests'
 changequote(,)dnl
@@ -909,6 +1012,8 @@ changequote([, ])dnl
       m4_if(m4_sysval, [0], [],
         [AC_FATAL([expected source file, required through AC_LIBSOURCES, not 
found])])
   ])
+  m4_popdef([GL_MODULE_INDICATOR_PREFIX])
+  m4_popdef([GL_MACRO_PREFIX])
   m4_popdef([gltests_LIBSOURCES_DIR])
   m4_popdef([gltests_LIBSOURCES_LIST])
   m4_popdef([AC_LIBSOURCES])
@@ -1092,6 +1197,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/libc-config.h
   lib/limits.in.h
   lib/lstat.c
+  lib/malloc.c
   lib/malloc/dynarray-skeleton.c
   lib/malloc/dynarray.h
   lib/malloc/dynarray_at_failure.c
@@ -1104,6 +1210,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/malloc/scratch_buffer_grow.c
   lib/malloc/scratch_buffer_grow_preserve.c
   lib/malloc/scratch_buffer_set_array_size.c
+  lib/md5-stream.c
   lib/md5.c
   lib/md5.h
   lib/memmem.c
@@ -1116,6 +1223,8 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/mkostemp.c
   lib/mktime-internal.h
   lib/mktime.c
+  lib/nproc.c
+  lib/nproc.h
   lib/nstrftime.c
   lib/open.c
   lib/openat-priv.h
@@ -1130,6 +1239,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/rawmemchr.valgrind
   lib/readlink.c
   lib/readlinkat.c
+  lib/realloc.c
   lib/regcomp.c
   lib/regex.c
   lib/regex.h
@@ -1250,6 +1360,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/libgmp.m4
   m4/limits-h.m4
   m4/lstat.m4
+  m4/malloc.m4
   m4/manywarnings-c++.m4
   m4/manywarnings.m4
   m4/mbstate_t.m4
@@ -1263,6 +1374,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/mode_t.m4
   m4/multiarch.m4
   m4/nocrash.m4
+  m4/nproc.m4
   m4/nstrftime.m4
   m4/off_t.m4
   m4/open-cloexec.m4
@@ -1276,6 +1388,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/rawmemchr.m4
   m4/readlink.m4
   m4/readlinkat.m4
+  m4/realloc.m4
   m4/regex.m4
   m4/sha1.m4
   m4/sha256.m4
@@ -1322,5 +1435,6 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/warnings.m4
   m4/wchar_t.m4
   m4/wint_t.m4
+  m4/year2038.m4
   m4/zzgnulib.m4
 ])
diff --git a/m4/inttypes.m4 b/m4/inttypes.m4
index f56e94a888..64b1de5c42 100644
--- a/m4/inttypes.m4
+++ b/m4/inttypes.m4
@@ -1,4 +1,4 @@
-# inttypes.m4 serial 32
+# inttypes.m4 serial 35
 dnl Copyright (C) 2006-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 dnl From Derek Price, Bruno Haible.
 dnl Test whether <inttypes.h> is supported or must be substituted.
 
-AC_DEFUN([gl_INTTYPES_H],
+AC_DEFUN_ONCE([gl_INTTYPES_H],
 [
   AC_REQUIRE([gl_INTTYPES_INCOMPLETE])
   gl_INTTYPES_PRI_SCN
@@ -136,19 +136,34 @@ AC_DEFUN([gl_INTTYPES_CHECK_LONG_LONG_INT_CONDITION],
   AC_SUBST([$1])
 ])
 
+# gl_INTTYPES_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_INTTYPES_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_INTTYPES_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_INTTYPES_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_INTTYPES_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_INTTYPES_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_IMAXABS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_IMAXDIV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOIMAX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOUMAX])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_INTTYPES_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_INTTYPES_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_INTTYPES_H_DEFAULTS],
 [
-  GNULIB_IMAXABS=0;      AC_SUBST([GNULIB_IMAXABS])
-  GNULIB_IMAXDIV=0;      AC_SUBST([GNULIB_IMAXDIV])
-  GNULIB_STRTOIMAX=0;    AC_SUBST([GNULIB_STRTOIMAX])
-  GNULIB_STRTOUMAX=0;    AC_SUBST([GNULIB_STRTOUMAX])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_DECL_IMAXABS=1;   AC_SUBST([HAVE_DECL_IMAXABS])
   HAVE_DECL_IMAXDIV=1;   AC_SUBST([HAVE_DECL_IMAXDIV])
diff --git a/m4/largefile.m4 b/m4/largefile.m4
index cadb16dc97..fbde5e6647 100644
--- a/m4/largefile.m4
+++ b/m4/largefile.m4
@@ -22,7 +22,8 @@ AC_DEFUN([gl_SET_LARGEFILE_SOURCE],
   esac
 ])
 
-# The following implementation works around a problem in autoconf <= 2.69;
+# Work around a problem in Autoconf through at least 2.71 on glibc 2.34+
+# with _TIME_BITS.  Also, work around a problem in autoconf <= 2.69:
 # AC_SYS_LARGEFILE does not configure for large inodes on Mac OS X 10.5,
 # or configures them incorrectly in some cases.
 m4_version_prereq([2.70], [], [
@@ -40,6 +41,7 @@ m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES],
                        && LARGE_OFF_T % 2147483647 == 1)
                       ? 1 : -1]];[]dnl
 ])
+])# m4_version_prereq 2.70
 
 
 # _AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, VALUE,
@@ -54,7 +56,8 @@ m4_define([_AC_SYS_LARGEFILE_MACRO_VALUE],
     [AC_LANG_PROGRAM([$5], [$6])],
     [$3=no; break])
   m4_ifval([$6], [AC_LINK_IFELSE], [AC_COMPILE_IFELSE])(
-    [AC_LANG_PROGRAM([#define $1 $2
+    [AC_LANG_PROGRAM([#undef $1
+#define $1 $2
 $5], [$6])],
     [$3=$2; break])
   $3=unknown
@@ -80,9 +83,8 @@ rm -rf conftest*[]dnl
 AC_DEFUN([AC_SYS_LARGEFILE],
 [AC_ARG_ENABLE(largefile,
                [  --disable-largefile     omit support for large files])
-if test "$enable_largefile" != no; then
-
-  AC_CACHE_CHECK([for special C compiler options needed for large files],
+AS_IF([test "$enable_largefile" != no],
+ [AC_CACHE_CHECK([for special C compiler options needed for large files],
     ac_cv_sys_largefile_CC,
     [ac_cv_sys_largefile_CC=no
      if test "$GCC" != yes; then
@@ -107,15 +109,15 @@ if test "$enable_largefile" != no; then
     ac_cv_sys_file_offset_bits,
     [Number of bits in a file offset, on hosts where this is settable.],
     [_AC_SYS_LARGEFILE_TEST_INCLUDES])
-  if test $ac_cv_sys_file_offset_bits = unknown; then
-    _AC_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES, 1,
-      ac_cv_sys_large_files,
-      [Define for large files, on AIX-style hosts.],
-      [_AC_SYS_LARGEFILE_TEST_INCLUDES])
-  fi
-fi
+  AS_CASE([$ac_cv_sys_file_offset_bits],
+    [unknown],
+      [_AC_SYS_LARGEFILE_MACRO_VALUE([_LARGE_FILES], [1],
+         [ac_cv_sys_large_files],
+         [Define for large files, on AIX-style hosts.],
+         [_AC_SYS_LARGEFILE_TEST_INCLUDES])],
+    [64],
+      [gl_YEAR2038_BODY([])])])
 ])# AC_SYS_LARGEFILE
-])# m4_version_prereq 2.70
 
 # Enable large files on systems where this is implemented by Gnulib, not by the
 # system headers.
diff --git a/m4/limits-h.m4 b/m4/limits-h.m4
index 70dbb7dcfa..00c9fe9e50 100644
--- a/m4/limits-h.m4
+++ b/m4/limits-h.m4
@@ -11,7 +11,7 @@ AC_DEFUN_ONCE([gl_LIMITS_H],
 [
   gl_CHECK_NEXT_HEADERS([limits.h])
 
-  AC_CACHE_CHECK([whether limits.h has LLONG_MAX, WORD_BIT, ULLONG_WIDTH etc.],
+  AC_CACHE_CHECK([whether limits.h has WORD_BIT, BOOL_WIDTH etc.],
     [gl_cv_header_limits_width],
     [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(
@@ -22,6 +22,7 @@ AC_DEFUN_ONCE([gl_LIMITS_H],
             long long llm = LLONG_MAX;
             int wb = WORD_BIT;
             int ullw = ULLONG_WIDTH;
+            int bw = BOOL_WIDTH;
           ]])],
        [gl_cv_header_limits_width=yes],
        [gl_cv_header_limits_width=no])])
diff --git a/m4/malloc.m4 b/m4/malloc.m4
new file mode 100644
index 0000000000..972e808ab7
--- /dev/null
+++ b/m4/malloc.m4
@@ -0,0 +1,174 @@
+# malloc.m4 serial 27
+dnl Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# This is adapted with modifications from upstream Autoconf here:
+# 
https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=v2.70#n949
+AC_DEFUN([_AC_FUNC_MALLOC_IF],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
+  AC_CACHE_CHECK([whether malloc (0) returns nonnull],
+    [ac_cv_func_malloc_0_nonnull],
+    [AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdlib.h>
+          ]],
+          [[void *p = malloc (0);
+            int result = !p;
+            free (p);
+            return result;]])
+       ],
+       [ac_cv_func_malloc_0_nonnull=yes],
+       [ac_cv_func_malloc_0_nonnull=no],
+       [case "$host_os" in
+          # Guess yes on platforms where we know the result.
+          *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
+          | gnu* | *-musl* | midnightbsd* \
+          | hpux* | solaris* | cygwin* | mingw* | msys* )
+            ac_cv_func_malloc_0_nonnull="guessing yes" ;;
+          # If we don't know, obey --enable-cross-guesses.
+          *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;;
+        esac
+       ])
+    ])
+  AS_CASE([$ac_cv_func_malloc_0_nonnull], [*yes], [$1], [$2])
+])# _AC_FUNC_MALLOC_IF
+
+# gl_FUNC_MALLOC_GNU
+# ------------------
+# Replace malloc if it is not compatible with GNU libc.
+AC_DEFUN([gl_FUNC_MALLOC_GNU],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
+  if test $REPLACE_MALLOC = 0; then
+    _AC_FUNC_MALLOC_IF([], [REPLACE_MALLOC=1])
+  fi
+])
+
+# gl_FUNC_MALLOC_PTRDIFF
+# ----------------------
+# Test whether malloc (N) reliably fails when N exceeds PTRDIFF_MAX,
+# and replace malloc otherwise.
+AC_DEFUN([gl_FUNC_MALLOC_PTRDIFF],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([gl_CHECK_MALLOC_PTRDIFF])
+  test "$gl_cv_malloc_ptrdiff" = yes || REPLACE_MALLOC=1
+])
+
+# Test whether malloc, realloc, calloc refuse to create objects
+# larger than what can be expressed in ptrdiff_t.
+# Set gl_cv_func_malloc_gnu to yes or no accordingly.
+AC_DEFUN([gl_CHECK_MALLOC_PTRDIFF],
+[
+  AC_CACHE_CHECK([whether malloc is ptrdiff_t safe],
+    [gl_cv_malloc_ptrdiff],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdint.h>
+          ]],
+          [[/* 64-bit ptrdiff_t is so wide that no practical platform
+               can exceed it.  */
+            #define WIDE_PTRDIFF (PTRDIFF_MAX >> 31 >> 31 != 0)
+
+            /* On rare machines where size_t fits in ptrdiff_t there
+               is no problem.  */
+            #define NARROW_SIZE (SIZE_MAX <= PTRDIFF_MAX)
+
+            /* glibc 2.30 and later malloc refuses to exceed ptrdiff_t
+               bounds even on 32-bit platforms.  We don't know which
+               non-glibc systems are safe.  */
+            #define KNOWN_SAFE (2 < __GLIBC__ + (30 <= __GLIBC_MINOR__))
+
+            #if WIDE_PTRDIFF || NARROW_SIZE || KNOWN_SAFE
+              return 0;
+            #else
+              #error "malloc might not be ptrdiff_t safe"
+              syntax error
+            #endif
+          ]])],
+       [gl_cv_malloc_ptrdiff=yes],
+       [gl_cv_malloc_ptrdiff=no])
+    ])
+])
+
+# gl_FUNC_MALLOC_POSIX
+# --------------------
+# Test whether 'malloc' is POSIX compliant (sets errno to ENOMEM when it
+# fails, and doesn't mess up with ptrdiff_t overflow), and replace
+# malloc if it is not.
+AC_DEFUN([gl_FUNC_MALLOC_POSIX],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_MALLOC_PTRDIFF])
+  AC_REQUIRE([gl_CHECK_MALLOC_POSIX])
+  if test "$gl_cv_func_malloc_posix" = yes; then
+    AC_DEFINE([HAVE_MALLOC_POSIX], [1],
+      [Define if malloc, realloc, and calloc set errno on allocation failure.])
+  else
+    REPLACE_MALLOC=1
+  fi
+])
+
+# Test whether malloc, realloc, calloc set errno to ENOMEM on failure.
+# Set gl_cv_func_malloc_posix to yes or no accordingly.
+AC_DEFUN([gl_CHECK_MALLOC_POSIX],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CACHE_CHECK([whether malloc, realloc, calloc set errno on failure],
+    [gl_cv_func_malloc_posix],
+    [
+      dnl It is too dangerous to try to allocate a large amount of memory:
+      dnl some systems go to their knees when you do that. So assume that
+      dnl all Unix implementations of the function set errno on failure,
+      dnl except on those platforms where we have seen 'test-malloc-gnu',
+      dnl 'test-realloc-gnu', 'test-calloc-gnu' fail.
+      case "$host_os" in
+        mingw*)
+          gl_cv_func_malloc_posix=no ;;
+        irix* | solaris*)
+          dnl On IRIX 6.5, the three functions return NULL with errno unset
+          dnl when the argument is larger than PTRDIFF_MAX.
+          dnl On Solaris 11.3, the three functions return NULL with errno set
+          dnl to EAGAIN, not ENOMEM, when the argument is larger than
+          dnl PTRDIFF_MAX.
+          dnl Here is a test program:
+m4_divert_push([KILL])
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define ptrdiff_t long
+#ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX ((ptrdiff_t) ((1UL << (8 * sizeof (ptrdiff_t) - 1)) - 1))
+#endif
+
+int main ()
+{
+  void *p;
+
+  fprintf (stderr, "PTRDIFF_MAX = %lu\n", (unsigned long) PTRDIFF_MAX);
+
+  errno = 0;
+  p = malloc ((unsigned long) PTRDIFF_MAX + 1);
+  fprintf (stderr, "p=%p errno=%d\n", p, errno);
+
+  errno = 0;
+  p = calloc (PTRDIFF_MAX / 2 + 1, 2);
+  fprintf (stderr, "p=%p errno=%d\n", p, errno);
+
+  errno = 0;
+  p = realloc (NULL, (unsigned long) PTRDIFF_MAX + 1);
+  fprintf (stderr, "p=%p errno=%d\n", p, errno);
+
+  return 0;
+}
+m4_divert_pop([KILL])
+          gl_cv_func_malloc_posix=no ;;
+        *)
+          gl_cv_func_malloc_posix=yes ;;
+      esac
+    ])
+])
diff --git a/m4/malloca.m4 b/m4/malloca.m4
deleted file mode 100644
index 7ee33773d2..0000000000
--- a/m4/malloca.m4
+++ /dev/null
@@ -1,14 +0,0 @@
-# malloca.m4 serial 2
-dnl Copyright (C) 2003-2004, 2006-2007, 2009-2021 Free Software
-dnl Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-AC_DEFUN([gl_MALLOCA],
-[
-  dnl Use the autoconf tests for alloca(), but not the AC_SUBSTed variables
-  dnl @ALLOCA@ and @LTALLOCA@.
-  dnl gl_FUNC_ALLOCA   dnl Already brought in by the module dependencies.
-  AC_REQUIRE([gl_EEMALLOC])
-])
diff --git a/m4/manywarnings.m4 b/m4/manywarnings.m4
index 53ab153403..872ea58e62 100644
--- a/m4/manywarnings.m4
+++ b/m4/manywarnings.m4
@@ -1,4 +1,4 @@
-# manywarnings.m4 serial 21
+# manywarnings.m4 serial 23
 dnl Copyright (C) 2008-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -195,15 +195,9 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC(C)],
     gl_AS_VAR_APPEND([$1], [' -Wno-uninitialized'])
   fi
 
-  # Some warnings have too many false alarms in GCC 10.1.
-  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93695
-  gl_AS_VAR_APPEND([$1], [' -Wno-analyzer-double-free'])
-  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94458
+  # This warning have too many false alarms in GCC 11.2.1.
+  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101713
   gl_AS_VAR_APPEND([$1], [' -Wno-analyzer-malloc-leak'])
-  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94851
-  gl_AS_VAR_APPEND([$1], [' -Wno-analyzer-null-dereference'])
-  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95758
-  gl_AS_VAR_APPEND([$1], [' -Wno-analyzer-use-after-free'])
 
   AC_LANG_POP([C])
 ])
diff --git a/m4/memmem.m4 b/m4/memmem.m4
index e2a785f48d..6dac766128 100644
--- a/m4/memmem.m4
+++ b/m4/memmem.m4
@@ -1,4 +1,4 @@
-# memmem.m4 serial 27
+# memmem.m4 serial 29
 dnl Copyright (C) 2002-2004, 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -10,7 +10,7 @@ AC_DEFUN([gl_FUNC_MEMMEM_SIMPLE],
   dnl Persuade glibc <string.h> to declare memmem().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_FUNCS([memmem])
   if test $ac_cv_func_memmem = yes; then
     HAVE_MEMMEM=1
@@ -50,6 +50,7 @@ AC_DEFUN([gl_FUNC_MEMMEM_SIMPLE],
          dnl Assume that it works on all other platforms (even if not linear).
          AC_EGREP_CPP([Lucky user],
            [
+#include <string.h> /* for __GNU_LIBRARY__ */
 #ifdef __GNU_LIBRARY__
  #include <features.h>
  #if ((__GLIBC__ == 2 && ((__GLIBC_MINOR > 0 && __GLIBC_MINOR__ < 9) \
diff --git a/m4/mempcpy.m4 b/m4/mempcpy.m4
index c5ee2af8cc..f9d9ec8f30 100644
--- a/m4/mempcpy.m4
+++ b/m4/mempcpy.m4
@@ -1,4 +1,4 @@
-# mempcpy.m4 serial 11
+# mempcpy.m4 serial 12
 dnl Copyright (C) 2003-2004, 2006-2007, 2009-2021 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -13,7 +13,7 @@ AC_DEFUN([gl_FUNC_MEMPCPY],
   dnl The mempcpy() declaration in lib/string.in.h uses 'restrict'.
   AC_REQUIRE([AC_C_RESTRICT])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_FUNCS([mempcpy])
   if test $ac_cv_func_mempcpy = no; then
     HAVE_MEMPCPY=0
diff --git a/m4/memrchr.m4 b/m4/memrchr.m4
index d0c05896e5..40f61c5ac0 100644
--- a/m4/memrchr.m4
+++ b/m4/memrchr.m4
@@ -1,4 +1,4 @@
-# memrchr.m4 serial 10
+# memrchr.m4 serial 11
 dnl Copyright (C) 2002-2003, 2005-2007, 2009-2021 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -10,7 +10,7 @@ AC_DEFUN([gl_FUNC_MEMRCHR],
   dnl Persuade glibc <string.h> to declare memrchr().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_DECLS_ONCE([memrchr])
   if test $ac_cv_have_decl_memrchr = no; then
     HAVE_DECL_MEMRCHR=0
diff --git a/m4/mktime.m4 b/m4/mktime.m4
index 245649e774..721189af56 100644
--- a/m4/mktime.m4
+++ b/m4/mktime.m4
@@ -1,4 +1,4 @@
-# serial 35
+# serial 36
 dnl Copyright (C) 2002-2003, 2005-2007, 2009-2021 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -255,7 +255,7 @@ main ()
 dnl Main macro of module 'mktime'.
 AC_DEFUN([gl_FUNC_MKTIME],
 [
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_CANONICAL_HOST])
   AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
 
diff --git a/m4/nproc.m4 b/m4/nproc.m4
new file mode 100644
index 0000000000..887c66bee8
--- /dev/null
+++ b/m4/nproc.m4
@@ -0,0 +1,54 @@
+# nproc.m4 serial 5
+dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_NPROC],
+[
+  gl_PREREQ_NPROC
+])
+
+# Prerequisites of lib/nproc.c.
+AC_DEFUN([gl_PREREQ_NPROC],
+[
+  dnl Persuade glibc <sched.h> to declare CPU_SETSIZE, CPU_ISSET etc.
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_HEADERS([sys/pstat.h sys/sysmp.h sys/param.h],,,
+    [AC_INCLUDES_DEFAULT])
+  dnl <sys/sysctl.h> requires <sys/param.h> on OpenBSD 4.0.
+  AC_CHECK_HEADERS([sys/sysctl.h],,,
+    [AC_INCLUDES_DEFAULT
+     #if HAVE_SYS_PARAM_H
+     # include <sys/param.h>
+     #endif
+    ])
+
+  AC_CHECK_FUNCS([sched_getaffinity sched_getaffinity_np \
+                  pstat_getdynamic sysmp sysctl])
+
+  dnl Test whether sched_getaffinity has the expected declaration.
+  dnl glibc 2.3.[0-2]:
+  dnl   int sched_getaffinity (pid_t, unsigned int, unsigned long int *);
+  dnl glibc 2.3.3:
+  dnl   int sched_getaffinity (pid_t, cpu_set_t *);
+  dnl glibc >= 2.3.4:
+  dnl   int sched_getaffinity (pid_t, size_t, cpu_set_t *);
+  if test $ac_cv_func_sched_getaffinity = yes; then
+    AC_CACHE_CHECK([for glibc compatible sched_getaffinity],
+      [gl_cv_func_sched_getaffinity3],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <errno.h>
+              #include <sched.h>]],
+            [[sched_getaffinity (0, 0, (cpu_set_t *) 0);]])],
+         [gl_cv_func_sched_getaffinity3=yes],
+         [gl_cv_func_sched_getaffinity3=no])
+      ])
+    if test $gl_cv_func_sched_getaffinity3 = yes; then
+      AC_DEFINE([HAVE_SCHED_GETAFFINITY_LIKE_GLIBC], [1],
+        [Define to 1 if sched_getaffinity has a glibc compatible declaration.])
+    fi
+  fi
+])
diff --git a/m4/pselect.m4 b/m4/pselect.m4
index 538fe7dc12..9de63baf99 100644
--- a/m4/pselect.m4
+++ b/m4/pselect.m4
@@ -1,4 +1,4 @@
-# pselect.m4 serial 9
+# pselect.m4 serial 10
 dnl Copyright (C) 2011-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,7 +6,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN([gl_FUNC_PSELECT],
 [
-  AC_REQUIRE([gl_HEADER_SYS_SELECT])
+  AC_REQUIRE([gl_SYS_SELECT_H])
   AC_REQUIRE([AC_C_RESTRICT])
   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
   AC_CHECK_FUNCS_ONCE([pselect])
diff --git a/m4/pthread_sigmask.m4 b/m4/pthread_sigmask.m4
index eb4c784965..ff7fa9610e 100644
--- a/m4/pthread_sigmask.m4
+++ b/m4/pthread_sigmask.m4
@@ -1,4 +1,4 @@
-# pthread_sigmask.m4 serial 19
+# pthread_sigmask.m4 serial 21
 dnl Copyright (C) 2011-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -111,9 +111,9 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK],
     AC_REQUIRE([AC_PROG_CC])
     AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
 
-    dnl On FreeBSD 6.4, HP-UX 11.31, Solaris 9, in programs that are not linked
-    dnl with -lpthread, the pthread_sigmask() function always returns 0 and has
-    dnl no effect.
+    dnl On FreeBSD 13.0, MidnightBSD 1.1, HP-UX 11.31, Solaris 9, in programs
+    dnl that are not linked with -lpthread, the pthread_sigmask() function
+    dnl always returns 0 and has no effect.
     if test -z "$LIB_PTHREAD_SIGMASK"; then
       case " $LIBS " in
         *' -pthread '*) ;;
@@ -138,7 +138,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK],
                 [
                  changequote(,)dnl
                  case "$host_os" in
-                   freebsd* | hpux* | solaris | solaris2.[2-9]*)
+                   freebsd* | midnightbsd* | hpux* | solaris | solaris2.[2-9]*)
                      gl_cv_func_pthread_sigmask_in_libc_works="guessing no";;
                    *)
                      gl_cv_func_pthread_sigmask_in_libc_works="guessing yes";;
diff --git a/m4/rawmemchr.m4 b/m4/rawmemchr.m4
index f92846543c..452fab18f1 100644
--- a/m4/rawmemchr.m4
+++ b/m4/rawmemchr.m4
@@ -1,4 +1,4 @@
-# rawmemchr.m4 serial 2
+# rawmemchr.m4 serial 3
 dnl Copyright (C) 2003, 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,7 +9,7 @@ AC_DEFUN([gl_FUNC_RAWMEMCHR],
   dnl Persuade glibc <string.h> to declare rawmemchr().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_FUNCS([rawmemchr])
   if test $ac_cv_func_rawmemchr = no; then
     HAVE_RAWMEMCHR=0
diff --git a/m4/realloc.m4 b/m4/realloc.m4
new file mode 100644
index 0000000000..0abc4185ed
--- /dev/null
+++ b/m4/realloc.m4
@@ -0,0 +1,63 @@
+# realloc.m4 serial 24
+dnl Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# This is adapted with modifications from upstream Autoconf here:
+# 
https://git.savannah.gnu.org/cgit/autoconf.git/tree/lib/autoconf/functions.m4?id=v2.70#n1455
+AC_DEFUN([_AC_FUNC_REALLOC_IF],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])dnl for cross-compiles
+  AC_CACHE_CHECK([whether realloc (0, 0) returns nonnull],
+    [ac_cv_func_realloc_0_nonnull],
+    [AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdlib.h>
+          ]],
+          [[void *p = realloc (0, 0);
+            int result = !p;
+            free (p);
+            return result;]])
+       ],
+       [ac_cv_func_realloc_0_nonnull=yes],
+       [ac_cv_func_realloc_0_nonnull=no],
+       [case "$host_os" in
+          # Guess yes on platforms where we know the result.
+          *-gnu* | freebsd* | netbsd* | openbsd* | bitrig* \
+          | gnu* | *-musl* | midnightbsd* \
+          | hpux* | solaris* | cygwin* | mingw* | msys* )
+            ac_cv_func_realloc_0_nonnull="guessing yes" ;;
+          # If we don't know, obey --enable-cross-guesses.
+          *) ac_cv_func_realloc_0_nonnull="$gl_cross_guess_normal" ;;
+        esac
+       ])
+    ])
+  AS_CASE([$ac_cv_func_realloc_0_nonnull], [*yes], [$1], [$2])
+])# AC_FUNC_REALLOC
+
+# gl_FUNC_REALLOC_GNU
+# -------------------
+# Replace realloc if it is not compatible with GNU libc.
+AC_DEFUN([gl_FUNC_REALLOC_GNU],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_REALLOC_POSIX])
+  if test $REPLACE_REALLOC = 0; then
+    _AC_FUNC_REALLOC_IF([], [REPLACE_REALLOC=1])
+  fi
+])# gl_FUNC_REALLOC_GNU
+
+# gl_FUNC_REALLOC_POSIX
+# ---------------------
+# Test whether 'realloc' is POSIX compliant (sets errno to ENOMEM when it
+# fails, and doesn't mess up with ptrdiff_t overflow),
+# and replace realloc if it is not.
+AC_DEFUN([gl_FUNC_REALLOC_POSIX],
+[
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_MALLOC_POSIX])
+  if test $REPLACE_MALLOC = 1; then
+    REPLACE_REALLOC=1
+  fi
+])
diff --git a/m4/regex.m4 b/m4/regex.m4
index 850c572228..1c7e562f6c 100644
--- a/m4/regex.m4
+++ b/m4/regex.m4
@@ -1,4 +1,4 @@
-# serial 71
+# serial 73
 
 # Copyright (C) 1996-2001, 2003-2021 Free Software Foundation, Inc.
 #
@@ -246,7 +246,7 @@ AC_DEFUN([gl_REGEX],
                            & ~RE_CONTEXT_INVALID_DUP
                            & ~RE_NO_EMPTY_RANGES);
             memset (&regex, 0, sizeof regex);
-            s = re_compile_pattern ("[[:alnum:]_-]\\\\+$", 16, &regex);
+            s = re_compile_pattern ("[[:alnum:]_-]\\\\+\$", 16, &regex);
             if (s)
               result |= 32;
             else
@@ -264,14 +264,50 @@ AC_DEFUN([gl_REGEX],
                back reference.  */
             re_set_syntax (RE_SYNTAX_POSIX_EGREP);
             memset (&regex, 0, sizeof regex);
-            s = re_compile_pattern ("0|()0|\\1|0", 10, &regex);
+            s = re_compile_pattern ("0|()0|\\\\1|0", 10, &regex);
             if (!s)
-              result |= 64;
+              {
+                memset (&regs, 0, sizeof regs);
+                i = re_search (&regex, "x", 1, 0, 1, &regs);
+                if (i != -1)
+                  result |= 64;
+                if (0 <= i)
+                  {
+                    free (regs.start);
+                    free (regs.end);
+                  }
+                regfree (&regex);
+              }
             else
               {
                 if (strcmp (s, "Invalid back reference"))
                   result |= 64;
+              }
+
+            /* glibc bug 11053.  */
+            re_set_syntax (RE_SYNTAX_POSIX_BASIC);
+            memset (&regex, 0, sizeof regex);
+            static char const pat_sub2[] = "\\\\(a*\\\\)*a*\\\\1";
+            s = re_compile_pattern (pat_sub2, sizeof pat_sub2 - 1, &regex);
+            if (s)
+              result |= 64;
+            else
+              {
+                memset (&regs, 0, sizeof regs);
+                static char const data[] = "a";
+                int datalen = sizeof data - 1;
+                i = re_search (&regex, data, datalen, 0, datalen, &regs);
+                if (i != 0)
+                  result |= 64;
+                else if (regs.num_regs < 2)
+                  result |= 64;
+                else if (! (regs.start[0] == 0 && regs.end[0] == 1))
+                  result |= 64;
+                else if (! (regs.start[1] == 0 && regs.end[1] == 0))
+                  result |= 64;
                 regfree (&regex);
+                free (regs.start);
+                free (regs.end);
               }
 
 #if 0
diff --git a/m4/sigdescr_np.m4 b/m4/sigdescr_np.m4
index f6fa63140c..17c22506cc 100644
--- a/m4/sigdescr_np.m4
+++ b/m4/sigdescr_np.m4
@@ -1,4 +1,4 @@
-# sigdescr_np.m4 serial 1
+# sigdescr_np.m4 serial 2
 dnl Copyright (C) 2020-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,7 +9,7 @@ AC_DEFUN([gl_FUNC_SIGDESCR_NP],
   dnl Persuade glibc <string.h> to declare sigdescr_np().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_FUNCS([sigdescr_np])
   if test $ac_cv_func_sigdescr_np = no; then
     HAVE_SIGDESCR_NP=0
diff --git a/m4/signal_h.m4 b/m4/signal_h.m4
index ff9f0251fd..8b938809b7 100644
--- a/m4/signal_h.m4
+++ b/m4/signal_h.m4
@@ -1,10 +1,10 @@
-# signal_h.m4 serial 19
+# signal_h.m4 serial 22
 dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_SIGNAL_H],
+AC_DEFUN_ONCE([gl_SIGNAL_H],
 [
   AC_REQUIRE([gl_SIGNAL_H_DEFAULTS])
   AC_REQUIRE([gl_CHECK_TYPE_SIGSET_T])
@@ -52,22 +52,37 @@ AC_DEFUN([gl_CHECK_TYPE_SIGSET_T],
   fi
 ])
 
+# gl_SIGNAL_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SIGNAL_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_SIGNAL_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SIGNAL_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SIGNAL_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SIGNAL_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTHREAD_SIGMASK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAISE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGNAL_H_SIGPIPE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGPROCMASK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGACTION])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_SIGNAL_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SIGNAL_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SIGNAL_H_DEFAULTS],
 [
-  GNULIB_PTHREAD_SIGMASK=0;    AC_SUBST([GNULIB_PTHREAD_SIGMASK])
-  GNULIB_RAISE=0;              AC_SUBST([GNULIB_RAISE])
-  GNULIB_SIGNAL_H_SIGPIPE=0;   AC_SUBST([GNULIB_SIGNAL_H_SIGPIPE])
-  GNULIB_SIGPROCMASK=0;        AC_SUBST([GNULIB_SIGPROCMASK])
-  GNULIB_SIGACTION=0;          AC_SUBST([GNULIB_SIGACTION])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_POSIX_SIGNALBLOCKING=1; AC_SUBST([HAVE_POSIX_SIGNALBLOCKING])
   HAVE_PTHREAD_SIGMASK=1;      AC_SUBST([HAVE_PTHREAD_SIGMASK])
diff --git a/m4/stdalign.m4 b/m4/stdalign.m4
index 8dcb634d55..e22d7f78c0 100644
--- a/m4/stdalign.m4
+++ b/m4/stdalign.m4
@@ -13,7 +13,8 @@ AC_DEFUN([gl_STDALIGN_H],
     [gl_cv_header_working_stdalign_h],
     [AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(
-          [[#include <stdalign.h>
+          [[#include <stdint.h>
+            #include <stdalign.h>
             #include <stddef.h>
 
             /* Test that alignof yields a result consistent with offsetof.
@@ -32,6 +33,7 @@ AC_DEFUN([gl_STDALIGN_H],
             /* Test _Alignas only on platforms where gnulib can help.  */
             #if \
                 ((defined __cplusplus && 201103 <= __cplusplus) \
+                 || (__TINYC__ && defined __attribute__) \
                  || (defined __APPLE__ && defined __MACH__ \
                      ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
                      : __GNUC__) \
diff --git a/m4/stddef_h.m4 b/m4/stddef_h.m4
index cd666c4a58..1303d2e06c 100644
--- a/m4/stddef_h.m4
+++ b/m4/stddef_h.m4
@@ -1,4 +1,4 @@
-# stddef_h.m4 serial 9
+# stddef_h.m4 serial 11
 dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,7 +6,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 dnl A placeholder for <stddef.h>, for platforms that have issues.
 
-AC_DEFUN([gl_STDDEF_H],
+AC_DEFUN_ONCE([gl_STDDEF_H],
 [
   AC_REQUIRE([gl_STDDEF_H_DEFAULTS])
   AC_REQUIRE([gt_TYPE_WCHAR_T])
@@ -68,13 +68,28 @@ AC_DEFUN([gl_STDDEF_H],
   fi
 ])
 
+# gl_STDDEF_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_STDDEF_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_STDDEF_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_STDDEF_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_STDDEF_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDDEF_H_MODULE_INDICATOR_DEFAULTS], [
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDDEF_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_STDDEF_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_STDDEF_H_DEFAULTS],
 [
   dnl Assume proper GNU behavior unless another module says otherwise.
diff --git a/m4/stdint.m4 b/m4/stdint.m4
index a785b44ed1..2eb1652d8e 100644
--- a/m4/stdint.m4
+++ b/m4/stdint.m4
@@ -1,4 +1,4 @@
-# stdint.m4 serial 58
+# stdint.m4 serial 60
 dnl Copyright (C) 2001-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -170,7 +170,7 @@ struct s {
       PTRDIFF_MIN == TYPE_MINIMUM (ptrdiff_t)
       && PTRDIFF_MAX == TYPE_MAXIMUM (ptrdiff_t)
       ? 1 : -1;
-  /* Detect bug in FreeBSD 6.0 / ia64.  */
+  /* Detect bug in FreeBSD 6.0/ia64 and FreeBSD 13.0/arm64.  */
   int check_SIG_ATOMIC:
       SIG_ATOMIC_MIN == TYPE_MINIMUM (sig_atomic_t)
       && SIG_ATOMIC_MAX == TYPE_MAXIMUM (sig_atomic_t)
@@ -527,7 +527,7 @@ AC_DEFUN([gl_STDINT_TYPE_PROPERTIES],
   dnl requirement that wint_t is "unchanged by default argument promotions".
   dnl In this case gnulib's <wchar.h> and <wctype.h> override wint_t.
   dnl Set the variable BITSIZEOF_WINT_T accordingly.
-  if test $GNULIB_OVERRIDES_WINT_T = 1; then
+  if test $GNULIBHEADERS_OVERRIDE_WINT_T = 1; then
     BITSIZEOF_WINT_T=32
   fi
 ])
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 4c3f24acca..e704383862 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,11 +1,12 @@
-# stdio_h.m4 serial 52
+# stdio_h.m4 serial 56
 dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_STDIO_H],
+AC_DEFUN_ONCE([gl_STDIO_H],
 [
+  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   AH_VERBATIM([MINGW_ANSI_STDIO],
 [/* Use GNU style printf and scanf.  */
 #ifndef __USE_MINGW_ANSI_STDIO
@@ -13,7 +14,6 @@ AC_DEFUN([gl_STDIO_H],
 #endif
 ])
   AC_DEFINE([__USE_MINGW_ANSI_STDIO])
-  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   gl_NEXT_HEADERS([stdio.h])
 
   dnl Determine whether __USE_MINGW_ANSI_STDIO makes printf and
@@ -40,17 +40,6 @@ AC_DEFUN([gl_STDIO_H],
        attribute "__gnu_printf__" instead of "__printf__"])
   fi
 
-  dnl No need to create extra modules for these functions. Everyone who uses
-  dnl <stdio.h> likely needs them.
-  GNULIB_FSCANF=1
-  gl_MODULE_INDICATOR([fscanf])
-  GNULIB_SCANF=1
-  gl_MODULE_INDICATOR([scanf])
-  GNULIB_FGETC=1
-  GNULIB_GETC=1
-  GNULIB_GETCHAR=1
-  GNULIB_FGETS=1
-  GNULIB_FREAD=1
   dnl This ifdef is necessary to avoid an error "missing file lib/stdio-read.c"
   dnl "expected source file, required through AC_LIBSOURCES, not found". It is
   dnl also an optimization, to avoid performing a configure check whose result
@@ -64,18 +53,6 @@ AC_DEFUN([gl_STDIO_H],
     fi
   ])
 
-  dnl No need to create extra modules for these functions. Everyone who uses
-  dnl <stdio.h> likely needs them.
-  GNULIB_FPRINTF=1
-  GNULIB_PRINTF=1
-  GNULIB_VFPRINTF=1
-  GNULIB_VPRINTF=1
-  GNULIB_FPUTC=1
-  GNULIB_PUTC=1
-  GNULIB_PUTCHAR=1
-  GNULIB_FPUTS=1
-  GNULIB_PUTS=1
-  GNULIB_FWRITE=1
   dnl This ifdef is necessary to avoid an error "missing file 
lib/stdio-write.c"
   dnl "expected source file, required through AC_LIBSOURCES, not found". It is
   dnl also an optimization, to avoid performing a configure check whose result
@@ -116,77 +93,92 @@ AC_DEFUN([gl_STDIO_H],
   fi
 ])
 
+# gl_STDIO_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_STDIO_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_STDIO_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCLOSE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDOPEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFLUSH])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FGETC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FGETS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FOPEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPURGE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPUTC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FPUTS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREAD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREOPEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSCANF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSEEK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSEEKO])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTELLO])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FWRITE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCHAR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDELIM])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLINE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OBSTACK_PRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PCLOSE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PERROR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POPEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTCHAR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REMOVE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RENAMEAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SCANF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SNPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SPRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_NONBLOCKING])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFPRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FILENO], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETW], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_PUTW], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TEMPNAM], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDIO_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_STDIO_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_STDIO_H_DEFAULTS],
 [
-  GNULIB_DPRINTF=0;              AC_SUBST([GNULIB_DPRINTF])
-  GNULIB_FCLOSE=0;               AC_SUBST([GNULIB_FCLOSE])
-  GNULIB_FDOPEN=0;               AC_SUBST([GNULIB_FDOPEN])
-  GNULIB_FFLUSH=0;               AC_SUBST([GNULIB_FFLUSH])
-  GNULIB_FGETC=0;                AC_SUBST([GNULIB_FGETC])
-  GNULIB_FGETS=0;                AC_SUBST([GNULIB_FGETS])
-  GNULIB_FOPEN=0;                AC_SUBST([GNULIB_FOPEN])
-  GNULIB_FPRINTF=0;              AC_SUBST([GNULIB_FPRINTF])
-  GNULIB_FPRINTF_POSIX=0;        AC_SUBST([GNULIB_FPRINTF_POSIX])
-  GNULIB_FPURGE=0;               AC_SUBST([GNULIB_FPURGE])
-  GNULIB_FPUTC=0;                AC_SUBST([GNULIB_FPUTC])
-  GNULIB_FPUTS=0;                AC_SUBST([GNULIB_FPUTS])
-  GNULIB_FREAD=0;                AC_SUBST([GNULIB_FREAD])
-  GNULIB_FREOPEN=0;              AC_SUBST([GNULIB_FREOPEN])
-  GNULIB_FSCANF=0;               AC_SUBST([GNULIB_FSCANF])
-  GNULIB_FSEEK=0;                AC_SUBST([GNULIB_FSEEK])
-  GNULIB_FSEEKO=0;               AC_SUBST([GNULIB_FSEEKO])
-  GNULIB_FTELL=0;                AC_SUBST([GNULIB_FTELL])
-  GNULIB_FTELLO=0;               AC_SUBST([GNULIB_FTELLO])
-  GNULIB_FWRITE=0;               AC_SUBST([GNULIB_FWRITE])
-  GNULIB_GETC=0;                 AC_SUBST([GNULIB_GETC])
-  GNULIB_GETCHAR=0;              AC_SUBST([GNULIB_GETCHAR])
-  GNULIB_GETDELIM=0;             AC_SUBST([GNULIB_GETDELIM])
-  GNULIB_GETLINE=0;              AC_SUBST([GNULIB_GETLINE])
-  GNULIB_OBSTACK_PRINTF=0;       AC_SUBST([GNULIB_OBSTACK_PRINTF])
-  GNULIB_OBSTACK_PRINTF_POSIX=0; AC_SUBST([GNULIB_OBSTACK_PRINTF_POSIX])
-  GNULIB_PCLOSE=0;               AC_SUBST([GNULIB_PCLOSE])
-  GNULIB_PERROR=0;               AC_SUBST([GNULIB_PERROR])
-  GNULIB_POPEN=0;                AC_SUBST([GNULIB_POPEN])
-  GNULIB_PRINTF=0;               AC_SUBST([GNULIB_PRINTF])
-  GNULIB_PRINTF_POSIX=0;         AC_SUBST([GNULIB_PRINTF_POSIX])
-  GNULIB_PUTC=0;                 AC_SUBST([GNULIB_PUTC])
-  GNULIB_PUTCHAR=0;              AC_SUBST([GNULIB_PUTCHAR])
-  GNULIB_PUTS=0;                 AC_SUBST([GNULIB_PUTS])
-  GNULIB_REMOVE=0;               AC_SUBST([GNULIB_REMOVE])
-  GNULIB_RENAME=0;               AC_SUBST([GNULIB_RENAME])
-  GNULIB_RENAMEAT=0;             AC_SUBST([GNULIB_RENAMEAT])
-  GNULIB_SCANF=0;                AC_SUBST([GNULIB_SCANF])
-  GNULIB_SNPRINTF=0;             AC_SUBST([GNULIB_SNPRINTF])
-  GNULIB_SPRINTF_POSIX=0;        AC_SUBST([GNULIB_SPRINTF_POSIX])
-  GNULIB_STDIO_H_NONBLOCKING=0;  AC_SUBST([GNULIB_STDIO_H_NONBLOCKING])
-  GNULIB_STDIO_H_SIGPIPE=0;      AC_SUBST([GNULIB_STDIO_H_SIGPIPE])
-  GNULIB_TMPFILE=0;              AC_SUBST([GNULIB_TMPFILE])
-  GNULIB_VASPRINTF=0;            AC_SUBST([GNULIB_VASPRINTF])
-  GNULIB_VFSCANF=0;              AC_SUBST([GNULIB_VFSCANF])
-  GNULIB_VSCANF=0;               AC_SUBST([GNULIB_VSCANF])
-  GNULIB_VDPRINTF=0;             AC_SUBST([GNULIB_VDPRINTF])
-  GNULIB_VFPRINTF=0;             AC_SUBST([GNULIB_VFPRINTF])
-  GNULIB_VFPRINTF_POSIX=0;       AC_SUBST([GNULIB_VFPRINTF_POSIX])
-  GNULIB_VPRINTF=0;              AC_SUBST([GNULIB_VPRINTF])
-  GNULIB_VPRINTF_POSIX=0;        AC_SUBST([GNULIB_VPRINTF_POSIX])
-  GNULIB_VSNPRINTF=0;            AC_SUBST([GNULIB_VSNPRINTF])
-  GNULIB_VSPRINTF_POSIX=0;       AC_SUBST([GNULIB_VSPRINTF_POSIX])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_FCLOSEALL=1;        AC_SUBST([GNULIB_MDA_FCLOSEALL])
-  GNULIB_MDA_FDOPEN=1;           AC_SUBST([GNULIB_MDA_FDOPEN])
-  GNULIB_MDA_FILENO=1;           AC_SUBST([GNULIB_MDA_FILENO])
-  GNULIB_MDA_GETW=1;             AC_SUBST([GNULIB_MDA_GETW])
-  GNULIB_MDA_PUTW=1;             AC_SUBST([GNULIB_MDA_PUTW])
-  GNULIB_MDA_TEMPNAM=1;          AC_SUBST([GNULIB_MDA_TEMPNAM])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_DECL_FCLOSEALL=1;         AC_SUBST([HAVE_DECL_FCLOSEALL])
   HAVE_DECL_FPURGE=1;            AC_SUBST([HAVE_DECL_FPURGE])
diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4
index 5a02972e05..9c1d1c76c1 100644
--- a/m4/stdlib_h.m4
+++ b/m4/stdlib_h.m4
@@ -1,10 +1,10 @@
-# stdlib_h.m4 serial 55
+# stdlib_h.m4 serial 63
 dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_STDLIB_H],
+AC_DEFUN_ONCE([gl_STDLIB_H],
 [
   AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
   gl_NEXT_HEADERS([stdlib.h])
@@ -28,7 +28,7 @@ AC_DEFUN([gl_STDLIB_H],
     posix_memalign posix_openpt ptsname ptsname_r qsort_r
     random random_r reallocarray realpath rpmatch secure_getenv setenv
     setstate setstate_r srandom srandom_r
-    strtod strtold strtoll strtoull unlockpt unsetenv])
+    strtod strtol strtold strtoll strtoul strtoull unlockpt unsetenv])
 
   AC_REQUIRE([AC_C_RESTRICT])
 
@@ -46,61 +46,78 @@ AC_DEFUN([gl_STDLIB_H],
   fi
 ])
 
+# gl_STDLIB_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_STDLIB_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_STDLIB_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB__EXIT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALIGNED_ALLOC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ATOLL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CALLOC_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CANONICALIZE_FILE_NAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FREE_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOADAVG])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSUBOPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GRANTPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MALLOC_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBTOWC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDTEMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKOSTEMPS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKSTEMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKSTEMPS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POSIX_MEMALIGN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_POSIX_OPENPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PTSNAME_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PUTENV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_QSORT_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RANDOM_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOCARRAY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALLOC_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_REALPATH])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RPMATCH])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SECURE_GETENV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETENV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOLL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOUL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOULL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYSTEM_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLOCKPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNSETENV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WCTOMB])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ECVT], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCVT], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GCVT], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_MKTEMP], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_PUTENV], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_STDLIB_H_DEFAULTS],
 [
-  GNULIB__EXIT=0;         AC_SUBST([GNULIB__EXIT])
-  GNULIB_ALIGNED_ALLOC=0; AC_SUBST([GNULIB_ALIGNED_ALLOC])
-  GNULIB_ATOLL=0;         AC_SUBST([GNULIB_ATOLL])
-  GNULIB_CALLOC_POSIX=0;  AC_SUBST([GNULIB_CALLOC_POSIX])
-  GNULIB_CANONICALIZE_FILE_NAME=0;  AC_SUBST([GNULIB_CANONICALIZE_FILE_NAME])
-  GNULIB_FREE_POSIX=0;    AC_SUBST([GNULIB_FREE_POSIX])
-  GNULIB_GETLOADAVG=0;    AC_SUBST([GNULIB_GETLOADAVG])
-  GNULIB_GETSUBOPT=0;     AC_SUBST([GNULIB_GETSUBOPT])
-  GNULIB_GRANTPT=0;       AC_SUBST([GNULIB_GRANTPT])
-  GNULIB_MALLOC_POSIX=0;  AC_SUBST([GNULIB_MALLOC_POSIX])
-  GNULIB_MBTOWC=0;        AC_SUBST([GNULIB_MBTOWC])
-  GNULIB_MKDTEMP=0;       AC_SUBST([GNULIB_MKDTEMP])
-  GNULIB_MKOSTEMP=0;      AC_SUBST([GNULIB_MKOSTEMP])
-  GNULIB_MKOSTEMPS=0;     AC_SUBST([GNULIB_MKOSTEMPS])
-  GNULIB_MKSTEMP=0;       AC_SUBST([GNULIB_MKSTEMP])
-  GNULIB_MKSTEMPS=0;      AC_SUBST([GNULIB_MKSTEMPS])
-  GNULIB_POSIX_MEMALIGN=0;AC_SUBST([GNULIB_POSIX_MEMALIGN])
-  GNULIB_POSIX_OPENPT=0;  AC_SUBST([GNULIB_POSIX_OPENPT])
-  GNULIB_PTSNAME=0;       AC_SUBST([GNULIB_PTSNAME])
-  GNULIB_PTSNAME_R=0;     AC_SUBST([GNULIB_PTSNAME_R])
-  GNULIB_PUTENV=0;        AC_SUBST([GNULIB_PUTENV])
-  GNULIB_QSORT_R=0;       AC_SUBST([GNULIB_QSORT_R])
-  GNULIB_RANDOM=0;        AC_SUBST([GNULIB_RANDOM])
-  GNULIB_RANDOM_R=0;      AC_SUBST([GNULIB_RANDOM_R])
-  GNULIB_REALLOCARRAY=0;  AC_SUBST([GNULIB_REALLOCARRAY])
-  GNULIB_REALLOC_POSIX=0; AC_SUBST([GNULIB_REALLOC_POSIX])
-  GNULIB_REALPATH=0;      AC_SUBST([GNULIB_REALPATH])
-  GNULIB_RPMATCH=0;       AC_SUBST([GNULIB_RPMATCH])
-  GNULIB_SECURE_GETENV=0; AC_SUBST([GNULIB_SECURE_GETENV])
-  GNULIB_SETENV=0;        AC_SUBST([GNULIB_SETENV])
-  GNULIB_STRTOD=0;        AC_SUBST([GNULIB_STRTOD])
-  GNULIB_STRTOLD=0;       AC_SUBST([GNULIB_STRTOLD])
-  GNULIB_STRTOLL=0;       AC_SUBST([GNULIB_STRTOLL])
-  GNULIB_STRTOULL=0;      AC_SUBST([GNULIB_STRTOULL])
-  GNULIB_SYSTEM_POSIX=0;  AC_SUBST([GNULIB_SYSTEM_POSIX])
-  GNULIB_UNLOCKPT=0;      AC_SUBST([GNULIB_UNLOCKPT])
-  GNULIB_UNSETENV=0;      AC_SUBST([GNULIB_UNSETENV])
-  GNULIB_WCTOMB=0;        AC_SUBST([GNULIB_WCTOMB])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_ECVT=1;      AC_SUBST([GNULIB_MDA_ECVT])
-  GNULIB_MDA_FCVT=1;      AC_SUBST([GNULIB_MDA_FCVT])
-  GNULIB_MDA_GCVT=1;      AC_SUBST([GNULIB_MDA_GCVT])
-  GNULIB_MDA_MKTEMP=1;    AC_SUBST([GNULIB_MDA_MKTEMP])
-  GNULIB_MDA_PUTENV=1;    AC_SUBST([GNULIB_MDA_PUTENV])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE__EXIT=1;              AC_SUBST([HAVE__EXIT])
   HAVE_ALIGNED_ALLOC=1;      AC_SUBST([HAVE_ALIGNED_ALLOC])
@@ -137,8 +154,10 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   HAVE_SETSTATE=1;           AC_SUBST([HAVE_SETSTATE])
   HAVE_DECL_SETSTATE=1;      AC_SUBST([HAVE_DECL_SETSTATE])
   HAVE_STRTOD=1;             AC_SUBST([HAVE_STRTOD])
+  HAVE_STRTOL=1;             AC_SUBST([HAVE_STRTOL])
   HAVE_STRTOLD=1;            AC_SUBST([HAVE_STRTOLD])
   HAVE_STRTOLL=1;            AC_SUBST([HAVE_STRTOLL])
+  HAVE_STRTOUL=1;            AC_SUBST([HAVE_STRTOUL])
   HAVE_STRTOULL=1;           AC_SUBST([HAVE_STRTOULL])
   HAVE_STRUCT_RANDOM_DATA=1; AC_SUBST([HAVE_STRUCT_RANDOM_DATA])
   HAVE_SYS_LOADAVG_H=0;      AC_SUBST([HAVE_SYS_LOADAVG_H])
@@ -160,11 +179,16 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS],
   REPLACE_RANDOM=0;          AC_SUBST([REPLACE_RANDOM])
   REPLACE_RANDOM_R=0;        AC_SUBST([REPLACE_RANDOM_R])
   REPLACE_REALLOC=0;         AC_SUBST([REPLACE_REALLOC])
+  REPLACE_REALLOCARRAY=0;    AC_SUBST([REPLACE_REALLOCARRAY])
   REPLACE_REALPATH=0;        AC_SUBST([REPLACE_REALPATH])
   REPLACE_SETENV=0;          AC_SUBST([REPLACE_SETENV])
   REPLACE_SETSTATE=0;        AC_SUBST([REPLACE_SETSTATE])
   REPLACE_STRTOD=0;          AC_SUBST([REPLACE_STRTOD])
+  REPLACE_STRTOL=0;          AC_SUBST([REPLACE_STRTOL])
   REPLACE_STRTOLD=0;         AC_SUBST([REPLACE_STRTOLD])
+  REPLACE_STRTOLL=0;         AC_SUBST([REPLACE_STRTOLL])
+  REPLACE_STRTOUL=0;         AC_SUBST([REPLACE_STRTOUL])
+  REPLACE_STRTOULL=0;        AC_SUBST([REPLACE_STRTOULL])
   REPLACE_UNSETENV=0;        AC_SUBST([REPLACE_UNSETENV])
   REPLACE_WCTOMB=0;          AC_SUBST([REPLACE_WCTOMB])
 ])
diff --git a/m4/stpcpy.m4 b/m4/stpcpy.m4
index 28db4f45df..eb44f03adb 100644
--- a/m4/stpcpy.m4
+++ b/m4/stpcpy.m4
@@ -1,4 +1,4 @@
-# stpcpy.m4 serial 8
+# stpcpy.m4 serial 9
 dnl Copyright (C) 2002, 2007, 2009-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -12,7 +12,7 @@ AC_DEFUN([gl_FUNC_STPCPY],
   dnl The stpcpy() declaration in lib/string.in.h uses 'restrict'.
   AC_REQUIRE([AC_C_RESTRICT])
 
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   AC_CHECK_FUNCS([stpcpy])
   if test $ac_cv_func_stpcpy = no; then
     HAVE_STPCPY=0
diff --git a/m4/string_h.m4 b/m4/string_h.m4
index a4cc5b4378..e88ac9ca85 100644
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -5,20 +5,15 @@
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 29
+# serial 34
 
 # Written by Paul Eggert.
 
-AC_DEFUN([gl_HEADER_STRING_H],
+AC_DEFUN_ONCE([gl_STRING_H],
 [
-  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
-  dnl once only, before all statements that occur in other macros.
-  AC_REQUIRE([gl_HEADER_STRING_H_BODY])
-])
-
-AC_DEFUN([gl_HEADER_STRING_H_BODY],
-[
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only, before all statements
+  dnl that occur in other macros.
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
   gl_NEXT_HEADERS([string.h])
 
   dnl Check for declarations of anything we want to poison if the
@@ -33,62 +28,79 @@ AC_DEFUN([gl_HEADER_STRING_H_BODY],
   AC_REQUIRE([AC_C_RESTRICT])
 ])
 
+# gl_STRING_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_STRING_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_STRING_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
-AC_DEFUN([gl_HEADER_STRING_H_DEFAULTS],
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_STRING_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXPLICIT_BZERO])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFSL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FFSLL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMMEM])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMPCPY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMRCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAWMEMCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPCPY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPNCPY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCHRNUL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRDUP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNCAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNDUP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRNLEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPBRK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSEP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSTR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRCASESTR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRTOK_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSLEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNLEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSRCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSTR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCASECMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSNCASECMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSPCASECMP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCASESTR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSCSPN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSPBRK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSPN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSSEP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MBSTOK_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERROR_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRERRORNAME_NP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGABBREV_NP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SIGDESCR_NP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRSIGNAL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRVERSCMP])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_MEMCCPY], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_STRDUP], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_STRING_H_MODULE_INDICATOR_DEFAULTS])
+  dnl Make sure the shell variable for GNULIB_FREE_POSIX is initialized.
+  gl_STDLIB_H_REQUIRE_DEFAULTS
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
+])
+
+AC_DEFUN([gl_STRING_H_DEFAULTS],
 [
-  GNULIB_EXPLICIT_BZERO=0;   AC_SUBST([GNULIB_EXPLICIT_BZERO])
-  GNULIB_FFSL=0;             AC_SUBST([GNULIB_FFSL])
-  GNULIB_FFSLL=0;            AC_SUBST([GNULIB_FFSLL])
-  GNULIB_MEMCHR=0;           AC_SUBST([GNULIB_MEMCHR])
-  GNULIB_MEMMEM=0;           AC_SUBST([GNULIB_MEMMEM])
-  GNULIB_MEMPCPY=0;          AC_SUBST([GNULIB_MEMPCPY])
-  GNULIB_MEMRCHR=0;          AC_SUBST([GNULIB_MEMRCHR])
-  GNULIB_RAWMEMCHR=0;        AC_SUBST([GNULIB_RAWMEMCHR])
-  GNULIB_STPCPY=0;           AC_SUBST([GNULIB_STPCPY])
-  GNULIB_STPNCPY=0;          AC_SUBST([GNULIB_STPNCPY])
-  GNULIB_STRCHRNUL=0;        AC_SUBST([GNULIB_STRCHRNUL])
-  GNULIB_STRDUP=0;           AC_SUBST([GNULIB_STRDUP])
-  GNULIB_STRNCAT=0;          AC_SUBST([GNULIB_STRNCAT])
-  GNULIB_STRNDUP=0;          AC_SUBST([GNULIB_STRNDUP])
-  GNULIB_STRNLEN=0;          AC_SUBST([GNULIB_STRNLEN])
-  GNULIB_STRPBRK=0;          AC_SUBST([GNULIB_STRPBRK])
-  GNULIB_STRSEP=0;           AC_SUBST([GNULIB_STRSEP])
-  GNULIB_STRSTR=0;           AC_SUBST([GNULIB_STRSTR])
-  GNULIB_STRCASESTR=0;       AC_SUBST([GNULIB_STRCASESTR])
-  GNULIB_STRTOK_R=0;         AC_SUBST([GNULIB_STRTOK_R])
-  GNULIB_MBSLEN=0;           AC_SUBST([GNULIB_MBSLEN])
-  GNULIB_MBSNLEN=0;          AC_SUBST([GNULIB_MBSNLEN])
-  GNULIB_MBSCHR=0;           AC_SUBST([GNULIB_MBSCHR])
-  GNULIB_MBSRCHR=0;          AC_SUBST([GNULIB_MBSRCHR])
-  GNULIB_MBSSTR=0;           AC_SUBST([GNULIB_MBSSTR])
-  GNULIB_MBSCASECMP=0;       AC_SUBST([GNULIB_MBSCASECMP])
-  GNULIB_MBSNCASECMP=0;      AC_SUBST([GNULIB_MBSNCASECMP])
-  GNULIB_MBSPCASECMP=0;      AC_SUBST([GNULIB_MBSPCASECMP])
-  GNULIB_MBSCASESTR=0;       AC_SUBST([GNULIB_MBSCASESTR])
-  GNULIB_MBSCSPN=0;          AC_SUBST([GNULIB_MBSCSPN])
-  GNULIB_MBSPBRK=0;          AC_SUBST([GNULIB_MBSPBRK])
-  GNULIB_MBSSPN=0;           AC_SUBST([GNULIB_MBSSPN])
-  GNULIB_MBSSEP=0;           AC_SUBST([GNULIB_MBSSEP])
-  GNULIB_MBSTOK_R=0;         AC_SUBST([GNULIB_MBSTOK_R])
-  GNULIB_STRERROR=0;         AC_SUBST([GNULIB_STRERROR])
-  GNULIB_STRERROR_R=0;       AC_SUBST([GNULIB_STRERROR_R])
-  GNULIB_STRERRORNAME_NP=0;  AC_SUBST([GNULIB_STRERRORNAME_NP])
-  GNULIB_SIGABBREV_NP=0;     AC_SUBST([GNULIB_SIGABBREV_NP])
-  GNULIB_SIGDESCR_NP=0;      AC_SUBST([GNULIB_SIGDESCR_NP])
-  GNULIB_STRSIGNAL=0;        AC_SUBST([GNULIB_STRSIGNAL])
-  GNULIB_STRVERSCMP=0;       AC_SUBST([GNULIB_STRVERSCMP])
   HAVE_MBSLEN=0;             AC_SUBST([HAVE_MBSLEN])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_MEMCCPY=1;      AC_SUBST([GNULIB_MDA_MEMCCPY])
-  GNULIB_MDA_STRDUP=1;       AC_SUBST([GNULIB_MDA_STRDUP])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_EXPLICIT_BZERO=1;        AC_SUBST([HAVE_EXPLICIT_BZERO])
   HAVE_FFSL=1;                  AC_SUBST([HAVE_FFSL])
diff --git a/m4/strnlen.m4 b/m4/strnlen.m4
index bb9a680fdc..1d4f10616e 100644
--- a/m4/strnlen.m4
+++ b/m4/strnlen.m4
@@ -1,4 +1,4 @@
-# strnlen.m4 serial 13
+# strnlen.m4 serial 14
 dnl Copyright (C) 2002-2003, 2005-2007, 2009-2021 Free Software Foundation,
 dnl Inc.
 dnl This file is free software; the Free Software Foundation
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN([gl_FUNC_STRNLEN],
 [
-  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
 
   dnl Persuade glibc <string.h> to declare strnlen().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
diff --git a/m4/strtoll.m4 b/m4/strtoll.m4
index d2c9e5310d..14455dc3db 100644
--- a/m4/strtoll.m4
+++ b/m4/strtoll.m4
@@ -1,4 +1,4 @@
-# strtoll.m4 serial 8
+# strtoll.m4 serial 9
 dnl Copyright (C) 2002, 2004, 2006, 2008-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -7,8 +7,40 @@ dnl with or without modifications, as long as this notice is 
preserved.
 AC_DEFUN([gl_FUNC_STRTOLL],
 [
   AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
   AC_CHECK_FUNCS([strtoll])
-  if test $ac_cv_func_strtoll = no; then
+  if test $ac_cv_func_strtoll = yes; then
+    AC_CACHE_CHECK([whether strtoll works],
+      [gl_cv_func_strtoll_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[#include <stdlib.h>]],
+            [[int result = 0;
+              char *term;
+              /* This test fails on Minix and native Windows.  */
+              {
+                const char input[] = "0x";
+                (void) strtoll (input, &term, 16);
+                if (term != input + 1)
+                  result |= 1;
+              }
+              return result;
+            ]])
+         ],
+         [gl_cv_func_strtoll_works=yes],
+         [gl_cv_func_strtoll_works=no],
+         [case "$host_os" in
+                    # Guess no on native Windows.
+            mingw*) gl_cv_func_strtoll_works="guessing no" ;;
+            *)      gl_cv_func_strtoll_works="$gl_cross_guess_normal" ;;
+          esac
+         ])
+    ])
+    case "$gl_cv_func_strtoll_works" in
+      *yes) ;;
+      *)    REPLACE_STRTOLL=1 ;;
+    esac
+  else
     HAVE_STRTOLL=0
   fi
 ])
diff --git a/m4/sys_random_h.m4 b/m4/sys_random_h.m4
index 45e0469ba0..37bc31606b 100644
--- a/m4/sys_random_h.m4
+++ b/m4/sys_random_h.m4
@@ -1,10 +1,10 @@
-# sys_random_h.m4 serial 5
+# sys_random_h.m4 serial 8
 dnl Copyright (C) 2020-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_HEADER_SYS_RANDOM],
+AC_DEFUN_ONCE([gl_SYS_RANDOM_H],
 [
   AC_REQUIRE([gl_SYS_RANDOM_H_DEFAULTS])
   dnl <sys/random.h> is always overridden, because of GNULIB_POSIXCHECK.
@@ -35,18 +35,33 @@ AC_DEFUN([gl_HEADER_SYS_RANDOM],
     [getrandom])
 ])
 
+# gl_SYS_RANDOM_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SYS_RANDOM_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_SYS_RANDOM_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SYS_RANDOM_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_RANDOM_H_REQUIRE_DEFAULTS],
+[
+  
m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_RANDOM_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETRANDOM])
+  ])
+  
m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_RANDOM_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_RANDOM_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SYS_RANDOM_H_DEFAULTS],
 [
-  GNULIB_GETRANDOM=0;     AC_SUBST([GNULIB_GETRANDOM])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_GETRANDOM=1;       AC_SUBST([HAVE_GETRANDOM])
   REPLACE_GETRANDOM=0;    AC_SUBST([REPLACE_GETRANDOM])
diff --git a/m4/sys_select_h.m4 b/m4/sys_select_h.m4
index 4b33d312e5..2e7d140dee 100644
--- a/m4/sys_select_h.m4
+++ b/m4/sys_select_h.m4
@@ -1,13 +1,13 @@
-# sys_select_h.m4 serial 20
+# sys_select_h.m4 serial 23
 dnl Copyright (C) 2006-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-AC_DEFUN([gl_HEADER_SYS_SELECT],
+AC_DEFUN_ONCE([gl_SYS_SELECT_H],
 [
-  AC_REQUIRE([AC_C_RESTRICT])
   AC_REQUIRE([gl_SYS_SELECT_H_DEFAULTS])
+  AC_REQUIRE([AC_C_RESTRICT])
   AC_CACHE_CHECK([whether <sys/select.h> is self-contained],
     [gl_cv_header_sys_select_h_selfcontained],
     [
@@ -75,19 +75,34 @@ AC_DEFUN([gl_HEADER_SYS_SELECT],
     ]], [pselect select])
 ])
 
+# gl_SYS_SELECT_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SYS_SELECT_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_SYS_SELECT_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SYS_SELECT_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_SELECT_H_REQUIRE_DEFAULTS],
+[
+  
m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_SELECT_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PSELECT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SELECT])
+  ])
+  
m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_SELECT_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_SELECT_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SYS_SELECT_H_DEFAULTS],
 [
-  GNULIB_PSELECT=0; AC_SUBST([GNULIB_PSELECT])
-  GNULIB_SELECT=0; AC_SUBST([GNULIB_SELECT])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_PSELECT=1; AC_SUBST([HAVE_PSELECT])
   REPLACE_PSELECT=0; AC_SUBST([REPLACE_PSELECT])
diff --git a/m4/sys_socket_h.m4 b/m4/sys_socket_h.m4
index 503cb9668b..5676a0d217 100644
--- a/m4/sys_socket_h.m4
+++ b/m4/sys_socket_h.m4
@@ -1,4 +1,4 @@
-# sys_socket_h.m4 serial 25
+# sys_socket_h.m4 serial 28
 dnl Copyright (C) 2005-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,7 +6,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 dnl From Simon Josefsson.
 
-AC_DEFUN([gl_HEADER_SYS_SOCKET],
+AC_DEFUN_ONCE([gl_SYS_SOCKET_H],
 [
   AC_REQUIRE([gl_SYS_SOCKET_H_DEFAULTS])
   AC_REQUIRE([AC_CANONICAL_HOST])
@@ -156,32 +156,47 @@ AC_DEFUN([gl_PREREQ_SYS_H_WS2TCPIP],
   AC_SUBST([HAVE_WS2TCPIP_H])
 ])
 
+# gl_SYS_SOCKET_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SYS_SOCKET_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_SYS_SOCKET_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SYS_SOCKET_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_SOCKET_H_REQUIRE_DEFAULTS],
+[
+  
m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_SOCKET_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SOCKET])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CONNECT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCEPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_BIND])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPEERNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSOCKNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETSOCKOPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LISTEN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RECV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SEND])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RECVFROM])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SENDTO])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETSOCKOPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SHUTDOWN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCEPT4])
+  ])
+  
m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_SOCKET_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_SOCKET_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SYS_SOCKET_H_DEFAULTS],
 [
-  GNULIB_SOCKET=0;      AC_SUBST([GNULIB_SOCKET])
-  GNULIB_CONNECT=0;     AC_SUBST([GNULIB_CONNECT])
-  GNULIB_ACCEPT=0;      AC_SUBST([GNULIB_ACCEPT])
-  GNULIB_BIND=0;        AC_SUBST([GNULIB_BIND])
-  GNULIB_GETPEERNAME=0; AC_SUBST([GNULIB_GETPEERNAME])
-  GNULIB_GETSOCKNAME=0; AC_SUBST([GNULIB_GETSOCKNAME])
-  GNULIB_GETSOCKOPT=0;  AC_SUBST([GNULIB_GETSOCKOPT])
-  GNULIB_LISTEN=0;      AC_SUBST([GNULIB_LISTEN])
-  GNULIB_RECV=0;        AC_SUBST([GNULIB_RECV])
-  GNULIB_SEND=0;        AC_SUBST([GNULIB_SEND])
-  GNULIB_RECVFROM=0;    AC_SUBST([GNULIB_RECVFROM])
-  GNULIB_SENDTO=0;      AC_SUBST([GNULIB_SENDTO])
-  GNULIB_SETSOCKOPT=0;  AC_SUBST([GNULIB_SETSOCKOPT])
-  GNULIB_SHUTDOWN=0;    AC_SUBST([GNULIB_SHUTDOWN])
-  GNULIB_ACCEPT4=0;     AC_SUBST([GNULIB_ACCEPT4])
   HAVE_STRUCT_SOCKADDR_STORAGE=1; AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE])
   HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY=1;
                         AC_SUBST([HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY])
diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4
index 23cbdd28eb..ac91d425bb 100644
--- a/m4/sys_stat_h.m4
+++ b/m4/sys_stat_h.m4
@@ -1,4 +1,4 @@
-# sys_stat_h.m4 serial 38   -*- Autoconf -*-
+# sys_stat_h.m4 serial 41   -*- Autoconf -*-
 dnl Copyright (C) 2006-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -7,7 +7,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 dnl From Eric Blake.
 dnl Provide a GNU-like <sys/stat.h>.
 
-AC_DEFUN([gl_HEADER_SYS_STAT_H],
+AC_DEFUN_ONCE([gl_SYS_STAT_H],
 [
   AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
 
@@ -52,38 +52,53 @@ AC_DEFUN([gl_HEADER_SYS_STAT_H],
   AC_REQUIRE([AC_C_RESTRICT])
 ])
 
+# gl_SYS_STAT_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SYS_STAT_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SYS_STAT_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_STAT_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_UNISTD_H_REQUIRE_DEFAULTS dnl for REPLACE_FCHDIR
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHMODAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTATAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FUTIMENS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETUMASK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LCHMOD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LSTAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDIRAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKFIFO])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKFIFOAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKNOD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKNODAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UTIMENSAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OVERRIDES_STRUCT_STAT])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CHMOD], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_MKDIR], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_UMASK], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
 [
-  AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR
-  GNULIB_FCHMODAT=0;    AC_SUBST([GNULIB_FCHMODAT])
-  GNULIB_FSTAT=0;       AC_SUBST([GNULIB_FSTAT])
-  GNULIB_FSTATAT=0;     AC_SUBST([GNULIB_FSTATAT])
-  GNULIB_FUTIMENS=0;    AC_SUBST([GNULIB_FUTIMENS])
-  GNULIB_GETUMASK=0;    AC_SUBST([GNULIB_GETUMASK])
-  GNULIB_LCHMOD=0;      AC_SUBST([GNULIB_LCHMOD])
-  GNULIB_LSTAT=0;       AC_SUBST([GNULIB_LSTAT])
-  GNULIB_MKDIR=0;       AC_SUBST([GNULIB_MKDIR])
-  GNULIB_MKDIRAT=0;     AC_SUBST([GNULIB_MKDIRAT])
-  GNULIB_MKFIFO=0;      AC_SUBST([GNULIB_MKFIFO])
-  GNULIB_MKFIFOAT=0;    AC_SUBST([GNULIB_MKFIFOAT])
-  GNULIB_MKNOD=0;       AC_SUBST([GNULIB_MKNOD])
-  GNULIB_MKNODAT=0;     AC_SUBST([GNULIB_MKNODAT])
-  GNULIB_STAT=0;        AC_SUBST([GNULIB_STAT])
-  GNULIB_UTIMENSAT=0;   AC_SUBST([GNULIB_UTIMENSAT])
-  GNULIB_OVERRIDES_STRUCT_STAT=0; AC_SUBST([GNULIB_OVERRIDES_STRUCT_STAT])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_CHMOD=1;   AC_SUBST([GNULIB_MDA_CHMOD])
-  GNULIB_MDA_MKDIR=1;   AC_SUBST([GNULIB_MDA_MKDIR])
-  GNULIB_MDA_UMASK=1;   AC_SUBST([GNULIB_MDA_UMASK])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_FCHMODAT=1;      AC_SUBST([HAVE_FCHMODAT])
   HAVE_FSTATAT=1;       AC_SUBST([HAVE_FSTATAT])
diff --git a/m4/sys_time_h.m4 b/m4/sys_time_h.m4
index 64f133d513..c425a9639a 100644
--- a/m4/sys_time_h.m4
+++ b/m4/sys_time_h.m4
@@ -1,5 +1,5 @@
 # Configure a replacement for <sys/time.h>.
-# serial 9
+# serial 12
 
 # Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -8,18 +8,13 @@
 
 # Written by Paul Eggert and Martin Lambers.
 
-AC_DEFUN([gl_HEADER_SYS_TIME_H],
+AC_DEFUN_ONCE([gl_SYS_TIME_H],
 [
   dnl Use AC_REQUIRE here, so that the REPLACE_GETTIMEOFDAY=0 statement
   dnl below is expanded once only, before all REPLACE_GETTIMEOFDAY=1
   dnl statements that occur in other macros.
-  AC_REQUIRE([gl_HEADER_SYS_TIME_H_BODY])
-])
-
-AC_DEFUN([gl_HEADER_SYS_TIME_H_BODY],
-[
+  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_C_RESTRICT])
-  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
   AC_CHECK_HEADERS_ONCE([sys/time.h])
   gl_CHECK_NEXT_HEADERS([sys/time.h])
 
@@ -89,18 +84,33 @@ AC_DEFUN([gl_HEADER_SYS_TIME_H_BODY],
     ]], [gettimeofday])
 ])
 
+# gl_SYS_TIME_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_SYS_TIME_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_SYS_TIME_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
-AC_DEFUN([gl_HEADER_SYS_TIME_H_DEFAULTS],
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_TIME_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_TIME_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETTIMEOFDAY])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_TIME_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_TIME_H_DEFAULTS])
+])
+
+AC_DEFUN([gl_SYS_TIME_H_DEFAULTS],
 [
-  GNULIB_GETTIMEOFDAY=0;     AC_SUBST([GNULIB_GETTIMEOFDAY])
   dnl Assume POSIX behavior unless another module says otherwise.
   HAVE_GETTIMEOFDAY=1;       AC_SUBST([HAVE_GETTIMEOFDAY])
   HAVE_STRUCT_TIMEVAL=1;     AC_SUBST([HAVE_STRUCT_TIMEVAL])
diff --git a/m4/sys_types_h.m4 b/m4/sys_types_h.m4
index 2172c836d9..6dd6fee10c 100644
--- a/m4/sys_types_h.m4
+++ b/m4/sys_types_h.m4
@@ -1,4 +1,4 @@
-# sys_types_h.m4 serial 11
+# sys_types_h.m4 serial 13
 dnl Copyright (C) 2011-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,10 +6,11 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN_ONCE([gl_SYS_TYPES_H],
 [
+  AC_REQUIRE([gl_SYS_TYPES_H_DEFAULTS])
+
   dnl Use sane struct stat types in OpenVMS 8.2 and later.
   AC_DEFINE([_USE_STD_STAT], 1, [For standard stat data types on VMS.])
 
-  AC_REQUIRE([gl_SYS_TYPES_H_DEFAULTS])
   gl_NEXT_HEADERS([sys/types.h])
 
   dnl Ensure the type pid_t gets defined.
@@ -30,6 +31,17 @@ AC_DEFUN_ONCE([gl_SYS_TYPES_H],
   AC_SUBST([WINDOWS_STAT_INODES])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_SYS_TYPES_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_TYPE_H_MODULE_INDICATOR_DEFAULTS], [
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_SYS_TYPE_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_SYS_TYPES_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_SYS_TYPES_H_DEFAULTS],
 [
 ])
diff --git a/m4/time_h.m4 b/m4/time_h.m4
index b6a1aa3bc0..b57474b48b 100644
--- a/m4/time_h.m4
+++ b/m4/time_h.m4
@@ -2,7 +2,7 @@
 
 # Copyright (C) 2000-2001, 2003-2007, 2009-2021 Free Software Foundation, Inc.
 
-# serial 15
+# serial 18
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -10,16 +10,11 @@
 
 # Written by Paul Eggert and Jim Meyering.
 
-AC_DEFUN([gl_HEADER_TIME_H],
+AC_DEFUN_ONCE([gl_TIME_H],
 [
-  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
-  dnl once only, before all statements that occur in other macros.
-  AC_REQUIRE([gl_HEADER_TIME_H_BODY])
-])
-
-AC_DEFUN([gl_HEADER_TIME_H_BODY],
-[
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only, before all statements
+  dnl that occur in other macros.
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
 
   gl_NEXT_HEADERS([time.h])
   AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
@@ -111,30 +106,45 @@ AC_DEFUN([gl_CHECK_TYPE_STRUCT_TIMESPEC],
   AC_SUBST([UNISTD_H_DEFINES_STRUCT_TIMESPEC])
 ])
 
+# gl_TIME_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_TIME_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_TIME_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
-AC_DEFUN([gl_HEADER_TIME_H_DEFAULTS],
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_TIME_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_TIME_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CTIME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKTIME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALTIME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NANOSLEEP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRFTIME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STRPTIME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMEGM])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIMESPEC_GET])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TIME_RZ])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TZSET])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_TZSET], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_TIME_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
+])
+
+AC_DEFUN([gl_TIME_H_DEFAULTS],
 [
-  GNULIB_CTIME=0;                        AC_SUBST([GNULIB_CTIME])
-  GNULIB_MKTIME=0;                       AC_SUBST([GNULIB_MKTIME])
-  GNULIB_LOCALTIME=0;                    AC_SUBST([GNULIB_LOCALTIME])
-  GNULIB_NANOSLEEP=0;                    AC_SUBST([GNULIB_NANOSLEEP])
-  GNULIB_STRFTIME=0;                     AC_SUBST([GNULIB_STRFTIME])
-  GNULIB_STRPTIME=0;                     AC_SUBST([GNULIB_STRPTIME])
-  GNULIB_TIMEGM=0;                       AC_SUBST([GNULIB_TIMEGM])
-  GNULIB_TIMESPEC_GET=0;                 AC_SUBST([GNULIB_TIMESPEC_GET])
-  GNULIB_TIME_R=0;                       AC_SUBST([GNULIB_TIME_R])
-  GNULIB_TIME_RZ=0;                      AC_SUBST([GNULIB_TIME_RZ])
-  GNULIB_TZSET=0;                        AC_SUBST([GNULIB_TZSET])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_TZSET=1;                    AC_SUBST([GNULIB_MDA_TZSET])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_DECL_LOCALTIME_R=1;               AC_SUBST([HAVE_DECL_LOCALTIME_R])
   HAVE_NANOSLEEP=1;                      AC_SUBST([HAVE_NANOSLEEP])
diff --git a/m4/time_r.m4 b/m4/time_r.m4
index 713e93ac26..2d49b64f12 100644
--- a/m4/time_r.m4
+++ b/m4/time_r.m4
@@ -12,7 +12,7 @@ AC_DEFUN([gl_TIME_R],
   dnl Persuade glibc and Solaris <time.h> to declare localtime_r.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
 
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_C_RESTRICT])
 
   dnl Some systems don't declare localtime_r() and gmtime_r() if _REENTRANT is
diff --git a/m4/time_rz.m4 b/m4/time_rz.m4
index 34ef0bab4b..c5e85dc625 100644
--- a/m4/time_rz.m4
+++ b/m4/time_rz.m4
@@ -10,7 +10,7 @@ dnl Written by Paul Eggert.
 AC_DEFUN([gl_TIME_RZ],
 [
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
   AC_REQUIRE([AC_STRUCT_TIMEZONE])
 
   # On Mac OS X 10.6, localtime loops forever with some time_t values.
diff --git a/m4/timegm.m4 b/m4/timegm.m4
index 098c857e7f..58123beb0c 100644
--- a/m4/timegm.m4
+++ b/m4/timegm.m4
@@ -1,4 +1,4 @@
-# timegm.m4 serial 12
+# timegm.m4 serial 13
 dnl Copyright (C) 2003, 2007, 2009-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,7 +6,7 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 AC_DEFUN([gl_FUNC_TIMEGM],
 [
-  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+  AC_REQUIRE([gl_TIME_H_DEFAULTS])
   AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
   REPLACE_TIMEGM=0
   AC_CHECK_FUNCS_ONCE([timegm])
diff --git a/m4/timer_time.m4 b/m4/timer_time.m4
index f0e5785e9a..003e36e9d1 100644
--- a/m4/timer_time.m4
+++ b/m4/timer_time.m4
@@ -1,4 +1,4 @@
-# timer_time.m4 serial 4
+# timer_time.m4 serial 5
 dnl Copyright (C) 2011-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -18,9 +18,13 @@ AC_DEFUN([gl_TIMER_TIME],
   dnl the threadlib.m4 file that is installed in $PREFIX/share/aclocal/.
   m4_ifdef([gl_][PTHREADLIB], [AC_REQUIRE([gl_][PTHREADLIB])])
 
+  AC_CHECK_DECL([timer_settime], [], [],
+                [[#include <time.h>
+                ]])
   LIB_TIMER_TIME=
   AC_SUBST([LIB_TIMER_TIME])
-  gl_saved_libs=$LIBS
+  AS_IF([test "$ac_cv_have_decl_timer_settime" = yes], [
+    gl_saved_libs=$LIBS
     AC_SEARCH_LIBS([timer_settime], [rt posix4],
                    [test "$ac_cv_search_timer_settime" = "none required" ||
                     LIB_TIMER_TIME=$ac_cv_search_timer_settime])
@@ -40,5 +44,6 @@ AC_DEFUN([gl_TIMER_TIME],
          ],
          [LIB_TIMER_TIME="$LIB_TIMER_TIME $LIBPMULTITHREAD"])])
     AC_CHECK_FUNCS([timer_settime])
-  LIBS=$gl_saved_libs
+    LIBS=$gl_saved_libs
+  ])
 ])
diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4
index 0f26fb908d..0ce4ea4511 100644
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 85
+# unistd_h.m4 serial 89
 dnl Copyright (C) 2006-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -6,10 +6,10 @@ dnl with or without modifications, as long as this notice is 
preserved.
 
 dnl Written by Simon Josefsson, Bruno Haible.
 
-AC_DEFUN([gl_UNISTD_H],
+AC_DEFUN_ONCE([gl_UNISTD_H],
 [
-  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
-  dnl once only, before all statements that occur in other macros.
+  dnl Ensure to expand the default settings once only, before all statements
+  dnl that occur in other macros.
   AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
 
   gl_CHECK_NEXT_HEADERS([unistd.h])
@@ -59,100 +59,116 @@ AC_DEFUN([gl_UNISTD_H],
   fi
 ])
 
+# gl_UNISTD_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
 AC_DEFUN([gl_UNISTD_MODULE_INDICATOR],
 [
-  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
-  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  dnl Ensure to expand the default settings once only.
+  gl_UNISTD_H_REQUIRE_DEFAULTS
   gl_MODULE_INDICATOR_SET_VARIABLE([$1])
   dnl Define it also as a C macro, for the benefit of the unit tests.
   gl_MODULE_INDICATOR_FOR_TESTS([$1])
 ])
 
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_UNISTD_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_UNISTD_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ACCESS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHOWN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CLOSE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_COPY_FILE_RANGE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP2])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUP3])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ENVIRON])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EUIDACCESS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECLE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECLP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECV])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_EXECVPE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FACCESSAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHOWNAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FDATASYNC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSYNC])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FTRUNCATE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETCWD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDOMAINNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETDTABLESIZE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETENTROPY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETGROUPS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETHOSTNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOGIN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOGIN_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETOPT_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPAGESIZE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETPASS])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETUSERSHELL])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GROUP_MEMBER])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISATTY])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LCHOWN])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LINK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LINKAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LSEEK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PIPE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PIPE2])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PREAD])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_PWRITE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READ])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READLINK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_READLINKAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RMDIR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETHOSTNAME])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SLEEP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYMLINK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SYMLINKAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TRUNCATE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TTYNAME_R])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_GETOPT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_NONBLOCKING])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNISTD_H_SIGPIPE])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLINK])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_UNLINKAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_USLEEP])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_WRITE])
+    dnl Support Microsoft deprecated alias function names by default.
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ACCESS], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CHDIR], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CLOSE], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_DUP], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_DUP2], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECL], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECLE], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECLP], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECV], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVE], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVP], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_EXECVPE], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETCWD], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_GETPID], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_ISATTY], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_LSEEK], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_READ], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_RMDIR], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_SWAB], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_UNLINK], [1])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_WRITE], [1])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_UNISTD_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+])
+
 AC_DEFUN([gl_UNISTD_H_DEFAULTS],
 [
-  GNULIB_ACCESS=0;               AC_SUBST([GNULIB_ACCESS])
-  GNULIB_CHDIR=0;                AC_SUBST([GNULIB_CHDIR])
-  GNULIB_CHOWN=0;                AC_SUBST([GNULIB_CHOWN])
-  GNULIB_CLOSE=0;                AC_SUBST([GNULIB_CLOSE])
-  GNULIB_COPY_FILE_RANGE=0;      AC_SUBST([GNULIB_COPY_FILE_RANGE])
-  GNULIB_DUP=0;                  AC_SUBST([GNULIB_DUP])
-  GNULIB_DUP2=0;                 AC_SUBST([GNULIB_DUP2])
-  GNULIB_DUP3=0;                 AC_SUBST([GNULIB_DUP3])
-  GNULIB_ENVIRON=0;              AC_SUBST([GNULIB_ENVIRON])
-  GNULIB_EUIDACCESS=0;           AC_SUBST([GNULIB_EUIDACCESS])
-  GNULIB_EXECL=0;                AC_SUBST([GNULIB_EXECL])
-  GNULIB_EXECLE=0;               AC_SUBST([GNULIB_EXECLE])
-  GNULIB_EXECLP=0;               AC_SUBST([GNULIB_EXECLP])
-  GNULIB_EXECV=0;                AC_SUBST([GNULIB_EXECV])
-  GNULIB_EXECVE=0;               AC_SUBST([GNULIB_EXECVE])
-  GNULIB_EXECVP=0;               AC_SUBST([GNULIB_EXECVP])
-  GNULIB_EXECVPE=0;              AC_SUBST([GNULIB_EXECVPE])
-  GNULIB_FACCESSAT=0;            AC_SUBST([GNULIB_FACCESSAT])
-  GNULIB_FCHDIR=0;               AC_SUBST([GNULIB_FCHDIR])
-  GNULIB_FCHOWNAT=0;             AC_SUBST([GNULIB_FCHOWNAT])
-  GNULIB_FDATASYNC=0;            AC_SUBST([GNULIB_FDATASYNC])
-  GNULIB_FSYNC=0;                AC_SUBST([GNULIB_FSYNC])
-  GNULIB_FTRUNCATE=0;            AC_SUBST([GNULIB_FTRUNCATE])
-  GNULIB_GETCWD=0;               AC_SUBST([GNULIB_GETCWD])
-  GNULIB_GETDOMAINNAME=0;        AC_SUBST([GNULIB_GETDOMAINNAME])
-  GNULIB_GETDTABLESIZE=0;        AC_SUBST([GNULIB_GETDTABLESIZE])
-  GNULIB_GETENTROPY=0;           AC_SUBST([GNULIB_GETENTROPY])
-  GNULIB_GETGROUPS=0;            AC_SUBST([GNULIB_GETGROUPS])
-  GNULIB_GETHOSTNAME=0;          AC_SUBST([GNULIB_GETHOSTNAME])
-  GNULIB_GETLOGIN=0;             AC_SUBST([GNULIB_GETLOGIN])
-  GNULIB_GETLOGIN_R=0;           AC_SUBST([GNULIB_GETLOGIN_R])
-  GNULIB_GETOPT_POSIX=0;         AC_SUBST([GNULIB_GETOPT_POSIX])
-  GNULIB_GETPAGESIZE=0;          AC_SUBST([GNULIB_GETPAGESIZE])
-  GNULIB_GETPASS=0;              AC_SUBST([GNULIB_GETPASS])
-  GNULIB_GETUSERSHELL=0;         AC_SUBST([GNULIB_GETUSERSHELL])
-  GNULIB_GROUP_MEMBER=0;         AC_SUBST([GNULIB_GROUP_MEMBER])
-  GNULIB_ISATTY=0;               AC_SUBST([GNULIB_ISATTY])
-  GNULIB_LCHOWN=0;               AC_SUBST([GNULIB_LCHOWN])
-  GNULIB_LINK=0;                 AC_SUBST([GNULIB_LINK])
-  GNULIB_LINKAT=0;               AC_SUBST([GNULIB_LINKAT])
-  GNULIB_LSEEK=0;                AC_SUBST([GNULIB_LSEEK])
-  GNULIB_PIPE=0;                 AC_SUBST([GNULIB_PIPE])
-  GNULIB_PIPE2=0;                AC_SUBST([GNULIB_PIPE2])
-  GNULIB_PREAD=0;                AC_SUBST([GNULIB_PREAD])
-  GNULIB_PWRITE=0;               AC_SUBST([GNULIB_PWRITE])
-  GNULIB_READ=0;                 AC_SUBST([GNULIB_READ])
-  GNULIB_READLINK=0;             AC_SUBST([GNULIB_READLINK])
-  GNULIB_READLINKAT=0;           AC_SUBST([GNULIB_READLINKAT])
-  GNULIB_RMDIR=0;                AC_SUBST([GNULIB_RMDIR])
-  GNULIB_SETHOSTNAME=0;          AC_SUBST([GNULIB_SETHOSTNAME])
-  GNULIB_SLEEP=0;                AC_SUBST([GNULIB_SLEEP])
-  GNULIB_SYMLINK=0;              AC_SUBST([GNULIB_SYMLINK])
-  GNULIB_SYMLINKAT=0;            AC_SUBST([GNULIB_SYMLINKAT])
-  GNULIB_TRUNCATE=0;             AC_SUBST([GNULIB_TRUNCATE])
-  GNULIB_TTYNAME_R=0;            AC_SUBST([GNULIB_TTYNAME_R])
-  GNULIB_UNISTD_H_NONBLOCKING=0; AC_SUBST([GNULIB_UNISTD_H_NONBLOCKING])
-  GNULIB_UNISTD_H_SIGPIPE=0;     AC_SUBST([GNULIB_UNISTD_H_SIGPIPE])
-  GNULIB_UNLINK=0;               AC_SUBST([GNULIB_UNLINK])
-  GNULIB_UNLINKAT=0;             AC_SUBST([GNULIB_UNLINKAT])
-  GNULIB_USLEEP=0;               AC_SUBST([GNULIB_USLEEP])
-  GNULIB_WRITE=0;                AC_SUBST([GNULIB_WRITE])
-  dnl Support Microsoft deprecated alias function names by default.
-  GNULIB_MDA_ACCESS=1;           AC_SUBST([GNULIB_MDA_ACCESS])
-  GNULIB_MDA_CHDIR=1;            AC_SUBST([GNULIB_MDA_CHDIR])
-  GNULIB_MDA_CLOSE=1;            AC_SUBST([GNULIB_MDA_CLOSE])
-  GNULIB_MDA_DUP=1;              AC_SUBST([GNULIB_MDA_DUP])
-  GNULIB_MDA_DUP2=1;             AC_SUBST([GNULIB_MDA_DUP2])
-  GNULIB_MDA_EXECL=1;            AC_SUBST([GNULIB_MDA_EXECL])
-  GNULIB_MDA_EXECLE=1;           AC_SUBST([GNULIB_MDA_EXECLE])
-  GNULIB_MDA_EXECLP=1;           AC_SUBST([GNULIB_MDA_EXECLP])
-  GNULIB_MDA_EXECV=1;            AC_SUBST([GNULIB_MDA_EXECV])
-  GNULIB_MDA_EXECVE=1;           AC_SUBST([GNULIB_MDA_EXECVE])
-  GNULIB_MDA_EXECVP=1;           AC_SUBST([GNULIB_MDA_EXECVP])
-  GNULIB_MDA_EXECVPE=1;          AC_SUBST([GNULIB_MDA_EXECVPE])
-  GNULIB_MDA_GETCWD=1;           AC_SUBST([GNULIB_MDA_GETCWD])
-  GNULIB_MDA_GETPID=1;           AC_SUBST([GNULIB_MDA_GETPID])
-  GNULIB_MDA_ISATTY=1;           AC_SUBST([GNULIB_MDA_ISATTY])
-  GNULIB_MDA_LSEEK=1;            AC_SUBST([GNULIB_MDA_LSEEK])
-  GNULIB_MDA_READ=1;             AC_SUBST([GNULIB_MDA_READ])
-  GNULIB_MDA_RMDIR=1;            AC_SUBST([GNULIB_MDA_RMDIR])
-  GNULIB_MDA_SWAB=1;             AC_SUBST([GNULIB_MDA_SWAB])
-  GNULIB_MDA_UNLINK=1;           AC_SUBST([GNULIB_MDA_UNLINK])
-  GNULIB_MDA_WRITE=1;            AC_SUBST([GNULIB_MDA_WRITE])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_CHOWN=1;           AC_SUBST([HAVE_CHOWN])
   HAVE_COPY_FILE_RANGE=1; AC_SUBST([HAVE_COPY_FILE_RANGE])
diff --git a/m4/unlocked-io.m4 b/m4/unlocked-io.m4
index a2dc8a144a..b689020ff4 100644
--- a/m4/unlocked-io.m4
+++ b/m4/unlocked-io.m4
@@ -1,4 +1,4 @@
-# unlocked-io.m4 serial 15
+# unlocked-io.m4 serial 16
 
 # Copyright (C) 1998-2006, 2009-2021 Free Software Foundation, Inc.
 #
@@ -16,11 +16,6 @@ dnl on Solaris 2.6).
 
 AC_DEFUN([gl_FUNC_GLIBC_UNLOCKED_IO],
 [
-  AC_DEFINE([USE_UNLOCKED_IO], [1],
-    [Define to 1 if you want getc etc. to use unlocked I/O if available.
-     Unlocked I/O can improve performance in unithreaded apps,
-     but it is not safe for multithreaded apps.])
-
   dnl Persuade glibc and Solaris <stdio.h> to declare
   dnl fgets_unlocked(), fputs_unlocked() etc.
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
diff --git a/m4/year2038.m4 b/m4/year2038.m4
new file mode 100644
index 0000000000..da0f8d7303
--- /dev/null
+++ b/m4/year2038.m4
@@ -0,0 +1,124 @@
+# year2038.m4 serial 7
+dnl Copyright (C) 2017-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Attempt to ensure that 'time_t' can go past the year 2038 and that
+dnl the functions 'time', 'stat', etc. work with post-2038 timestamps.
+
+AC_DEFUN([gl_YEAR2038_EARLY],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  case "$host_os" in
+    mingw*)
+      AC_DEFINE([__MINGW_USE_VC2005_COMPAT], [1],
+        [For 64-bit time_t on 32-bit mingw.])
+      ;;
+  esac
+])
+
+# gl_YEAR2038_TEST_INCLUDES
+# -------------------------
+AC_DEFUN([gl_YEAR2038_TEST_INCLUDES],
+[[
+  #include <time.h>
+  /* Check that time_t can represent 2**32 - 1 correctly.  */
+  #define LARGE_TIME_T \\
+    ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30)))
+  int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535
+                           && LARGE_TIME_T % 65537 == 0)
+                          ? 1 : -1];
+]])
+
+# gl_YEAR2038_BODY(REQUIRE-YEAR2038-SAFE)
+-----------------------------------------
+AC_DEFUN([gl_YEAR2038_BODY],
+[
+ AC_ARG_ENABLE([year2038],
+   [  --disable-year2038      omit support for timestamps past the year 2038])
+ AS_IF([test "$enable_year2038" != no],
+ [
+  dnl On many systems, time_t is already a 64-bit type.
+  dnl On those systems where time_t is still 32-bit, it requires kernel
+  dnl and libc support to make it 64-bit. For glibc 2.34 and later on Linux,
+  dnl defining _TIME_BITS=64 and _FILE_OFFSET_BITS=64 is needed on x86 and ARM.
+  dnl
+  dnl On native Windows, the system include files define types __time32_t
+  dnl and __time64_t. By default, time_t is an alias of
+  dnl   - __time32_t on 32-bit mingw,
+  dnl   - __time64_t on 64-bit mingw and on MSVC (since MSVC 8).
+  dnl But when compiling with -D__MINGW_USE_VC2005_COMPAT, time_t is an
+  dnl alias of __time64_t.
+  dnl And when compiling with -D_USE_32BIT_TIME_T, time_t is an alias of
+  dnl __time32_t.
+  AC_CACHE_CHECK([for time_t past the year 2038], [gl_cv_type_time_t_y2038],
+    [AC_COMPILE_IFELSE(
+       [AC_LANG_SOURCE([gl_YEAR2038_TEST_INCLUDES])],
+       [gl_cv_type_time_t_y2038=yes], [gl_cv_type_time_t_y2038=no])
+    ])
+  if test "$gl_cv_type_time_t_y2038" = no; then
+    AC_CACHE_CHECK([for 64-bit time_t with _TIME_BITS=64],
+      [gl_cv_type_time_t_bits_macro],
+      [AC_COMPILE_IFELSE(
+         [AC_LANG_SOURCE([[#define _TIME_BITS 64
+                           #define _FILE_OFFSET_BITS 64
+                           ]gl_YEAR2038_TEST_INCLUDES])],
+         [gl_cv_type_time_t_bits_macro=yes],
+         [gl_cv_type_time_t_bits_macro=no])
+      ])
+    if test "$gl_cv_type_time_t_bits_macro" = yes; then
+      AC_DEFINE([_TIME_BITS], [64],
+        [Number of bits in a timestamp, on hosts where this is settable.])
+      dnl AC_SYS_LARGFILE also defines this; it's OK if we do too.
+      AC_DEFINE([_FILE_OFFSET_BITS], [64],
+        [Number of bits in a file offset, on hosts where this is settable.])
+      gl_cv_type_time_t_y2038=yes
+    fi
+  fi
+  if test $gl_cv_type_time_t_y2038 = no; then
+    AC_COMPILE_IFELSE(
+      [AC_LANG_SOURCE(
+         [[#ifdef _USE_32BIT_TIME_T
+             int ok;
+           #else
+             error fail
+           #endif
+         ]])],
+      [AC_MSG_FAILURE(
+         [The 'time_t' type stops working after January 2038.
+          Remove _USE_32BIT_TIME_T from the compiler flags.])],
+      [# If not cross-compiling and $1 says we should check,
+       # and 'touch' works with a large timestamp, then evidently wider time_t
+       # is desired and supported, so fail and ask the builder to fix the
+       # problem.  Otherwise, just warn the builder.
+       m4_ifval([$1],
+         [if test $cross_compiling = no \
+             && TZ=UTC0 touch -t 210602070628.15 conftest.time 2>/dev/null; 
then
+            case `TZ=UTC0 LC_ALL=C ls -l conftest.time 2>/dev/null` in
+              *'Feb  7  2106'* | *'Feb  7 17:10'*)
+                AC_MSG_FAILURE(
+                  [The 'time_t' type stops working after January 2038,
+                   and your system appears to support a wider 'time_t'.
+                   Try configuring with 'CC="${CC} -m64"'.
+                   To build with a 32-bit time_t anyway (not recommended),
+                   configure with '--disable-year2038'.]);;
+            esac
+            rm -f conftest.time
+          fi])
+       if test "$gl_warned_about_y2038" != yes; then
+         AC_MSG_WARN(
+           [The 'time_t' type stops working after January 2038,
+            and this package needs a wider 'time_t' type
+            if there is any way to access timestamps after that.
+            Configure with 'CC="${CC} -m64"' perhaps?])
+         gl_warned_about_y2038=yes
+       fi
+      ])
+  fi])
+])
+
+AC_DEFUN([gl_YEAR2038],
+[
+  gl_YEAR2038_BODY([require-year2038-safe])
+])
diff --git a/make-dist b/make-dist
index 7074bb801b..eb040150d9 100755
--- a/make-dist
+++ b/make-dist
@@ -366,9 +366,9 @@ possibly_non_vc_files="
   src/config.in
 "$(
   find admin doc etc lisp \
-    \( -name '*.el' -o -name '*.elc' -o -name '*.map' -o -name '*.stamp' \
-       -o -name '*.texi' -o -name '*.tex' -o -name '*.txt' \) \
-    ! -name 'site-init*' ! -name 'site-load*' ! -name 'default*'
+   \( -name '*.el' -o -name '*.elc' -o -name '*.map' -o -name '*.stamp' \
+      -o -name '*.texi' -o -name '*.tex' -o -name '*.txt' -o -name '*.pdf' \) \
+   ! -name 'site-init*' ! -name 'site-load*' ! -name 'default*'
 ) || exit
 
 if [ $with_info = yes ]; then
diff --git a/msdos/autogen/config.in b/msdos/autogen/config.in
index 263cba15a2..560f5f346f 100644
--- a/msdos/autogen/config.in
+++ b/msdos/autogen/config.in
@@ -1712,7 +1712,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
   /* Suppress GCC's bogus "no previous prototype for 'FOO'"
      and "no previous declaration for 'FOO'"  diagnostics,
      when FOO is an inline function in the header; see
-     <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>.  */
+     <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54113>.  */
 # define _GL_INLINE_HEADER_BEGIN \
     _Pragma ("GCC diagnostic push") \
     _Pragma ("GCC diagnostic ignored \"-Wmissing-prototypes\"") \
diff --git a/msdos/sed2v2.inp b/msdos/sed2v2.inp
index ce45a7c80e..ef4bc24fe4 100644
--- a/msdos/sed2v2.inp
+++ b/msdos/sed2v2.inp
@@ -66,7 +66,7 @@
 /^#undef PACKAGE_NAME/s/^.*$/#define PACKAGE_NAME ""/
 /^#undef PACKAGE_STRING/s/^.*$/#define PACKAGE_STRING ""/
 /^#undef PACKAGE_TARNAME/s/^.*$/#define PACKAGE_TARNAME ""/
-/^#undef PACKAGE_VERSION/s/^.*$/#define PACKAGE_VERSION "28.0.50"/
+/^#undef PACKAGE_VERSION/s/^.*$/#define PACKAGE_VERSION "29.0.50"/
 /^#undef SYSTEM_TYPE/s/^.*$/#define SYSTEM_TYPE "ms-dos"/
 /^#undef HAVE_DECL_GETENV/s/^.*$/#define HAVE_DECL_GETENV 1/
 /^#undef SYS_SIGLIST_DECLARED/s/^.*$/#define SYS_SIGLIST_DECLARED 1/
diff --git a/nextstep/templates/Info.plist.in b/nextstep/templates/Info.plist.in
index 66cde9f4ee..f9f0ec0857 100644
--- a/nextstep/templates/Info.plist.in
+++ b/nextstep/templates/Info.plist.in
@@ -555,7 +555,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.
                        <key>UTTypeIdentifier</key>
                        <string>org.orgmode.org</string>
                        <key>UTTypeReferenceURL</key>
-                       <string>http://orgmode.org</string>
+                       <string>https://orgmode.org</string>
                        <key>UTTypeTagSpecification</key>
                        <dict>
                                <key>public.filename-extension</key>
diff --git a/nt/ChangeLog.1 b/nt/ChangeLog.1
index 247f10a733..d0aed936d1 100644
--- a/nt/ChangeLog.1
+++ b/nt/ChangeLog.1
@@ -222,7 +222,7 @@
        as earlier versions.  This is so GetVersion and GetVersionEx APIs
        used for bug reporting and other purposes return accurate version
        number on Windows 8.1.  See the discussion on MSDN
-       http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
+       https://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
        for more details.
 
 2013-12-12  Eli Zaretskii  <eliz@gnu.org>
diff --git a/nt/INSTALL b/nt/INSTALL
index 9f543151a9..c324fb4ae7 100644
--- a/nt/INSTALL
+++ b/nt/INSTALL
@@ -488,6 +488,7 @@ build will run on Windows 9X and newer systems).
        Does Emacs use a gif library?                           yes
        Does Emacs use a png library?                           yes
        Does Emacs use -lrsvg-2?                                yes
+       Does Emacs use -lwebp?                                  yes
        Does Emacs use cairo?                                   no
        Does Emacs use -llcms2?                                 yes
        Does Emacs use imagemagick?                             no
@@ -597,8 +598,8 @@ build will run on Windows 9X and newer systems).
 * Optional image library support
 
   In addition to its "native" image formats (pbm and xbm), Emacs can
-  handle other image types: xpm, tiff, gif, png, jpeg and experimental
-  support for svg.
+  handle other image types: xpm, tiff, gif, png, jpeg, webp and
+  experimental support for svg.
 
   To build Emacs with support for them, the corresponding headers must
   be in the include path and libraries should be where the linker
@@ -736,6 +737,18 @@ build will run on Windows 9X and newer systems).
   without it by specifying the --without-rsvg switch to the configure
   script.
 
+  For WebP images you will need libwebp.  You can find it here:
+
+    http://sourceforge.net/projects/ezwinports/files/
+
+  Note: the MS-Windows binary distribution on the Google site:
+
+    https://developers.google.com/speed/webp/
+
+  was compiled by MSVC, and includes only static libraries, no DLLs.
+  So you cannot use that to build Emacs with WebP support on
+  MS-Windows, as that needs libwebp as a DLL.
+
   Binaries for the other image libraries can be found on the
   ezwinports site or at the GnuWin32 project (the latter are generally
   very old, so not recommended).  Note specifically that, due to some
diff --git a/nt/INSTALL.W64 b/nt/INSTALL.W64
index 8f0d0c9528..c3845d5b17 100644
--- a/nt/INSTALL.W64
+++ b/nt/INSTALL.W64
@@ -51,6 +51,7 @@ packages (you can copy and paste it into the shell with Shift 
+ Insert):
   mingw-w64-x86_64-libpng \
   mingw-w64-x86_64-libjpeg-turbo \
   mingw-w64-x86_64-librsvg \
+  mingw-w64-x86_64-libwebp \
   mingw-w64-x86_64-lcms2 \
   mingw-w64-x86_64-jansson \
   mingw-w64-x86_64-libxml2 \
diff --git a/nt/Makefile.in b/nt/Makefile.in
index 3274ff924f..811680da85 100644
--- a/nt/Makefile.in
+++ b/nt/Makefile.in
@@ -144,6 +144,7 @@ LIBS_ADDPM = -lole32 -luuid
 ## Compilation and linking flags
 BASE_CFLAGS = $(C_SWITCH_SYSTEM) $(C_SWITCH_MACHINE) \
              $(WARN_CFLAGS) $(WERROR_CFLAGS) \
+             -I../src -I${srcdir}/../src -I../lib -I${srcdir}/../lib \
              -I. -I${srcdir}
 
 ALL_CFLAGS = ${BASE_CFLAGS} ${PROFILING_CFLAGS} ${LDFLAGS} ${CPPFLAGS} 
${CFLAGS}
diff --git a/nt/README.W32 b/nt/README.W32
index ed5673334a..495af0baed 100644
--- a/nt/README.W32
+++ b/nt/README.W32
@@ -1,7 +1,7 @@
 Copyright (C) 2001-2021 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
-               Emacs version 28.0.50 for MS-Windows
+               Emacs version 29.0.50 for MS-Windows
 
   This README file describes how to set up and run a precompiled
   distribution of the latest version of GNU Emacs for MS-Windows.  You
diff --git a/nt/addpm.c b/nt/addpm.c
index f54a6ea9f7..4fbcf6c05e 100644
--- a/nt/addpm.c
+++ b/nt/addpm.c
@@ -34,6 +34,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
    installed, then the DDE fallback for creating icons the Windows 3.1
    progman way will be used instead, but that is prone to lockups
    caused by other applications not servicing their message queues.  */
+
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <malloc.h>
diff --git a/nt/cmdproxy.c b/nt/cmdproxy.c
index 224f68b1e8..f5a0550aa9 100644
--- a/nt/cmdproxy.c
+++ b/nt/cmdproxy.c
@@ -27,6 +27,9 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <windows.h>
 
 #include <stdarg.h>  /* va_args */
diff --git a/nt/ddeclient.c b/nt/ddeclient.c
index c577bfcfa9..0a44cbfd77 100644
--- a/nt/ddeclient.c
+++ b/nt/ddeclient.c
@@ -16,6 +16,9 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <windows.h>
 #include <ddeml.h>
 #include <stdlib.h>
diff --git a/nt/gnulib-cfg.mk b/nt/gnulib-cfg.mk
index c85b9150f0..e9f00e748e 100644
--- a/nt/gnulib-cfg.mk
+++ b/nt/gnulib-cfg.mk
@@ -49,10 +49,14 @@ OMIT_GNULIB_MODULE_dirent = true
 OMIT_GNULIB_MODULE_dirfd = true
 OMIT_GNULIB_MODULE_fcntl = true
 OMIT_GNULIB_MODULE_fcntl-h = true
+OMIT_GNULIB_MODULE_free-posix = true
 OMIT_GNULIB_MODULE_fsusage = true
 OMIT_GNULIB_MODULE_inttypes-incomplete = true
+OMIT_GNULIB_MODULE_malloc-posix = true
 OMIT_GNULIB_MODULE_open = true
 OMIT_GNULIB_MODULE_pipe2 = true
+OMIT_GNULIB_MODULE_realloc-gnu = true
+OMIT_GNULIB_MODULE_realloc-posix = true
 OMIT_GNULIB_MODULE_secure_getenv = true
 OMIT_GNULIB_MODULE_signal-h = true
 OMIT_GNULIB_MODULE_stdio = true
@@ -69,3 +73,4 @@ OMIT_GNULIB_MODULE_lchmod = true
 OMIT_GNULIB_MODULE_futimens = true
 OMIT_GNULIB_MODULE_utimensat = true
 OMIT_GNULIB_MODULE_file-has-acl = true
+OMIT_GNULIB_MODULE_nproc = true
diff --git a/nt/preprep.c b/nt/preprep.c
index 78ed1c3238..8b054b19a7 100644
--- a/nt/preprep.c
+++ b/nt/preprep.c
@@ -21,6 +21,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.
      based on code from addsection.c
 */
 
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <fcntl.h>
diff --git a/nt/runemacs.c b/nt/runemacs.c
index 308e856be2..b4ed9fb156 100644
--- a/nt/runemacs.c
+++ b/nt/runemacs.c
@@ -40,6 +40,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 /* #define CHOOSE_NEWEST_EXE */
 
+#define DEFER_MS_W32_H
+#include <config.h>
+
 #include <windows.h>
 #include <string.h>
 #include <malloc.h>
diff --git a/oldXMenu/AddPane.c b/oldXMenu/AddPane.c
index b14b3e82e4..8616de804f 100644
--- a/oldXMenu/AddPane.c
+++ b/oldXMenu/AddPane.c
@@ -30,8 +30,8 @@ without express or implied warranty.
  *
  */
 
-#include <string.h>
 #include "XMenuInt.h"
+#include <string.h>
 
 int
 XMenuAddPane(Display *display, register XMenu *menu, register char const 
*label, int active)
diff --git a/oldXMenu/AddSel.c b/oldXMenu/AddSel.c
index 9596caed0e..d81c54b870 100644
--- a/oldXMenu/AddSel.c
+++ b/oldXMenu/AddSel.c
@@ -31,8 +31,8 @@ without express or implied warranty.
  *
  */
 
-#include <string.h>
 #include "XMenuInt.h"
+#include <string.h>
 
 int
 XMenuAddSelection(Display *display, register XMenu *menu, register int p_num, 
char *data, char *label, int active, char const *help)
diff --git a/src/Makefile.in b/src/Makefile.in
index c11d96d2c4..e82eb4fa9e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -55,6 +55,8 @@ lwlibdir = ../lwlib
 # Configuration files for .o files to depend on.
 config_h = config.h $(srcdir)/conf_post.h
 
+HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@
+
 ## ns-app if NS self contained app, else empty.
 OTHER_FILES = @OTHER_FILES@
 
@@ -122,7 +124,7 @@ LIB_MATH=@LIB_MATH@
 ## -lpthread, or empty.
 LIB_PTHREAD=@LIB_PTHREAD@
 
-LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@
+LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@
 
 XCB_LIBS=@XCB_LIBS@
 XFT_LIBS=@XFT_LIBS@
@@ -221,6 +223,8 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
 RSVG_LIBS= @RSVG_LIBS@
 RSVG_CFLAGS= @RSVG_CFLAGS@
 
+WEBP_CFLAGS= @WEBP_CFLAGS@
+
 WEBKIT_LIBS= @WEBKIT_LIBS@
 WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
 
@@ -370,7 +374,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
   $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
   $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(LIBGCCJIT_CFLAGS) $(DBUS_CFLAGS) \
   $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
-  $(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \
+  $(WEBKIT_CFLAGS) $(WEBP_CFLAGS) $(LCMS2_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
   $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \
@@ -449,6 +453,9 @@ ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
 
 # Must be first, before dep inclusion!
 all: emacs$(EXEEXT) $(pdmp) $(OTHER_FILES)
+ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
+all: ../native-lisp
+endif
 .PHONY: all
 
 dmpstruct_headers=$(srcdir)/lisp.h $(srcdir)/buffer.h \
@@ -775,6 +782,51 @@ tags: TAGS ../lisp/TAGS $(lwlibdir)/TAGS
        @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="$(bootstrap_exe)"\
                THEFILE=$< $<c
 
+ifeq ($(HAVE_NATIVE_COMP):$(NATIVE_DISABLED),yes:)
+## The following rules are used only when building a source tarball
+## for the first time, when the native-lisp/ directory doesn't yet
+## exist and needs to be created and populated with the preloaded
+## *.eln files.
+
+## List of *.eln files we need to produce in addition to the preloaded
+## ones in $(lisp).
+elnlisp := \
+       emacs-lisp/autoload.eln \
+       emacs-lisp/byte-opt.eln \
+       emacs-lisp/bytecomp.eln \
+       emacs-lisp/cconv.eln \
+       international/charscript.eln \
+       emacs-lisp/comp.eln \
+       emacs-lisp/comp-cstr.eln \
+       international/emoji-zwj.eln
+elnlisp := $(addprefix ${lispsource}/,${elnlisp}) $(lisp:.elc=.eln)
+
+%.eln: %.el | emacs$(EXEEXT) $(pdmp)
+       @$(MAKE) $(AM_V_NO_PD) -C ../lisp EMACS="../src/emacs$(EXEEXT)"\
+               THEFILE=$< $<n
+
+## FIXME: this is fragile!  We lie to Make about the files produced by
+## this rule, and we rely on the absence of the native-lisp directory
+## to trigger it.  This means that if anything goes wrong during
+## native compilation, the only way to trigger it again is to remove
+## the directory and re-native-compile everything.  The main
+## underlying problem is that the name of the subdirectory of
+## native-lisp where the *.eln files will be produced, and the exact
+## names of those *.eln files, cannot be known in advance; we must ask
+## Emacs to produce them.
+../native-lisp: | $(pdmp)
+       @if test ! -d $@; then \
+         mkdir $@ && $(MAKE) $(AM_V_NO_PD) $(elnlisp); \
+         if test $(SYSTEM_TYPE) = cygwin; then \
+           find $@ -name '*.eln' | rebase -v -O -T -; \
+         fi; \
+         LC_ALL=C $(RUN_TEMACS) -batch $(BUILD_DETAILS) -l loadup 
--temacs=pdump \
+               --bin-dest $(BIN_DESTDIR) --eln-dest $(ELN_DESTDIR) \
+         && cp -f emacs$(EXEEXT) bootstrap-emacs$(EXEEXT) \
+         && cp -f $(pdmp) $(bootstrap_pdmp); \
+       fi
+endif
+
 ## VCSWITNESS points to the file that holds info about the current checkout.
 ## We use it as a heuristic to decide when to rebuild loaddefs.el.
 ## If empty it is ignored; the parent makefile can set it to some other value.
diff --git a/src/alloc.c b/src/alloc.c
index 4ea337ddba..aa790d3afa 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -765,7 +765,7 @@ xmalloc (size_t size)
   val = lmalloc (size, false);
   MALLOC_UNBLOCK_INPUT;
 
-  if (!val && size)
+  if (!val)
     memory_full (size);
   MALLOC_PROBE (size);
   return val;
@@ -782,7 +782,7 @@ xzalloc (size_t size)
   val = lmalloc (size, true);
   MALLOC_UNBLOCK_INPUT;
 
-  if (!val && size)
+  if (!val)
     memory_full (size);
   MALLOC_PROBE (size);
   return val;
@@ -796,15 +796,15 @@ xrealloc (void *block, size_t size)
   void *val;
 
   MALLOC_BLOCK_INPUT;
-  /* We must call malloc explicitly when BLOCK is 0, since some
-     reallocs don't do this.  */
+  /* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
+     platforms lacking support for realloc (NULL, size).  */
   if (! block)
     val = lmalloc (size, false);
   else
     val = lrealloc (block, size);
   MALLOC_UNBLOCK_INPUT;
 
-  if (!val && size)
+  if (!val)
     memory_full (size);
   MALLOC_PROBE (size);
   return val;
@@ -1030,7 +1030,7 @@ lisp_malloc (size_t nbytes, bool clearit, enum mem_type 
type)
 #endif
 
   MALLOC_UNBLOCK_INPUT;
-  if (!val && nbytes)
+  if (!val)
     memory_full (nbytes);
   MALLOC_PROBE (nbytes);
   return val;
@@ -1329,16 +1329,20 @@ laligned (void *p, size_t size)
          || size % LISP_ALIGNMENT != 0);
 }
 
-/* Like malloc and realloc except that if SIZE is Lisp-aligned, make
-   sure the result is too, if necessary by reallocating (typically
-   with larger and larger sizes) until the allocator returns a
-   Lisp-aligned pointer.  Code that needs to allocate C heap memory
+/* Like malloc and realloc except return null only on failure,
+   the result is Lisp-aligned if SIZE is, and lrealloc's pointer
+   argument must be nonnull.  Code allocating C heap memory
    for a Lisp object should use one of these functions to obtain a
    pointer P; that way, if T is an enum Lisp_Type value and L ==
    make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
 
+   If CLEARIT, arrange for the allocated memory to be cleared.
+   This might use calloc, as calloc can be faster than malloc+memset.
+
    On typical modern platforms these functions' loops do not iterate.
-   On now-rare (and perhaps nonexistent) platforms, the loops in
+   On now-rare (and perhaps nonexistent) platforms, the code can loop,
+   reallocating (typically with larger and larger sizes) until the
+   allocator returns a Lisp-aligned pointer.  This loop in
    theory could repeat forever.  If an infinite loop is possible on a
    platform, a build would surely loop and the builder can then send
    us a bug report.  Adding a counter to try to detect any such loop
@@ -1352,8 +1356,13 @@ lmalloc (size_t size, bool clearit)
   if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
     {
       void *p = aligned_alloc (LISP_ALIGNMENT, size);
-      if (clearit && p)
-       memclear (p, size);
+      if (p)
+       {
+         if (clearit)
+           memclear (p, size);
+       }
+      else if (! (MALLOC_0_IS_NONNULL || size))
+       return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
       return p;
     }
 #endif
@@ -1361,7 +1370,7 @@ lmalloc (size_t size, bool clearit)
   while (true)
     {
       void *p = clearit ? calloc (1, size) : malloc (size);
-      if (laligned (p, size))
+      if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
        return p;
       free (p);
       size_t bigger = size + LISP_ALIGNMENT;
@@ -1376,7 +1385,7 @@ lrealloc (void *p, size_t size)
   while (true)
     {
       p = realloc (p, size);
-      if (laligned (p, size))
+      if (laligned (p, size) && (size || p))
        return p;
       size_t bigger = size + LISP_ALIGNMENT;
       if (size < bigger)
@@ -1929,8 +1938,7 @@ allocate_string_data (struct Lisp_String *s,
    The character is at byte offset CIDX_BYTE in the string.
    The character being replaced is CLEN bytes long,
    and the character that will replace it is NEW_CLEN bytes long.
-   Return the address of where the caller should store the
-   the new character.  */
+   Return the address where the caller should store the new character.  */
 
 unsigned char *
 resize_string_data (Lisp_Object string, ptrdiff_t cidx_byte,
diff --git a/src/atimer.c b/src/atimer.c
index 9b198675ab..490c21bff1 100644
--- a/src/atimer.c
+++ b/src/atimer.c
@@ -305,6 +305,7 @@ set_alarm (void)
 #ifdef HAVE_ITIMERSPEC
       if (0 <= timerfd || alarm_timer_ok)
        {
+         bool exit = false;
          struct itimerspec ispec;
          ispec.it_value = atimers->expiration;
          ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0;
@@ -312,11 +313,14 @@ set_alarm (void)
          if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0)
            {
              add_timer_wait_descriptor (timerfd);
-             return;
+             exit = true;
            }
 # endif
          if (alarm_timer_ok
              && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0)
+           exit = true;
+
+         if (exit)
            return;
        }
 #endif
@@ -333,9 +337,8 @@ set_alarm (void)
       memset (&it, 0, sizeof it);
       it.it_value = make_timeval (interval);
       setitimer (ITIMER_REAL, &it, 0);
-#else /* not HAVE_SETITIMER */
-      alarm (max (interval.tv_sec, 1));
 #endif /* not HAVE_SETITIMER */
+      alarm (max (interval.tv_sec, 1));
     }
 }
 
@@ -583,15 +586,17 @@ init_atimer (void)
   timerfd = (egetenv ("EMACS_IGNORE_TIMERFD") || have_buggy_timerfd () ? -1 :
             timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC));
 # endif
-  if (timerfd < 0)
-    {
-      struct sigevent sigev;
-      sigev.sigev_notify = SIGEV_SIGNAL;
-      sigev.sigev_signo = SIGALRM;
-      sigev.sigev_value.sival_ptr = &alarm_timer;
-      alarm_timer_ok
-       = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0;
-    }
+  /* We're starting the alarms even if we have timerfd, because
+     timerfd events do not fire while Emacs Lisp is busy and doesn't
+     call thread_select.  This might or might not mean that the
+     timerfd code doesn't really give us anything and should be
+     removed, see discussion in bug#19776.  */
+  struct sigevent sigev;
+  sigev.sigev_notify = SIGEV_SIGNAL;
+  sigev.sigev_signo = SIGALRM;
+  sigev.sigev_value.sival_ptr = &alarm_timer;
+  alarm_timer_ok
+    = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0;
 #endif
   free_atimers = stopped_atimers = atimers = NULL;
 
diff --git a/src/bidi.c b/src/bidi.c
index 1413ba6b88..890a60acc4 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -3564,11 +3564,19 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
 }
 
 /* Utility function for looking for strong directional characters
-   whose bidi type was overridden by a directional override.  */
+   whose bidi type was overridden by directional override or embedding
+   or isolate control characters.  */
 ptrdiff_t
 bidi_find_first_overridden (struct bidi_it *bidi_it)
 {
   ptrdiff_t found_pos = ZV;
+  /* Maximum bidi levels we allow for L2R and R2L characters.  Note
+     that these are levels after resolving explicit embeddings,
+     overrides, and isolates, i.e. before resolving implicit levels.  */
+  int max_l2r = bidi_it->paragraph_dir == L2R ? 0 : 2;
+  int max_r2l = 1;
+  /* Same for WEAK and NEUTRAL_ON types.  */
+  int max_weak = bidi_it->paragraph_dir == L2R ? 1 : 2;
 
   do
     {
@@ -3576,11 +3584,28 @@ bidi_find_first_overridden (struct bidi_it *bidi_it)
         because the directional overrides are applied by the
         former.  */
       bidi_type_t type = bidi_resolve_weak (bidi_it);
+      unsigned level = bidi_it->level_stack[bidi_it->stack_idx].level;
+      bidi_category_t category = bidi_get_category (bidi_it->orig_type);
 
+      /* Detect strong L or R types that have been overridden by
+        explicit overrides.  */
       if ((type == STRONG_R && bidi_it->orig_type == STRONG_L)
          || (type == STRONG_L
              && (bidi_it->orig_type == STRONG_R
-                 || bidi_it->orig_type == STRONG_AL)))
+                 || bidi_it->orig_type == STRONG_AL))
+         /* Detect strong L or R types or WEAK_EN types that were
+            pushed into higher embedding levels (and will thus
+            reorder) by explicit embeddings and isolates.  */
+         || ((bidi_it->orig_type == STRONG_L
+              || bidi_it->orig_type == WEAK_EN)
+             && level > max_l2r)
+         || ((bidi_it->orig_type == STRONG_R
+              || bidi_it->orig_type == STRONG_AL)
+             && level > max_r2l)
+         /* Detect other weak or neutral types whose level was
+            tweaked by explicit embeddings and isolates.  */
+         || ((category == WEAK || bidi_it->orig_type == NEUTRAL_ON)
+             && level > max_weak))
        found_pos = bidi_it->charpos;
     } while (found_pos == ZV
             && bidi_it->charpos < ZV
diff --git a/src/buffer.c b/src/buffer.c
index 4eb7ab6d6b..9d8892a797 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1434,7 +1434,7 @@ and `buffer-file-truename' are non-nil.  */)
 DEFUN ("restore-buffer-modified-p", Frestore_buffer_modified_p,
        Srestore_buffer_modified_p, 1, 1, 0,
        doc: /* Like `set-buffer-modified-p', but doesn't redisplay buffer's 
mode line.
-This function also locks and unlocks the file visited by the buffer,
+This function also locks or unlocks the file visited by the buffer,
 if both `buffer-file-truename' and `buffer-file-name' are non-nil.
 
 It is not ensured that mode lines will be updated to show the modified
@@ -2805,7 +2805,7 @@ current buffer is cleared.  */)
 }
 
 DEFUN ("kill-all-local-variables", Fkill_all_local_variables,
-       Skill_all_local_variables, 0, 0, 0,
+       Skill_all_local_variables, 0, 1, 0,
        doc: /* Switch to Fundamental mode by killing current buffer's local 
variables.
 Most local variable bindings are eliminated so that the default values
 become effective once more.  Also, the syntax table is set from
@@ -2816,18 +2816,20 @@ This function also forces redisplay of the mode line.
 Every function to select a new major mode starts by
 calling this function.
 
-As a special exception, local variables whose names have
-a non-nil `permanent-local' property are not eliminated by this function.
+As a special exception, local variables whose names have a non-nil
+`permanent-local' property are not eliminated by this function.  If
+the optional KILL-PERMANENT argument is non-nil, clear out these local
+variables, too.
 
 The first thing this function does is run
 the normal hook `change-major-mode-hook'.  */)
-  (void)
+  (Lisp_Object kill_permanent)
 {
   run_hook (Qchange_major_mode_hook);
 
   /* Actually eliminate all local bindings of this buffer.  */
 
-  reset_buffer_local_variables (current_buffer, 0);
+  reset_buffer_local_variables (current_buffer, !NILP (kill_permanent));
 
   /* Force mode-line redisplay.  Useful here because all major mode
      commands call this function.  */
@@ -3843,7 +3845,9 @@ fix_overlays_before (struct buffer *bp, ptrdiff_t prev, 
ptrdiff_t pos)
      or the found one ends before PREV,
      or the found one is the last one in the list,
      we don't have to fix anything.  */
-  if (!tail || end < prev || !tail->next)
+  if (!tail)
+    return;
+  if (end < prev || !tail->next)
     return;
 
   right_pair = parent;
diff --git a/src/casefiddle.c b/src/casefiddle.c
index a7a2541490..81e9ed153f 100644
--- a/src/casefiddle.c
+++ b/src/casefiddle.c
@@ -54,6 +54,9 @@ struct casing_context
 
   /* Whether the context is within a word.  */
   bool inword;
+
+  /* What the last operation was.  */
+  bool downcase_last;
 };
 
 /* Initialize CTX structure for casing characters.  */
@@ -143,10 +146,14 @@ case_character_impl (struct casing_str_buf *buf,
 
   /* Handle simple, one-to-one case.  */
   if (flag == CASE_DOWN)
-    cased = downcase (ch);
+    {
+      cased = downcase (ch);
+      ctx->downcase_last = true;
+    }
   else
     {
       bool cased_is_set = false;
+      ctx->downcase_last = false;
       if (!NILP (ctx->titlecase_char_table))
        {
          prop = CHAR_TABLE_REF (ctx->titlecase_char_table, ch);
@@ -297,6 +304,16 @@ do_casify_multibyte_string (struct casing_context *ctx, 
Lisp_Object obj)
   return obj;
 }
 
+static int
+ascii_casify_character (bool downcase, int c)
+{
+  Lisp_Object cased = CHAR_TABLE_REF (downcase?
+                                     uniprop_table (Qlowercase) :
+                                     uniprop_table (Quppercase),
+                                     c);
+  return FIXNATP (cased) ? XFIXNAT (cased) : c;
+}
+
 static Lisp_Object
 do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
 {
@@ -310,11 +327,12 @@ do_casify_unibyte_string (struct casing_context *ctx, 
Lisp_Object obj)
       cased = case_single_character (ctx, ch);
       if (ch == cased)
        continue;
-      cased = make_char_unibyte (cased);
-      /* If the char can't be converted to a valid byte, just don't
-        change it.  */
-      if (SINGLE_BYTE_CHAR_P (cased))
-       SSET (obj, i, cased);
+      /* If down/upcasing changed an ASCII character into a non-ASCII
+        character (this can happen in some locales, like the Turkish
+        "I"), downcase using the ASCII char table.  */
+      if (ASCII_CHAR_P (ch) && !SINGLE_BYTE_CHAR_P (cased))
+       cased = ascii_casify_character (ctx->downcase_last, ch);
+      SSET (obj, i, make_char_unibyte (cased));
     }
   return obj;
 }
@@ -339,10 +357,13 @@ casify_object (enum case_action flag, Lisp_Object obj)
 
 DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
        doc: /* Convert argument to upper case and return that.
-The argument may be a character or string.  The result has the same type.
+The argument may be a character or string.  The result has the same
+type.  (See `downcase' for further details about the type.)
+
 The argument object is not altered--the value is a copy.  If argument
 is a character, characters which map to multiple code points when
 cased, e.g. fi, are returned unchanged.
+
 See also `capitalize', `downcase' and `upcase-initials'.  */)
   (Lisp_Object obj)
 {
@@ -351,7 +372,15 @@ See also `capitalize', `downcase' and `upcase-initials'.  
*/)
 
 DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0,
        doc: /* Convert argument to lower case and return that.
-The argument may be a character or string.  The result has the same type.
+The argument may be a character or string.  The result has the same type,
+including the multibyteness of the string.
+
+This means that if this function is called with a unibyte string
+argument, and downcasing it would turn it into a multibyte string
+(according to the current locale), the downcasing is done using ASCII
+\"C\" rules instead.  To accurately downcase according to the current
+locale, the string must be converted into multibyte first.
+
 The argument object is not altered--the value is a copy.  */)
   (Lisp_Object obj)
 {
@@ -362,7 +391,10 @@ DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0,
        doc: /* Convert argument to capitalized form and return that.
 This means that each word's first character is converted to either
 title case or upper case, and the rest to lower case.
-The argument may be a character or string.  The result has the same type.
+
+The argument may be a character or string.  The result has the same
+type.  (See `downcase' for further details about the type.)
+
 The argument object is not altered--the value is a copy.  If argument
 is a character, characters which map to multiple code points when
 cased, e.g. fi, are returned unchanged.  */)
@@ -377,7 +409,10 @@ DEFUN ("upcase-initials", Fupcase_initials, 
Supcase_initials, 1, 1, 0,
        doc: /* Convert the initial of each word in the argument to upper case.
 This means that each word's first character is converted to either
 title case or upper case, and the rest are left unchanged.
-The argument may be a character or string.  The result has the same type.
+
+The argument may be a character or string.  The result has the same
+type.  (See `downcase' for further details about the type.)
+
 The argument object is not altered--the value is a copy.  If argument
 is a character, characters which map to multiple code points when
 cased, e.g. fi, are returned unchanged.  */)
@@ -651,6 +686,8 @@ syms_of_casefiddle (void)
   DEFSYM (Qbounds, "bounds");
   DEFSYM (Qidentity, "identity");
   DEFSYM (Qtitlecase, "titlecase");
+  DEFSYM (Qlowercase, "lowercase");
+  DEFSYM (Quppercase, "uppercase");
   DEFSYM (Qspecial_uppercase, "special-uppercase");
   DEFSYM (Qspecial_lowercase, "special-lowercase");
   DEFSYM (Qspecial_titlecase, "special-titlecase");
diff --git a/src/character.h b/src/character.h
index 1a745484da..6ee6bcab20 100644
--- a/src/character.h
+++ b/src/character.h
@@ -82,6 +82,8 @@ enum
   LEFT_ANGLE_BRACKET = 0x3008,
   RIGHT_ANGLE_BRACKET = 0x3009,
   OBJECT_REPLACEMENT_CHARACTER = 0xFFFC,
+  TAG_SPACE = 0xE0020,
+  CANCEL_TAG = 0xE007F,
 };
 
 extern int char_string (unsigned, unsigned char *);
diff --git a/src/comp.c b/src/comp.c
index bc1adcf4e2..5b947fc99b 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -4123,7 +4123,7 @@ one for the file name and another for its contents, 
followed by .eln.  */)
   FOR_EACH_TAIL (lds_re_tail)
     {
       Lisp_Object match_idx =
-       Fstring_match (XCAR (lds_re_tail), filename, Qnil);
+       Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil);
       if (EQ (match_idx, make_fixnum (0)))
        {
          filename =
@@ -5260,7 +5260,8 @@ file_in_eln_sys_dir (Lisp_Object filename)
     eln_sys_dir = XCAR (tmp);
   return !NILP (Fstring_match (Fregexp_quote (Fexpand_file_name (eln_sys_dir,
                                                                 Qnil)),
-                              Fexpand_file_name (filename, Qnil), Qnil));
+                              Fexpand_file_name (filename, Qnil),
+                              Qnil, Qnil));
 }
 
 /* Load related routines.  */
diff --git a/src/composite.c b/src/composite.c
index e97f8e2b4c..c170805d9d 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -882,14 +882,15 @@ fill_gstring_body (Lisp_Object gstring)
 /* Try to compose the characters at CHARPOS according to composition
    rule RULE ([PATTERN PREV-CHARS FUNC]).  LIMIT limits the characters
    to compose.  STRING, if not nil, is a target string.  WIN is a
-   window where the characters are being displayed.  If characters are
+   window where the characters are being displayed.  CH is the
+   character that triggered the composition check.  If characters are
    successfully composed, return the composition as a glyph-string
    object.  Otherwise return nil.  */
 
 static Lisp_Object
 autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
               ptrdiff_t limit, struct window *win, struct face *face,
-              Lisp_Object string, Lisp_Object direction)
+              Lisp_Object string, Lisp_Object direction, int ch)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object pos = make_fixnum (charpos);
@@ -920,7 +921,7 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, 
ptrdiff_t bytepos,
   struct frame *f = XFRAME (font_object);
   if (FRAME_WINDOW_P (f))
     {
-      font_object = font_range (charpos, bytepos, &to, win, face, string);
+      font_object = font_range (charpos, bytepos, &to, win, face, string, ch);
       if (! FONT_OBJECT_P (font_object)
          || (! NILP (re)
              && to < limit
@@ -953,6 +954,9 @@ char_composable_p (int c)
   Lisp_Object val;
   return (c >= ' '
          && (c == ZERO_WIDTH_NON_JOINER || c == ZERO_WIDTH_JOINER
+             /* Per Unicode TR51, these tag characters can be part of
+                Emoji sequences.  */
+             || (TAG_SPACE <= c && c <= CANCEL_TAG)
              /* unicode-category-table may not be available during
                 dumping.  */
              || (CHAR_TABLE_P (Vunicode_category_table)
@@ -1269,7 +1273,7 @@ composition_reseat_it (struct composition_it *cmp_it, 
ptrdiff_t charpos,
              if (XFIXNAT (AREF (elt, 1)) != cmp_it->lookback)
                goto no_composition;
              lgstring = autocmp_chars (elt, charpos, bytepos, endpos,
-                                       w, face, string, direction);
+                                       w, face, string, direction, cmp_it->ch);
              if (composition_gstring_p (lgstring))
                break;
              lgstring = Qnil;
@@ -1307,7 +1311,7 @@ composition_reseat_it (struct composition_it *cmp_it, 
ptrdiff_t charpos,
          else
            direction = QR2L;
          lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
-                                   string, direction);
+                                   string, direction, cmp_it->ch);
          if (! composition_gstring_p (lgstring)
              || cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos)
            /* Composition failed or didn't cover the current
@@ -1676,7 +1680,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t 
limit, ptrdiff_t backlim,
                  for (check = cur; check_pos < check.pos; )
                    BACKWARD_CHAR (check, stop);
                  *gstring = autocmp_chars (elt, check.pos, check.pos_byte,
-                                           tail, w, NULL, string, Qnil);
+                                           tail, w, NULL, string, Qnil, c);
                  need_adjustment = 1;
                  if (NILP (*gstring))
                    {
@@ -2120,6 +2124,17 @@ GSTRING, or modify GSTRING itself and return it.
 See also the documentation of `auto-composition-mode'.  */);
   Vcomposition_function_table = Fmake_char_table (Qnil, Qnil);
 
+  DEFVAR_LISP ("auto-composition-emoji-eligible-codepoints", 
Vauto_composition_emoji_eligible_codepoints,
+              doc: /* List of codepoints for which auto-composition will check 
for an emoji font.
+
+These are codepoints which have Emoji_Presentation = No, and thus by
+default are not displayed as emoji.  In certain circumstances, such as
+when followed by U+FE0F (VS-16) the emoji font should be used for
+them anyway.
+
+This list is auto-generated, you should not need to modify it.  */);
+  Vauto_composition_emoji_eligible_codepoints = Qnil;
+
   defsubr (&Scompose_region_internal);
   defsubr (&Scompose_string_internal);
   defsubr (&Sfind_composition_internal);
diff --git a/src/composite.h b/src/composite.h
index 67e87201bf..945f261291 100644
--- a/src/composite.h
+++ b/src/composite.h
@@ -254,6 +254,10 @@ composition_valid_p (ptrdiff_t start, ptrdiff_t end, 
Lisp_Object prop)
 #define LGSTRING_HEADER(lgs) AREF (lgs, 0)
 #define LGSTRING_SET_HEADER(lgs, header) ASET (lgs, 0, header)
 
+/* LGSTRING_FONT retrieves the font used for LGSTRING, if we are going
+   to display it on a GUI frame.  On text-mode frames, that slot
+   stores the coding-system that should be used to write output to the
+   frame's terminal.  */
 #define LGSTRING_FONT(lgs) AREF (LGSTRING_HEADER (lgs), 0)
 #define LGSTRING_CHAR(lgs, i) AREF (LGSTRING_HEADER (lgs), (i) + 1)
 #define LGSTRING_CHAR_LEN(lgs) (ASIZE (LGSTRING_HEADER (lgs)) - 1)
diff --git a/src/conf_post.h b/src/conf_post.h
index 8558dc466c..2c6fbb0dba 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -293,7 +293,6 @@ extern int emacs_setenv_TZ (char const *);
   ATTRIBUTE_FORMAT ((PRINTF_ARCHETYPE, string_index, first_to_check))
 
 #define ARG_NONNULL ATTRIBUTE_NONNULL
-#define ATTRIBUTE_UNUSED MAYBE_UNUSED
 
 /* Declare NAME to be a pointer to an object of type TYPE, initialized
    to the address ADDR, which may be of a different type.  Accesses
diff --git a/src/dispextern.h b/src/dispextern.h
index 6aefe43e19..f17f095e0d 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -536,8 +536,8 @@ struct glyph
     int img_id;
 
 #ifdef HAVE_XWIDGETS
-    /* Xwidget reference (type == XWIDGET_GLYPH).  */
-    struct xwidget *xwidget;
+    /* Xwidget ID.  */
+    uint32_t xwidget;
 #endif
 
     /* Sub-structure for type == STRETCH_GLYPH.  */
@@ -1326,7 +1326,9 @@ struct glyph_string
   /* The area within row.  */
   enum glyph_row_area area;
 
-  /* Characters to be drawn, and number of characters.  */
+  /* Characters to be drawn, and number of characters.  Note that
+     NCHARS can be zero if this is a composition glyph string, as
+     evidenced by FIRST_GLYPH->type.  */
   unsigned *char2b;
   int nchars;
 
@@ -3160,7 +3162,7 @@ struct image_cache
 
 /* Size of bucket vector of image caches.  Should be prime.  */
 
-#define IMAGE_CACHE_BUCKETS_SIZE 1001
+#define IMAGE_CACHE_BUCKETS_SIZE 1009
 
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -3720,10 +3722,8 @@ extern Lisp_Object gui_default_parameter (struct frame 
*, Lisp_Object,
                                           const char *, const char *,
                                           enum resource_types);
 
-#ifndef HAVE_NS /* These both used on W32 and X only.  */
 extern bool gui_mouse_grabbed (Display_Info *);
 extern void gui_redo_mouse_highlight (Display_Info *);
-#endif /* HAVE_NS */
 
 #endif /* HAVE_WINDOW_SYSTEM */
 
diff --git a/src/dispnew.c b/src/dispnew.c
index 69c2023fdf..632eec2f03 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -475,7 +475,8 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix 
*matrix, int x, int y
                = row->glyphs[TEXT_AREA] + dim.width - left - right;
              /* Leave room for a border glyph.  */
              if (!FRAME_WINDOW_P (XFRAME (w->frame))
-                 && !WINDOW_RIGHTMOST_P (w))
+                 && !WINDOW_RIGHTMOST_P (w)
+                 && right > 0)
                row->glyphs[RIGHT_MARGIN_AREA] -= 1;
              row->glyphs[LAST_AREA]
                = row->glyphs[LEFT_MARGIN_AREA] + dim.width;
@@ -1148,7 +1149,8 @@ prepare_desired_row (struct window *w, struct glyph_row 
*row, bool mode_line_p)
          row->glyphs[RIGHT_MARGIN_AREA] = row->glyphs[LAST_AREA] - right;
          /* Leave room for a border glyph.  */
          if (!FRAME_WINDOW_P (XFRAME (w->frame))
-             && !WINDOW_RIGHTMOST_P (w))
+             && !WINDOW_RIGHTMOST_P (w)
+             && right > 0)
            row->glyphs[RIGHT_MARGIN_AREA] -= 1;
        }
     }
@@ -3848,6 +3850,9 @@ gui_update_window_end (struct window *w, bool cursor_on_p,
                                w->output_cursor.hpos, w->output_cursor.vpos,
                                w->output_cursor.x, w->output_cursor.y);
 
+      if (cursor_in_mouse_face_p (w) && cursor_on_p)
+       mouse_face_overwritten_p = 1;
+
       if (draw_window_fringes (w, true))
        {
          if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
@@ -4444,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p)
        break;
     }
 
-#ifdef HAVE_XWIDGETS
-  /* Currently this seems needed to detect xwidget movement reliably.
-     This is most probably because an xwidget glyph is represented in
-     struct glyph's 'union u' by a pointer to a struct, which takes 8
-     bytes in 64-bit builds, and thus the comparison of u.val values
-     done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the
-     size of the union is 4 bytes.  FIXME.  */
-    return 0;
-#endif
-
   /* Can't scroll the display of w32 GUI frames when position of point
      is indicated by the system caret, because scrolling the display
      will then "copy" the pixels used by the caret.  */
diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in
index fe52587c1a..a56e4dd12a 100644
--- a/src/emacs-module.h.in
+++ b/src/emacs-module.h.in
@@ -169,6 +169,19 @@ struct emacs_env_28
 @module_env_snippet_28@
 };
 
+struct emacs_env_29
+{
+@module_env_snippet_25@
+
+@module_env_snippet_26@
+
+@module_env_snippet_27@
+
+@module_env_snippet_28@
+
+@module_env_snippet_29@
+};
+
 /* Every module should define a function as follows.  */
 extern int emacs_module_init (struct emacs_runtime *runtime)
   EMACS_NOEXCEPT
diff --git a/src/emacs.c b/src/emacs.c
index 866e43fda9..032b27fcf3 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -133,6 +133,7 @@ extern char etext;
 #endif
 
 #include "pdumper.h"
+#include "fingerprint.h"
 #include "epaths.h"
 
 static const char emacs_version[] = PACKAGE_VERSION;
@@ -255,6 +256,7 @@ Initialization options:\n\
 #ifdef HAVE_PDUMPER
     "\
 --dump-file FILE            read dumped state from FILE\n\
+--fingerprint               output fingerprint and exit\n\
 ",
 #endif
 #if SECCOMP_USABLE
@@ -830,6 +832,8 @@ load_pdump (int argc, char **argv)
   const char *const suffix = ".pdmp";
   int result;
   char *emacs_executable = argv[0];
+  ptrdiff_t hexbuf_size;
+  char *hexbuf;
   const char *strip_suffix =
 #if defined DOS_NT || defined CYGWIN
     ".exe"
@@ -924,12 +928,18 @@ load_pdump (int argc, char **argv)
   path_exec = ns_relocate (path_exec);
 #endif
 
-  /* Look for "emacs.pdmp" in PATH_EXEC.  We hardcode "emacs" in
-     "emacs.pdmp" so that the Emacs binary still works if the user
-     copies and renames it.  */
+  /* Look for "emacs-FINGERPRINT.pdmp" in PATH_EXEC.  We hardcode
+     "emacs" in "emacs-FINGERPRINT.pdmp" so that the Emacs binary
+     still works if the user copies and renames it.  */
+  hexbuf_size = 2 * sizeof fingerprint;
+  hexbuf = xmalloc (hexbuf_size + 1);
+  hexbuf_digest (hexbuf, (char *) fingerprint, sizeof fingerprint);
+  hexbuf[hexbuf_size] = '\0';
   needed = (strlen (path_exec)
            + 1
            + strlen (argv0_base)
+           + 1
+           + strlen (hexbuf)
            + strlen (suffix)
            + 1);
   if (bufsize < needed)
@@ -937,8 +947,8 @@ load_pdump (int argc, char **argv)
       xfree (dump_file);
       dump_file = xpalloc (NULL, &bufsize, needed - bufsize, -1, 1);
     }
-  sprintf (dump_file, "%s%c%s%s",
-           path_exec, DIRECTORY_SEP, argv0_base, suffix);
+  sprintf (dump_file, "%s%c%s-%s%s",
+           path_exec, DIRECTORY_SEP, argv0_base, hexbuf, suffix);
 #if !defined (NS_SELF_CONTAINED)
   /* Assume the Emacs binary lives in a sibling directory as set up by
      the default installation configuration.  */
@@ -1387,6 +1397,24 @@ main (int argc, char **argv)
       exit (0);
     }
 
+#ifdef HAVE_PDUMPER
+  if (argmatch (argv, argc, "-fingerprint", "--fingerprint", 4,
+               NULL, &skip_args))
+    {
+      if (initialized)
+        {
+          dump_fingerprint (stdout, "",
+                           (unsigned char *) fingerprint);
+          exit (0);
+        }
+      else
+        {
+          fputs ("Not initialized\n", stderr);
+          exit (1);
+        }
+    }
+#endif
+
   emacs_wd = emacs_get_current_dir_name ();
 #ifdef HAVE_PDUMPER
   if (dumped_with_pdumper_p ())
@@ -1844,7 +1872,6 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   init_bignum ();
   init_threads ();
   init_eval ();
-  init_atimer ();
   running_asynch_code = 0;
   init_random ();
 
@@ -2006,6 +2033,9 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   if (!will_dump_p ())
     set_initial_environment ();
 
+  /* Has to run after the environment is set up. */
+  init_atimer ();
+
 #ifdef WINDOWSNT
   globals_of_w32 ();
 #ifdef HAVE_W32NOTIFY
@@ -2305,6 +2335,11 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
   if (dump_mode)
     Vdump_mode = build_string (dump_mode);
 
+#ifdef HAVE_PDUMPER
+  /* Allow code to be run (mostly useful after redumping). */
+  safe_run_hooks (Qafter_pdump_load_hook);
+#endif
+
   /* Enter editor command loop.  This never returns.  */
   set_initial_minibuffer_mode ();
   Frecursive_edit ();
@@ -2327,6 +2362,9 @@ struct standard_args
 static const struct standard_args standard_args[] =
 {
   { "-version", "--version", 150, 0 },
+#ifdef HAVE_PDUMPER
+  { "-fingerprint", "--fingerprint", 140, 0 },
+#endif
   { "-chdir", "--chdir", 130, 1 },
   { "-t", "--terminal", 120, 1 },
   { "-nw", "--no-window-system", 110, 0 },
diff --git a/src/eval.c b/src/eval.c
index 2bb7cfe600..94ad060773 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -29,6 +29,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "dispextern.h"
 #include "buffer.h"
 #include "pdumper.h"
+#include "atimer.h"
 
 /* CACHEABLE is ordinarily nothing, except it is 'volatile' if
    necessary to cajole GCC into not warning incorrectly that a
@@ -1078,6 +1079,47 @@ usage: (while TEST BODY...)  */)
   return Qnil;
 }
 
+static void
+with_delayed_message_display (struct atimer *timer)
+{
+  message3 (build_string (timer->client_data));
+}
+
+static void
+with_delayed_message_cancel (void *timer)
+{
+  xfree (((struct atimer *) timer)->client_data);
+  cancel_atimer (timer);
+}
+
+DEFUN ("funcall-with-delayed-message",
+       Ffuncall_with_delayed_message, Sfuncall_with_delayed_message,
+       3, 3, 0,
+       doc: /* Like `funcall', but display MESSAGE if FUNCTION takes longer 
than TIMEOUT.
+TIMEOUT is a number of seconds, and can be an integer or a floating
+point number.
+
+If FUNCTION takes less time to execute than TIMEOUT seconds, MESSAGE
+is not displayed.  */)
+  (Lisp_Object timeout, Lisp_Object message, Lisp_Object function)
+{
+  ptrdiff_t count = SPECPDL_INDEX ();
+
+  CHECK_NUMBER (timeout);
+  CHECK_STRING (message);
+
+  /* Set up the atimer.  */
+  struct timespec interval = dtotimespec (XFLOATINT (timeout));
+  struct atimer *timer = start_atimer (ATIMER_RELATIVE, interval,
+                                      with_delayed_message_display,
+                                      xstrdup (SSDATA (message)));
+  record_unwind_protect_ptr (with_delayed_message_cancel, timer);
+
+  Lisp_Object result = CALLN (Ffuncall, function);
+
+  return unbind_to (count, result);
+}
+
 DEFUN ("macroexpand", Fmacroexpand, Smacroexpand, 1, 2, 0,
        doc: /* Return result of expanding macros at top level of FORM.
 If FORM is not a macro call, it is returned unchanged.
@@ -3245,6 +3287,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
     emacs_abort ();
 
   i = optional = rest = 0;
+  bool previous_rest = false;
   for (; CONSP (syms_left); syms_left = XCDR (syms_left))
     {
       maybe_quit ();
@@ -3255,13 +3298,14 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
 
       if (EQ (next, Qand_rest))
         {
-          if (rest)
+          if (rest || previous_rest)
             xsignal1 (Qinvalid_function, fun);
           rest = 1;
+         previous_rest = true;
         }
       else if (EQ (next, Qand_optional))
         {
-          if (optional || rest)
+          if (optional || rest || previous_rest)
             xsignal1 (Qinvalid_function, fun);
           optional = 1;
         }
@@ -3287,10 +3331,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs,
          else
            /* Dynamically bind NEXT.  */
            specbind (next, arg);
+         previous_rest = false;
        }
     }
 
-  if (!NILP (syms_left))
+  if (!NILP (syms_left) || previous_rest)
     xsignal1 (Qinvalid_function, fun);
   else if (i < nargs)
     xsignal2 (Qwrong_number_of_arguments, fun, make_fixnum (nargs));
@@ -4308,13 +4353,19 @@ syms_of_eval (void)
 {
   DEFVAR_INT ("max-specpdl-size", max_specpdl_size,
              doc: /* Limit on number of Lisp variable bindings and 
`unwind-protect's.
-If Lisp code tries to increase the total number past this amount,
-an error is signaled.
-You can safely use a value considerably larger than the default value,
-if that proves inconveniently small.  However, if you increase it too far,
-Emacs could run out of memory trying to make the stack bigger.
-Note that this limit may be silently increased by the debugger
-if `debug-on-error' or `debug-on-quit' is set.  */);
+
+If Lisp code tries to use more bindings than this amount, an error is
+signaled.
+
+You can safely increase this variable substantially if the default
+value proves inconveniently small.  However, if you increase it too
+much, Emacs could run out of memory trying to make the stack bigger.
+Note that this limit may be silently increased by the debugger if
+`debug-on-error' or `debug-on-quit' is set.
+
+\"spec\" is short for \"special variables\", i.e., dynamically bound
+variables.  \"PDL\" is short for \"push-down list\", which is an old
+term for \"stack\".  */);
 
   DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth,
              doc: /* Limit on depth in `eval', `apply' and `funcall' before 
error.
@@ -4502,6 +4553,7 @@ alist of active lexical bindings.  */);
   defsubr (&Slet);
   defsubr (&SletX);
   defsubr (&Swhile);
+  defsubr (&Sfuncall_with_delayed_message);
   defsubr (&Smacroexpand);
   defsubr (&Scatch);
   defsubr (&Sthrow);
diff --git a/src/fns.c b/src/fns.c
index a72e41aee5..76c76c92ba 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -672,6 +672,9 @@ DEFUN ("concat", Fconcat, Sconcat, 0, MANY, 0,
        doc: /* Concatenate all the arguments and make the result a string.
 The result is a string whose elements are the elements of all the arguments.
 Each argument may be a string or a list or vector of characters (integers).
+
+Values of the `composition' property of the result are not guaranteed
+to be `eq'.
 usage: (concat &rest SEQUENCES)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
@@ -2852,12 +2855,16 @@ mapcar1 (EMACS_INT leni, Lisp_Object *vals, Lisp_Object 
fn, Lisp_Object seq)
   return leni;
 }
 
-DEFUN ("mapconcat", Fmapconcat, Smapconcat, 3, 3, 0,
+DEFUN ("mapconcat", Fmapconcat, Smapconcat, 2, 3, 0,
        doc: /* Apply FUNCTION to each element of SEQUENCE, and concat the 
results as strings.
 In between each pair of results, stick in SEPARATOR.  Thus, " " as
   SEPARATOR results in spaces between the values returned by FUNCTION.
+
 SEQUENCE may be a list, a vector, a bool-vector, or a string.
-SEPARATOR must be a string, a vector, or a list of characters.
+
+Optional argument SEPARATOR must be a string, a vector, or a list of
+characters; nil stands for the empty string.
+
 FUNCTION must be a function of one argument, and must return a value
   that is a sequence of characters: either a string, or a vector or
   list of numbers that are valid character codepoints.  */)
diff --git a/src/font.c b/src/font.c
index e043ef8d01..f70054ea40 100644
--- a/src/font.c
+++ b/src/font.c
@@ -57,24 +57,26 @@ struct table_entry
   int numeric;
   /* The first one is a valid name as a face attribute.
      The second one (if any) is a typical name in XLFD field.  */
-  const char *names[5];
+  const char *names[6];
 };
 
 /* Table of weight numeric values and their names.  This table must be
-   sorted by numeric values in ascending order.  */
+   sorted by numeric values in ascending order and the numeric values
+   must approximately match the weights in the font files.  */
 
 static const struct table_entry weight_table[] =
 {
   { 0, { "thin" }},
-  { 20, { "ultra-light", "ultralight" }},
-  { 40, { "extra-light", "extralight" }},
+  { 40, { "ultra-light", "ultralight", "extra-light", "extralight" }},
   { 50, { "light" }},
-  { 75, { "semi-light", "semilight", "demilight", "book" }},
-  { 100, { "normal", "medium", "regular", "unspecified" }},
-  { 180, { "semi-bold", "semibold", "demibold", "demi" }},
+  { 55, { "semi-light", "semilight", "demilight" }},
+  { 80, { "regular", "normal", "unspecified", "book" }},
+  { 100, { "medium" }},
+  { 180, { "semi-bold", "semibold", "demibold", "demi-bold", "demi" }},
   { 200, { "bold" }},
-  { 205, { "extra-bold", "extrabold" }},
-  { 210, { "ultra-bold", "ultrabold", "black" }}
+  { 205, { "extra-bold", "extrabold", "ultra-bold", "ultrabold" }},
+  { 210, { "black", "heavy" }},
+  { 250, { "ultra-heavy", "ultraheavy" }}
 };
 
 /* Table of slant numeric values and their names.  This table must be
@@ -1484,11 +1486,20 @@ font_parse_fcname (char *name, ptrdiff_t len, 
Lisp_Object font)
 #define PROP_MATCH(STR) (word_len == strlen (STR)              \
                         && memcmp (p, STR, strlen (STR)) == 0)
 
-                 if (PROP_MATCH ("light")
+                 if (PROP_MATCH ("thin")
+                     || PROP_MATCH ("ultra-light")
+                     || PROP_MATCH ("light")
+                     || PROP_MATCH ("semi-light")
+                     || PROP_MATCH ("book")
                      || PROP_MATCH ("medium")
+                     || PROP_MATCH ("normal")
+                     || PROP_MATCH ("semibold")
                      || PROP_MATCH ("demibold")
                      || PROP_MATCH ("bold")
-                     || PROP_MATCH ("black"))
+                     || PROP_MATCH ("ultra-bold")
+                     || PROP_MATCH ("black")
+                     || PROP_MATCH ("heavy")
+                     || PROP_MATCH ("ultra-heavy"))
                    FONT_SET_STYLE (font, FONT_WEIGHT_INDEX, val);
                  else if (PROP_MATCH ("roman")
                           || PROP_MATCH ("italic")
@@ -3860,12 +3871,32 @@ font_at (int c, ptrdiff_t pos, struct face *face, 
struct window *w,
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+/* Check if CH is a codepoint for which we should attempt to use the
+   emoji font, even if the codepoint itself has Emoji_Presentation =
+   No.  Vauto_composition_emoji_eligible_codepoints is filled in for
+   us by admin/unidata/emoji-zwj.awk.  */
+static bool
+codepoint_is_emoji_eligible (int ch)
+{
+  if (EQ (CHAR_TABLE_REF (Vchar_script_table, ch), Qemoji))
+    return true;
+
+  if (! NILP (Fmemq (make_fixnum (ch),
+                    Vauto_composition_emoji_eligible_codepoints)))
+    return true;
+
+  return false;
+}
+
 /* Check how many characters after character/byte position POS/POS_BYTE
    (at most to *LIMIT) can be displayed by the same font in the window W.
    FACE, if non-NULL, is the face selected for the character at POS.
    If STRING is not nil, it is the string to check instead of the current
    buffer.  In that case, FACE must be not NULL.
 
+   CH is the character that actually caused the composition
+   process to start, it may be different from the character at POS.
+
    The return value is the font-object for the character at POS.
    *LIMIT is set to the position where that font can't be used.
 
@@ -3873,15 +3904,16 @@ font_at (int c, ptrdiff_t pos, struct face *face, 
struct window *w,
 
 Lisp_Object
 font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit,
-           struct window *w, struct face *face, Lisp_Object string)
+           struct window *w, struct face *face, Lisp_Object string,
+           int ch)
 {
   ptrdiff_t ignore;
   int c;
   Lisp_Object font_object = Qnil;
+  struct frame *f = XFRAME (w->frame);
 
   if (!face)
     {
-      struct frame *f = XFRAME (w->frame);
       int face_id;
 
       if (NILP (string))
@@ -3900,6 +3932,23 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t 
*limit,
       face = FACE_FROM_ID (f, face_id);
     }
 
+  /* If the composition was triggered by an emoji, use a character
+     from 'script-representative-chars', rather than the first
+     character in the string, to determine the font to use.  */
+  if (codepoint_is_emoji_eligible (ch))
+    {
+      Lisp_Object val = assq_no_quit (Qemoji, Vscript_representative_chars);
+      if (CONSP (val))
+       {
+         val = XCDR (val);
+         if (CONSP (val))
+           val = XCAR (val);
+         else if (VECTORP (val))
+           val = AREF (val, 0);
+         font_object = font_for_char (face, XFIXNAT (val), pos, string);
+       }
+    }
+
   while (pos < *limit)
     {
       c = (NILP (string)
@@ -4928,6 +4977,33 @@ If the font is not OpenType font, CAPABILITY is nil.  */)
                 : Qnil));
 }
 
+DEFUN ("font-has-char-p", Ffont_has_char_p, Sfont_has_char_p, 2, 3, 0,
+       doc:
+       /* Return non-nil if FONT on FRAME has a glyph for character CH.
+FONT can be either a font-entity or a font-object.  If it is
+a font-entity and the result is nil, it means the font needs to be
+opened (with `open-font') to check.
+FRAME defaults to the selected frame if it is nil or omitted.  */)
+  (Lisp_Object font, Lisp_Object ch, Lisp_Object frame)
+{
+  struct frame *f;
+  CHECK_FONT (font);
+  CHECK_CHARACTER (ch);
+
+  if (NILP (frame))
+    f = XFRAME (selected_frame);
+  else
+    {
+      CHECK_FRAME (frame);
+      f = XFRAME (frame);
+    }
+
+  if (font_has_char (f, font, XFIXNAT (ch)) <= 0)
+    return Qnil;
+  else
+    return Qt;
+}
+
 DEFUN ("font-get-glyphs", Ffont_get_glyphs, Sfont_get_glyphs, 3, 4, 0,
        doc:
        /* Return a vector of FONT-OBJECT's glyphs for the specified characters.
@@ -4946,8 +5022,13 @@ where
   CODE is the glyph-code of C in FONT-OBJECT.
   WIDTH thru DESCENT are the metrics (in pixels) of the glyph.
   ADJUSTMENT is always nil.
-If FONT-OBJECT doesn't have a glyph for a character,
-the corresponding element is nil.  */)
+
+If FONT-OBJECT doesn't have a glyph for a character, the corresponding
+element is nil.
+
+Also see `font-has-char-p', which is more efficient than this function
+if you just want to check whether FONT-OBJECT has a glyph for a
+character.  */)
   (Lisp_Object font_object, Lisp_Object from, Lisp_Object to,
    Lisp_Object object)
 {
@@ -5423,6 +5504,7 @@ syms_of_font (void)
   DEFSYM (Qiso8859_1, "iso8859-1");
   DEFSYM (Qiso10646_1, "iso10646-1");
   DEFSYM (Qunicode_bmp, "unicode-bmp");
+  DEFSYM (Qemoji, "emoji");
 
   /* Symbols representing keys of font extra info.  */
   DEFSYM (QCotf, ":otf");
@@ -5498,6 +5580,7 @@ syms_of_font (void)
   defsubr (&Sclose_font);
   defsubr (&Squery_font);
   defsubr (&Sfont_get_glyphs);
+  defsubr (&Sfont_has_char_p);
   defsubr (&Sfont_match_p);
   defsubr (&Sfont_at);
 #if 0
diff --git a/src/font.h b/src/font.h
index d3e1530642..1da72cca07 100644
--- a/src/font.h
+++ b/src/font.h
@@ -885,7 +885,7 @@ valid_font_driver (struct font_driver const *d)
 extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list);
 extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *,
                               struct window *, struct face *,
-                              Lisp_Object);
+                              Lisp_Object, int);
 extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned 
int);
 
 extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop,
diff --git a/src/frame.c b/src/frame.c
index f95566818a..79a7c89e0d 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -5028,8 +5028,6 @@ gui_set_no_special_glyphs (struct frame *f, Lisp_Object 
new_value, Lisp_Object o
 }
 
 
-#ifndef HAVE_NS
-
 /* Non-zero if mouse is grabbed on DPYINFO
    and we know the frame where it is.  */
 
@@ -5054,8 +5052,6 @@ gui_redo_mouse_highlight (Display_Info *dpyinfo)
                          dpyinfo->last_mouse_motion_y);
 }
 
-#endif /* HAVE_NS */
-
 /* Subroutines of creating an X frame.  */
 
 /* Make sure that Vx_resource_name is set to a reasonable value.
@@ -6238,7 +6234,10 @@ when the mouse is over clickable text.  */);
 
   DEFVAR_LISP ("make-pointer-invisible", Vmake_pointer_invisible,
                doc: /* If non-nil, make mouse pointer invisible while typing.
-The pointer becomes visible again when the mouse is moved.  */);
+The pointer becomes visible again when the mouse is moved.
+
+When using this, you might also want to disable highlighting of
+clickable text.  See `mouse-highlight'.  */);
   Vmake_pointer_invisible = Qt;
 
   DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions,
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 313cfc82c2..a9eabf47d8 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -2237,20 +2237,34 @@ xg_get_file_name (struct frame *f,
 
 #ifdef HAVE_GTK3
 
-#define XG_WEIGHT_TO_SYMBOL(w)                 \
-  (w <= PANGO_WEIGHT_THIN ? Qextra_light       \
-   : w <= PANGO_WEIGHT_ULTRALIGHT ? Qlight     \
-   : w <= PANGO_WEIGHT_LIGHT ? Qsemi_light     \
-   : w < PANGO_WEIGHT_MEDIUM ? Qnormal         \
-   : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold   \
-   : w <= PANGO_WEIGHT_BOLD ? Qbold            \
-   : w <= PANGO_WEIGHT_HEAVY ? Qextra_bold     \
-   : Qultra_bold)
-
-#define XG_STYLE_TO_SYMBOL(s)                  \
-  (s == PANGO_STYLE_OBLIQUE ? Qoblique         \
-   : s == PANGO_STYLE_ITALIC ? Qitalic         \
-   : Qnormal)
+static
+Lisp_Object xg_weight_to_symbol (PangoWeight w)
+{
+  return
+    (w <= PANGO_WEIGHT_THIN ? Qthin                  /* 100 */
+     : w <= PANGO_WEIGHT_ULTRALIGHT ? Qultra_light   /* 200 */
+     : w <= PANGO_WEIGHT_LIGHT ? Qlight              /* 300 */
+#if PANGO_VERSION_CHECK(1, 36, 7)
+     : w <= PANGO_WEIGHT_SEMILIGHT ? Qsemi_light     /* 350 */
+#endif
+     : w <= PANGO_WEIGHT_BOOK ? Qbook                /* 380 */
+     : w <= PANGO_WEIGHT_NORMAL ? Qnormal            /* 400 */
+     : w <= PANGO_WEIGHT_MEDIUM ? Qmedium            /* 500 */
+     : w <= PANGO_WEIGHT_SEMIBOLD ? Qsemi_bold       /* 600 */
+     : w <= PANGO_WEIGHT_BOLD ? Qbold                /* 700 */
+     : w <= PANGO_WEIGHT_ULTRABOLD ? Qultra_bold     /* 800 */
+     : w <= PANGO_WEIGHT_HEAVY ? Qblack              /* 900 */
+     : Qultra_heavy);                                /* 1000 */
+}
+
+static
+Lisp_Object xg_style_to_symbol (PangoStyle s)
+{
+  return
+    (s == PANGO_STYLE_OBLIQUE ? Qoblique
+     : s == PANGO_STYLE_ITALIC ? Qitalic
+     : Qnormal);
+}
 
 #endif /* HAVE_GTK3 */
 
@@ -2341,8 +2355,8 @@ xg_get_font (struct frame *f, const char *default_name)
          font = CALLN (Ffont_spec,
                        QCfamily, build_string (family),
                        QCsize, make_float (pango_units_to_double (size)),
-                       QCweight, XG_WEIGHT_TO_SYMBOL (weight),
-                       QCslant, XG_STYLE_TO_SYMBOL (style));
+                       QCweight, xg_weight_to_symbol (weight),
+                       QCslant, xg_style_to_symbol (style));
 
           char *font_desc_str = pango_font_description_to_string (desc);
           dupstring (&x_last_font_name, font_desc_str);
@@ -2932,8 +2946,9 @@ xg_item_label_same_p (GtkMenuItem *witem, const char 
*label)
   char *utf8_label = get_utf8_string (label);
   const char *old_label = witem ? xg_get_menu_item_label (witem) : 0;
 
-  bool is_same = (!old_label == !utf8_label
-                 && (!old_label || strcmp (utf8_label, old_label) == 0));
+  bool is_same = (old_label
+                 ? utf8_label && strcmp (utf8_label, old_label) == 0
+                 : !utf8_label);
 
   if (utf8_label) g_free (utf8_label);
 
diff --git a/src/image.c b/src/image.c
index 206c7baa2f..6769e49120 100644
--- a/src/image.c
+++ b/src/image.c
@@ -3547,10 +3547,8 @@ convert_mono_to_color_image (struct frame *f, struct 
image *img,
   release_frame_dc (f, hdc);
   old_prev = SelectObject (old_img_dc, img->pixmap);
   new_prev = SelectObject (new_img_dc, new_pixmap);
-  /* Windows convention for mono bitmaps is black = background,
-     white = foreground.  */
-  SetTextColor (new_img_dc, background);
-  SetBkColor (new_img_dc, foreground);
+  SetTextColor (new_img_dc, foreground);
+  SetBkColor (new_img_dc, background);
 
   BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
          0, 0, SRCCOPY);
@@ -4116,9 +4114,9 @@ struct xpm_cached_color
 };
 
 /* The hash table used for the color cache, and its bucket vector
-   size.  */
+   size (which should be prime).  */
 
-#define XPM_COLOR_CACHE_BUCKETS        1001
+#define XPM_COLOR_CACHE_BUCKETS 1009
 static struct xpm_cached_color **xpm_color_cache;
 
 /* Initialize the color cache.  */
@@ -6421,9 +6419,8 @@ image_can_use_native_api (Lisp_Object type)
 }
 
 /*
- * These functions are actually defined in the OS-native implementation
- * file.  Currently, for Windows GDI+ interface, w32image.c, but other
- * operating systems can follow suit.
+ * These functions are actually defined in the OS-native implementation file.
+ * Currently, for Windows GDI+ interface, w32image.c, and nsimage.m for macOS.
  */
 
 /* Indices of image specification fields in native format, below.  */
@@ -8233,24 +8230,30 @@ gif_image_p (Lisp_Object object)
 #   undef DrawText
 #  endif
 
-/* Giflib before 5.0 didn't define these macros (used only if HAVE_NTGUI).  */
-#  ifndef GIFLIB_MINOR
-#   define GIFLIB_MINOR 0
-#  endif
-#  ifndef GIFLIB_RELEASE
-#   define GIFLIB_RELEASE 0
-#  endif
-
 # else /* HAVE_NTGUI */
 
 #  include <gif_lib.h>
 
 # endif /* HAVE_NTGUI */
 
-/* Giflib before 5.0 didn't define these macros.  */
+/* Giflib before 4.1.6 didn't define these macros.  */
 # ifndef GIFLIB_MAJOR
 #  define GIFLIB_MAJOR 4
 # endif
+# ifndef GIFLIB_MINOR
+#  define GIFLIB_MINOR 0
+# endif
+# ifndef GIFLIB_RELEASE
+#  define GIFLIB_RELEASE 0
+# endif
+/* Giflib before 5.0 didn't define these macros.  */
+# if GIFLIB_MAJOR < 5
+#  define DISPOSAL_UNSPECIFIED    0    /* No disposal specified.  */
+#  define DISPOSE_DO_NOT          1    /* Leave image in place.  */
+#  define DISPOSE_BACKGROUND      2    /* Set area too background color.  */
+#  define DISPOSE_PREVIOUS        3    /* Restore to previous content.  */
+#  define NO_TRANSPARENT_COLOR    -1
+# endif
 
 /* GifErrorString is declared to return char const * when GIFLIB_MAJOR
    and GIFLIB_MINOR indicate 5.1 or later.  Do not bother using it in
@@ -8273,6 +8276,8 @@ DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char 
*));
 #  else
 DEF_DLL_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *));
 DEF_DLL_FN (GifFileType *, DGifOpenFileName, (const char *, int *));
+DEF_DLL_FN (int, DGifSavedExtensionToGCB,
+           (GifFileType *, int, GraphicsControlBlock *));
 #  endif
 #  if HAVE_GIFERRORSTRING
 DEF_DLL_FN (char const *, GifErrorString, (int));
@@ -8290,6 +8295,9 @@ init_gif_functions (void)
   LOAD_DLL_FN (library, DGifSlurp);
   LOAD_DLL_FN (library, DGifOpen);
   LOAD_DLL_FN (library, DGifOpenFileName);
+#  if GIFLIB_MAJOR >= 5
+  LOAD_DLL_FN (library, DGifSavedExtensionToGCB);
+#  endif
 #  if HAVE_GIFERRORSTRING
   LOAD_DLL_FN (library, GifErrorString);
 #  endif
@@ -8300,12 +8308,18 @@ init_gif_functions (void)
 #  undef DGifOpen
 #  undef DGifOpenFileName
 #  undef DGifSlurp
+#  if GIFLIB_MAJOR >= 5
+#   undef DGifSavedExtensionToGCB
+#  endif
 #  undef GifErrorString
 
 #  define DGifCloseFile fn_DGifCloseFile
 #  define DGifOpen fn_DGifOpen
 #  define DGifOpenFileName fn_DGifOpenFileName
 #  define DGifSlurp fn_DGifSlurp
+#  if GIFLIB_MAJOR >= 5
+#   define DGifSavedExtensionToGCB fn_DGifSavedExtensionToGCB
+#  endif
 #  define GifErrorString fn_GifErrorString
 
 # endif /* WINDOWSNT */
@@ -8383,7 +8397,7 @@ gif_load (struct frame *f, struct image *img)
       if (!STRINGP (file))
        {
          image_error ("Cannot find image file `%s'", specified_file);
-         return 0;
+         return false;
        }
 
       Lisp_Object encoded_file = ENCODE_FILE (file);
@@ -8406,8 +8420,7 @@ gif_load (struct frame *f, struct image *img)
          else
 #endif
          image_error ("Cannot open `%s'", file);
-
-         return 0;
+         return false;
        }
     }
   else
@@ -8415,7 +8428,7 @@ gif_load (struct frame *f, struct image *img)
       if (!STRINGP (specified_data))
        {
          image_error ("Invalid image data `%s'", specified_data);
-         return 0;
+         return false;
        }
 
       /* Read from memory! */
@@ -8439,7 +8452,7 @@ gif_load (struct frame *f, struct image *img)
          else
 #endif
          image_error ("Cannot open memory source `%s'", img->spec);
-         return 0;
+         return false;
        }
     }
 
@@ -8447,8 +8460,7 @@ gif_load (struct frame *f, struct image *img)
   if (!check_image_size (f, gif->SWidth, gif->SHeight))
     {
       image_size_error ();
-      gif_close (gif, NULL);
-      return 0;
+      goto gif_error;
     }
 
   /* Read entire contents.  */
@@ -8459,8 +8471,7 @@ gif_load (struct frame *f, struct image *img)
        image_error ("Error reading `%s'", img->spec);
       else
        image_error ("Error reading GIF data");
-      gif_close (gif, NULL);
-      return 0;
+      goto gif_error;
     }
 
   /* Which sub-image are we to display?  */
@@ -8471,8 +8482,7 @@ gif_load (struct frame *f, struct image *img)
       {
        image_error ("Invalid image number `%s' in image `%s'",
                     image_number, img->spec);
-       gif_close (gif, NULL);
-       return 0;
+       goto gif_error;
       }
   }
 
@@ -8489,8 +8499,7 @@ gif_load (struct frame *f, struct image *img)
   if (!check_image_size (f, width, height))
     {
       image_size_error ();
-      gif_close (gif, NULL);
-      return 0;
+      goto gif_error;
     }
 
   /* Check that the selected subimages fit.  It's not clear whether
@@ -8507,18 +8516,14 @@ gif_load (struct frame *f, struct image *img)
             && 0 <= subimg_left && subimg_left <= width - subimg_width))
        {
          image_error ("Subimage does not fit in image");
-         gif_close (gif, NULL);
-         return 0;
+         goto gif_error;
        }
     }
 
   /* Create the X image and pixmap.  */
   Emacs_Pix_Container ximg;
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
-    {
-      gif_close (gif, NULL);
-      return 0;
-    }
+    goto gif_error;
 
   /* Clear the part of the screen image not covered by the image.
      Full animated GIF support requires more here (see the gif89 spec,
@@ -8577,13 +8582,17 @@ gif_load (struct frame *f, struct image *img)
         char *, which invites problems with bytes >= 0x80.  */
       struct SavedImage *subimage = gif->SavedImages + j;
       unsigned char *raster = (unsigned char *) subimage->RasterBits;
-      int transparency_color_index = -1;
-      int disposal = 0;
       int subimg_width = subimage->ImageDesc.Width;
       int subimg_height = subimage->ImageDesc.Height;
       int subimg_top = subimage->ImageDesc.Top;
       int subimg_left = subimage->ImageDesc.Left;
 
+      /* From gif89a spec: 1 = "keep in place", 2 = "restore
+        to background".  Treat any other value like 2.  */
+      int disposal = DISPOSAL_UNSPECIFIED;
+      int transparency_color_index = NO_TRANSPARENT_COLOR;
+
+#if GIFLIB_MAJOR < 5
       /* Find the Graphic Control Extension block for this sub-image.
         Extract the disposal method and transparency color.  */
       for (i = 0; i < subimage->ExtensionBlockCount; i++)
@@ -8594,24 +8603,29 @@ gif_load (struct frame *f, struct image *img)
              && extblock->ByteCount == 4
              && extblock->Bytes[0] & 1)
            {
-             /* From gif89a spec: 1 = "keep in place", 2 = "restore
-                to background".  Treat any other value like 2.  */
              disposal = (extblock->Bytes[0] >> 2) & 7;
              transparency_color_index = (unsigned char) extblock->Bytes[3];
              break;
            }
        }
+#else
+      GraphicsControlBlock gcb;
+      DGifSavedExtensionToGCB (gif, j, &gcb);
+      disposal = gcb.DisposalMode;
+      transparency_color_index = gcb.TransparentColor;
+#endif
 
       /* We can't "keep in place" the first subimage.  */
       if (j == 0)
-       disposal = 2;
+       disposal = DISPOSE_BACKGROUND;
 
-      /* For disposal == 0, the spec says "No disposal specified. The
-        decoder is not required to take any action."  In practice, it
-        seems we need to treat this like "keep in place", see e.g.
+      /* For disposal == 0 (DISPOSAL_UNSPECIFIED), the spec says
+        "No disposal specified.  The decoder is not required to take
+        any action."  In practice, it seems we need to treat this
+        like "keep in place" (DISPOSE_DO_NOT), see e.g.
         https://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */
-      if (disposal == 0)
-       disposal = 1;
+      if (disposal == DISPOSAL_UNSPECIFIED)
+       disposal = DISPOSE_DO_NOT;
 
       gif_color_map = subimage->ImageDesc.ColorMap;
       if (!gif_color_map)
@@ -8650,7 +8664,7 @@ gif_load (struct frame *f, struct image *img)
              for (x = 0; x < subimg_width; x++)
                {
                  int c = raster[y * subimg_width + x];
-                 if (transparency_color_index != c || disposal != 1)
+                 if (transparency_color_index != c || disposal != 
DISPOSE_DO_NOT)
                     {
                       PUT_PIXEL (ximg, x + subimg_left, row + subimg_top,
                                  pixel_colors[c]);
@@ -8664,7 +8678,7 @@ gif_load (struct frame *f, struct image *img)
            for (x = 0; x < subimg_width; ++x)
              {
                int c = raster[y * subimg_width + x];
-               if (transparency_color_index != c || disposal != 1)
+               if (transparency_color_index != c || disposal != DISPOSE_DO_NOT)
                   {
                     PUT_PIXEL (ximg, x + subimg_left, y + subimg_top,
                                pixel_colors[c]);
@@ -8734,14 +8748,296 @@ gif_load (struct frame *f, struct image *img)
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
 
-  return 1;
+  return true;
+
+ gif_error:
+  gif_close (gif, NULL);
+  return false;
 }
 
 #endif /* HAVE_GIF */
 
 
+#ifdef HAVE_WEBP
+
+
+/***********************************************************************
+                                WebP
+ ***********************************************************************/
+
+#include "webp/decode.h"
+
+/* Indices of image specification fields in webp_format, below.  */
+
+enum webp_keyword_index
+{
+  WEBP_TYPE,
+  WEBP_DATA,
+  WEBP_FILE,
+  WEBP_ASCENT,
+  WEBP_MARGIN,
+  WEBP_RELIEF,
+  WEBP_ALGORITHM,
+  WEBP_HEURISTIC_MASK,
+  WEBP_MASK,
+  WEBP_BACKGROUND,
+  WEBP_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+   of valid user-defined image specifications.  */
+
+static const struct image_keyword webp_format[WEBP_LAST] =
+{
+  {":type",            IMAGE_SYMBOL_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
+  {":margin",          IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
+  {":relief",          IMAGE_INTEGER_VALUE,                    0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
+};
+
+/* Return true if OBJECT is a valid WebP image specification.  */
+
+static bool
+webp_image_p (Lisp_Object object)
+{
+  struct image_keyword fmt[WEBP_LAST];
+  memcpy (fmt, webp_format, sizeof fmt);
+
+  if (!parse_image_spec (object, fmt, WEBP_LAST, Qwebp))
+    return false;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[WEBP_FILE].count + fmt[WEBP_DATA].count == 1;
+}
+
+#ifdef WINDOWSNT
+
+/* WebP library details.  */
+
+DEF_DLL_FN (int, WebPGetInfo, (const uint8_t *, size_t, int *, int *));
+/* WebPGetFeatures is a static inline function defined in WebP's
+   decode.h.  Since we cannot use that with dynamically-loaded libwebp
+   DLL, we instead load the internal function it calls and redirect to
+   that through a macro.  */
+DEF_DLL_FN (VP8StatusCode, WebPGetFeaturesInternal,
+           (const uint8_t *, size_t, WebPBitstreamFeatures *, int));
+DEF_DLL_FN (uint8_t *, WebPDecodeRGBA, (const uint8_t *, size_t, int *, int 
*));
+DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *));
+DEF_DLL_FN (void, WebPFree, (void *));
+
+static bool
+init_webp_functions (void)
+{
+  HMODULE library;
+
+  if (!(library = w32_delayed_load (Qwebp)))
+    return false;
+
+  LOAD_DLL_FN (library, WebPGetInfo);
+  LOAD_DLL_FN (library, WebPGetFeaturesInternal);
+  LOAD_DLL_FN (library, WebPDecodeRGBA);
+  LOAD_DLL_FN (library, WebPDecodeRGB);
+  LOAD_DLL_FN (library, WebPFree);
+  return true;
+}
+
+#undef WebPGetInfo
+#undef WebPGetFeatures
+#undef WebPDecodeRGBA
+#undef WebPDecodeRGB
+#undef WebPFree
+
+#define WebPGetInfo fn_WebPGetInfo
+#define WebPGetFeatures(d,s,f)                                 \
+  fn_WebPGetFeaturesInternal(d,s,f,WEBP_DECODER_ABI_VERSION)
+#define WebPDecodeRGBA fn_WebPDecodeRGBA
+#define WebPDecodeRGB fn_WebPDecodeRGB
+#define WebPFree fn_WebPFree
+
+#endif /* WINDOWSNT */
+
+/* Load WebP image IMG for use on frame F.  Value is true if
+   successful.  */
+
+static bool
+webp_load (struct frame *f, struct image *img)
+{
+  ptrdiff_t size = 0;
+  uint8_t *contents;
+  Lisp_Object file;
+
+  /* Open the WebP file.  */
+  Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+  Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
+
+  if (NILP (specified_data))
+    {
+      int fd;
+      file = image_find_image_fd (specified_file, &fd);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file);
+         return false;
+       }
+
+      contents = (uint8_t *) slurp_file (fd, &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading WebP image `%s'", file);
+         return false;
+       }
+    }
+  else
+    {
+      if (!STRINGP (specified_data))
+       {
+         image_error ("Invalid image data `%s'", specified_data);
+         return false;
+       }
+      contents = SDATA (specified_data);
+      size = SBYTES (specified_data);
+    }
+
+  /* Validate the WebP image header.  */
+  if (!WebPGetInfo (contents, size, NULL, NULL))
+    {
+      if (NILP (specified_data))
+       image_error ("Not a WebP file: `%s'", file);
+      else
+       image_error ("Invalid header in WebP image data");
+      goto webp_error1;
+    }
+
+  /* Get WebP features.  */
+  WebPBitstreamFeatures features;
+  VP8StatusCode result = WebPGetFeatures (contents, size, &features);
+  switch (result)
+    {
+    case VP8_STATUS_OK:
+      break;
+    case VP8_STATUS_NOT_ENOUGH_DATA:
+    case VP8_STATUS_OUT_OF_MEMORY:
+    case VP8_STATUS_INVALID_PARAM:
+    case VP8_STATUS_BITSTREAM_ERROR:
+    case VP8_STATUS_UNSUPPORTED_FEATURE:
+    case VP8_STATUS_SUSPENDED:
+    case VP8_STATUS_USER_ABORT:
+    default:
+      /* Error out in all other cases.  */
+      if (NILP (specified_data))
+       image_error ("Error when interpreting WebP image data: `%s'", file);
+      else
+       image_error ("Error when interpreting WebP image data");
+      goto webp_error1;
+    }
+
+  /* Decode WebP data.  */
+  uint8_t *decoded;
+  int width, height;
+  if (features.has_alpha)
+    /* Linear [r0, g0, b0, a0, r1, g1, b1, a1, ...] order.  */
+    decoded = WebPDecodeRGBA (contents, size, &width, &height);
+  else
+    /* Linear [r0, g0, b0, r1, g1, b1, ...] order.  */
+    decoded = WebPDecodeRGB (contents, size, &width, &height);
+
+  if (!(width <= INT_MAX && height <= INT_MAX
+       && check_image_size (f, width, height)))
+    {
+      image_size_error ();
+      goto webp_error2;
+    }
+
+  /* Create the x image and pixmap.  */
+  Emacs_Pix_Container ximg, mask_img;
+  if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 
false))
+    goto webp_error2;
+
+  /* Create an image and pixmap serving as mask if the WebP image
+     contains an alpha channel.  */
+  if (features.has_alpha
+      && !image_create_x_image_and_pixmap (f, img, width, height, 1, 
&mask_img, true))
+    {
+      image_destroy_x_image (ximg);
+      image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
+      goto webp_error2;
+    }
+
+  /* Fill the X image and mask from WebP data.  */
+  init_color_table ();
+
+  uint8_t *p = decoded;
+  for (int y = 0; y < height; ++y)
+    {
+      for (int x = 0; x < width; ++x)
+       {
+         int r = *p++ << 8;
+         int g = *p++ << 8;
+         int b = *p++ << 8;
+         PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
+
+         /* An alpha channel associates variable transparency with an
+            image.  WebP allows up to 256 levels of partial transparency.
+            We handle this like with PNG (which see), using the frame's
+            background color to combine the image with.  */
+         if (features.has_alpha)
+           {
+             if (mask_img)
+               PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : 
PIX_MASK_RETAIN);
+             ++p;
+           }
+       }
+    }
+
+#ifdef COLOR_TABLE_SUPPORT
+  /* Remember colors allocated for this image.  */
+  img->colors = colors_in_color_table (&img->ncolors);
+  free_color_table ();
+#endif /* COLOR_TABLE_SUPPORT */
+
+  /* Put ximg into the image.  */
+  image_put_x_image (f, img, ximg, 0);
+
+  /* Same for the mask.  */
+  if (mask_img)
+    {
+      /* Fill in the background_transparent field while we have the
+        mask handy.  Casting avoids a GCC warning.  */
+      image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
+
+      image_put_x_image (f, img, mask_img, 1);
+    }
+
+  img->width = width;
+  img->height = height;
+
+  /* Clean up.  */
+  WebPFree (decoded);
+  if (NILP (specified_data))
+    xfree (contents);
+  return true;
+
+ webp_error2:
+  WebPFree (decoded);
+
+ webp_error1:
+  if (NILP (specified_data))
+    xfree (contents);
+  return false;
+}
+
+#endif /* HAVE_WEBP */
+
+
 #ifdef HAVE_IMAGEMAGICK
 
+
 /***********************************************************************
                                 ImageMagick
 ***********************************************************************/
@@ -9676,14 +9972,15 @@ DEF_DLL_FN (void, rsvg_handle_get_intrinsic_dimensions,
 DEF_DLL_FN (gboolean, rsvg_handle_get_geometry_for_layer,
            (RsvgHandle *, const char *, const RsvgRectangle *,
             RsvgRectangle *, RsvgRectangle *, GError **));
+#  else
+DEF_DLL_FN (void, rsvg_handle_get_dimensions,
+           (RsvgHandle *, RsvgDimensionData *));
 #  endif
 
 #  if LIBRSVG_CHECK_VERSION (2, 48, 0)
 DEF_DLL_FN (gboolean, rsvg_handle_set_stylesheet,
            (RsvgHandle *, const guint8 *, gsize, GError **));
 #  endif
-DEF_DLL_FN (void, rsvg_handle_get_dimensions,
-           (RsvgHandle *, RsvgDimensionData *));
 DEF_DLL_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *));
 DEF_DLL_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *));
 DEF_DLL_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *));
@@ -9734,11 +10031,12 @@ init_svg_functions (void)
 #if LIBRSVG_CHECK_VERSION (2, 46, 0)
   LOAD_DLL_FN (library, rsvg_handle_get_intrinsic_dimensions);
   LOAD_DLL_FN (library, rsvg_handle_get_geometry_for_layer);
+#else
+  LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
 #endif
 #if LIBRSVG_CHECK_VERSION (2, 48, 0)
   LOAD_DLL_FN (library, rsvg_handle_set_stylesheet);
 #endif
-  LOAD_DLL_FN (library, rsvg_handle_get_dimensions);
   LOAD_DLL_FN (library, rsvg_handle_get_pixbuf);
 
   LOAD_DLL_FN (gdklib, gdk_pixbuf_get_width);
@@ -9776,8 +10074,9 @@ init_svg_functions (void)
 #  if LIBRSVG_CHECK_VERSION (2, 46, 0)
 #   undef rsvg_handle_get_intrinsic_dimensions
 #   undef rsvg_handle_get_geometry_for_layer
+#  else
+#   undef rsvg_handle_get_dimensions
 #  endif
-#  undef rsvg_handle_get_dimensions
 #  if LIBRSVG_CHECK_VERSION (2, 48, 0)
 #   undef rsvg_handle_set_stylesheet
 #  endif
@@ -9812,8 +10111,9 @@ init_svg_functions (void)
        fn_rsvg_handle_get_intrinsic_dimensions
 #   define rsvg_handle_get_geometry_for_layer  \
        fn_rsvg_handle_get_geometry_for_layer
+#  else
+#   define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
 #  endif
-#  define rsvg_handle_get_dimensions fn_rsvg_handle_get_dimensions
 #  if LIBRSVG_CHECK_VERSION (2, 48, 0)
 #   define rsvg_handle_set_stylesheet fn_rsvg_handle_set_stylesheet
 #  endif
@@ -9996,10 +10296,16 @@ svg_load_image (struct frame *f, struct image *img, 
char *contents,
   if (!STRINGP (lcss))
     {
       /* Generate the CSS for the SVG image.  */
-      const char *css_spec = "svg{font-family:\"%s\";font-size:%4dpx}";
-      int css_len = strlen (css_spec) + strlen (img->face_font_family);
+      /* FIXME: The below calculations leave enough space for a font
+        size up to 9999, if it overflows we just throw an error but
+        should probably increase the buffer size.  */
+      const char *css_spec = "svg{font-family:\"%s\";font-size:%dpx}";
+      int css_len = strlen (css_spec) + strlen (img->face_font_family) + 1;
       css = xmalloc (css_len);
-      snprintf (css, css_len, css_spec, img->face_font_family, 
img->face_font_size);
+      if (css_len <= snprintf (css, css_len, css_spec,
+                              img->face_font_family, img->face_font_size))
+       goto rsvg_error;
+
       rsvg_handle_set_stylesheet (rsvg_handle, (guint8 *)css, strlen (css), 
NULL);
     }
   else
@@ -10082,21 +10388,13 @@ svg_load_image (struct frame *f, struct image *img, 
char *contents,
       viewbox_width = viewbox.x + viewbox.width;
       viewbox_height = viewbox.y + viewbox.height;
     }
-
-  if (viewbox_width == 0 || viewbox_height == 0)
+#else
+  /* In librsvg before 2.46.0, guess the viewbox from the image dimensions.  */
+  RsvgDimensionData dimension_data;
+  rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
+  viewbox_width = dimension_data.width;
+  viewbox_height = dimension_data.height;
 #endif
-  {
-    /* The functions used above to get the geometry of the visible
-       area of the SVG are only available in librsvg 2.46 and above,
-       so in certain circumstances this code path can result in some
-       parts of the SVG being cropped.  */
-    RsvgDimensionData dimension_data;
-
-    rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
-
-    viewbox_width = dimension_data.width;
-    viewbox_height = dimension_data.height;
-  }
 
   compute_image_size (viewbox_width, viewbox_height, img,
                       &width, &height);
@@ -10157,12 +10455,11 @@ svg_load_image (struct frame *f, struct image *img, 
char *contents,
 
     wrapped_contents = xmalloc (buffer_size);
 
-    if (!wrapped_contents
-        || buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
-                                    foreground & 0xFFFFFF, width, height,
-                                    viewbox_width, viewbox_height,
-                                    background & 0xFFFFFF,
-                                    SSDATA (encoded_contents)))
+    if (buffer_size <= snprintf (wrapped_contents, buffer_size, wrapper,
+                                foreground & 0xFFFFFF, width, height,
+                                viewbox_width, viewbox_height,
+                                background & 0xFFFFFF,
+                                SSDATA (encoded_contents)))
       goto rsvg_error;
 
     wrapped_size = strlen (wrapped_contents);
@@ -10721,6 +11018,10 @@ static struct image_type const image_types[] =
 #if defined HAVE_XPM || defined HAVE_NS
  { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
    IMAGE_TYPE_INIT (init_xpm_functions) },
+#endif
+#if defined HAVE_WEBP
+ { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image,
+   IMAGE_TYPE_INIT (init_webp_functions) },
 #endif
  { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image },
  { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
@@ -10887,6 +11188,11 @@ non-numeric, there is no explicit limit on the size of 
images.  */);
   add_image_type (Qpng);
 #endif
 
+#if defined (HAVE_WEBP)
+  DEFSYM (Qwebp, "webp");
+  add_image_type (Qwebp);
+#endif
+
 #if defined (HAVE_IMAGEMAGICK)
   DEFSYM (Qimagemagick, "imagemagick");
   add_image_type (Qimagemagick);
diff --git a/src/intervals.c b/src/intervals.c
index f88a41f254..11d5b6bbb6 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -166,10 +166,11 @@ merge_properties (register INTERVAL source, register 
INTERVAL target)
     }
 }
 
-/* Return true if the two intervals have the same properties.  */
+/* Return true if the two intervals have the same properties.
+   If use_equal is true, use Fequal for comparisons instead of EQ.  */
 
-bool
-intervals_equal (INTERVAL i0, INTERVAL i1)
+static bool
+intervals_equal_1 (INTERVAL i0, INTERVAL i1, bool use_equal)
 {
   Lisp_Object i0_cdr, i0_sym;
   Lisp_Object i1_cdr, i1_val;
@@ -204,7 +205,8 @@ intervals_equal (INTERVAL i0, INTERVAL i1)
       /* i0 and i1 both have sym, but it has different values in each.  */
       if (!CONSP (i1_val)
          || (i1_val = XCDR (i1_val), !CONSP (i1_val))
-         || !EQ (XCAR (i1_val), XCAR (i0_cdr)))
+         || use_equal ? NILP (Fequal (XCAR (i1_val), XCAR (i0_cdr)))
+                      : !EQ (XCAR (i1_val), XCAR (i0_cdr)))
        return false;
 
       i0_cdr = XCDR (i0_cdr);
@@ -218,6 +220,14 @@ intervals_equal (INTERVAL i0, INTERVAL i1)
   /* Lengths of the two plists were equal.  */
   return (NILP (i0_cdr) && NILP (i1_cdr));
 }
+
+/* Return true if the two intervals have the same properties.  */
+
+bool
+intervals_equal (INTERVAL i0, INTERVAL i1)
+{
+  return intervals_equal_1 (i0, i1, false);
+}
 
 
 /* Traverse an interval tree TREE, performing FUNCTION on each node.
@@ -2291,7 +2301,7 @@ compare_string_intervals (Lisp_Object s1, Lisp_Object s2)
 
       /* If we ever find a mismatch between the strings,
         they differ.  */
-      if (! intervals_equal (i1, i2))
+      if (! intervals_equal_1 (i1, i2, true))
        return 0;
 
       /* Advance POS till the end of the shorter interval,
diff --git a/src/keyboard.c b/src/keyboard.c
index bc6f97586d..de9805df32 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -375,6 +375,7 @@ static void timer_resume_idle (void);
 static void deliver_user_signal (int);
 static char *find_user_signal_name (int);
 static void store_user_signal_events (void);
+static bool is_ignored_event (union buffered_input_event *);
 
 /* Advance or retreat a buffered input event pointer.  */
 
@@ -2943,20 +2944,8 @@ read_char (int commandflag, Lisp_Object map,
       last_input_event = c;
       call4 (Qcommand_execute, tem, Qnil, Fvector (1, &last_input_event), Qt);
 
-      if (CONSP (c)
-          && (EQ (XCAR (c), Qselect_window)
-              || EQ (XCAR (c), Qfocus_out)
-#ifdef HAVE_DBUS
-             || EQ (XCAR (c), Qdbus_event)
-#endif
-#ifdef USE_FILE_NOTIFY
-             || EQ (XCAR (c), Qfile_notify)
-#endif
-#ifdef THREADS_ENABLED
-             || EQ (XCAR (c), Qthread_event)
-#endif
-             || EQ (XCAR (c), Qconfig_changed_event))
-          && !end_time)
+      if (CONSP (c) && !NILP (Fmemq (XCAR (c), Vwhile_no_input_ignore_events))
+         && !end_time)
        /* We stopped being idle for this event; undo that.  This
           prevents automatic window selection (under
           mouse-autoselect-window) from acting as a real input event, for
@@ -3458,10 +3447,17 @@ readable_events (int flags)
   if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
     timer_check ();
 
-  /* If the buffer contains only FOCUS_IN/OUT_EVENT events, and
-     READABLE_EVENTS_FILTER_EVENTS is set, report it as empty.  */
+  /* READABLE_EVENTS_FILTER_EVENTS is meant to be used only by
+     input-pending-p and similar callers, which aren't interested in
+     some input events.  If this flag is set, and
+     input-pending-p-filter-events is non-nil, ignore events in
+     while-no-input-ignore-events.  If the flag is set and
+     input-pending-p-filter-events is nil, ignore only
+     FOCUS_IN/OUT_EVENT events.  */
   if (kbd_fetch_ptr != kbd_store_ptr)
     {
+      /* See https://lists.gnu.org/r/emacs-devel/2005-05/msg00297.html
+        for why we treat toolkit scroll-bar events specially here.  */
       if (flags & (READABLE_EVENTS_FILTER_EVENTS
 #ifdef USE_TOOLKIT_SCROLL_BARS
                   | READABLE_EVENTS_IGNORE_SQUEEZABLES
@@ -3476,8 +3472,11 @@ readable_events (int flags)
 #ifdef USE_TOOLKIT_SCROLL_BARS
                    (flags & READABLE_EVENTS_FILTER_EVENTS) &&
 #endif
-                   (event->kind == FOCUS_IN_EVENT
-                     || event->kind == FOCUS_OUT_EVENT))
+                   ((!input_pending_p_filter_events
+                     && (event->kind == FOCUS_IN_EVENT
+                         || event->kind == FOCUS_OUT_EVENT))
+                    || (input_pending_p_filter_events
+                        && is_ignored_event (event))))
 #ifdef USE_TOOLKIT_SCROLL_BARS
                  && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
                       && (event->kind == SCROLL_BAR_CLICK_EVENT
@@ -3659,29 +3658,10 @@ kbd_buffer_store_buffered_event (union 
buffered_input_event *event,
 #endif /* subprocesses */
     }
 
-  Lisp_Object ignore_event;
-
-  switch (event->kind)
-    {
-    case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break;
-    case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break;
-    case HELP_EVENT: ignore_event = Qhelp_echo; break;
-    case ICONIFY_EVENT: ignore_event = Qiconify_frame; break;
-    case DEICONIFY_EVENT: ignore_event = Qmake_frame_visible; break;
-    case SELECTION_REQUEST_EVENT: ignore_event = Qselection_request; break;
-#ifdef USE_FILE_NOTIFY
-    case FILE_NOTIFY_EVENT: ignore_event = Qfile_notify; break;
-#endif
-#ifdef HAVE_DBUS
-    case DBUS_EVENT: ignore_event = Qdbus_event; break;
-#endif
-    default: ignore_event = Qnil; break;
-    }
-
   /* If we're inside while-no-input, and this event qualifies
      as input, set quit-flag to cause an interrupt.  */
   if (!NILP (Vthrow_on_input)
-      && NILP (Fmemq (ignore_event, Vwhile_no_input_ignore_events)))
+      && !is_ignored_event (event))
     Vquit_flag = Vthrow_on_input;
 }
 
@@ -4013,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #endif
 #ifdef HAVE_XWIDGETS
       case XWIDGET_EVENT:
+      case XWIDGET_DISPLAY_EVENT:
 #endif
       case SAVE_SESSION_EVENT:
       case NO_EVENT:
@@ -4917,7 +4898,7 @@ static const char *const lispy_kana_keys[] =
 
 /* You'll notice that this table is arranged to be conveniently
    indexed by X Windows keysym values.  */
-static const char *const lispy_function_keys[] =
+const char *const lispy_function_keys[] =
   {
     /* X Keysym value */
 
@@ -5122,7 +5103,20 @@ make_lispy_position (struct frame *f, Lisp_Object x, 
Lisp_Object y,
 #endif
       )
     {
-      posn = EQ (window_or_frame, f->tab_bar_window) ? Qtab_bar : Qtool_bar;
+      /* FIXME: While track_mouse is non-nil, we do not report this
+        event as something that happened on the tool or tab bar since
+        that would break mouse dragging operations that originate from
+        an ordinary window beneath and expect the window to auto-scroll
+        as soon as the mouse cursor appears above or beneath it
+        (Bug#50993).  Since this "fix" might break track_mouse based
+        operations originating from the tool or tab bar itself, such
+        operations should set track_mouse to some special value that
+        would be recognized by the following check.
+
+        This issue should be properly handled by 'mouse-drag-track' and
+        friends, so the below is only a temporary workaround.  */
+      if (NILP (track_mouse))
+       posn = EQ (window_or_frame, f->tab_bar_window) ? Qtab_bar : Qtool_bar;
       /* Kludge alert: for mouse events on the tab bar and tool bar,
         keyboard.c wants the frame, not the special-purpose window
         we use to display those, and it wants frame-relative
@@ -5130,7 +5124,8 @@ make_lispy_position (struct frame *f, Lisp_Object x, 
Lisp_Object y,
       window_or_frame = Qnil;
     }
 #endif
-  if (!FRAME_WINDOW_P (f)
+  if (f
+      && !FRAME_WINDOW_P (f)
       && FRAME_TAB_BAR_LINES (f) > 0
       && my >= FRAME_MENU_BAR_LINES (f)
       && my < FRAME_MENU_BAR_LINES (f) + FRAME_TAB_BAR_LINES (f))
@@ -6128,23 +6123,20 @@ make_lispy_event (struct input_event *event)
 
 #ifdef HAVE_DBUS
     case DBUS_EVENT:
-      {
-       return Fcons (Qdbus_event, event->arg);
-      }
+      return Fcons (Qdbus_event, event->arg);
 #endif /* HAVE_DBUS */
 
 #ifdef THREADS_ENABLED
     case THREAD_EVENT:
-      {
-       return Fcons (Qthread_event, event->arg);
-      }
+      return Fcons (Qthread_event, event->arg);
 #endif /* THREADS_ENABLED */
 
 #ifdef HAVE_XWIDGETS
     case XWIDGET_EVENT:
-      {
-        return Fcons (Qxwidget_event, event->arg);
-      }
+      return Fcons (Qxwidget_event, event->arg);
+
+    case XWIDGET_DISPLAY_EVENT:
+      return list2 (Qxwidget_display_event, event->arg);
 #endif
 
 #ifdef USE_FILE_NOTIFY
@@ -7840,7 +7832,9 @@ parse_menu_item (Lisp_Object item, int inmenubar)
              else if (EQ (tem, QCkeys))
                {
                  tem = XCAR (item);
-                 if (CONSP (tem) || STRINGP (tem))
+                 if (FUNCTIONP (tem))
+                   ASET (item_properties, ITEM_PROPERTY_KEYEQ, call0 (tem));
+                 else if (CONSP (tem) || STRINGP (tem))
                    ASET (item_properties, ITEM_PROPERTY_KEYEQ, tem);
                }
              else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
@@ -10168,7 +10162,8 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object 
prompt,
         use the corresponding lower-case letter instead.  */
       if (NILP (current_binding)
          && /* indec.start >= t && fkey.start >= t && */ keytran.start >= t
-         && FIXNUMP (key))
+         && FIXNUMP (key)
+         && translate_upper_case_key_bindings)
        {
          Lisp_Object new_key;
          EMACS_INT k = XFIXNUM (key);
@@ -10220,12 +10215,14 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object 
prompt,
          int modifiers
            = CONSP (breakdown) ? (XFIXNUM (XCAR (XCDR (breakdown)))) : 0;
 
-         if (modifiers & shift_modifier
-             /* Treat uppercase keys as shifted.  */
-             || (FIXNUMP (key)
-                 && (KEY_TO_CHAR (key)
-                     < XCHAR_TABLE (BVAR (current_buffer, 
downcase_table))->header.size)
-                 && uppercasep (KEY_TO_CHAR (key))))
+         if (translate_upper_case_key_bindings
+             && (modifiers & shift_modifier
+                 /* Treat uppercase keys as shifted.  */
+                 || (FIXNUMP (key)
+                     && (KEY_TO_CHAR (key)
+                         < XCHAR_TABLE (BVAR (current_buffer,
+                                              downcase_table))->header.size)
+                     && uppercasep (KEY_TO_CHAR (key)))))
            {
              Lisp_Object new_key
                = (modifiers & shift_modifier
@@ -11332,6 +11329,8 @@ The elements of this list correspond to the arguments of
 DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
        doc: /* Return position information for pixel coordinates X and Y.
 By default, X and Y are relative to text area of the selected window.
+Note that the text area includes the header-line and the tab-line of
+the window, if any of them are present.
 Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window.
 If optional fourth arg WHOLE is non-nil, X is relative to the left
 edge of the window.
@@ -11599,6 +11598,52 @@ static const struct event_head head_table[] = {
   {SYMBOL_INDEX (Qselect_window),       SYMBOL_INDEX (Qswitch_frame)}
 };
 
+static Lisp_Object
+init_while_no_input_ignore_events (void)
+{
+  Lisp_Object events = listn (9, Qselect_window, Qhelp_echo, Qmove_frame,
+                             Qiconify_frame, Qmake_frame_visible,
+                             Qfocus_in, Qfocus_out, Qconfig_changed_event,
+                             Qselection_request);
+
+#ifdef HAVE_DBUS
+  events = Fcons (Qdbus_event, events);
+#endif
+#ifdef USE_FILE_NOTIFY
+  events = Fcons (Qfile_notify, events);
+#endif
+#ifdef THREADS_ENABLED
+  events = Fcons (Qthread_event, events);
+#endif
+
+  return events;
+}
+
+static bool
+is_ignored_event (union buffered_input_event *event)
+{
+  Lisp_Object ignore_event;
+
+  switch (event->kind)
+    {
+    case FOCUS_IN_EVENT: ignore_event = Qfocus_in; break;
+    case FOCUS_OUT_EVENT: ignore_event = Qfocus_out; break;
+    case HELP_EVENT: ignore_event = Qhelp_echo; break;
+    case ICONIFY_EVENT: ignore_event = Qiconify_frame; break;
+    case DEICONIFY_EVENT: ignore_event = Qmake_frame_visible; break;
+    case SELECTION_REQUEST_EVENT: ignore_event = Qselection_request; break;
+#ifdef USE_FILE_NOTIFY
+    case FILE_NOTIFY_EVENT: ignore_event = Qfile_notify; break;
+#endif
+#ifdef HAVE_DBUS
+    case DBUS_EVENT: ignore_event = Qdbus_event; break;
+#endif
+    default: ignore_event = Qnil; break;
+    }
+
+  return !NILP (Fmemq (ignore_event, Vwhile_no_input_ignore_events));
+}
+
 static void syms_of_keyboard_for_pdumper (void);
 
 void
@@ -11685,6 +11730,7 @@ syms_of_keyboard (void)
 
 #ifdef HAVE_XWIDGETS
   DEFSYM (Qxwidget_event, "xwidget-event");
+  DEFSYM (Qxwidget_display_event, "xwidget-display-event");
 #endif
 
 #ifdef USE_FILE_NOTIFY
@@ -12493,7 +12539,29 @@ If nil, Emacs crashes immediately in response to fatal 
signals.  */);
 
   DEFVAR_LISP ("while-no-input-ignore-events",
                Vwhile_no_input_ignore_events,
-               doc: /* Ignored events from while-no-input.  */);
+               doc: /* Ignored events from `while-no-input'.
+Events in this list do not count as pending input while running
+`while-no-input' and do not cause any idle timers to get reset when they
+occur.  */);
+  Vwhile_no_input_ignore_events = init_while_no_input_ignore_events ();
+
+  DEFVAR_BOOL ("translate-upper-case-key-bindings",
+               translate_upper_case_key_bindings,
+               doc: /* If non-nil, interpret upper case keys as lower case 
(when applicable).
+Emacs allows binding both upper and lower case key sequences to
+commands.  However, if there is a lower case key sequence bound to a
+command, and the user enters an upper case key sequence that is not
+bound to a command, Emacs will use the lower case binding.  Setting
+this variable to nil inhibits this behaviour.  */);
+  translate_upper_case_key_bindings = true;
+
+  DEFVAR_BOOL ("input-pending-p-filter-events",
+               input_pending_p_filter_events,
+               doc: /* If non-nil, `input-pending-p' ignores some input events.
+If this variable is non-nil (the default), `input-pending-p' and
+other similar functions ignore input events in `while-no-input-ignore-events'.
+This flag may eventually be removed once this behavior is deemed safe.  */);
+  input_pending_p_filter_events = true;
 
   pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
 }
diff --git a/src/keyboard.h b/src/keyboard.h
index 8bdffaa2bf..21c51ec386 100644
--- a/src/keyboard.h
+++ b/src/keyboard.h
@@ -491,7 +491,7 @@ extern void process_pending_signals (void);
 extern struct timespec timer_check (void);
 extern void mark_kboards (void);
 
-#ifdef HAVE_NTGUI
+#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS
 extern const char *const lispy_function_keys[];
 #endif
 
diff --git a/src/keymap.c b/src/keymap.c
index be45d2be1e..29d2ca7ab7 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -65,6 +65,9 @@ static Lisp_Object exclude_keys;
 /* Pre-allocated 2-element vector for Fcommand_remapping to use.  */
 static Lisp_Object command_remapping_vector;
 
+/* Char table for the backwards-compatibility part in Flookup_key.  */
+static Lisp_Object unicode_case_table;
+
 /* Hash table used to cache a reverse-map to speed up calls to where-is.  */
 static Lisp_Object where_is_cache;
 /* Which keymaps are reverse-stored in the cache.  */
@@ -629,6 +632,9 @@ the definition it is bound to.  The event may be a 
character range.
 If KEYMAP has a parent, the parent's bindings are included as well.
 This works recursively: if the parent has itself a parent, then the
 grandparent's bindings are also included and so on.
+
+For more information, see Info node `(elisp) Keymaps'.
+
 usage: (map-keymap FUNCTION KEYMAP)  */)
   (Lisp_Object function, Lisp_Object keymap, Lisp_Object sort_first)
 {
@@ -1024,6 +1030,28 @@ is not copied.  */)
 
 /* Simple Keymap mutators and accessors.                               */
 
+static Lisp_Object
+possibly_translate_key_sequence (Lisp_Object key, ptrdiff_t *length)
+{
+  if (VECTORP (key) && ASIZE (key) == 1 && STRINGP (AREF (key, 0)))
+    {
+      /* KEY is on the ["C-c"] format, so translate to internal
+        format.  */
+      if (NILP (Ffboundp (Qkbd_valid_p)))
+       xsignal2 (Qerror,
+                 build_string ("`kbd-valid-p' is not defined, so this syntax 
can't be used: %s"),
+                 key);
+      if (NILP (call1 (Qkbd_valid_p, AREF (key, 0))))
+       xsignal2 (Qerror, build_string ("Invalid `kbd' syntax: %S"), key);
+      key = call1 (Qkbd, AREF (key, 0));
+      *length = CHECK_VECTOR_OR_STRING (key);
+      if (*length == 0)
+       xsignal2 (Qerror, build_string ("Invalid `kbd' syntax: %S"), key);
+    }
+
+  return key;
+}
+
 /* GC is possible in this function if it autoloads a keymap.  */
 
 DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
@@ -1047,7 +1075,9 @@ DEF is anything that can be a key's definition:
     function definition, which should at that time be one of the above,
     or another symbol whose function definition is used, etc.),
  a cons (STRING . DEFN), meaning that DEFN is the definition
-    (DEFN should be a valid definition in its own right),
+    (DEFN should be a valid definition in its own right) and
+    STRING is the menu item name (which is used only if the containing
+    keymap has been created with a menu name, see `make-keymap'),
  or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
  or an extended menu item definition.
  (See info node `(elisp)Extended Menu Items'.)
@@ -1082,6 +1112,8 @@ binding KEY to DEF is added at the front of KEYMAP.  */)
       def = tmp;
     }
 
+  key = possibly_translate_key_sequence (key, &length);
+
   ptrdiff_t idx = 0;
   while (1)
     {
@@ -1180,27 +1212,8 @@ remapping in all currently active keymaps.  */)
   return FIXNUMP (command) ? Qnil : command;
 }
 
-/* Value is number if KEY is too long; nil if valid but has no definition.  */
-/* GC is possible in this function.  */
-
-DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
-       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
-A value of nil means undefined.  See doc of `define-key'
-for kinds of definitions.
-
-A number as value means KEY is "too long";
-that is, characters or symbols in it except for the last one
-fail to be a valid sequence of prefix characters in KEYMAP.
-The number is how many characters at the front of KEY
-it takes to reach a non-prefix key.
-KEYMAP can also be a list of keymaps.
-
-Normally, `lookup-key' ignores bindings for t, which act as default
-bindings, used when nothing else in the keymap applies; this makes it
-usable as a general function for probing keymaps.  However, if the
-third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
-recognize the default bindings, just as `read-key-sequence' does.  */)
-  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+static Lisp_Object
+lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
 {
   bool t_ok = !NILP (accept_default);
 
@@ -1211,6 +1224,8 @@ recognize the default bindings, just as 
`read-key-sequence' does.  */)
   if (length == 0)
     return keymap;
 
+  key = possibly_translate_key_sequence (key, &length);
+
   ptrdiff_t idx = 0;
   while (1)
     {
@@ -1240,6 +1255,156 @@ recognize the default bindings, just as 
`read-key-sequence' does.  */)
     }
 }
 
+/* Value is number if KEY is too long; nil if valid but has no definition.  */
+/* GC is possible in this function.  */
+
+DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
+       doc: /* Look up key sequence KEY in KEYMAP.  Return the definition.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
+
+A number as value means KEY is "too long";
+that is, characters or symbols in it except for the last one
+fail to be a valid sequence of prefix characters in KEYMAP.
+The number is how many characters at the front of KEY
+it takes to reach a non-prefix key.
+KEYMAP can also be a list of keymaps.
+
+Normally, `lookup-key' ignores bindings for t, which act as default
+bindings, used when nothing else in the keymap applies; this makes it
+usable as a general function for probing keymaps.  However, if the
+third optional argument ACCEPT-DEFAULT is non-nil, `lookup-key' will
+recognize the default bindings, just as `read-key-sequence' does.  */)
+  (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
+{
+  Lisp_Object found = lookup_key_1 (keymap, key, accept_default);
+  if (!NILP (found) && !NUMBERP (found))
+    return found;
+
+  /* Menu definitions might use mixed case symbols (notably in old
+     versions of `easy-menu-define'), or use " " instead of "-".
+     The rest of this function is about accepting these variations for
+     backwards-compatibility.  (Bug#50752) */
+
+  /* Just skip everything below unless this is a menu item.  */
+  if (!VECTORP (key) || !(ASIZE (key) > 0)
+      || !EQ (AREF (key, 0), Qmenu_bar))
+    return found;
+
+  /* Initialize the unicode case table, if it wasn't already.  */
+  if (NILP (unicode_case_table))
+    {
+      unicode_case_table = uniprop_table (intern ("lowercase"));
+      /* uni-lowercase.el might be unavailable during bootstrap.  */
+      if (NILP (unicode_case_table))
+       return found;
+      staticpro (&unicode_case_table);
+    }
+
+  ptrdiff_t key_len = ASIZE (key);
+  Lisp_Object new_key = make_vector (key_len, Qnil);
+
+  /* Try both the Unicode case table, and the buffer local one.
+     Otherwise, we will fail for e.g. the "Turkish" language
+     environment where 'I' does not downcase to 'i'.  */
+  Lisp_Object tables[2] = {unicode_case_table, Fcurrent_case_table ()};
+  for (int tbl_num = 0; tbl_num < 2; tbl_num++)
+    {
+      /* First, let's try converting all symbols like "Foo-Bar-Baz" to
+        "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+       {
+         Lisp_Object item = AREF (key, i);
+         if (!SYMBOLP (item))
+           ASET (new_key, i, item);
+         else
+           {
+             Lisp_Object key_item = Fsymbol_name (item);
+             Lisp_Object new_item;
+             if (!STRING_MULTIBYTE (key_item))
+               new_item = Fdowncase (key_item);
+             else
+               {
+                 USE_SAFE_ALLOCA;
+                 ptrdiff_t size = SCHARS (key_item), n;
+                 if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+                   n = PTRDIFF_MAX;
+                 unsigned char *dst = SAFE_ALLOCA (n);
+                 unsigned char *p = dst;
+                 ptrdiff_t j_char = 0, j_byte = 0;
+
+                 while (j_char < size)
+                   {
+                     int ch = fetch_string_char_advance (key_item,
+                                                         &j_char, &j_byte);
+                     Lisp_Object ch_conv = CHAR_TABLE_REF (tables[tbl_num],
+                                                           ch);
+                     if (!NILP (ch_conv))
+                       CHAR_STRING (XFIXNUM (ch_conv), p);
+                     else
+                       CHAR_STRING (ch, p);
+                     p = dst + j_byte;
+                   }
+                 new_item = make_multibyte_string ((char *) dst,
+                                                   SCHARS (key_item),
+                                                   SBYTES (key_item));
+                 SAFE_FREE ();
+               }
+             ASET (new_key, i, Fintern (new_item, Qnil));
+           }
+       }
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+       break;
+
+      /* If we still don't have a match, let's convert any spaces in
+        our lowercased string into dashes, e.g. "foo bar baz" to
+        "foo-bar-baz".  */
+      for (int i = 0; i < key_len; i++)
+       {
+         if (!SYMBOLP (AREF (new_key, i)))
+           continue;
+
+         Lisp_Object lc_key = Fsymbol_name (AREF (new_key, i));
+
+         /* If there are no spaces in this symbol, just skip it.  */
+         if (!strstr (SSDATA (lc_key), " "))
+           continue;
+
+         USE_SAFE_ALLOCA;
+         ptrdiff_t size = SCHARS (lc_key), n;
+         if (INT_MULTIPLY_WRAPV (size, MAX_MULTIBYTE_LENGTH, &n))
+           n = PTRDIFF_MAX;
+         unsigned char *dst = SAFE_ALLOCA (n);
+
+         /* We can walk the string data byte by byte, because UTF-8
+            encoding ensures that no other byte of any multibyte
+            sequence will ever include a 7-bit byte equal to an ASCII
+            single-byte character.  */
+         memcpy (dst, SSDATA (lc_key), SBYTES (lc_key));
+         for (int i = 0; i < SBYTES (lc_key); ++i)
+           {
+             if (dst[i] == ' ')
+               dst[i] = '-';
+           }
+         Lisp_Object new_it =
+           make_multibyte_string ((char *) dst,
+                                  SCHARS (lc_key), SBYTES (lc_key));
+         ASET (new_key, i, Fintern (new_it, Qnil));
+         SAFE_FREE ();
+       }
+
+      /* Check for match.  */
+      found = lookup_key_1 (keymap, new_key, accept_default);
+      if (!NILP (found) && !NUMBERP (found))
+       break;
+    }
+
+  return found;
+}
+
 /* Make KEYMAP define event C as a keymap (i.e., as a prefix).
    Assume that currently it does not define C at all.
    Return the keymap.  */
@@ -2768,7 +2933,10 @@ You type        Translation\n\
        {
          if (EQ (start1, BVAR (XBUFFER (buffer), keymap)))
            {
-             Lisp_Object msg = build_unibyte_string ("\f\nMajor Mode 
Bindings");
+             Lisp_Object msg =
+               CALLN (Fformat,
+                      build_unibyte_string ("\f\n`%s' Major Mode Bindings"),
+                      XBUFFER (buffer)->major_mode_);
              CALLN (Ffuncall,
                     Qdescribe_map_tree,
                     start1, Qt, shadow, prefix,
@@ -3261,4 +3429,7 @@ that describe key bindings.  That is why the default is 
nil.  */);
   defsubr (&Stext_char_description);
   defsubr (&Swhere_is_internal);
   defsubr (&Sdescribe_buffer_bindings);
+
+  DEFSYM (Qkbd, "kbd");
+  DEFSYM (Qkbd_valid_p, "kbd-valid-p");
 }
diff --git a/src/lisp.h b/src/lisp.h
index 09e0b8e9bd..31656bb3b1 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2827,9 +2827,8 @@ enum Lisp_Compiled
   };
 
 /* Flag bits in a character.  These also get used in termhooks.h.
-   Richard Stallman <rms@gnu.ai.mit.edu> thinks that MULE
-   (MUlti-Lingual Emacs) might need 22 bits for the character value
-   itself, so we probably shouldn't use any bits lower than 0x0400000.  */
+   Emacs needs 22 bits for the character value itself, see MAX_CHAR,
+   so we shouldn't use any bits lower than 0x0400000.  */
 enum char_bits
   {
     CHAR_ALT = 0x0400000,
@@ -3948,7 +3947,8 @@ build_string (const char *str)
 
 extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
-extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
+extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t)
+  ATTRIBUTE_RETURNS_NONNULL;
 
 /* Make an uninitialized vector for SIZE objects.  NOTE: you must
    be sure that GC cannot happen until the vector is completely
@@ -3961,7 +3961,8 @@ extern struct Lisp_Vector *allocate_nil_vector 
(ptrdiff_t);
 
    allocate_vector has a similar problem.  */
 
-extern struct Lisp_Vector *allocate_vector (ptrdiff_t);
+extern struct Lisp_Vector *allocate_vector (ptrdiff_t)
+  ATTRIBUTE_RETURNS_NONNULL;
 
 INLINE Lisp_Object
 make_uninit_vector (ptrdiff_t size)
@@ -3993,7 +3994,8 @@ make_nil_vector (ptrdiff_t size)
 }
 
 extern struct Lisp_Vector *allocate_pseudovector (int, int, int,
-                                                 enum pvec_type);
+                                                 enum pvec_type)
+  ATTRIBUTE_RETURNS_NONNULL;
 
 /* Allocate uninitialized pseudovector with no Lisp_Object slots.  */
 
@@ -4025,7 +4027,7 @@ extern void free_cons (struct Lisp_Cons *);
 extern void init_alloc_once (void);
 extern void init_alloc (void);
 extern void syms_of_alloc (void);
-extern struct buffer * allocate_buffer (void);
+extern struct buffer *allocate_buffer (void) ATTRIBUTE_RETURNS_NONNULL;
 extern int valid_lisp_object_p (Lisp_Object);
 
 /* Defined in gmalloc.c.  */
@@ -4183,7 +4185,8 @@ extern Lisp_Object internal_condition_case_n
     (Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *,
      Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *));
 extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, 
Lisp_Object (*) (enum nonlocal_exit, Lisp_Object));
-extern struct handler *push_handler (Lisp_Object, enum handlertype);
+extern struct handler *push_handler (Lisp_Object, enum handlertype)
+  ATTRIBUTE_RETURNS_NONNULL;
 extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype);
 extern void specbind (Lisp_Object, Lisp_Object);
 extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object);
@@ -4324,9 +4327,10 @@ extern void syms_of_marker (void);
 
 /* Defined in fileio.c.  */
 
-extern char *splice_dir_file (char *, char const *, char const *);
+extern char *splice_dir_file (char *, char const *, char const *)
+  ATTRIBUTE_RETURNS_NONNULL;
 extern bool file_name_absolute_p (const char *);
-extern char const *get_homedir (void);
+extern char const *get_homedir (void) ATTRIBUTE_RETURNS_NONNULL;
 extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
 extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
                                 Lisp_Object, Lisp_Object, Lisp_Object,
@@ -4480,7 +4484,7 @@ INLINE void fixup_locale (void) {}
 INLINE void synchronize_system_messages_locale (void) {}
 INLINE void synchronize_system_time_locale (void) {}
 #endif
-extern char *emacs_strerror (int);
+extern char *emacs_strerror (int) ATTRIBUTE_RETURNS_NONNULL;
 extern void shut_down_emacs (int, Lisp_Object);
 
 /* True means don't do interactive redisplay and don't change tty modes.  */
@@ -4546,7 +4550,7 @@ extern void setup_process_coding_systems (Lisp_Object);
 
 extern int emacs_spawn (pid_t *, int, int, int, char **, char **,
                         const char *, const char *, const sigset_t *);
-extern char **make_environment_block (Lisp_Object);
+extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL;
 extern void init_callproc_1 (void);
 extern void init_callproc (void);
 extern void set_initial_environment (void);
@@ -4815,17 +4819,24 @@ extern char my_edata[];
 extern char my_endbss[];
 extern char *my_endbss_static;
 
-extern void *xmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1));
-extern void *xzalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1));
-extern void *xrealloc (void *, size_t) ATTRIBUTE_ALLOC_SIZE ((2));
+extern void *xmalloc (size_t)
+  ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
+extern void *xzalloc (size_t)
+  ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
+extern void *xrealloc (void *, size_t)
+  ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL;
 extern void xfree (void *);
-extern void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2));
+extern void *xnmalloc (ptrdiff_t, ptrdiff_t)
+  ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL;
 extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
-  ATTRIBUTE_ALLOC_SIZE ((2,3));
-extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t);
-
-extern char *xstrdup (const char *) ATTRIBUTE_MALLOC;
-extern char *xlispstrdup (Lisp_Object) ATTRIBUTE_MALLOC;
+  ATTRIBUTE_ALLOC_SIZE ((2,3)) ATTRIBUTE_RETURNS_NONNULL;
+extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t)
+  ATTRIBUTE_RETURNS_NONNULL;
+
+extern char *xstrdup (char const *)
+  ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+extern char *xlispstrdup (Lisp_Object)
+  ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
 extern void dupstring (char **, char const *);
 
 /* Make DEST a copy of STRING's data.  Return a pointer to DEST's terminating
@@ -4875,7 +4886,8 @@ extern void init_system_name (void);
 
 enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 };
 
-extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1));
+extern void *record_xmalloc (size_t)
+  ATTRIBUTE_ALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
 
 #define USE_SAFE_ALLOCA                        \
   ptrdiff_t sa_avail = MAX_ALLOCA;     \
diff --git a/src/lread.c b/src/lread.c
index 2abe2fd91a..b3f9e6ff52 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -165,6 +165,12 @@ static void readevalloop (Lisp_Object, struct infile *, 
Lisp_Object, bool,
                           Lisp_Object, Lisp_Object);
 
 static void build_load_history (Lisp_Object, bool);
+
+static Lisp_Object oblookup_considering_shorthand (Lisp_Object, const char *,
+                                                  ptrdiff_t, ptrdiff_t,
+                                                  char **, ptrdiff_t *,
+                                                  ptrdiff_t *);
+
 
 /* Functions that read one byte from the current source READCHARFUN
    or unreads one byte.  If the integer argument C is -1, it returns
@@ -2956,7 +2962,6 @@ read_integer (Lisp_Object readcharfun, int radix,
   return unbind_to (count, string_to_number (read_buffer, radix, NULL));
 }
 
-
 /* If the next token is ')' or ']' or '.', we store that character
    in *PCH and the return value is not interesting.  Else, we store
    zero in *PCH and we read and return one lisp object.
@@ -2968,6 +2973,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
 {
   int c;
   bool uninterned_symbol = false;
+  bool skip_shorthand = false;
   bool multibyte;
   char stackbuf[stackbufsize];
   current_thread->stack_top = stackbuf;
@@ -3363,6 +3369,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
       if (c == ':')
        {
          uninterned_symbol = true;
+       read_hash_prefixed_symbol:
          c = READCHAR;
          if (!(c > 040
                && c != NO_BREAK_SPACE
@@ -3376,6 +3383,12 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
            }
          goto read_symbol;
        }
+      /* #_foo is really the symbol foo, regardless of shorthands  */
+      if (c == '_')
+       {
+         skip_shorthand = true;
+         goto read_hash_prefixed_symbol;
+       }
       /* ## is the empty symbol.  */
       if (c == '#')
        return Fintern (empty_unibyte_string, Qnil);
@@ -3756,7 +3769,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
        ptrdiff_t nbytes = p - read_buffer;
        UNREAD (c);
 
-       if (!quoted && !uninterned_symbol)
+       if (!quoted && !uninterned_symbol && !skip_shorthand)
          {
            ptrdiff_t len;
            Lisp_Object result = string_to_number (read_buffer, 10, &len);
@@ -3786,11 +3799,36 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
 
                 Like intern_1 but supports multibyte names.  */
              Lisp_Object obarray = check_obarray (Vobarray);
-             Lisp_Object tem = oblookup (obarray, read_buffer,
-                                         nchars, nbytes);
+
+             char* longhand = NULL;
+             ptrdiff_t longhand_chars = 0;
+             ptrdiff_t longhand_bytes = 0;
+
+             Lisp_Object tem;
+             if (skip_shorthand
+                 /* The following ASCII characters are used in the
+                    only "core" Emacs Lisp symbols that are comprised
+                    entirely of characters that have the 'symbol
+                    constituent' syntax.  We exempt them from
+                    transforming according to shorthands.  */
+                 || strspn (read_buffer, "^*+-/<=>_|") >= nbytes)
+               tem = oblookup (obarray, read_buffer, nchars, nbytes);
+             else
+               tem = oblookup_considering_shorthand (obarray, read_buffer,
+                                                     nchars, nbytes, &longhand,
+                                                     &longhand_chars,
+                                                     &longhand_bytes);
 
              if (SYMBOLP (tem))
                result = tem;
+             else if (longhand)
+               {
+                 Lisp_Object name
+                   = make_specified_string (longhand, longhand_chars,
+                                            longhand_bytes, multibyte);
+                 xfree (longhand);
+                 result = intern_driver (name, obarray, tem);
+               }
              else
                {
                  Lisp_Object name
@@ -4339,6 +4377,7 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, 
Lisp_Object index)
 Lisp_Object
 intern_driver (Lisp_Object string, Lisp_Object obarray, Lisp_Object index)
 {
+  SET_SYMBOL_VAL (XSYMBOL (Qobarray_cache), Qnil);
   return intern_sym (Fmake_symbol (string), obarray, index);
 }
 
@@ -4407,10 +4446,28 @@ it defaults to the value of `obarray'.  */)
   obarray = check_obarray (NILP (obarray) ? Vobarray : obarray);
   CHECK_STRING (string);
 
-  tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
+
+  char* longhand = NULL;
+  ptrdiff_t longhand_chars = 0;
+  ptrdiff_t longhand_bytes = 0;
+  tem = oblookup_considering_shorthand (obarray, SSDATA (string),
+                                       SCHARS (string), SBYTES (string),
+                                       &longhand, &longhand_chars,
+                                       &longhand_bytes);
+
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-                        obarray, tem);
+    {
+      if (longhand)
+       {
+         tem = intern_driver (make_specified_string (longhand, longhand_chars,
+                                                     longhand_bytes, true),
+                              obarray, tem);
+         xfree (longhand);
+       }
+      else
+       tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
+                            obarray, tem);
+    }
   return tem;
 }
 
@@ -4429,17 +4486,29 @@ it defaults to the value of `obarray'.  */)
 
   if (!SYMBOLP (name))
     {
+      char *longhand = NULL;
+      ptrdiff_t longhand_chars = 0;
+      ptrdiff_t longhand_bytes = 0;
+
       CHECK_STRING (name);
       string = name;
+      tem = oblookup_considering_shorthand (obarray, SSDATA (string),
+                                           SCHARS (string), SBYTES (string),
+                                           &longhand, &longhand_chars,
+                                           &longhand_bytes);
+      if (longhand)
+       xfree (longhand);
+      return FIXNUMP (tem) ? Qnil : tem;
     }
   else
-    string = SYMBOL_NAME (name);
-
-  tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
-  if (FIXNUMP (tem) || (SYMBOLP (name) && !EQ (name, tem)))
-    return Qnil;
-  else
-    return tem;
+    {
+      /* If already a symbol, we don't do shorthand-longhand translation,
+        as promised in the docstring.  */
+      string = SYMBOL_NAME (name);
+      tem
+       = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
+      return EQ (name, tem) ? name : Qnil;
+    }
 }
 
 DEFUN ("unintern", Funintern, Sunintern, 1, 2, 0,
@@ -4451,7 +4520,8 @@ OBARRAY, if nil, defaults to the value of the variable 
`obarray'.
 usage: (unintern NAME OBARRAY)  */)
   (Lisp_Object name, Lisp_Object obarray)
 {
-  register Lisp_Object string, tem;
+  register Lisp_Object tem;
+  Lisp_Object string;
   size_t hash;
 
   if (NILP (obarray)) obarray = Vobarray;
@@ -4465,9 +4535,16 @@ usage: (unintern NAME OBARRAY)  */)
       string = name;
     }
 
-  tem = oblookup (obarray, SSDATA (string),
-                 SCHARS (string),
-                 SBYTES (string));
+  char *longhand = NULL;
+  ptrdiff_t longhand_chars = 0;
+  ptrdiff_t longhand_bytes = 0;
+  tem = oblookup_considering_shorthand (obarray, SSDATA (string),
+                                       SCHARS (string), SBYTES (string),
+                                       &longhand, &longhand_chars,
+                                       &longhand_bytes);
+  if (longhand)
+    xfree(longhand);
+
   if (FIXNUMP (tem))
     return Qnil;
   /* If arg was a symbol, don't delete anything but that symbol itself.  */
@@ -4554,6 +4631,70 @@ oblookup (Lisp_Object obarray, register const char *ptr, 
ptrdiff_t size, ptrdiff
   XSETINT (tem, hash);
   return tem;
 }
+
+/* Like 'oblookup', but considers 'Vread_symbol_shorthands',
+   potentially recognizing that IN is shorthand for some other
+   longhand name, which is then then placed in OUT.  In that case,
+   memory is malloc'ed for OUT (which the caller must free) while
+   SIZE_OUT and SIZE_BYTE_OUT respectively hold the character and byte
+   sizes of the transformed symbol name.  If IN is not recognized
+   shorthand for any other symbol, OUT is set to point to NULL and
+   'oblookup' is called.  */
+
+Lisp_Object
+oblookup_considering_shorthand (Lisp_Object obarray, const char *in,
+                               ptrdiff_t size, ptrdiff_t size_byte, char **out,
+                               ptrdiff_t *size_out, ptrdiff_t *size_byte_out)
+{
+  Lisp_Object tail = Vread_symbol_shorthands;
+
+  /* First, assume no transformation will take place.  */
+  *out = NULL;
+  /* Then, iterate each pair in Vread_symbol_shorthands.  */
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      Lisp_Object pair = XCAR (tail);
+      /* Be lenient to 'read-symbol-shorthands': if some element isn't a
+        cons, or some member of that cons isn't a string, just skip
+        to the next element.  */
+      if (!CONSP (pair))
+       continue;
+      Lisp_Object sh_prefix = XCAR (pair);
+      Lisp_Object lh_prefix = XCDR (pair);
+      if (!STRINGP (sh_prefix) || !STRINGP (lh_prefix))
+       continue;
+      ptrdiff_t sh_prefix_size = SBYTES (sh_prefix);
+
+      /* Compare the prefix of the transformation pair to the symbol
+        name.  If a match occurs, do the renaming and exit the loop.
+        In other words, only one such transformation may take place.
+        Calculate the amount of memory to allocate for the longhand
+        version of the symbol name with xrealloc.  This isn't
+        strictly needed, but it could later be used as a way for
+        multiple transformations on a single symbol name.  */
+      if (sh_prefix_size <= size_byte
+         && memcmp (SSDATA (sh_prefix), in, sh_prefix_size) == 0)
+       {
+         ptrdiff_t lh_prefix_size = SBYTES (lh_prefix);
+         ptrdiff_t suffix_size = size_byte - sh_prefix_size;
+         *out = xrealloc (*out, lh_prefix_size + suffix_size);
+         memcpy (*out, SSDATA(lh_prefix), lh_prefix_size);
+         memcpy (*out + lh_prefix_size, in + sh_prefix_size, suffix_size);
+         *size_out = SCHARS (lh_prefix) - SCHARS (sh_prefix) + size;
+         *size_byte_out = lh_prefix_size + suffix_size;
+         break;
+       }
+    }
+  /* Now, as promised, call oblookup with the "final" symbol name to
+     lookup.  That function remains oblivious to whether a
+     transformation happened here or not, but the caller of this
+     function can tell by inspecting the OUT parameter.  */
+  if (*out)
+    return oblookup (obarray, *out, *size_out, *size_byte_out);
+  else
+    return oblookup (obarray, in, size, size_byte);
+}
+
 
 void
 map_obarray (Lisp_Object obarray, void (*fn) (Lisp_Object, Lisp_Object), 
Lisp_Object arg)
@@ -5310,4 +5451,11 @@ that are loaded before your customizations are read!  
*/);
   DEFSYM (Qrehash_threshold, "rehash-threshold");
 
   DEFSYM (Qchar_from_name, "char-from-name");
+
+  DEFVAR_LISP ("read-symbol-shorthands", Vread_symbol_shorthands,
+          doc: /* Alist of known symbol-name shorthands.
+This variable's value can only be set via file-local variables.
+See Info node `(elisp)Shorthands' for more details.  */);
+  Vread_symbol_shorthands = Qnil;
+  DEFSYM (Qobarray_cache, "obarray-cache");
 }
diff --git a/src/macfont.m b/src/macfont.m
index d86f09f485..1426cae6dc 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -613,6 +613,21 @@ get_cgcolor(unsigned long idx, struct frame *f)
   return cgColor;
 }
 
+static CGColorRef
+get_cgcolor_from_nscolor (NSColor *nsColor, struct frame *f)
+{
+  [nsColor set];
+  CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
+  NSInteger noc = [nsColor numberOfComponents];
+  CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
+  CGColorRef cgColor;
+
+  [nsColor getComponents: components];
+  cgColor = CGColorCreate (colorSpace, components);
+  xfree (components);
+  return cgColor;
+}
+
 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
   do {                                                                  \
     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
@@ -2415,8 +2430,12 @@ macfont_list (struct frame *f, Lisp_Object spec)
             continue;
 
           /* Don't use a color bitmap font unless its family is
-             explicitly specified.  */
-          if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family))
+             explicitly specified or we're looking for a font for
+             emoji.  */
+          if ((sym_traits & kCTFontTraitColorGlyphs)
+              && NILP (family)
+              && !EQ (CDR_SAFE (assq_no_quit (QCscript, AREF (spec, 
FONT_EXTRA_INDEX))),
+                      Qemoji))
             continue;
 
           if (j > 0
@@ -2907,14 +2926,14 @@ macfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
 
   if (!CGRectIsNull (background_rect))
     {
-      if (s->hl == DRAW_MOUSE_FACE)
+      if (s->hl == DRAW_CURSOR)
         {
-          face = FACE_FROM_ID_OR_NULL (s->f,
-                                      MOUSE_HL_INFO 
(s->f)->mouse_face_face_id);
-          if (!face)
-            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+         CGColorRef *colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR 
(f), f);
+         CGContextSetFillColorWithColor (context, colorref);
+         CGColorRelease (colorref);
         }
-      CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
+      else
+       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
       CGContextFillRects (context, &background_rect, 1);
     }
 
@@ -2923,7 +2942,14 @@ macfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
       CGAffineTransform atfm;
 
       CGContextScaleCTM (context, 1, -1);
-      CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
+      if (s->hl == DRAW_CURSOR)
+        {
+         CGColorRef *colorref = get_cgcolor_from_nscolor 
(FRAME_BACKGROUND_COLOR (f), f);
+         CGContextSetFillColorWithColor (context, colorref);
+         CGColorRelease (colorref);
+        }
+      else
+       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
       if (macfont_info->synthetic_italic_p)
         atfm = synthetic_italic_atfm;
       else
diff --git a/src/minibuf.c b/src/minibuf.c
index 4b72d3e896..6c0cd358c5 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -1005,7 +1005,7 @@ set_minibuffer_mode (Lisp_Object buf, EMACS_INT depth)
       if (!NILP (Ffboundp (Qminibuffer_inactive_mode)))
        call0 (Qminibuffer_inactive_mode);
       else
-       Fkill_all_local_variables ();
+       Fkill_all_local_variables (Qnil);
     }
   buf = unbind_to (count, buf);
 }
@@ -1545,6 +1545,27 @@ minibuf_conform_representation (Lisp_Object string, 
Lisp_Object basis)
     return Fstring_make_multibyte (string);
 }
 
+static bool
+match_regexps (Lisp_Object string, Lisp_Object regexps,
+              bool ignore_case)
+{
+  ptrdiff_t val;
+  for (; CONSP (regexps); regexps = XCDR (regexps))
+    {
+      CHECK_STRING (XCAR (regexps));
+
+      val = fast_string_match_internal
+       (XCAR (regexps), string,
+        (ignore_case ? BVAR (current_buffer, case_canon_table) : Qnil));
+
+      if (val == -2)
+       error ("Stack overflow in regexp matcher");
+      if (val < 0)
+       return false;
+    }
+  return true;
+}
+
 DEFUN ("try-completion", Ftry_completion, Stry_completion, 2, 3, 0,
        doc: /* Return common substring of all completions of STRING in 
COLLECTION.
 Test each possible completion specified by COLLECTION
@@ -1578,6 +1599,7 @@ Additionally to this predicate, `completion-regexp-list'
 is used to further constrain the set of candidates.  */)
   (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate)
 {
+
   Lisp_Object bestmatch, tail, elt, eltstring;
   /* Size in bytes of BESTMATCH.  */
   ptrdiff_t bestmatchsize = 0;
@@ -1591,7 +1613,6 @@ is used to further constrain the set of candidates.  */)
               ? list_table : function_table));
   ptrdiff_t idx = 0, obsize = 0;
   int matchcount = 0;
-  ptrdiff_t bindcount = -1;
   Lisp_Object bucket, zero, end, tem;
 
   CHECK_STRING (string);
@@ -1670,27 +1691,10 @@ is used to further constrain the set of candidates.  */)
                                      completion_ignore_case ? Qt : Qnil),
              EQ (Qt, tem)))
        {
-         /* Yes.  */
-         Lisp_Object regexps;
-
          /* Ignore this element if it fails to match all the regexps.  */
-         {
-           for (regexps = Vcompletion_regexp_list; CONSP (regexps);
-                regexps = XCDR (regexps))
-             {
-               if (bindcount < 0)
-                 {
-                   bindcount = SPECPDL_INDEX ();
-                   specbind (Qcase_fold_search,
-                             completion_ignore_case ? Qt : Qnil);
-                 }
-               tem = Fstring_match (XCAR (regexps), eltstring, zero);
-               if (NILP (tem))
-                 break;
-             }
-           if (CONSP (regexps))
-             continue;
-         }
+         if (!match_regexps (eltstring, Vcompletion_regexp_list,
+                             completion_ignore_case))
+           continue;
 
          /* Ignore this element if there is a predicate
             and the predicate doesn't like it.  */
@@ -1701,11 +1705,6 @@ is used to further constrain the set of candidates.  */)
                tem = Fcommandp (elt, Qnil);
              else
                {
-                 if (bindcount >= 0)
-                   {
-                     unbind_to (bindcount, Qnil);
-                     bindcount = -1;
-                   }
                  tem = (type == hash_table
                         ? call2 (predicate, elt,
                                  HASH_VALUE (XHASH_TABLE (collection),
@@ -1787,9 +1786,6 @@ is used to further constrain the set of candidates.  */)
        }
     }
 
-  if (bindcount >= 0)
-    unbind_to (bindcount, Qnil);
-
   if (NILP (bestmatch))
     return Qnil;               /* No completions found.  */
   /* If we are ignoring case, and there is no exact match,
@@ -1849,7 +1845,6 @@ with a space are ignored unless STRING itself starts with 
a space.  */)
     : VECTORP (collection) ? 2
     : NILP (collection) || (CONSP (collection) && !FUNCTIONP (collection));
   ptrdiff_t idx = 0, obsize = 0;
-  ptrdiff_t bindcount = -1;
   Lisp_Object bucket, tem, zero;
 
   CHECK_STRING (string);
@@ -1934,27 +1929,10 @@ with a space are ignored unless STRING itself starts 
with a space.  */)
                                      completion_ignore_case ? Qt : Qnil),
              EQ (Qt, tem)))
        {
-         /* Yes.  */
-         Lisp_Object regexps;
-
          /* Ignore this element if it fails to match all the regexps.  */
-         {
-           for (regexps = Vcompletion_regexp_list; CONSP (regexps);
-                regexps = XCDR (regexps))
-             {
-               if (bindcount < 0)
-                 {
-                   bindcount = SPECPDL_INDEX ();
-                   specbind (Qcase_fold_search,
-                             completion_ignore_case ? Qt : Qnil);
-                 }
-               tem = Fstring_match (XCAR (regexps), eltstring, zero);
-               if (NILP (tem))
-                 break;
-             }
-           if (CONSP (regexps))
-             continue;
-         }
+         if (!match_regexps (eltstring, Vcompletion_regexp_list,
+                             completion_ignore_case))
+           continue;
 
          /* Ignore this element if there is a predicate
             and the predicate doesn't like it.  */
@@ -1965,11 +1943,6 @@ with a space are ignored unless STRING itself starts 
with a space.  */)
                tem = Fcommandp (elt, Qnil);
              else
                {
-                 if (bindcount >= 0)
-                   {
-                     unbind_to (bindcount, Qnil);
-                     bindcount = -1;
-                   }
                  tem = type == 3
                    ? call2 (predicate, elt,
                             HASH_VALUE (XHASH_TABLE (collection), idx - 1))
@@ -1982,9 +1955,6 @@ with a space are ignored unless STRING itself starts with 
a space.  */)
        }
     }
 
-  if (bindcount >= 0)
-    unbind_to (bindcount, Qnil);
-
   return Fnreverse (allmatches);
 }
 
@@ -2068,7 +2038,7 @@ If COLLECTION is a function, it is called with three 
arguments:
 the values STRING, PREDICATE and `lambda'.  */)
   (Lisp_Object string, Lisp_Object collection, Lisp_Object predicate)
 {
-  Lisp_Object regexps, tail, tem = Qnil;
+  Lisp_Object tail, tem = Qnil;
   ptrdiff_t i = 0;
 
   CHECK_STRING (string);
@@ -2154,20 +2124,9 @@ the values STRING, PREDICATE and `lambda'.  */)
     return call3 (collection, string, predicate, Qlambda);
 
   /* Reject this element if it fails to match all the regexps.  */
-  if (CONSP (Vcompletion_regexp_list))
-    {
-      ptrdiff_t count = SPECPDL_INDEX ();
-      specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil);
-      for (regexps = Vcompletion_regexp_list; CONSP (regexps);
-          regexps = XCDR (regexps))
-       {
-          /* We can test against STRING, because if we got here, then
-             the element is equivalent to it.  */
-          if (NILP (Fstring_match (XCAR (regexps), string, Qnil)))
-           return unbind_to (count, Qnil);
-       }
-      unbind_to (count, Qnil);
-    }
+  if (!match_regexps (string, Vcompletion_regexp_list,
+                     completion_ignore_case))
+    return Qnil;
 
   /* Finally, check the predicate.  */
   if (!NILP (predicate))
diff --git a/src/module-env-28.h b/src/module-env-28.h
index f8820b0606..bea80a5553 100644
--- a/src/module-env-28.h
+++ b/src/module-env-28.h
@@ -1,7 +1,3 @@
-  /* Add module environment functions newly added in Emacs 28 here.
-     Before Emacs 28 is released, remove this comment and start
-     module-env-29.h on the master branch.  */
-
   void (*(*EMACS_ATTRIBUTE_NONNULL (1)
             get_function_finalizer) (emacs_env *env,
                                      emacs_value arg)) (void *) EMACS_NOEXCEPT;
diff --git a/src/module-env-29.h b/src/module-env-29.h
new file mode 100644
index 0000000000..6ca0377318
--- /dev/null
+++ b/src/module-env-29.h
@@ -0,0 +1,3 @@
+  /* Add module environment functions newly added in Emacs 29 here.
+     Before Emacs 29 is released, remove this comment and start
+     module-env-30.h on the master branch.  */
diff --git a/src/msdos.c b/src/msdos.c
index 5da01c9e7c..bf058c8aff 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -1794,7 +1794,7 @@ internal_terminal_init (void)
        }
 
       Vinitial_window_system = Qpc;
-      Vwindow_system_version = make_fixnum (28); /* RE Emacs version */
+      Vwindow_system_version = make_fixnum (29); /* RE Emacs version */
       tty->terminal->type = output_msdos_raw;
 
       /* If Emacs was dumped on DOS/V machine, forget the stale VRAM
diff --git a/src/nsfns.m b/src/nsfns.m
index 07bcab1816..f4d8172246 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -609,13 +609,72 @@ ns_set_menu_bar_lines (struct frame *f, Lisp_Object 
value, Lisp_Object oldval)
     }
 }
 
+void
+ns_change_tab_bar_height (struct frame *f, int height)
+{
+  int unit = FRAME_LINE_HEIGHT (f);
+  int old_height = FRAME_TAB_BAR_HEIGHT (f);
+  int lines = (height + unit - 1) / unit;
+  Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
+
+  /* Make sure we redisplay all windows in this frame.  */
+  fset_redisplay (f);
+
+  /* Recalculate tab bar and frame text sizes.  */
+  FRAME_TAB_BAR_HEIGHT (f) = height;
+  FRAME_TAB_BAR_LINES (f) = lines;
+  store_frame_param (f, Qtab_bar_lines, make_fixnum (lines));
+
+  if (FRAME_NS_WINDOW (f) && FRAME_TAB_BAR_HEIGHT (f) == 0)
+    {
+      clear_frame (f);
+      clear_current_matrices (f);
+    }
+
+  if ((height < old_height) && WINDOWP (f->tab_bar_window))
+    clear_glyph_matrix (XWINDOW (f->tab_bar_window)->current_matrix);
+
+  if (!f->tab_bar_resized)
+    {
+      /* As long as tab_bar_resized is false, effectively try to change
+        F's native height.  */
+      if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth))
+       adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+                          1, false, Qtab_bar_lines);
+      else
+       adjust_frame_size (f, -1, -1, 4, false, Qtab_bar_lines);
+
+      f->tab_bar_resized = f->tab_bar_redisplayed;
+    }
+  else
+    /* Any other change may leave the native size of F alone.  */
+    adjust_frame_size (f, -1, -1, 3, false, Qtab_bar_lines);
+
+  /* adjust_frame_size might not have done anything, garbage frame
+     here.  */
+  adjust_frame_glyphs (f);
+  SET_FRAME_GARBAGED (f);
+}
 
 /* tabbar support */
 static void
 ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
 {
-  /* Currently unimplemented.  */
-  NSTRACE ("ns_set_tab_bar_lines");
+  int olines = FRAME_TAB_BAR_LINES (f);
+  int nlines;
+
+  /* Treat tab bars like menu bars.  */
+  if (FRAME_MINIBUF_ONLY_P (f))
+    return;
+
+  /* Use VALUE only if an int >= 0.  */
+  if (RANGED_FIXNUMP (0, value, INT_MAX))
+    nlines = XFIXNAT (value);
+  else
+    nlines = 0;
+
+  if (nlines != olines && (olines == 0 || nlines == 0))
+    ns_change_tab_bar_height (f, nlines * FRAME_LINE_HEIGHT (f));
 }
 
 
@@ -1177,6 +1236,7 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
                          "fontBackend", "FontBackend", RES_TYPE_STRING);
 
   {
+#ifdef NS_IMPL_COCOA
     /* use for default font name */
     id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
     gui_default_parameter (f, parms, Qfontsize,
@@ -1191,6 +1251,11 @@ DEFUN ("x-create-frame", Fx_create_frame, 
Sx_create_frame,
                            build_string (fontname),
                            "font", "Font", RES_TYPE_STRING);
     xfree (fontname);
+#else
+    gui_default_parameter (f, parms, Qfont,
+                           build_string ("fixed"),
+                           "font", "Font", RES_TYPE_STRING);
+#endif
   }
   unblock_input ();
 
@@ -1966,12 +2031,14 @@ is layered in front of the windows of other 
applications.  */)
       [NSApp unhide: NSApp];
       [NSApp activateIgnoringOtherApps: YES];
     }
+#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION >= 27
   else if (EQ (on, intern ("activate-front")))
     {
       [NSApp unhide: NSApp];
       [[NSRunningApplication currentApplication]
         activateWithOptions: NSApplicationActivateIgnoringOtherApps];
     }
+#endif
   else if (NILP (on))
     [NSApp unhide: NSApp];
   else
diff --git a/src/nsfont.m b/src/nsfont.m
index 5a9cdfebc0..b3224629f0 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -1,4 +1,4 @@
-/* Font back-end driver for the NeXT/Open/GNUstep and macOS window system.
+/* Font back-end driver for the GNUstep window system.
    See font.h
    Copyright (C) 2006-2021 Free Software Foundation, Inc.
 
@@ -38,47 +38,269 @@ Author: Adrian Robert (arobert@cogsci.ucsd.edu)
 #include "termchar.h"
 #include "pdumper.h"
 
-/* TODO: Drop once we can assume gnustep-gui 0.17.1.  */
+#import <Foundation/NSException.h>
 #import <AppKit/NSFontDescriptor.h>
+#import <AppKit/NSLayoutManager.h>
+#import <GNUstepGUI/GSLayoutManager.h>
+#import <GNUstepGUI/GSFontInfo.h>
 
 #define NSFONT_TRACE 0
-#define LCD_SMOOTHING_MARGIN 2
 
-/* Font glyph and metrics caching functions, implemented at end.  */
-static void ns_uni_to_glyphs (struct nsfont_info *font_info,
-                              unsigned char block);
-static void ns_glyph_metrics (struct nsfont_info *font_info,
-                              unsigned char block);
+/* Structure used by GS `shape' functions for storing layout
+   information for each glyph.  Borrowed from macfont.h.  */
+struct ns_glyph_layout
+{
+  /* Range of indices of the characters composed into the group of
+     glyphs that share the cursor position with this glyph.  The
+     members `location' and `length' are in UTF-16 indices.  */
+  NSRange comp_range;
 
-#define INVALID_GLYPH 0xFFFF
+  /* UTF-16 index in the source string for the first character
+     associated with this glyph.  */
+  NSUInteger string_index;
 
-/* ==========================================================================
+  /* Horizontal and vertical adjustments of glyph position.  The
+     coordinate space is that of Core Text.  So, the `baseline_delta'
+     value is negative if the glyph should be placed below the
+     baseline.  */
+  CGFloat advance_delta, baseline_delta;
 
-    Utilities
+  /* Typographical width of the glyph.  */
+  CGFloat advance;
 
-   ========================================================================== 
*/
+  /* Glyph ID of the glyph.  */
+  NSGlyph glyph_id;
+};
+
+
+enum lgstring_direction
+  {
+    DIR_R2L = -1, DIR_UNKNOWN = 0, DIR_L2R = 1
+  };
+
+enum gs_font_slant
+  {
+    GS_FONT_SLANT_ITALIC,
+    GS_FONT_SLANT_REVERSE_ITALIC,
+    GS_FONT_SLANT_NORMAL
+  };
+
+enum gs_font_weight
+  {
+    GS_FONT_WEIGHT_LIGHT,
+    GS_FONT_WEIGHT_BOLD,
+    GS_FONT_WEIGHT_NORMAL
+  };
+
+enum gs_font_width
+  {
+    GS_FONT_WIDTH_CONDENSED,
+    GS_FONT_WIDTH_EXPANDED,
+    GS_FONT_WIDTH_NORMAL
+  };
+
+enum gs_specified
+  {
+    GS_SPECIFIED_SLANT = 1,
+    GS_SPECIFIED_WEIGHT = 1 << 1,
+    GS_SPECIFIED_WIDTH = 1 << 2,
+    GS_SPECIFIED_FAMILY = 1 << 3,
+    GS_SPECIFIED_SPACING = 1 << 4
+  };
 
+struct gs_font_data
+{
+  int specified;
+  enum gs_font_slant slant;
+  enum gs_font_weight weight;
+  enum gs_font_width width;
+  bool monospace_p;
+  char *family_name;
+};
 
-/* Replace spaces w/another character so emacs core font parsing routines
-   aren't thrown off.  */
 static void
-ns_escape_name (char *name)
+ns_done_font_data (struct gs_font_data *data)
 {
-  for (; *name; name++)
-    if (*name == ' ')
-      *name = '_';
+  if (data->specified & GS_SPECIFIED_FAMILY)
+    xfree (data->family_name);
 }
 
-
-/* Reconstruct spaces in a font family name passed through emacs.  */
 static void
-ns_unescape_name (char *name)
+ns_get_font_data (NSFontDescriptor *desc, struct gs_font_data *dat)
 {
-  for (; *name; name++)
-    if (*name == '_')
-      *name = ' ';
+  NSNumber *tem;
+  NSFontSymbolicTraits traits = [desc symbolicTraits];
+  NSDictionary *dict = [desc objectForKey: NSFontTraitsAttribute];
+  NSString *family = [desc objectForKey: NSFontFamilyAttribute];
+
+  dat->specified = 0;
+
+  if (family != nil)
+    {
+      dat->specified |= GS_SPECIFIED_FAMILY;
+      dat->family_name = xstrdup ([family cStringUsingEncoding: 
NSUTF8StringEncoding]);
+    }
+
+  tem = [desc objectForKey: NSFontFixedAdvanceAttribute];
+
+  if ((tem != nil && [tem boolValue] != NO)
+      || (traits & NSFontMonoSpaceTrait))
+    {
+      dat->specified |= GS_SPECIFIED_SPACING;
+      dat->monospace_p = true;
+    }
+  else if (tem != nil && [tem boolValue] == NO)
+    {
+      dat->specified |= GS_SPECIFIED_SPACING;
+      dat->monospace_p = false;
+    }
+
+  if (traits & NSFontBoldTrait)
+    {
+      dat->specified |= GS_SPECIFIED_WEIGHT;
+      dat->weight = GS_FONT_WEIGHT_BOLD;
+    }
+
+  if (traits & NSFontItalicTrait)
+    {
+      dat->specified |= GS_SPECIFIED_SLANT;
+      dat->slant = GS_FONT_SLANT_ITALIC;
+    }
+
+  if (traits & NSFontCondensedTrait)
+    {
+      dat->specified |= GS_SPECIFIED_WIDTH;
+      dat->width = GS_FONT_WIDTH_CONDENSED;
+    }
+  else if (traits & NSFontExpandedTrait)
+    {
+      dat->specified |= GS_SPECIFIED_WIDTH;
+      dat->width = GS_FONT_WIDTH_EXPANDED;
+    }
+
+  if (dict != nil)
+    {
+      tem = [dict objectForKey: NSFontSlantTrait];
+
+      if (tem != nil)
+       {
+         dat->specified |= GS_SPECIFIED_SLANT;
+
+         dat->slant = [tem floatValue] > 0
+           ? GS_FONT_SLANT_ITALIC
+           : ([tem floatValue] < 0
+              ? GS_FONT_SLANT_REVERSE_ITALIC
+              : GS_FONT_SLANT_NORMAL);
+       }
+
+      tem = [dict objectForKey: NSFontWeightTrait];
+
+      if (tem != nil)
+       {
+         dat->specified |= GS_SPECIFIED_WEIGHT;
+
+         dat->weight = [tem floatValue] > 0
+           ? GS_FONT_WEIGHT_BOLD
+           : ([tem floatValue] < -0.4f
+              ? GS_FONT_WEIGHT_LIGHT
+              : GS_FONT_WEIGHT_NORMAL);
+       }
+
+      tem = [dict objectForKey: NSFontWidthTrait];
+
+      if (tem != nil)
+       {
+         dat->specified |= GS_SPECIFIED_WIDTH;
+
+         dat->width = [tem floatValue] > 0
+           ? GS_FONT_WIDTH_EXPANDED
+           : ([tem floatValue] < 0
+              ? GS_FONT_WIDTH_NORMAL
+              : GS_FONT_WIDTH_CONDENSED);
+       }
+    }
+}
+
+static bool
+ns_font_descs_match_p (NSFontDescriptor *desc, NSFontDescriptor *target)
+{
+  struct gs_font_data dat;
+  struct gs_font_data t;
+
+  ns_get_font_data (desc, &dat);
+  ns_get_font_data (target, &t);
+
+  if (!(t.specified & GS_SPECIFIED_WIDTH))
+    t.width = GS_FONT_WIDTH_NORMAL;
+  if (!(t.specified & GS_SPECIFIED_WEIGHT))
+    t.weight = GS_FONT_WEIGHT_NORMAL;
+  if (!(t.specified & GS_SPECIFIED_SPACING))
+    t.monospace_p = false;
+  if (!(t.specified & GS_SPECIFIED_SLANT))
+    t.slant = GS_FONT_SLANT_NORMAL;
+
+  if (!(t.specified & GS_SPECIFIED_FAMILY))
+    emacs_abort ();
+
+  bool match_p = true;
+
+  if (dat.specified & GS_SPECIFIED_WIDTH
+      && dat.width != t.width)
+    {
+      match_p = false;
+      goto gout;
+    }
+
+  if (dat.specified & GS_SPECIFIED_WEIGHT
+      && dat.weight != t.weight)
+    {
+      match_p = false;
+      goto gout;
+    }
+
+  if (dat.specified & GS_SPECIFIED_SPACING
+      && dat.monospace_p != t.monospace_p)
+    {
+      match_p = false;
+      goto gout;
+    }
+
+  if (dat.specified & GS_SPECIFIED_SLANT
+      && dat.monospace_p != t.monospace_p)
+    {
+      if (NSFONT_TRACE)
+       printf ("Matching monospace for %s: %d %d\n",
+               t.family_name, dat.monospace_p,
+               t.monospace_p);
+      match_p = false;
+      goto gout;
+    }
+
+  if (dat.specified & GS_SPECIFIED_FAMILY
+      && strcmp (dat.family_name, t.family_name))
+    match_p = false;
+
+ gout:
+  ns_done_font_data (&dat);
+  ns_done_font_data (&t);
+
+  return match_p;
 }
 
+/* Font glyph and metrics caching functions, implemented at end.  */
+static void ns_uni_to_glyphs (struct nsfont_info *font_info,
+                              unsigned char block);
+static void ns_glyph_metrics (struct nsfont_info *font_info,
+                              unsigned int block);
+
+#define INVALID_GLYPH 0xFFFF
+
+/* ==========================================================================
+
+    Utilities
+
+   ========================================================================== 
*/
+
 
 /* Extract family name from a font spec.  */
 static NSString *
@@ -91,66 +313,116 @@ ns_get_family (Lisp_Object font_spec)
     {
       char *tmp = xlispstrdup (SYMBOL_NAME (tem));
       NSString *family;
-      ns_unescape_name (tmp);
       family = [NSString stringWithUTF8String: tmp];
       xfree (tmp);
       return family;
     }
 }
 
-
-/* Return 0 if attr not set, else value (which might also be 0).
-   On Leopard 0 gets returned even on descriptors where the attribute
-   was never set, so there's no way to distinguish between unspecified
-   and set to not have.  Callers should assume 0 means unspecified.  */
-static float
-ns_attribute_fvalue (NSFontDescriptor *fdesc, NSString *trait)
-{
-    NSDictionary *tdict = [fdesc objectForKey: NSFontTraitsAttribute];
-    NSNumber *val = [tdict objectForKey: trait];
-    return val == nil ? 0.0F : [val floatValue];
-}
-
-
 /* Converts FONT_WEIGHT, FONT_SLANT, FONT_WIDTH, plus family and script/lang
    to NSFont descriptor.  Information under extra only needed for matching.  */
-#define STYLE_REF 100
 static NSFontDescriptor *
 ns_spec_to_descriptor (Lisp_Object font_spec)
 {
     NSFontDescriptor *fdesc;
     NSMutableDictionary *fdAttrs = [NSMutableDictionary new];
-    NSMutableDictionary *tdict = [NSMutableDictionary new];
     NSString *family = ns_get_family (font_spec);
-    float n;
-
-    /* Add each attr in font_spec to fdAttrs.  */
-    n = min (FONT_WEIGHT_NUMERIC (font_spec), 200);
-    if (n != -1 && n != STYLE_REF)
-       [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
-                 forKey: NSFontWeightTrait];
-    n = min (FONT_SLANT_NUMERIC (font_spec), 200);
-    if (n != -1 && n != STYLE_REF)
-       [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
-                 forKey: NSFontSlantTrait];
-    n = min (FONT_WIDTH_NUMERIC (font_spec), 200);
-    if (n > -1 && (n > STYLE_REF + 10 || n < STYLE_REF - 10))
-       [tdict setObject: [NSNumber numberWithFloat: (n - 100.0F) / 100.0F]
-                 forKey: NSFontWidthTrait];
-    if ([tdict count] > 0)
-       [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
+    NSMutableDictionary *tdict = [NSMutableDictionary new];
 
-    fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
-               retain] autorelease];
+    Lisp_Object tem;
+
+    tem = FONT_SLANT_SYMBOLIC (font_spec);
+    if (!NILP (tem))
+      {
+       if (EQ (tem, Qitalic) || EQ (tem, Qoblique))
+         [tdict setObject: [NSNumber numberWithFloat: 1.0]
+                   forKey: NSFontSlantTrait];
+       else if (EQ (tem, intern ("reverse-italic")) ||
+                EQ (tem, intern ("reverse-oblique")))
+         [tdict setObject: [NSNumber numberWithFloat: -1.0]
+                   forKey: NSFontSlantTrait];
+       else
+         [tdict setObject: [NSNumber numberWithFloat: 0.0]
+                   forKey: NSFontSlantTrait];
+      }
+
+    tem = FONT_WIDTH_SYMBOLIC (font_spec);
+    if (!NILP (tem))
+      {
+       if (EQ (tem, Qcondensed))
+         [tdict setObject: [NSNumber numberWithFloat: -1.0]
+                   forKey: NSFontWidthTrait];
+       else if (EQ (tem, Qexpanded))
+         [tdict setObject: [NSNumber numberWithFloat: 1.0]
+                   forKey: NSFontWidthTrait];
+       else
+         [tdict setObject: [NSNumber numberWithFloat: 0.0]
+                   forKey: NSFontWidthTrait];
+      }
+
+    tem = FONT_WEIGHT_SYMBOLIC (font_spec);
+
+    if (!NILP (tem))
+      {
+       if (EQ (tem, Qbold))
+         {
+           [tdict setObject: [NSNumber numberWithFloat: 1.0]
+                     forKey: NSFontWeightTrait];
+         }
+       else if (EQ (tem, Qlight))
+         {
+           [tdict setObject: [NSNumber numberWithFloat: -1.0]
+                     forKey: NSFontWeightTrait];
+         }
+       else
+         {
+           [tdict setObject: [NSNumber numberWithFloat: 0.0]
+                     forKey: NSFontWeightTrait];
+         }
+      }
+
+    tem = AREF (font_spec, FONT_SPACING_INDEX);
 
     if (family != nil)
       {
-        NSFontDescriptor *fdesc2 = [fdesc fontDescriptorWithFamily: family];
-        fdesc = [[fdesc2 retain] autorelease];
+       [fdAttrs setObject: family
+                   forKey: NSFontFamilyAttribute];
       }
 
-    [fdAttrs release];
+    if (FIXNUMP (tem))
+      {
+       if (XFIXNUM (tem) != FONT_SPACING_PROPORTIONAL)
+         {
+           [fdAttrs setObject: [NSNumber numberWithBool:YES]
+                       forKey: NSFontFixedAdvanceAttribute];
+         }
+       else
+         {
+           [fdAttrs setObject: [NSNumber numberWithBool:NO]
+                       forKey: NSFontFixedAdvanceAttribute];
+         }
+      }
+
+    /* Handle special families such as ``fixed'' or ``Sans Serif''.  */
+
+    if ([family isEqualToString: @"fixed"])
+      {
+       [fdAttrs setObject: [[NSFont userFixedPitchFontOfSize: 0] familyName]
+                   forKey: NSFontFamilyAttribute];
+      }
+    else if ([family isEqualToString: @"Sans Serif"])
+      {
+       [fdAttrs setObject: [[NSFont userFontOfSize: 0] familyName]
+                   forKey: NSFontFamilyAttribute];
+      }
+
+    [fdAttrs setObject: tdict forKey: NSFontTraitsAttribute];
+
+    fdesc = [[[NSFontDescriptor fontDescriptorWithFontAttributes: fdAttrs]
+               retain] autorelease];
+
     [tdict release];
+    [fdAttrs release];
     return fdesc;
 }
 
@@ -161,61 +433,64 @@ ns_descriptor_to_entity (NSFontDescriptor *desc,
                          Lisp_Object extra,
                          const char *style)
 {
-    Lisp_Object font_entity = font_make_entity ();
-    /*   NSString *psName = [desc postscriptName]; */
-    NSString *family = [desc objectForKey: NSFontFamilyAttribute];
-    unsigned int traits = [desc symbolicTraits];
-    char *escapedFamily;
-
-    /* Shouldn't happen, but on Tiger fallback desc gets name but no family.  
*/
-    if (family == nil)
-      family = [desc objectForKey: NSFontNameAttribute];
-    if (family == nil)
-      family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
-
-    escapedFamily = xstrdup ([family UTF8String]);
-    ns_escape_name (escapedFamily);
-
-    ASET (font_entity, FONT_TYPE_INDEX, Qns);
-    ASET (font_entity, FONT_FOUNDRY_INDEX, Qapple);
-    ASET (font_entity, FONT_FAMILY_INDEX, intern (escapedFamily));
-    ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
-    ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
-
-    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
-                   traits & NSFontBoldTrait ? Qbold : Qmedium);
-/*    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
-                   make_fixnum (100 + 100
-                       * ns_attribute_fvalue (desc, NSFontWeightTrait)));*/
-    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
-                   traits & NSFontItalicTrait ? Qitalic : Qnormal);
-/*    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
-                   make_fixnum (100 + 100
-                        * ns_attribute_fvalue (desc, NSFontSlantTrait)));*/
-    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
-                    traits & NSFontCondensedTrait ? Qcondensed :
-                    traits & NSFontExpandedTrait ? Qexpanded : Qnormal);
-/*    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
-                   make_fixnum (100 + 100
-                        * ns_attribute_fvalue (desc, NSFontWidthTrait)));*/
-
-    ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
-    ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
-    ASET (font_entity, FONT_SPACING_INDEX,
-         make_fixnum([desc symbolicTraits] & NSFontMonoSpaceTrait
-             ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
-
-    ASET (font_entity, FONT_EXTRA_INDEX, extra);
-    ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
+  Lisp_Object font_entity = font_make_entity ();
+  struct gs_font_data data;
+  ns_get_font_data (desc, &data);
+
+  ASET (font_entity, FONT_TYPE_INDEX, Qns);
+  ASET (font_entity, FONT_FOUNDRY_INDEX, Qns);
+  if (data.specified & GS_SPECIFIED_FAMILY)
+    ASET (font_entity, FONT_FAMILY_INDEX, intern (data.family_name));
+  ASET (font_entity, FONT_ADSTYLE_INDEX, style ? intern (style) : Qnil);
+  ASET (font_entity, FONT_REGISTRY_INDEX, Qiso10646_1);
+
+  if (data.specified & GS_SPECIFIED_WEIGHT)
+    {
+      FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX,
+                     data.weight == GS_FONT_WEIGHT_BOLD
+                     ? Qbold : (data.weight == GS_FONT_WEIGHT_LIGHT
+                                ? Qlight : Qnormal));
+    }
+  else
+    FONT_SET_STYLE (font_entity, FONT_WEIGHT_INDEX, Qnormal);
 
-    if (NSFONT_TRACE)
-      {
-       fputs ("created font_entity:\n    ", stderr);
-       debug_print (font_entity);
-      }
+  if (data.specified & GS_SPECIFIED_SLANT)
+    {
+      FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX,
+                     data.slant == GS_FONT_SLANT_ITALIC
+                     ? Qitalic : (data.slant == GS_FONT_SLANT_REVERSE_ITALIC
+                                  ? intern ("reverse-italic") : Qnormal));
+    }
+  else
+    FONT_SET_STYLE (font_entity, FONT_SLANT_INDEX, Qnormal);
+
+  if (data.specified & GS_SPECIFIED_WIDTH)
+    {
+      FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX,
+                     data.width == GS_FONT_WIDTH_CONDENSED
+                     ? Qcondensed : (data.width == GS_FONT_WIDTH_EXPANDED
+                                     ? intern ("expanded") : Qnormal));
+    }
+  else
+    FONT_SET_STYLE (font_entity, FONT_WIDTH_INDEX, Qnormal);
 
-    xfree (escapedFamily);
-    return font_entity;
+  ASET (font_entity, FONT_SIZE_INDEX, make_fixnum (0));
+  ASET (font_entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
+  ASET (font_entity, FONT_SPACING_INDEX,
+       make_fixnum ((data.specified & GS_SPECIFIED_WIDTH && data.monospace_p)
+                    ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL));
+
+  ASET (font_entity, FONT_EXTRA_INDEX, extra);
+  ASET (font_entity, FONT_OBJLIST_INDEX, Qnil);
+
+  if (NSFONT_TRACE)
+    {
+      fputs ("created font_entity:\n    ", stderr);
+      debug_print (font_entity);
+    }
+
+  ns_done_font_data (&data);
+  return font_entity;
 }
 
 
@@ -223,8 +498,7 @@ ns_descriptor_to_entity (NSFontDescriptor *desc,
 static Lisp_Object
 ns_fallback_entity (void)
 {
-  return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 0]
-      fontDescriptor], Qnil, NULL);
+  return ns_descriptor_to_entity ([[NSFont userFixedPitchFontOfSize: 1] 
fontDescriptor], Qnil, NULL);
 }
 
 
@@ -510,21 +784,20 @@ static NSSet
     return families;
 }
 
+/* GNUstep font matching is very mediocre (it can't even compare
+   symbolic styles correctly), which is why our own font matching
+   mechanism must be implemented.  */
 
-/* Implementation for list() and match().  List() can return nil, match()
-must return something.  Strategy is to drop family name from attribute
-matching set for match.  */
+/* Implementation for list and match.  */
 static Lisp_Object
 ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
 {
     Lisp_Object tem, list = Qnil;
-    NSFontDescriptor *fdesc, *desc;
-    NSMutableSet *fkeys;
-    NSArray *matchingDescs;
-    NSEnumerator *dEnum;
-    NSString *family;
+    NSFontDescriptor *fdesc;
+    NSArray *all_descs;
+    GSFontEnumerator *enumerator = [GSFontEnumerator sharedEnumerator];
+
     NSSet *cFamilies;
-    BOOL foundItal = NO;
 
     block_input ();
     if (NSFONT_TRACE)
@@ -537,43 +810,22 @@ ns_findfonts (Lisp_Object font_spec, BOOL isMatch)
     cFamilies = ns_get_covering_families (ns_get_req_script (font_spec), 0.90);
 
     fdesc = ns_spec_to_descriptor (font_spec);
-    fkeys = [NSMutableSet setWithArray: [[fdesc fontAttributes] allKeys]];
-    if (isMatch)
-       [fkeys removeObject: NSFontFamilyAttribute];
-
-    matchingDescs = [fdesc matchingFontDescriptorsWithMandatoryKeys: fkeys];
+    all_descs = [enumerator availableFontDescriptors];
 
-    if (NSFONT_TRACE)
-       NSLog(@"Got desc %@ and found %lu matching fonts from it: ", fdesc,
-             (unsigned long)[matchingDescs count]);
-
-    for (dEnum = [matchingDescs objectEnumerator]; (desc = [dEnum 
nextObject]);)
+    for (NSFontDescriptor *desc in all_descs)
       {
        if (![cFamilies containsObject:
                 [desc objectForKey: NSFontFamilyAttribute]])
            continue;
+       if (!ns_font_descs_match_p (fdesc, desc))
+         continue;
+
         tem = ns_descriptor_to_entity (desc,
-                                        AREF (font_spec, FONT_EXTRA_INDEX),
+                                      AREF (font_spec, FONT_EXTRA_INDEX),
                                        NULL);
         if (isMatch)
           return tem;
        list = Fcons (tem, list);
-       if (fabs (ns_attribute_fvalue (desc, NSFontSlantTrait)) > 0.05)
-           foundItal = YES;
-      }
-
-    /* Add synthItal member if needed.  */
-    family = [fdesc objectForKey: NSFontFamilyAttribute];
-    if (family != nil && !foundItal && !NILP (list))
-      {
-        NSFontDescriptor *s1 = [NSFontDescriptor new];
-        NSFontDescriptor *sDesc
-          = [[s1 fontDescriptorWithSymbolicTraits: NSFontItalicTrait]
-              fontDescriptorWithFamily: family];
-       list = Fcons (ns_descriptor_to_entity (sDesc,
-                                        AREF (font_spec, FONT_EXTRA_INDEX),
-                                        "synthItal"), list);
-        [s1 release];
       }
 
     unblock_input ();
@@ -652,7 +904,6 @@ nsfont_list_family (struct frame *f)
                objectEnumerator];
   while ((family = [families nextObject]))
       list = Fcons (intern ([family UTF8String]), list);
-  /* FIXME: escape the name?  */
 
   if (NSFONT_TRACE)
     fprintf (stderr, "nsfont: list families returning %"pD"d entries\n",
@@ -668,18 +919,15 @@ nsfont_list_family (struct frame *f)
 static Lisp_Object
 nsfont_open (struct frame *f, Lisp_Object font_entity, int pixel_size)
 {
-  BOOL synthItal;
-  unsigned int traits = 0;
   struct nsfont_info *font_info;
   struct font *font;
   NSFontDescriptor *fontDesc = ns_spec_to_descriptor (font_entity);
   NSFontManager *fontMgr = [NSFontManager sharedFontManager];
   NSString *family;
   NSFont *nsfont, *sfont;
-  Lisp_Object tem;
   NSRect brect;
   Lisp_Object font_object;
-  int fixLeopardBug;
+  Lisp_Object tem;
 
   block_input ();
 
@@ -692,42 +940,20 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, 
int pixel_size)
   if (pixel_size <= 0)
     {
       /* try to get it out of frame params */
-        Lisp_Object tem = get_frame_param (f, Qfontsize);
-        pixel_size = NILP (tem) ? 0 : XFIXNAT (tem);
+      tem = get_frame_param (f, Qfontsize);
+      pixel_size = NILP (tem) ? 0 : XFIXNAT (tem);
     }
 
   tem = AREF (font_entity, FONT_ADSTYLE_INDEX);
-  synthItal = !NILP (tem) && !strncmp ("synthItal", SSDATA (SYMBOL_NAME (tem)),
-                                       9);
   family = ns_get_family (font_entity);
   if (family == nil)
     family = [[NSFont userFixedPitchFontOfSize: 0] familyName];
-  /* Should be > 0.23 as some font descriptors (e.g. Terminus) set to that
-     when setting family in ns_spec_to_descriptor().  */
-  if (ns_attribute_fvalue (fontDesc, NSFontWeightTrait) > 0.50F)
-      traits |= NSBoldFontMask;
-  if (ns_attribute_fvalue (fontDesc, NSFontSlantTrait) > 0.05F)
-      traits |= NSItalicFontMask;
-
-  /* see 
https://web.archive.org/web/20100201175731/http://cocoadev.com/forums/comments.php?DiscussionID=74
 */
-  fixLeopardBug = traits & NSBoldFontMask ? 10 : 5;
-  nsfont = [fontMgr fontWithFamily: family
-                            traits: traits weight: fixLeopardBug
-                             size: pixel_size];
-  /* if didn't find, try synthetic italic */
-  if (nsfont == nil && synthItal)
-    {
-      nsfont = [fontMgr fontWithFamily: family
-                                traits: traits & ~NSItalicFontMask
-                                weight: fixLeopardBug size: pixel_size];
-    }
+
+  nsfont = [NSFont fontWithDescriptor: fontDesc
+                                size: pixel_size];
 
   if (nsfont == nil)
-    {
-      message_with_string ("*** Warning: font in family `%s' not found",
-                          build_string ([family UTF8String]), 1);
-      nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
-    }
+    nsfont = [NSFont userFixedPitchFontOfSize: pixel_size];
 
   if (NSFONT_TRACE)
     NSLog (@"%@\n", nsfont);
@@ -740,7 +966,7 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int 
pixel_size)
   if (!font)
     {
       unblock_input ();
-      return Qnil; /* FIXME: other terms do, but returning Qnil causes 
segfault.  */
+      return Qnil;
     }
 
   font_info->glyphs = xzalloc (0x100 * sizeof *font_info->glyphs);
@@ -781,7 +1007,7 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int 
pixel_size)
     font_info->name = xstrdup (fontName);
     font_info->bold = [fontMgr traitsOfFont: nsfont] & NSBoldFontMask;
     font_info->ital =
-      synthItal || ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
+      ([fontMgr traitsOfFont: nsfont] & NSItalicFontMask);
 
     /* Metrics etc.; some fonts return an unusually large max advance, so we
        only use it for fonts that have wide characters.  */
@@ -808,8 +1034,6 @@ nsfont_open (struct frame *f, Lisp_Object font_entity, int 
pixel_size)
       lrint (brect.size.width - (CGFloat) font_info->width);
 
     /* set up metrics portion of font struct */
-    font->ascent = lrint([sfont ascender]);
-    font->descent = -lrint(floor(adjusted_descender));
     font->space_width = lrint (ns_char_width (sfont, ' '));
     font->max_width = lrint (font_info->max_bounds.width);
     font->min_width = font->space_width;  /* Approximate.  */
@@ -871,7 +1095,7 @@ nsfont_encode_char (struct font *font, int c)
 {
   struct nsfont_info *font_info = (struct nsfont_info *)font;
   unsigned char high = (c & 0xff00) >> 8, low = c & 0x00ff;
-  unsigned short g;
+  unsigned int g;
 
   if (c > 0xFFFF)
     return FONT_INVALID_CODE;
@@ -934,51 +1158,23 @@ nsfont_text_extents (struct font *font, const unsigned 
int *code,
 static int
 nsfont_draw (struct glyph_string *s, int from, int to, int x, int y,
              bool with_background)
-/* NOTE: focus and clip must be set.  */
 {
-  static unsigned char cbuf[1024];
-  unsigned char *c = cbuf;
-#if GNUSTEP_GUI_MAJOR_VERSION > 0 || GNUSTEP_GUI_MINOR_VERSION > 22
-  static CGFloat advances[1024];
-  CGFloat *adv = advances;
-#else
-  static float advances[1024];
-  float *adv = advances;
-#endif
+  NSGlyph *c = alloca ((to - from) * sizeof *c);
+
   struct face *face;
   NSRect r;
   struct nsfont_info *font;
-  NSColor *col, *bgCol;
-  unsigned *t = s->char2b;
-  int i, len, flags;
+  NSColor *col;
+  int len = to - from;
   char isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
 
   block_input ();
 
-  font = (struct nsfont_info *)s->face->font;
+  font = (struct nsfont_info *) s->font;
   if (font == NULL)
     font = (struct nsfont_info *)FRAME_FONT (s->f);
 
-  /* Select face based on input flags.  */
-  flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
-    (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
-     (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
-      NS_DUMPGLYPH_NORMAL));
-
-  switch (flags)
-    {
-    case NS_DUMPGLYPH_CURSOR:
-      face = s->face;
-      break;
-    case NS_DUMPGLYPH_MOUSEFACE:
-      face = FACE_FROM_ID_OR_NULL (s->f,
-                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
-      if (!face)
-        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-      break;
-    default:
-      face = s->face;
-    }
+  face = s->face;
 
   r.origin.x = s->x;
   if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
@@ -987,91 +1183,24 @@ nsfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
   r.origin.y = s->y;
   r.size.height = FONT_HEIGHT (font);
 
-  /* Convert UTF-16 (?) to UTF-8 and determine advances.  Note if we just ask
-     NS to render the string, it will come out differently from the individual
-     character widths added up because of layout processing.  */
-  {
-    int cwidth, twidth = 0;
-    int hi, lo;
-    /* FIXME: composition: no vertical displacement is considered.  */
-    t += from; /* advance into composition */
-    for (i = from; i < to; i++, t++)
-      {
-        hi = (*t & 0xFF00) >> 8;
-        lo = *t & 0x00FF;
-        if (isComposite)
-          {
-           if (!s->first_glyph->u.cmp.automatic)
-               cwidth = s->cmp->offsets[i * 2] /* (H offset) */ - twidth;
-           else
-             {
-               Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
-               Lisp_Object glyph = LGSTRING_GLYPH (gstring, i);
-               if (NILP (LGLYPH_ADJUSTMENT (glyph)))
-                   cwidth = LGLYPH_WIDTH (glyph);
-               else
-                 {
-                   cwidth = LGLYPH_WADJUST (glyph);
-                   *(adv-1) += LGLYPH_XOFF (glyph);
-                 }
-             }
-          }
-        else
-          {
-            if (!font->metrics[hi]) /* FIXME: why/how can we need this now?  */
-              ns_glyph_metrics (font, hi);
-            cwidth = font->metrics[hi][lo].width;
-          }
-        twidth += cwidth;
-        *adv++ = cwidth;
-        c += CHAR_STRING (*t, c); /* This converts the char to UTF-8.  */
-      }
-    len = adv - advances;
-    r.size.width = twidth;
-    *c = 0;
-  }
+  for (int i = from; i < to; ++i)
+    c[i] = s->char2b[i];
 
   /* Fill background if requested.  */
   if (with_background && !isComposite)
     {
-      NSRect br = r;
-      int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
-      int mbox_line_width = max (s->face->box_vertical_line_width, 0);
-
-      if (s->row->full_width_p)
-        {
-          if (br.origin.x <= fibw + 1 + mbox_line_width)
-            {
-              br.size.width += br.origin.x - mbox_line_width;
-              br.origin.x = mbox_line_width;
-            }
-          if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width)
-                <= fibw+1)
-            br.size.width += fibw;
-        }
-      if (s->face->box == FACE_NO_BOX)
-        {
-          /* Expand unboxed top row over internal border.  */
-          if (br.origin.y <= fibw + 1 + mbox_line_width)
-            {
-              br.size.height += br.origin.y;
-              br.origin.y = 0;
-            }
-        }
-      else
-        {
-          int correction = abs (s->face->box_horizontal_line_width)+1;
-          br.origin.y += correction;
-          br.size.height -= 2*correction;
-          correction = abs (s->face->box_vertical_line_width)+1;
-          br.origin.x += correction;
-          br.size.width -= 2*correction;
-        }
+      NSRect br = NSMakeRect (x, y - FONT_BASE (s->font),
+                             s->width, FONT_HEIGHT (s->font));
 
       if (!s->face->stipple)
-        [(NS_FACE_BACKGROUND (face) != 0
-          ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
-          : FRAME_BACKGROUND_COLOR (s->f)) set];
+       {
+         if (s->hl != DRAW_CURSOR)
+           [(NS_FACE_BACKGROUND (face) != 0
+             ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
+             : FRAME_BACKGROUND_COLOR (s->f)) set];
+         else
+           [FRAME_CURSOR_COLOR (s->f) set];
+       }
       else
         {
           struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
@@ -1080,43 +1209,32 @@ nsfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
       NSRectFill (br);
     }
 
-
   /* set up for character rendering */
   r.origin.y = y;
 
-  col = (NS_FACE_FOREGROUND (face) != 0
-         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
-         : FRAME_FOREGROUND_COLOR (s->f));
-
-  bgCol = (flags != NS_DUMPGLYPH_FOREGROUND ? nil
-           : (NS_FACE_BACKGROUND (face) != 0
-              ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
-              : FRAME_BACKGROUND_COLOR (s->f)));
+  if (s->hl == DRAW_CURSOR)
+    col = FRAME_BACKGROUND_COLOR (s->f);
+  else
+    col = (NS_FACE_FOREGROUND (face) != 0
+          ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f)
+          : FRAME_FOREGROUND_COLOR (s->f));
 
   /* render under GNUstep using DPS */
   {
-    NSGraphicsContext *context = GSCurrentContext ();
-
+    NSGraphicsContext *context = [NSGraphicsContext currentContext];
     DPSgsave (context);
-    [font->nsfont set];
-
-    /* do erase if "foreground" mode */
-    if (bgCol != nil)
+    if (s->clip_head)
       {
-        [bgCol set];
-        DPSmoveto (context, r.origin.x, r.origin.y);
-/*[context GSSetTextDrawingMode: GSTextFillStroke]; /// not implemented yet */
-        DPSxshow (context, (const char *) cbuf, advances, len);
-        DPSstroke (context);
-        [col set];
-/*[context GSSetTextDrawingMode: GSTextFill]; /// not implemented yet */
+       DPSrectclip (context, s->clip_head->x, 0,
+                    FRAME_PIXEL_WIDTH (s->f),
+                    FRAME_PIXEL_HEIGHT (s->f));
       }
+    [font->nsfont set];
 
     [col set];
 
-    /* draw with DPSxshow () */
     DPSmoveto (context, r.origin.x, r.origin.y);
-    DPSxshow (context, (const char *) cbuf, advances, len);
+    GSShowGlyphs (context, c, len);
     DPSstroke (context);
 
     DPSgrestore (context);
@@ -1126,6 +1244,360 @@ nsfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
   return to-from;
 }
 
+static NSUInteger
+ns_font_shape (NSFont *font, NSString *string,
+              struct ns_glyph_layout *glyph_layouts, NSUInteger glyph_len,
+              enum lgstring_direction dir)
+{
+  NSUInteger i;
+  NSUInteger result = 0;
+  NSTextStorage *textStorage;
+  NSLayoutManager *layoutManager;
+  NSTextContainer *textContainer;
+  NSUInteger stringLength;
+  NSPoint spaceLocation;
+  /* numberOfGlyphs can't actually be 0, but this pacifies GCC */
+  NSUInteger used, numberOfGlyphs = 0;
+
+  textStorage = [[NSTextStorage alloc] initWithString:string];
+  layoutManager = [[NSLayoutManager alloc] init];
+  textContainer = [[NSTextContainer alloc] init];
+
+  /* Append a trailing space to measure baseline position.  */
+  [textStorage appendAttributedString:([[[NSAttributedString alloc]
+                                          initWithString:@" "] autorelease])];
+  [textStorage setFont:font];
+  [textContainer setLineFragmentPadding:0];
+
+  [layoutManager addTextContainer:textContainer];
+  [textContainer release];
+  [textStorage addLayoutManager:layoutManager];
+  [layoutManager release];
+
+  if (!(textStorage && layoutManager && textContainer))
+    emacs_abort ();
+
+  stringLength = [string length];
+
+  /* Force layout.  */
+  (void) [layoutManager glyphRangeForTextContainer:textContainer];
+
+  spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
+
+  /* Remove the appended trailing space because otherwise it may
+     generate a wrong result for a right-to-left text.  */
+  [textStorage beginEditing];
+  [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
+  [textStorage endEditing];
+  (void) [layoutManager glyphRangeForTextContainer:textContainer];
+
+  i = 0;
+  while (i < stringLength)
+    {
+      NSRange range;
+      NSFont *fontInTextStorage =
+        [textStorage attribute: NSFontAttributeName
+                      atIndex:i
+                     longestEffectiveRange: &range
+                       inRange: NSMakeRange (0, stringLength)];
+
+      if (!(fontInTextStorage == font
+            || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
+        break;
+      i = NSMaxRange (range);
+    }
+  if (i < stringLength)
+    /* Make the test `used <= glyph_len' below fail if textStorage
+       contained some fonts other than the specified one.  */
+    used = glyph_len + 1;
+  else
+    {
+      NSRange range = NSMakeRange (0, stringLength);
+
+      range = [layoutManager glyphRangeForCharacterRange:range
+                                    actualCharacterRange:NULL];
+      numberOfGlyphs = NSMaxRange (range);
+      used = numberOfGlyphs;
+      for (i = 0; i < numberOfGlyphs; i++)
+        if ([layoutManager notShownAttributeForGlyphAtIndex:i])
+          used--;
+    }
+
+  if (0 < used && used <= glyph_len)
+    {
+      NSUInteger glyphIndex, prevGlyphIndex;
+      NSUInteger *permutation;
+      NSRange compRange, range;
+      CGFloat totalAdvance;
+
+      glyphIndex = 0;
+      while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+        glyphIndex++;
+
+      permutation = NULL;
+#define RIGHT_TO_LEFT_P permutation
+
+      /* Fill the `comp_range' member of struct mac_glyph_layout, and
+         setup a permutation for right-to-left text.  */
+      compRange = NSMakeRange (0, 0);
+      for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
+           range.length++)
+        {
+          struct ns_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
+          NSUInteger characterIndex =
+            [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
+
+          gl->string_index = characterIndex;
+
+          if (characterIndex >= NSMaxRange (compRange))
+            {
+              compRange.location = NSMaxRange (compRange);
+              do
+                {
+                  NSRange characterRange =
+                    [string
+                      rangeOfComposedCharacterSequenceAtIndex:characterIndex];
+
+                  compRange.length =
+                    NSMaxRange (characterRange) - compRange.location;
+                  [layoutManager glyphRangeForCharacterRange:compRange
+                                        actualCharacterRange:&characterRange];
+                  characterIndex = NSMaxRange (characterRange) - 1;
+                }
+              while (characterIndex >= NSMaxRange (compRange));
+
+              if (RIGHT_TO_LEFT_P)
+                for (i = 0; i < range.length; i++)
+                  permutation[range.location + i] = NSMaxRange (range) - i - 1;
+
+              range = NSMakeRange (NSMaxRange (range), 0);
+            }
+
+          gl->comp_range.location = compRange.location;
+          gl->comp_range.length = compRange.length;
+
+          while (++glyphIndex < numberOfGlyphs)
+            if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+              break;
+        }
+      if (RIGHT_TO_LEFT_P)
+        for (i = 0; i < range.length; i++)
+          permutation[range.location + i] = NSMaxRange (range) - i - 1;
+
+      /* Then fill the remaining members.  */
+      glyphIndex = prevGlyphIndex = 0;
+      while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
+        glyphIndex++;
+
+      if (!RIGHT_TO_LEFT_P)
+        totalAdvance = 0;
+      else
+        {
+          NSUInteger nrects;
+          NSRect *glyphRects =
+            [layoutManager
+              rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
+              withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+                     inTextContainer:textContainer rectCount:&nrects];
+
+          totalAdvance = NSMaxX (glyphRects[0]);
+        }
+
+      for (i = 0; i < used; i++)
+        {
+          struct ns_glyph_layout *gl;
+          NSPoint location;
+          NSUInteger nextGlyphIndex;
+          NSRange glyphRange;
+          NSRect *glyphRects;
+          NSUInteger nrects;
+
+          if (!RIGHT_TO_LEFT_P)
+            gl = glyph_layouts + i;
+          else
+            {
+              NSUInteger dest = permutation[i];
+
+              gl = glyph_layouts + dest;
+              if (i < dest)
+                {
+                  NSUInteger tmp = gl->string_index;
+
+                  gl->string_index = glyph_layouts[i].string_index;
+                  glyph_layouts[i].string_index = tmp;
+                }
+            }
+          gl->glyph_id = [layoutManager glyphAtIndex: glyphIndex];
+
+          location = [layoutManager locationForGlyphAtIndex:glyphIndex];
+          gl->baseline_delta = spaceLocation.y - location.y;
+
+          for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < 
numberOfGlyphs;
+               nextGlyphIndex++)
+            if (![layoutManager
+                   notShownAttributeForGlyphAtIndex:nextGlyphIndex])
+              break;
+
+          if (!RIGHT_TO_LEFT_P)
+            {
+              CGFloat maxX;
+
+              if (prevGlyphIndex == 0)
+                glyphRange = NSMakeRange (0, nextGlyphIndex);
+              else
+                glyphRange = NSMakeRange (glyphIndex,
+                                          nextGlyphIndex - glyphIndex);
+              glyphRects =
+                [layoutManager
+                  rectArrayForGlyphRange:glyphRange
+                  withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+                         inTextContainer:textContainer rectCount:&nrects];
+              maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
+              gl->advance_delta = location.x - totalAdvance;
+              gl->advance = maxX - totalAdvance;
+              totalAdvance = maxX;
+            }
+          else
+            {
+              CGFloat minX;
+
+              if (nextGlyphIndex == numberOfGlyphs)
+                glyphRange = NSMakeRange (prevGlyphIndex,
+                                          numberOfGlyphs - prevGlyphIndex);
+              else
+                glyphRange = NSMakeRange (prevGlyphIndex,
+                                          glyphIndex + 1 - prevGlyphIndex);
+              glyphRects =
+                [layoutManager
+                  rectArrayForGlyphRange:glyphRange
+                  withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
+                         inTextContainer:textContainer rectCount:&nrects];
+              minX = min (NSMinX (glyphRects[0]), totalAdvance);
+              gl->advance = totalAdvance - minX;
+              totalAdvance = minX;
+              gl->advance_delta = location.x - totalAdvance;
+            }
+
+          prevGlyphIndex = glyphIndex + 1;
+          glyphIndex = nextGlyphIndex;
+        }
+
+      if (RIGHT_TO_LEFT_P)
+        xfree (permutation);
+
+#undef RIGHT_TO_LEFT_P
+
+      result = used;
+    }
+  [textStorage release];
+
+  return result;
+}
+
+static Lisp_Object
+nsfont_shape (Lisp_Object lgstring, Lisp_Object direction)
+{
+  struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+  struct nsfont_info *font_info = (struct nsfont_info *) font;
+  struct ns_glyph_layout *glyph_layouts;
+  NSFont *nsfont = font_info->nsfont;
+  ptrdiff_t glyph_len, len, i;
+  Lisp_Object tem;
+  unichar *mb_buf;
+  NSUInteger used;
+
+  glyph_len = LGSTRING_GLYPH_LEN (lgstring);
+  for (i = 0; i < glyph_len; ++i)
+    {
+      tem = LGSTRING_GLYPH (lgstring, i);
+
+      if (NILP (tem))
+       break;
+    }
+
+  len = i;
+
+  if (INT_MAX / 2 < len)
+    memory_full (SIZE_MAX);
+
+  block_input ();
+
+  mb_buf = alloca (len * sizeof *mb_buf);
+
+  for (i = 0; i < len; ++i)
+    {
+      uint32_t c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
+      mb_buf[i] = (unichar) c;
+    }
+
+  NSString *string = [NSString stringWithCharacters: mb_buf
+                                            length: len];
+  unblock_input ();
+
+  if (!string)
+    return Qnil;
+
+  block_input ();
+
+  enum lgstring_direction dir = DIR_UNKNOWN;
+
+  if (EQ (direction, QL2R))
+    dir = DIR_L2R;
+  else if (EQ (direction, QR2L))
+    dir = DIR_R2L;
+  glyph_layouts = alloca (sizeof (struct ns_glyph_layout) * glyph_len);
+  used = ns_font_shape (nsfont, string, glyph_layouts, glyph_len, dir);
+
+  for (i = 0; i < used; i++)
+    {
+      Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
+      struct ns_glyph_layout *gl = glyph_layouts + i;
+      EMACS_INT from, to;
+      struct font_metrics metrics;
+
+      if (NILP (lglyph))
+        {
+          lglyph = LGLYPH_NEW ();
+          LGSTRING_SET_GLYPH (lgstring, i, lglyph);
+        }
+
+      from = gl->comp_range.location;
+      LGLYPH_SET_FROM (lglyph, from);
+
+      to = gl->comp_range.location + gl->comp_range.length;
+      LGLYPH_SET_TO (lglyph, to - 1);
+
+      /* LGLYPH_CHAR is used in `describe-char' for checking whether
+         the composition is trivial.  */
+      {
+        UTF32Char c;
+
+        if (mb_buf[gl->string_index] >= 0xD800
+            && mb_buf[gl->string_index] < 0xDC00)
+          c = (((mb_buf[gl->string_index] - 0xD800) << 10)
+               + (mb_buf[gl->string_index + 1] - 0xDC00) + 0x10000);
+        else
+          c = mb_buf[gl->string_index];
+
+        LGLYPH_SET_CHAR (lglyph, c);
+      }
+
+      {
+        unsigned long cc = gl->glyph_id;
+        LGLYPH_SET_CODE (lglyph, cc);
+      }
+
+      nsfont_text_extents (font, &gl->glyph_id, 1, &metrics);
+      LGLYPH_SET_WIDTH (lglyph, metrics.width);
+      LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
+      LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
+      LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
+      LGLYPH_SET_DESCENT (lglyph, metrics.descent);
+    }
+  unblock_input ();
+
+  return make_fixnum (used);
+}
 
 
 /* ==========================================================================
@@ -1134,6 +1606,50 @@ nsfont_draw (struct glyph_string *s, int from, int to, 
int x, int y,
 
    ========================================================================== 
*/
 
+static NSGlyph
+ns_uni_to_glyphs_1 (struct nsfont_info *info, unsigned int c)
+{
+  unichar characters[] = { c };
+  NSString *string =
+    [NSString stringWithCharacters: characters
+                           length: 1];
+  NSDictionary *attributes =
+    [NSDictionary dictionaryWithObjectsAndKeys:
+                   info->nsfont, NSFontAttributeName, nil];
+  NSTextStorage *storage = [[NSTextStorage alloc] initWithString: string
+                                                     attributes: attributes];
+  NSTextContainer *text_container = [[NSTextContainer alloc] init];
+  NSLayoutManager *manager = [[NSLayoutManager alloc] init];
+
+  [manager addTextContainer: text_container];
+  [text_container release]; /* Retained by manager */
+  [storage addLayoutManager: manager];
+  [manager release]; /* Retained by storage */
+
+  NSFont *font_in_storage = [storage attribute: NSFontAttributeName
+                                      atIndex:0
+                               effectiveRange: NULL];
+  NSGlyph glyph = FONT_INVALID_CODE;
+
+  if ((font_in_storage == info->nsfont
+       || [[font_in_storage fontName] isEqualToString: [info->nsfont 
fontName]]))
+    {
+      @try
+       {
+         glyph = [manager glyphAtIndex: 0];
+       }
+      @catch (NSException *e)
+       {
+         /* GNUstep bug? */
+         glyph = 'X';
+       }
+    }
+
+  [storage release];
+
+  return glyph;
+}
+
 /* Find and cache corresponding glyph codes for unicode values in given
    hi-byte block of 256.  */
 static void
@@ -1141,7 +1657,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned 
char block)
 {
   unichar *unichars = xmalloc (0x101 * sizeof (unichar));
   unsigned int i, g, idx;
-  unsigned short *glyphs;
+  unsigned int *glyphs;
 
   if (NSFONT_TRACE)
     fprintf (stderr, "%p\tFinding glyphs for glyphs in block %d\n",
@@ -1149,7 +1665,7 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned 
char block)
 
   block_input ();
 
-  font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned short));
+  font_info->glyphs[block] = xmalloc (0x100 * sizeof (unsigned int));
   if (!unichars || !(font_info->glyphs[block]))
     emacs_abort ();
 
@@ -1166,7 +1682,8 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, unsigned 
char block)
     for (i = 0; i < 0x100; i++, glyphs++)
       {
         g = unichars[i];
-        *glyphs = g;
+       NSGlyph glyph = ns_uni_to_glyphs_1 (font_info, g);
+        *glyphs = glyph;
       }
   }
 
@@ -1175,18 +1692,19 @@ ns_uni_to_glyphs (struct nsfont_info *font_info, 
unsigned char block)
 }
 
 
-/* Determine and cache metrics for corresponding glyph codes in given
-   hi-byte block of 256.  */
+/* Determine and cache metrics for glyphs in given hi-byte block of
+   256.  */
 static void
-ns_glyph_metrics (struct nsfont_info *font_info, unsigned char block)
+ns_glyph_metrics (struct nsfont_info *font_info, unsigned int block)
 {
-  unsigned int i, g;
+  unsigned int i;
+  NSGlyph g;
   unsigned int numGlyphs = [font_info->nsfont numberOfGlyphs];
   NSFont *sfont;
   struct font_metrics *metrics;
 
   if (NSFONT_TRACE)
-    fprintf (stderr, "%p\tComputing metrics for glyphs in block %d\n",
+    fprintf (stderr, "%p\tComputing metrics for glyphs in block %u\n",
             font_info, block);
 
   /* not implemented yet (as of startup 0.18), so punt */
@@ -1209,19 +1727,14 @@ ns_glyph_metrics (struct nsfont_info *font_info, 
unsigned char block)
       w = max ([sfont advancementForGlyph: g].width, 2.0);
       metrics->width = lrint (w);
 
-      lb = r.origin.x;
-      rb = r.size.width - w;
-      // Add to bearing for LCD smoothing.  We don't know if it is there.
-      if (lb < 0)
-        metrics->lbearing = round (lb - LCD_SMOOTHING_MARGIN);
-      if (font_info->ital)
-        rb += (CGFloat) (0.22F * font_info->height);
-      metrics->rbearing = lrint (w + rb + LCD_SMOOTHING_MARGIN);
-
-      metrics->descent = r.origin.y < 0 ? -r.origin.y : 0;
-      /* lrint (hshrink * [sfont ascender] + expand * hd/2); */
-      metrics->ascent = r.size.height - metrics->descent;
-      /* -lrint (hshrink* [sfont descender] - expand * hd/2); */
+      lb = NSMinX (r);
+      rb = NSMaxX (r);
+
+      metrics->rbearing = lrint (rb);
+      metrics->lbearing = lrint (lb);
+
+      metrics->descent = NSMinY (r);
+      metrics->ascent = NSMaxY (r);
     }
   unblock_input ();
 }
@@ -1257,6 +1770,7 @@ struct font_driver const nsfont_driver =
   .has_char = nsfont_has_char,
   .encode_char = nsfont_encode_char,
   .text_extents = nsfont_text_extents,
+  .shape = nsfont_shape,
   .draw = nsfont_draw,
   };
 
@@ -1265,7 +1779,6 @@ syms_of_nsfont (void)
 {
   DEFSYM (Qcondensed, "condensed");
   DEFSYM (Qexpanded, "expanded");
-  DEFSYM (Qapple, "apple");
   DEFSYM (Qmedium, "medium");
   DEFVAR_LISP ("ns-reg-to-script", Vns_reg_to_script,
                doc: /* Internal use: maps font registry to Unicode script.  
*/);
diff --git a/src/nsmenu.m b/src/nsmenu.m
index f0c5bb24e6..29201e6907 100644
--- a/src/nsmenu.m
+++ b/src/nsmenu.m
@@ -101,6 +101,15 @@ popup_activated (void)
 static void
 ns_update_menubar (struct frame *f, bool deep_p)
 {
+#ifdef NS_IMPL_GNUSTEP
+  static int inside = 0;
+
+  if (inside)
+    return;
+
+  inside++;
+#endif
+
   BOOL needsSet = NO;
   id menu = [NSApp mainMenu];
   bool owfi;
@@ -120,7 +129,12 @@ ns_update_menubar (struct frame *f, bool deep_p)
   NSTRACE ("ns_update_menubar");
 
   if (f != SELECTED_FRAME () || FRAME_EXTERNAL_MENU_BAR (f) == 0)
+    {
+#ifdef NS_IMPL_GNUSTEP
+      inside--;
+#endif
       return;
+    }
   XSETFRAME (Vmenu_updating_frame, f);
 /*fprintf (stderr, "ns_update_menubar: frame: %p\tdeep: %d\tsub: %p\n", f, 
deep_p, submenu); */
 
@@ -144,10 +158,6 @@ ns_update_menubar (struct frame *f, bool deep_p)
   t = -(1000*tb.time+tb.millitm);
 #endif
 
-#ifdef NS_IMPL_GNUSTEP
-  deep_p = 1; /* See comment in menuNeedsUpdate.  */
-#endif
-
   if (deep_p)
     {
       /* Make a widget-value tree representing the entire menu trees.  */
@@ -275,6 +285,9 @@ ns_update_menubar (struct frame *f, bool deep_p)
          free_menubar_widget_value_tree (first_wv);
          discard_menu_items ();
          unbind_to (specpdl_count, Qnil);
+#ifdef NS_IMPL_GNUSTEP
+         inside--;
+#endif
          return;
        }
 
@@ -408,6 +421,10 @@ ns_update_menubar (struct frame *f, bool deep_p)
   if (needsSet)
     [NSApp setMainMenu: menu];
 
+#ifdef NS_IMPL_GNUSTEP
+  inside--;
+#endif
+
   unblock_input ();
 
 }
@@ -452,17 +469,34 @@ set_frame_menubar (struct frame *f, bool deep_p)
    call to ns_update_menubar.  */
 - (void)menuNeedsUpdate: (NSMenu *)menu
 {
+#ifdef NS_IMPL_GNUSTEP
+  static int inside = 0;
+#endif
+
   if (!FRAME_LIVE_P (SELECTED_FRAME ()))
     return;
 
-#ifdef NS_IMPL_COCOA
-/* TODO: GNUstep calls this method when the menu is still being built
-   which results in a recursive stack overflow.  One possible solution
-   is to use menuWillOpen instead, but the Apple docs explicitly warn
-   against changing the contents of the menu in it.  I don't know what
-   the right thing to do for GNUstep is.  */
+#ifdef NS_IMPL_GNUSTEP
+  /* GNUstep calls this method when the menu is still being built
+     which results in a recursive stack overflow, which this variable
+     prevents.  */
+
+  if (!inside)
+    ++inside;
+  else
+    return;
+#endif
+
   if (needsUpdate)
-    ns_update_menubar (SELECTED_FRAME (), true);
+    {
+#ifdef NS_IMPL_GNUSTEP
+      needsUpdate = NO;
+#endif
+      ns_update_menubar (SELECTED_FRAME (), true);
+    }
+
+#ifdef NS_IMPL_GNUSTEP
+  --inside;
 #endif
 }
 
@@ -789,6 +823,9 @@ ns_menu_show (struct frame *f, int x, int y, int menuflags,
 
   p.x = x; p.y = y;
 
+  /* Don't GC due to a mysterious bug.  */
+  inhibit_garbage_collection ();
+
   /* now parse stage 2 as in ns_update_menubar */
   wv = make_widget_value ("contextmenu", NULL, true, Qnil);
   wv->button_type = BUTTON_TYPE_NONE;
@@ -960,15 +997,17 @@ ns_menu_show (struct frame *f, int x, int y, int 
menuflags,
 
   pmenu = [[EmacsMenu alloc] initWithTitle:
                    NILP (title) ? @"" : [NSString stringWithLispString: 
title]];
+  /* On GNUstep, this call makes menu_items nil for whatever reason
+     when displaying a context menu from `context-menu-mode'.  */
+  Lisp_Object items = menu_items;
   [pmenu fillWithWidgetValue: first_wv->contents];
+  menu_items = items;
   free_menubar_widget_value_tree (first_wv);
-  unbind_to (specpdl_count, Qnil);
-
   popup_activated_flag = 1;
   tem = [pmenu runMenuAt: p forFrame: f keymaps: keymaps];
   popup_activated_flag = 0;
   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
-
+  unbind_to (specpdl_count, Qnil);
   unblock_input ();
   return tem;
 }
@@ -995,31 +1034,39 @@ free_frame_tool_bar (struct frame *f)
   /* Note: This triggers an animation, which calls windowDidResize
      repeatedly.  */
   f->output_data.ns->in_animation = 1;
-  [[[view window] toolbar] setVisible: NO];
+  [[[view window] toolbar] setVisible:NO];
   f->output_data.ns->in_animation = 0;
 
+  [[view window] setToolbar:nil];
+
   unblock_input ();
 }
 
 void
-update_frame_tool_bar (struct frame *f)
+update_frame_tool_bar_1 (struct frame *f, EmacsToolbar *toolbar)
 /* --------------------------------------------------------------------------
     Update toolbar contents.
    -------------------------------------------------------------------------- 
*/
 {
   int i, k = 0;
-  NSWindow *window = [FRAME_NS_VIEW (f) window];
-  EmacsToolbar *toolbar = (EmacsToolbar *)[window toolbar];
 
   NSTRACE ("update_frame_tool_bar");
 
-  if (window == nil || toolbar == nil) return;
   block_input ();
 
 #ifdef NS_IMPL_COCOA
   [toolbar clearActive];
 #else
   [toolbar clearAll];
+  /* It takes at least 3 such adjustments to fix an issue where the
+     tool bar is 2x too tall when a frame's tool bar is first shown.
+     This is ugly, but I have no other solution for this problem.  */
+  if (FRAME_OUTPUT_DATA (f)->tool_bar_adjusted < 3)
+    {
+      [toolbar setVisible: NO];
+      FRAME_OUTPUT_DATA (f)->tool_bar_adjusted++;
+      [toolbar setVisible: YES];
+    }
 #endif
 
   /* Update EmacsToolbar as in GtkUtils, build items list.  */
@@ -1094,13 +1141,6 @@ update_frame_tool_bar (struct frame *f)
 #undef TOOLPROP
     }
 
-  if (![toolbar isVisible] != !FRAME_EXTERNAL_TOOL_BAR (f))
-    {
-      f->output_data.ns->in_animation = 1;
-      [toolbar setVisible: FRAME_EXTERNAL_TOOL_BAR (f)];
-      f->output_data.ns->in_animation = 0;
-    }
-
 #ifdef NS_IMPL_COCOA
   if ([toolbar changed])
     {
@@ -1124,9 +1164,28 @@ update_frame_tool_bar (struct frame *f)
       [newDict release];
     }
 #endif
+
+  [toolbar setVisible:YES];
   unblock_input ();
 }
 
+void
+update_frame_tool_bar (struct frame *f)
+{
+  EmacsWindow *window = (EmacsWindow *)[FRAME_NS_VIEW (f) window];
+  EmacsToolbar *toolbar = (EmacsToolbar *)[window toolbar];
+
+  if (!toolbar)
+    {
+      [window createToolbar:f];
+      return;
+    }
+
+  if (window == nil || toolbar == nil) return;
+
+  update_frame_tool_bar_1 (f, toolbar);
+}
+
 
 /* ==========================================================================
 
diff --git a/src/nsterm.h b/src/nsterm.h
index 6d4ea77121..8175f99664 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1,3 +1,4 @@
+/* -*- objc -*- */
 /* Definitions and headers for communication with NeXT/Open/GNUstep API.
    Copyright (C) 1989, 1993, 2005, 2008-2021 Free Software Foundation,
    Inc.
@@ -418,6 +419,7 @@ typedef id instancetype;
 
 - (instancetype)initWithEmacsFrame:(struct frame *)f;
 - (instancetype)initWithEmacsFrame:(struct frame *)f 
fullscreen:(BOOL)fullscreen screen:(NSScreen *)screen;
+- (void)createToolbar:(struct frame *)f;
 - (void)setParentChildRelationships;
 - (NSInteger)borderWidth;
 - (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above;
@@ -488,7 +490,7 @@ typedef id instancetype;
 - (void)lockFocus;
 - (void)unlockFocus;
 #endif
-- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect;
+- (void)copyRect:(NSRect)srcRect to:(NSPoint)dest;
 
 /* Non-notification versions of NSView methods. Used for direct calls.  */
 - (void)windowWillEnterFullScreen;
@@ -818,7 +820,7 @@ struct nsfont_info
   XCharStruct max_bounds;
   /* We compute glyph codes and metrics on-demand in blocks of 256 indexed
      by hibyte, lobyte.  */
-  unsigned short **glyphs; /* map Unicode index to glyph */
+  unsigned int **glyphs; /* map Unicode index to glyph */
   struct font_metrics **metrics;
 };
 #endif
@@ -976,6 +978,12 @@ struct ns_output
 
   /* Non-zero if we are doing an animation, e.g. toggling the tool bar.  */
   int in_animation;
+
+#ifdef NS_IMPL_GNUSTEP
+  /* Zero if this is the first time a toolbar has been updated on this
+     frame. */
+  int tool_bar_adjusted;
+#endif
 };
 
 /* This dummy declaration needed to support TTYs.  */
@@ -1134,6 +1142,7 @@ extern void ns_implicitly_set_name (struct frame *f, 
Lisp_Object arg,
                                     Lisp_Object oldval);
 extern void ns_set_scroll_bar_default_width (struct frame *f);
 extern void ns_set_scroll_bar_default_height (struct frame *f);
+extern void ns_change_tab_bar_height (struct frame *f, int height);
 extern const char *ns_get_string_resource (void *_rdb,
                                            const char *name,
                                            const char *class);
@@ -1148,6 +1157,10 @@ extern void ns_init_locale (void);
 
 /* in nsmenu */
 extern void update_frame_tool_bar (struct frame *f);
+#ifdef __OBJC__
+extern void update_frame_tool_bar_1 (struct frame *f, EmacsToolbar *toolbar);
+#endif
+
 extern void free_frame_tool_bar (struct frame *f);
 extern Lisp_Object find_and_return_menu_selection (struct frame *f,
                                                    bool keymaps,
diff --git a/src/nsterm.m b/src/nsterm.m
index 4ef20e4c2b..ed0e7a2aae 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -65,6 +65,7 @@ GNUstep port and post-20 update by Adrian Robert 
(arobert@cogsci.ucsd.edu)
 
 #ifdef NS_IMPL_GNUSTEP
 #include "process.h"
+#import <GNUstepGUI/GSDisplayServer.h>
 #endif
 
 #ifdef NS_IMPL_COCOA
@@ -543,8 +544,10 @@ ns_init_locale (void)
       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
                                      [locale localeIdentifier]];
 
-      /* Set LANG to locale, but not if LANG is already set.  */
+      /* Set LANG and LC_ALL to locale, but not if the variables are
+         already set.  */
       setenv("LANG", [localeID UTF8String], 0);
+      setenv("LC_ALL", [localeID UTF8String], 0);
     }
   @catch (NSException *e)
     {
@@ -1021,15 +1024,6 @@ ns_update_begin (struct frame *f)
 
   ns_update_auto_hide_menu_bar ();
 
-  NSToolbar *toolbar = [[FRAME_NS_VIEW (f) window] toolbar];
-  if (toolbar)
-  {
-    /* Ensure the toolbars visibility is set correctly.  */
-    BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
-    if (! tbar_visible != ! [toolbar isVisible])
-      [toolbar setVisible: tbar_visible];
-  }
-
   ns_updating_frame = f;
   [view lockFocus];
 }
@@ -1086,11 +1080,16 @@ ns_focus (struct frame *f, NSRect *r, int n)
   /* clipping */
   if (r)
     {
-      [[NSGraphicsContext currentContext] saveGraphicsState];
+      NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
+      [ctx saveGraphicsState];
+#ifdef NS_IMPL_COCOA
       if (n == 2)
         NSRectClipList (r, 2);
       else
         NSRectClip (*r);
+#else
+      GSRectClipList (ctx, r, n);
+#endif
       gsaved = YES;
     }
 }
@@ -2258,13 +2257,19 @@ frame_set_mouse_pixel_position (struct frame *f, int 
pix_x, int pix_y)
 {
   NSTRACE ("frame_set_mouse_pixel_position");
 
-  /* FIXME: what about GNUstep?  */
 #ifdef NS_IMPL_COCOA
   CGPoint mouse_pos =
     CGPointMake(f->left_pos + pix_x,
                 f->top_pos + pix_y +
                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
   CGWarpMouseCursorPosition (mouse_pos);
+#else
+  GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]);
+  [server setMouseLocation: NSMakePoint (f->left_pos + pix_x,
+                                        f->top_pos + pix_y
+                                        + FRAME_NS_TITLEBAR_HEIGHT(f)
+                                        + FRAME_TOOLBAR_HEIGHT(f))
+                 onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]];
 #endif
 }
 
@@ -2442,9 +2447,6 @@ ns_define_frame_cursor (struct frame *f, Emacs_Cursor 
cursor)
       EmacsView *view = FRAME_NS_VIEW (f);
       FRAME_POINTER_TYPE (f) = cursor;
       [[view window] invalidateCursorRectsForView: view];
-      /* Redisplay assumes this function also draws the changed frame
-         cursor, but this function doesn't, so do it explicitly.  */
-      gui_update_cursor (f, 1);
     }
 }
 
@@ -2580,8 +2582,7 @@ ns_get_shifted_character (NSEvent *event)
    ========================================================================== 
*/
 
 
-#if 0
-/* FIXME: Remove this function. */
+#ifdef NS_IMPL_GNUSTEP
 static void
 ns_redraw_scroll_bars (struct frame *f)
 {
@@ -2626,10 +2627,9 @@ ns_clear_frame (struct frame *f)
   NSRectFill (r);
   ns_unfocus (f);
 
-  /* as of 2006/11 or so this is now needed */
-  /* FIXME: I don't see any reason for this and removing it makes no
-     difference here.  Do we need it for GNUstep?  */
-  //ns_redraw_scroll_bars (f);
+#ifdef NS_IMPL_GNUSTEP
+  ns_redraw_scroll_bars (f);
+#endif
   unblock_input ();
 }
 
@@ -2710,10 +2710,10 @@ ns_scroll_run (struct window *w, struct run *run)
 
   {
     NSRect srcRect = NSMakeRect (x, from_y, width, height);
-    NSRect dstRect = NSMakeRect (x, to_y, width, height);
+    NSPoint dest = NSMakePoint (x, to_y);
     EmacsView *view = FRAME_NS_VIEW (f);
 
-    [view copyRect:srcRect to:dstRect];
+    [view copyRect:srcRect to:dest];
 #ifdef NS_IMPL_COCOA
     [view setNeedsDisplayInRect:srcRect];
 #endif
@@ -2730,11 +2730,10 @@ ns_clear_under_internal_border (struct frame *f)
 
   if (FRAME_LIVE_P (f) && FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
     {
-      int border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
-      NSView *view = FRAME_NS_VIEW (f);
-      NSRect edge_rect, frame_rect = [view bounds];
-      NSRectEdge edge[] = {NSMinXEdge, NSMinYEdge, NSMaxXEdge, NSMaxYEdge};
-
+      int border = FRAME_INTERNAL_BORDER_WIDTH (f);
+      int width = FRAME_PIXEL_WIDTH (f);
+      int height = FRAME_PIXEL_HEIGHT (f);
+      int margin = FRAME_TOP_MARGIN_HEIGHT (f);
       int face_id =
         (FRAME_PARENT_FRAME (f)
          ? (!NILP (Vface_remapping_alist)
@@ -2756,12 +2755,12 @@ ns_clear_under_internal_border (struct frame *f)
 
       ns_focus (f, NULL, 1);
       [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
-      for (int i = 0; i < 4 ; i++)
-        {
-          NSDivideRect (frame_rect, &edge_rect, &frame_rect, border_width, 
edge[i]);
 
-          NSRectFill (edge_rect);
-        }
+      NSRectFill (NSMakeRect (0, margin, width, border));
+      NSRectFill (NSMakeRect (0, 0, border, height));
+      NSRectFill (NSMakeRect (0, margin, width, border));
+      NSRectFill (NSMakeRect (width - border, 0, border, height));
+      NSRectFill (NSMakeRect (0, height - border, width, border));
       ns_unfocus (f);
     }
 }
@@ -2835,11 +2834,11 @@ ns_shift_glyphs_for_insert (struct frame *f,
    -------------------------------------------------------------------------- 
*/
 {
   NSRect srcRect = NSMakeRect (x, y, width, height);
-  NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
+  NSPoint dest = NSMakePoint (x+shift_by, y);
 
   NSTRACE ("ns_shift_glyphs_for_insert");
 
-  [FRAME_NS_VIEW (f) copyRect:srcRect to:dstRect];
+  [FRAME_NS_VIEW (f) copyRect:srcRect to:dest];
 }
 
 
@@ -2857,31 +2856,31 @@ ns_compute_glyph_string_overhangs (struct glyph_string 
*s)
      External (RIF); compute left/right overhang of whole string and set in s
    -------------------------------------------------------------------------- 
*/
 {
-  struct font *font = s->font;
-
-  if (s->char2b)
+  if (s->cmp == NULL
+      && (s->first_glyph->type == CHAR_GLYPH
+         || s->first_glyph->type == COMPOSITE_GLYPH))
     {
       struct font_metrics metrics;
-      unsigned int codes[2];
-      codes[0] = *(s->char2b);
-      codes[1] = *(s->char2b + s->nchars - 1);
 
-      font->driver->text_extents (font, codes, 2, &metrics);
-      s->left_overhang = -metrics.lbearing;
-      s->right_overhang
-       = metrics.rbearing > metrics.width
-       ? metrics.rbearing - metrics.width : 0;
+      if (s->first_glyph->type == CHAR_GLYPH)
+       {
+         struct font *font = s->font;
+         font->driver->text_extents (font, s->char2b, s->nchars, &metrics);
+       }
+      else
+       {
+         Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
+
+         composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics);
+       }
+      s->right_overhang = (metrics.rbearing > metrics.width
+                          ? metrics.rbearing - metrics.width : 0);
+      s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0;
     }
-  else
+  else if (s->cmp)
     {
-      s->left_overhang = 0;
-#ifdef NS_IMPL_GNUSTEP
-      if (EQ (font->driver->type, Qns))
-        s->right_overhang = ((struct nsfont_info *)font)->ital ?
-          FONT_HEIGHT (font) * 0.2 : 0;
-      else
-#endif
-        s->right_overhang = 0;
+      s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
+      s->left_overhang = - s->cmp->lbearing;
     }
 }
 
@@ -3021,14 +3020,13 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
   struct frame *f = WINDOW_XFRAME (w);
   struct glyph *phys_cursor_glyph;
   struct glyph *cursor_glyph;
-  struct face *face;
-  NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
 
   /* If cursor is out of bounds, don't draw garbage.  This can happen
      in mini-buffer windows when switching between echo area glyphs
      and mini-buffer.  */
 
-  NSTRACE ("ns_draw_window_cursor");
+  NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)",
+          on_p, cursor_type);
 
   if (!on_p)
     return;
@@ -3044,6 +3042,8 @@ ns_draw_window_cursor (struct window *w, struct glyph_row 
*glyph_row,
 
   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
     {
+      NSTRACE_MSG ("No phys cursor glyph was found!");
+
       if (glyph_row->exact_window_width_line_p
           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
         {
@@ -3053,10 +3053,6 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
       return;
     }
 
-  /* We draw the cursor (with NSRectFill), then draw the glyph on top
-     (other terminals do it the other way round).  We must set
-     w->phys_cursor_width to the cursor width.  For bar cursors, that
-     is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
 
   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
@@ -3088,17 +3084,17 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
   /* Prevent the cursor from being drawn outside the text area.  */
   r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
 
-  ns_focus (f, &r, 1);
+  ns_focus (f, NULL, 0);
 
-  face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
-  if (face && NS_FACE_BACKGROUND (face)
-      == ns_index_color (FRAME_CURSOR_COLOR (f), f))
-    {
-      [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
-      hollow_color = FRAME_CURSOR_COLOR (f);
-    }
-  else
-    [FRAME_CURSOR_COLOR (f) set];
+  NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
+  [ctx saveGraphicsState];
+#ifdef NS_IMPL_GNUSTEP
+  GSRectClipList (ctx, &r, 1);
+#else
+  NSRectClip (r);
+#endif
+
+  [FRAME_CURSOR_COLOR (f) set];
 
   switch (cursor_type)
     {
@@ -3106,13 +3102,11 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
     case NO_CURSOR:
       break;
     case FILLED_BOX_CURSOR:
-      NSRectFill (r);
+      draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
       break;
     case HOLLOW_BOX_CURSOR:
-      NSRectFill (r);
-      [hollow_color set];
-      NSRectFill (NSInsetRect (r, 1, 1));
-      [FRAME_CURSOR_COLOR (f) set];
+      draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT);
+      [NSBezierPath strokeRect: r];
       break;
     case HBAR_CURSOR:
       NSRectFill (r);
@@ -3128,12 +3122,9 @@ ns_draw_window_cursor (struct window *w, struct 
glyph_row *glyph_row,
       NSRectFill (s);
       break;
     }
-  ns_unfocus (f);
 
-  /* Draw the character under the cursor.  Other terms only draw
-     the character on top of box cursors, so do the same here.  */
-  if (cursor_type == FILLED_BOX_CURSOR || cursor_type == HOLLOW_BOX_CURSOR)
-    draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+  [ctx restoreGraphicsState];
+  ns_unfocus (f);
 }
 
 
@@ -3313,16 +3304,18 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
   if (s->for_overlaps)
     return;
 
+  if (s->hl == DRAW_CURSOR)
+    [FRAME_BACKGROUND_COLOR (s->f) set];
+  else if (face->underline_defaulted_p)
+    [defaultCol set];
+  else
+    [ns_lookup_indexed_color (face->underline_color, s->f) set];
+
   /* Do underline.  */
   if (face->underline)
     {
       if (s->face->underline == FACE_UNDER_WAVE)
         {
-          if (face->underline_defaulted_p)
-            [defaultCol set];
-          else
-            [ns_lookup_indexed_color (face->underline_color, s->f) set];
-
           ns_draw_underwave (s, width, x);
         }
       else if (s->face->underline == FACE_UNDER_LINE)
@@ -3393,11 +3386,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
           s->underline_position = position;
 
           r = NSMakeRect (x, s->ybase + position, width, thickness);
-
-          if (face->underline_defaulted_p)
-            [defaultCol set];
-          else
-            [ns_lookup_indexed_color (face->underline_color, s->f) set];
           NSRectFill (r);
         }
     }
@@ -3407,11 +3395,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
     {
       NSRect r;
       r = NSMakeRect (x, s->y, width, 1);
-
-      if (face->overline_color_defaulted_p)
-        [defaultCol set];
-      else
-        [ns_lookup_indexed_color (face->overline_color, s->f) set];
       NSRectFill (r);
     }
 
@@ -3434,10 +3417,6 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
       dy = lrint ((glyph_height - h) / 2);
       r = NSMakeRect (x, glyph_y + dy, width, 1);
 
-      if (face->strike_through_color_defaulted_p)
-        [defaultCol set];
-      else
-        [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
       NSRectFill (r);
     }
 }
@@ -3522,7 +3501,12 @@ ns_draw_relief (NSRect outer, int hthickness, int 
vthickness, char raised_p,
     }
 
   /* Calculate the inner rectangle.  */
-  inner = NSInsetRect (outer, hthickness, vthickness);
+  inner = NSMakeRect (NSMinX (outer) + (left_p ? hthickness : 0),
+                      NSMinY (outer) + (top_p ? vthickness : 0),
+                      NSWidth (outer) - (left_p ? hthickness : 0)
+                                      - (right_p ? hthickness : 0),
+                      NSHeight (outer) - (top_p ? vthickness : 0)
+                                       - (bottom_p ? vthickness : 0));
 
   [(raised_p ? lightCol : darkCol) set];
 
@@ -3580,17 +3564,7 @@ ns_dumpglyphs_box_or_relief (struct glyph_string *s)
   struct glyph *last_glyph;
   NSRect r;
   int hthickness, vthickness;
-  struct face *face;
-
-  if (s->hl == DRAW_MOUSE_FACE)
-    {
-      face = FACE_FROM_ID_OR_NULL (s->f,
-                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
-      if (!face)
-        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-    }
-  else
-    face = s->face;
+  struct face *face = s->face;
 
   vthickness = face->box_vertical_line_width;
   hthickness = face->box_horizontal_line_width;
@@ -3664,34 +3638,26 @@ ns_maybe_dumpglyphs_background (struct glyph_string *s, 
char force_p)
          || FONT_TOO_HIGH (s->font)
           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
        {
-          struct face *face;
-          if (s->hl == DRAW_MOUSE_FACE)
-            {
-              face
-               = FACE_FROM_ID_OR_NULL (s->f,
-                                       MOUSE_HL_INFO 
(s->f)->mouse_face_face_id);
-              if (!face)
-                face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-            }
-          else
-            face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+          struct face *face = s->face;
           if (!face->stipple)
-            [(NS_FACE_BACKGROUND (face) != 0
-              ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
-              : FRAME_BACKGROUND_COLOR (s->f)) set];
+           {
+             if (s->hl != DRAW_CURSOR)
+               [(NS_FACE_BACKGROUND (face) != 0
+                 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
+                 : FRAME_BACKGROUND_COLOR (s->f)) set];
+             else
+               [FRAME_CURSOR_COLOR (s->f) set];
+           }
           else
             {
               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
             }
 
-          if (s->hl != DRAW_CURSOR)
-            {
-              NSRect r = NSMakeRect (s->x, s->y + box_line_width,
-                                    s->background_width,
-                                    s->height-2*box_line_width);
-              NSRectFill (r);
-            }
+         NSRect r = NSMakeRect (s->x, s->y + box_line_width,
+                                s->background_width,
+                                s->height-2*box_line_width);
+         NSRectFill (r);
 
          s->background_filled_p = 1;
        }
@@ -3712,7 +3678,7 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
   int th;
   char raised_p;
   NSRect br;
-  struct face *face;
+  struct face *face = s->face;
   NSColor *tdCol;
 
   NSTRACE ("ns_dumpglyphs_image");
@@ -3733,15 +3699,6 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
   /* Draw BG: if we need larger area than image itself cleared, do that,
      otherwise, since we composite the image under NS (instead of mucking
      with its background color), we must clear just the image area.  */
-  if (s->hl == DRAW_MOUSE_FACE)
-    {
-      face = FACE_FROM_ID_OR_NULL (s->f,
-                                  MOUSE_HL_INFO (s->f)->mouse_face_face_id);
-      if (!face)
-       face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-    }
-  else
-    face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
 
   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
 
@@ -3812,16 +3769,8 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
 
   if (s->hl == DRAW_CURSOR)
     {
-    [FRAME_CURSOR_COLOR (s->f) set];
-    if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
+      [FRAME_CURSOR_COLOR (s->f) set];
       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
-    else
-      /* Currently on NS img->mask is always 0.  Since
-         get_window_cursor_type specifies a hollow box cursor when on
-         a non-masked image we never reach this clause.  But we put it
-         in, in anticipation of better support for image masks on
-         NS.  */
-      tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
     }
   else
     {
@@ -3873,66 +3822,35 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
 static void
 ns_dumpglyphs_stretch (struct glyph_string *s)
 {
-  NSRect r[2];
   NSRect glyphRect;
-  int n;
-  struct face *face;
+  struct face *face = s->face;
   NSColor *fgCol, *bgCol;
 
   if (!s->background_filled_p)
     {
-      n = ns_get_glyph_string_clip_rect (s, r);
-      ns_focus (s->f, r, n);
 
-      if (s->hl == DRAW_MOUSE_FACE)
-        {
-          face = FACE_FROM_ID_OR_NULL (s->f,
-                                       MOUSE_HL_INFO 
(s->f)->mouse_face_face_id);
-          if (!face)
-            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-        }
-      else
-        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+      face = s->face;
 
       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
 
+      if (s->hl == DRAW_CURSOR)
+       {
+         fgCol = bgCol;
+         bgCol = FRAME_CURSOR_COLOR (s->f);
+       }
+
       glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height);
 
       [bgCol set];
 
-      /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
-         overwriting cursor (usually when cursor on a tab) */
-      if (s->hl == DRAW_CURSOR)
-        {
-          CGFloat x, width;
-
-          /* FIXME: This looks like it will only work for left to
-             right languages.  */
-          x = NSMinX (glyphRect);
-          width = s->w->phys_cursor_width;
-          glyphRect.size.width -= width;
-          glyphRect.origin.x += width;
-
-          NSRectFill (glyphRect);
-
-          /* Draw overlining, etc. on the cursor. */
-          if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
-            ns_draw_text_decoration (s, face, bgCol, width, x);
-          else
-            ns_draw_text_decoration (s, face, fgCol, width, x);
-        }
-      else
-        {
-          NSRectFill (glyphRect);
-        }
+      NSRectFill (glyphRect);
 
       /* Draw overlining, etc. on the stretch glyph (or the part
          of the stretch glyph after the cursor). */
       ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect),
                                NSMinX (glyphRect));
 
-      ns_unfocus (s->f);
       s->background_filled_p = 1;
     }
 }
@@ -3941,7 +3859,7 @@ ns_dumpglyphs_stretch (struct glyph_string *s)
 static void
 ns_draw_glyph_string_foreground (struct glyph_string *s)
 {
-  int x, flags;
+  int x;
   struct font *font = s->font;
 
   /* If first glyph of S has a left box line, start drawing the text
@@ -3952,15 +3870,9 @@ ns_draw_glyph_string_foreground (struct glyph_string *s)
   else
     x = s->x;
 
-  flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
-    (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
-     (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
-      NS_DUMPGLYPH_NORMAL));
-
   font->driver->draw
     (s, s->cmp_from, s->nchars, x, s->ybase,
-     (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
-     || flags == NS_DUMPGLYPH_MOUSEFACE);
+     !s->for_overlaps && !s->background_filled_p);
 }
 
 
@@ -4067,9 +3979,9 @@ ns_draw_glyph_string (struct glyph_string *s)
   struct font *font = s->face->font;
   if (! font) font = FRAME_FONT (s->f);
 
-  NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
+  NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl);
 
-  if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
+  if (s->next && s->right_overhang && !s->for_overlaps)
     {
       int width;
       struct glyph_string *next;
@@ -4079,17 +3991,17 @@ ns_draw_glyph_string (struct glyph_string *s)
           width += next->width, next = next->next)
        if (next->first_glyph->type != IMAGE_GLYPH)
           {
+           n = ns_get_glyph_string_clip_rect (s->next, r);
+           ns_focus (s->f, r, n);
             if (next->first_glyph->type != STRETCH_GLYPH)
               {
-                n = ns_get_glyph_string_clip_rect (s->next, r);
-                ns_focus (s->f, r, n);
                 ns_maybe_dumpglyphs_background (s->next, 1);
-                ns_unfocus (s->f);
               }
             else
               {
                 ns_dumpglyphs_stretch (s->next);
               }
+           ns_unfocus (s->f);
             next->num_clips = 0;
           }
     }
@@ -4106,14 +4018,21 @@ ns_draw_glyph_string (struct glyph_string *s)
       box_drawn_p = 1;
     }
 
+  n = ns_get_glyph_string_clip_rect (s, r);
+
+  if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */
+      && !s->clip_tail
+      && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
+         || (s->next && s->next->hl != s->hl && s->right_overhang)))
+    r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, 
s->height));
+
+  ns_focus (s->f, r, n);
+
   switch (s->first_glyph->type)
     {
 
     case IMAGE_GLYPH:
-      n = ns_get_glyph_string_clip_rect (s, r);
-      ns_focus (s->f, r, n);
       ns_dumpglyphs_image (s, r[0]);
-      ns_unfocus (s->f);
       break;
 
     case XWIDGET_GLYPH:
@@ -4126,57 +4045,36 @@ ns_draw_glyph_string (struct glyph_string *s)
 
     case CHAR_GLYPH:
     case COMPOSITE_GLYPH:
-      n = ns_get_glyph_string_clip_rect (s, r);
-      ns_focus (s->f, r, n);
-
-      if (s->for_overlaps || (s->cmp_from > 0
-                             && ! s->first_glyph->u.cmp.automatic))
-        s->background_filled_p = 1;
-      else
-        ns_maybe_dumpglyphs_background
-          (s, s->first_glyph->type == COMPOSITE_GLYPH);
-
-      if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
-        {
-          unsigned long tmp = NS_FACE_BACKGROUND (s->face);
-          NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
-          NS_FACE_FOREGROUND (s->face) = tmp;
-        }
-
       {
-        BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
+       BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
+       if (s->for_overlaps || (isComposite
+                               && (s->cmp_from > 0
+                                   && ! s->first_glyph->u.cmp.automatic)))
+         s->background_filled_p = 1;
+       else
+         ns_maybe_dumpglyphs_background
+           (s, s->first_glyph->type == COMPOSITE_GLYPH);
 
-        if (isComposite)
-          ns_draw_composite_glyph_string_foreground (s);
-        else
-          ns_draw_glyph_string_foreground (s);
-      }
+       if (isComposite)
+         ns_draw_composite_glyph_string_foreground (s);
+       else
+         ns_draw_glyph_string_foreground (s);
 
-      {
-        NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
-                        ? ns_lookup_indexed_color (NS_FACE_FOREGROUND 
(s->face),
-                                                   s->f)
-                        : FRAME_FOREGROUND_COLOR (s->f));
-        [col set];
-
-        /* Draw underline, overline, strike-through. */
-        ns_draw_text_decoration (s, s->face, col, s->width, s->x);
+       {
+         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
+                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND 
(s->face),
+                                                    s->f)
+                         : FRAME_FOREGROUND_COLOR (s->f));
+         [col set];
+
+         /* Draw underline, overline, strike-through. */
+         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
+       }
       }
 
-      if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
-        {
-          unsigned long tmp = NS_FACE_BACKGROUND (s->face);
-          NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
-          NS_FACE_FOREGROUND (s->face) = tmp;
-        }
-
-      ns_unfocus (s->f);
       break;
 
     case GLYPHLESS_GLYPH:
-      n = ns_get_glyph_string_clip_rect (s, r);
-      ns_focus (s->f, r, n);
-
       if (s->for_overlaps || (s->cmp_from > 0
                              && ! s->first_glyph->u.cmp.automatic))
         s->background_filled_p = 1;
@@ -4186,7 +4084,6 @@ ns_draw_glyph_string (struct glyph_string *s)
       /* ... */
       /* Not yet implemented.  */
       /* ... */
-      ns_unfocus (s->f);
       break;
 
     default:
@@ -4195,13 +4092,92 @@ ns_draw_glyph_string (struct glyph_string *s)
 
   /* Draw box if not done already.  */
   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
+    ns_dumpglyphs_box_or_relief (s);
+
+  ns_unfocus (s->f);
+
+  /* Draw surrounding overhangs. */
+  if (s->prev)
     {
-      n = ns_get_glyph_string_clip_rect (s, r);
-      ns_focus (s->f, r, n);
-      ns_dumpglyphs_box_or_relief (s);
+      ns_focus (s->f, NULL, 0);
+      struct glyph_string *prev;
+
+      for (prev = s->prev; prev; prev = prev->prev)
+       if (prev->hl != s->hl
+           && prev->x + prev->width + prev->right_overhang > s->x)
+         {
+           /* As prev was drawn while clipped to its own area, we
+              must draw the right_overhang part using s->hl now.  */
+           enum draw_glyphs_face save = prev->hl;
+           struct face *save_face = prev->face;
+
+           prev->face = s->face;
+           NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
+           [[NSGraphicsContext currentContext] saveGraphicsState];
+           NSRectClip (r);
+#ifdef NS_IMPL_GNUSTEP
+           DPSgsave ([NSGraphicsContext currentContext]);
+           DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
+                        s->width, s->height);
+#endif
+           prev->num_clips = 1;
+           prev->hl = s->hl;
+           if (prev->first_glyph->type == CHAR_GLYPH)
+             ns_draw_glyph_string_foreground (prev);
+           else
+             ns_draw_composite_glyph_string_foreground (prev);
+#ifdef NS_IMPL_GNUSTEP
+           DPSgrestore ([NSGraphicsContext currentContext]);
+#endif
+           [[NSGraphicsContext currentContext] restoreGraphicsState];
+           prev->hl = save;
+           prev->face = save_face;
+           prev->num_clips = 0;
+         }
       ns_unfocus (s->f);
     }
 
+  if (s->next)
+    {
+      ns_focus (s->f, NULL, 0);
+      struct glyph_string *next;
+
+      for (next = s->next; next; next = next->next)
+       if (next->hl != s->hl
+           && next->x - next->left_overhang < s->x + s->width)
+         {
+           /* As next will be drawn while clipped to its own area,
+              we must draw the left_overhang part using s->hl now.  */
+           enum draw_glyphs_face save = next->hl;
+           struct face *save_face = next->face;
+
+           next->hl = s->hl;
+           next->face = s->face;
+           NSRect r = NSMakeRect (s->x, s->y, s->width, s->height);
+           [[NSGraphicsContext currentContext] saveGraphicsState];
+           NSRectClip (r);
+#ifdef NS_IMPL_GNUSTEP
+           DPSgsave ([NSGraphicsContext currentContext]);
+           DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y,
+                        s->width, s->height);
+#endif
+           next->num_clips = 1;
+           if (next->first_glyph->type == CHAR_GLYPH)
+             ns_draw_glyph_string_foreground (next);
+           else
+             ns_draw_composite_glyph_string_foreground (next);
+#ifdef NS_IMPL_GNUSTEP
+           DPSgrestore ([NSGraphicsContext currentContext]);
+#endif
+           [[NSGraphicsContext currentContext] restoreGraphicsState];
+           next->hl = save;
+           next->num_clips = 0;
+           next->face = save_face;
+           next->clip_head = next;
+           next->background_filled_p = 0;
+         }
+      ns_unfocus (s->f);
+    }
   s->num_clips = 0;
 }
 
@@ -4951,6 +4927,17 @@ ns_default_font_parameter (struct frame *f, Lisp_Object 
parms)
 {
 }
 
+#ifdef NS_IMPL_GNUSTEP
+static void
+ns_update_window_end (struct window *w, bool cursor_on_p,
+                     bool mouse_face_overwritten_p)
+{
+  NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p);
+
+  ns_redraw_scroll_bars (WINDOW_XFRAME (w));
+}
+#endif
+
 /* This and next define (many of the) public functions in this file.  */
 /* gui_* are generic versions in xdisp.c that we, and other terms, get away
          with using despite presence in the "system dependent" redisplay
@@ -4967,7 +4954,11 @@ static struct redisplay_interface ns_redisplay_interface 
=
   ns_scroll_run,
   ns_after_update_window_line,
   NULL, /* update_window_begin */
+#ifndef NS_IMPL_GNUSTEP
   NULL, /* update_window_end   */
+#else
+  ns_update_window_end,
+#endif
   0, /* flush_display */
   gui_clear_window_mouse_face,
   gui_get_glyph_overhangs,
@@ -5075,6 +5066,7 @@ ns_create_terminal (struct ns_display_info *dpyinfo)
   terminal->free_pixmap = ns_free_pixmap;
   terminal->delete_frame_hook = ns_destroy_window;
   terminal->delete_terminal_hook = ns_delete_terminal;
+  terminal->change_tab_bar_height_hook = ns_change_tab_bar_height;
   /* Other hooks are NULL by default.  */
 
   return terminal;
@@ -6193,9 +6185,11 @@ not_in_argv (NSString *arg)
       Lisp_Object kind = fnKeysym ? QCfunction : QCordinary;
       emacs_event->modifiers = EV_MODIFIERS2 (flags, kind);
 
+#ifndef NS_IMPL_GNUSTEP
       if (NS_KEYLOG)
         fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = 
%x\n",
                  code, fnKeysym, flags, emacs_event->modifiers);
+#endif
 
       /* If it was a function key or had control-like modifiers, pass
          it directly to Emacs.  */
@@ -6684,10 +6678,35 @@ not_in_argv (NSString *arg)
     }
   else
     {
-      emacs_event->kind = MOUSE_CLICK_EVENT;
+      Lisp_Object tab_bar_arg = Qnil;
+      bool tab_bar_p = false;
+
+      if (WINDOWP (emacsframe->tab_bar_window)
+         && WINDOW_TOTAL_LINES (XWINDOW (emacsframe->tab_bar_window)))
+       {
+         Lisp_Object window;
+         int x = lrint (p.x);
+         int y = lrint (p.y);
+
+         window = window_from_coordinates (emacsframe, x, y, 0, true, true);
+         tab_bar_p = EQ (window, emacsframe->tab_bar_window);
+
+         if (tab_bar_p)
+           tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, 
EV_UDMODIFIERS (theEvent) & down_modifier,
+                                               EV_MODIFIERS (theEvent) | 
EV_UDMODIFIERS (theEvent));
+       }
+
+      if (!(tab_bar_p && NILP (tab_bar_arg)))
+       emacs_event->kind = MOUSE_CLICK_EVENT;
+      emacs_event->arg = tab_bar_arg;
       emacs_event->code = EV_BUTTON (theEvent);
       emacs_event->modifiers = EV_MODIFIERS (theEvent)
                              | EV_UDMODIFIERS (theEvent);
+
+      if (emacs_event->modifiers & down_modifier)
+       FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent);
+      else
+       FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON 
(theEvent));
     }
 
   XSETINT (emacs_event->x, lrint (p.x));
@@ -6983,13 +7002,17 @@ not_in_argv (NSString *arg)
   if (! FRAME_LIVE_P (emacsframe))
     return;
 
-  frame = [self frame];
+  frame = [[self superview] bounds];
   width = (int)NSWidth (frame);
   height = (int)NSHeight (frame);
 
   NSTRACE_SIZE ("New size", NSMakeSize (width, height));
-  NSTRACE_SIZE ("Original size", size);
 
+  /* Reset the frame size to match the bounds of the superview (the
+     NSWindow's contentView).  We need to do this as sometimes the
+     view's frame isn't resized correctly, or can end up with the
+     wrong origin.  */
+  [self setFrame:frame];
   change_frame_size (emacsframe, width, height, false, YES, false);
 
   SET_FRAME_GARBAGED (emacsframe);
@@ -7052,6 +7075,7 @@ not_in_argv (NSString *arg)
       XSETFRAME (frame, emacsframe);
       help_echo_string = Qnil;
       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
+      any_help_event_p = NO;
     }
 
   if (emacs_event && is_focus_frame)
@@ -7401,7 +7425,6 @@ not_in_argv (NSString *arg)
     }
   else
     {
-      BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
       unsigned val = (unsigned)[NSApp presentationOptions];
@@ -7419,7 +7442,6 @@ not_in_argv (NSString *arg)
           [NSApp setPresentationOptions: options];
         }
 #endif
-      [[[self window]toolbar] setVisible:tbar_visible];
     }
 }
 
@@ -7460,14 +7482,6 @@ not_in_argv (NSString *arg)
 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
   [self updateCollectionBehavior];
 #endif
-  if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
-    {
-      [[[self window] toolbar] setVisible:YES];
-      update_frame_tool_bar (emacsframe);
-      [[self window] display];
-    }
-  else
-    [[[self window] toolbar] setVisible:NO];
 
   if (next_maximized != -1)
     [[self window] performZoom:self];
@@ -7873,17 +7887,39 @@ not_in_argv (NSString *arg)
 #endif /* NS_IMPL_COCOA */
 
 
-- (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
+- (void)copyRect:(NSRect)srcRect to:(NSPoint)dest
 {
   NSTRACE ("[EmacsView copyRect:To:]");
   NSTRACE_RECT ("Source", srcRect);
-  NSTRACE_RECT ("Destination", dstRect);
+  NSTRACE_POINT ("Destination", dest);
+
+  NSRect dstRect = NSMakeRect (dest.x, dest.y, NSWidth (srcRect),
+                               NSHeight (srcRect));
+  NSRect frame = [self frame];
+
+  /* TODO: This check is an attempt to debug a rare graphical glitch
+     on macOS and should be removed before the Emacs 28 release.  */
+  if (!NSContainsRect (frame, srcRect)
+      || !NSContainsRect (frame, dstRect))
+    {
+      NSLog (@"[EmacsView copyRect:to:] Attempting to copy to or "
+             "from an area outside the graphics buffer.");
+      NSLog (@"  Frame: (%f, %f) %f×%f",
+             NSMinX (frame), NSMinY (frame),
+             NSWidth (frame), NSHeight (frame));
+      NSLog (@"  Source: (%f, %f) %f×%f",
+             NSMinX (srcRect), NSMinY (srcRect),
+             NSWidth (srcRect), NSHeight (srcRect));
+      NSLog (@"  Destination: (%f, %f) %f×%f",
+             NSMinX (dstRect), NSMinY (dstRect),
+             NSWidth (dstRect), NSHeight (dstRect));
+    }
 
 #ifdef NS_IMPL_COCOA
   if ([self wantsLayer])
     {
       double scale = [[self window] backingScaleFactor];
-      CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
+      CGContextRef context = [(EmacsLayer *)[self layer] getContext];
       int bpp = CGBitmapContextGetBitsPerPixel (context) / 8;
       void *pixels = CGBitmapContextGetData (context);
       int rowSize = CGBitmapContextGetBytesPerRow (context);
@@ -7892,8 +7928,8 @@ not_in_argv (NSString *arg)
                         + (int) (NSMinY (srcRect) * scale * rowSize
                                  + NSMinX (srcRect) * scale * bpp);
       void *dstPixels = (char *) pixels
-                        + (int) (NSMinY (dstRect) * scale * rowSize
-                                 + NSMinX (dstRect) * scale * bpp);
+                        + (int) (dest.y * scale * rowSize
+                                 + dest.x * scale * bpp);
 
       if (NSIntersectsRect (srcRect, dstRect)
           && NSMinY (srcRect) < NSMinY (dstRect))
@@ -8298,8 +8334,7 @@ not_in_argv (NSString *arg)
         [self setOpaque:NO];
 
       /* toolbar support */
-      if (! FRAME_UNDECORATED (f))
-        [self createToolbar:f];
+      [self createToolbar:f];
 
       /* macOS Sierra automatically enables tabbed windows.  We can't
          allow this to be enabled until it's available on a Free system.
@@ -8316,13 +8351,17 @@ not_in_argv (NSString *arg)
 
 - (void)createToolbar: (struct frame *)f
 {
+  if (FRAME_UNDECORATED (f) || !FRAME_EXTERNAL_TOOL_BAR (f))
+    return;
+
   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
 
   EmacsToolbar *toolbar = [[EmacsToolbar alloc]
                             initForView:view
                             withIdentifier:[NSString 
stringWithLispString:f->name]];
-  [toolbar setVisible:NO];
+
   [self setToolbar:toolbar];
+  update_frame_tool_bar_1 (f, toolbar);
 
 #ifdef NS_IMPL_COCOA
   {
diff --git a/src/pdumper.c b/src/pdumper.c
index 2291fced5d..9eff5c48d0 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -312,14 +312,15 @@ dump_reloc_set_offset (struct dump_reloc *reloc, dump_off 
offset)
     error ("dump relocation out of range");
 }
 
-static void
-dump_fingerprint (char const *label,
+void
+dump_fingerprint (FILE *output, char const *label,
                  unsigned char const xfingerprint[sizeof fingerprint])
 {
   enum { hexbuf_size = 2 * sizeof fingerprint };
   char hexbuf[hexbuf_size];
   hexbuf_digest (hexbuf, xfingerprint, sizeof fingerprint);
-  fprintf (stderr, "%s: %.*s\n", label, hexbuf_size, hexbuf);
+  fprintf (output, "%s%s%.*s\n", label, *label ? ": " : "",
+          hexbuf_size, hexbuf);
 }
 
 /* To be used if some order in the relocation process has to be enforced. */
@@ -799,7 +800,7 @@ dump_tailq_length (const struct dump_tailq *tailq)
   return tailq->length;
 }
 
-static void ATTRIBUTE_UNUSED
+static void
 dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object value)
 {
   Lisp_Object link = Fcons (value, tailq->head);
@@ -809,24 +810,6 @@ dump_tailq_prepend (struct dump_tailq *tailq, Lisp_Object 
value)
   tailq->length += 1;
 }
 
-static void ATTRIBUTE_UNUSED
-dump_tailq_append (struct dump_tailq *tailq, Lisp_Object value)
-{
-  Lisp_Object link = Fcons (value, Qnil);
-  if (NILP (tailq->head))
-    {
-      eassert (NILP (tailq->tail));
-      tailq->head = tailq->tail = link;
-    }
-  else
-    {
-      eassert (!NILP (tailq->tail));
-      XSETCDR (tailq->tail, link);
-      tailq->tail = link;
-    }
-  tailq->length += 1;
-}
-
 static bool
 dump_tailq_empty_p (struct dump_tailq *tailq)
 {
@@ -4145,7 +4128,7 @@ types.  */)
     ctx->header.fingerprint[i] = fingerprint[i];
 
   const dump_off header_start = ctx->offset;
-  dump_fingerprint ("Dumping fingerprint", ctx->header.fingerprint);
+  dump_fingerprint (stderr, "Dumping fingerprint", ctx->header.fingerprint);
   dump_write (ctx, &ctx->header, sizeof (ctx->header));
   const dump_off header_end = ctx->offset;
 
@@ -5313,6 +5296,9 @@ dump_do_dump_relocation (const uintptr_t dump_base,
          error ("Trying to load incoherent dumped eln file %s",
                 SSDATA (comp_u->file));
 
+       if (!CONSP (comp_u->file))
+         error ("Incoherent compilation unit for dump was dumped");
+
        /* emacs_execdir is always unibyte, but the file names in
           comp_u->file could be multibyte, so we need to encode
           them.  */
@@ -5614,8 +5600,8 @@ pdumper_load (const char *dump_filename, char *argv0)
     desired[i] = fingerprint[i];
   if (memcmp (header->fingerprint, desired, sizeof desired) != 0)
     {
-      dump_fingerprint ("desired fingerprint", desired);
-      dump_fingerprint ("found fingerprint", header->fingerprint);
+      dump_fingerprint (stderr, "desired fingerprint", desired);
+      dump_fingerprint (stderr, "found fingerprint", header->fingerprint);
       goto out;
     }
 
@@ -5723,6 +5709,7 @@ pdumper_load (const char *dump_filename, char *argv0)
     dump_mmap_release (&sections[i]);
   if (dump_fd >= 0)
     emacs_close (dump_fd);
+
   return err;
 }
 
@@ -5807,6 +5794,7 @@ syms_of_pdumper (void)
   DEFSYM (Qdumped_with_pdumper, "dumped-with-pdumper");
   DEFSYM (Qload_time, "load-time");
   DEFSYM (Qdump_file_name, "dump-file-name");
+  DEFSYM (Qafter_pdump_load_hook, "after-pdump-load-hook");
   defsubr (&Spdumper_stats);
 #endif /* HAVE_PDUMPER */
 }
diff --git a/src/pdumper.h b/src/pdumper.h
index deec9af046..7f1f5e46ad 100644
--- a/src/pdumper.h
+++ b/src/pdumper.h
@@ -20,6 +20,8 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #ifndef EMACS_PDUMPER_H
 #define EMACS_PDUMPER_H
 
+#include <stdio.h>
+#include "fingerprint.h"
 #include "lisp.h"
 
 INLINE_HEADER_BEGIN
@@ -50,6 +52,9 @@ enum { PDUMPER_NO_OBJECT = -1 };
 #define PDUMPER_REMEMBER_SCALAR(thing)                  \
   pdumper_remember_scalar (&(thing), sizeof (thing))
 
+extern void dump_fingerprint (FILE *output, const char *label,
+                              unsigned char const fingerp[sizeof fingerprint]);
+
 extern void pdumper_remember_scalar_impl (void *data, ptrdiff_t nbytes);
 
 INLINE void
diff --git a/src/print.c b/src/print.c
index d4301fd7b6..adadb289de 100644
--- a/src/print.c
+++ b/src/print.c
@@ -564,7 +564,7 @@ temp_output_buffer_setup (const char *bufname)
 
   Fset_buffer (Fget_buffer_create (build_string (bufname), Qnil));
 
-  Fkill_all_local_variables ();
+  Fkill_all_local_variables (Qnil);
   delete_all_overlays (current_buffer);
   bset_directory (current_buffer, BVAR (old, directory));
   bset_read_only (current_buffer, Qnil);
@@ -941,7 +941,11 @@ print_error_message (Lisp_Object data, Lisp_Object stream, 
const char *context,
   else
     {
       Lisp_Object error_conditions = Fget (errname, Qerror_conditions);
-      errmsg = call1 (Qsubstitute_command_keys, Fget (errname, 
Qerror_message));
+      errmsg = Fget (errname, Qerror_message);
+      /* During loadup 'substitute-command-keys' might not be available.  */
+      if (!NILP (Ffboundp (Qsubstitute_command_keys)))
+       errmsg = call1 (Qsubstitute_command_keys, errmsg);
+
       file_error = Fmemq (Qfile_error, error_conditions);
     }
 
@@ -1517,8 +1521,26 @@ print_vectorlike (Lisp_Object obj, Lisp_Object 
printcharfun, bool escapeflag,
       printchar ('>', printcharfun);
       break;
 
-    case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW:
-      print_c_string ("#<xwidget ", printcharfun);
+    case PVEC_XWIDGET:
+#ifdef HAVE_XWIDGETS
+      {
+#ifdef USE_GTK
+       int len = sprintf (buf, "#<xwidget %u %p>",
+                          XXWIDGET (obj)->xwidget_id,
+                          XXWIDGET (obj)->widget_osr);
+#else
+       int len = sprintf (buf, "#<xwidget %u %p>",
+                          XXWIDGET (obj)->xwidget_id,
+                          XXWIDGET (obj)->xwWidget);
+#endif
+       strout (buf, len, len, printcharfun);
+       break;
+      }
+#else
+      emacs_abort ();
+#endif
+    case PVEC_XWIDGET_VIEW:
+      print_c_string ("#<xwidget view", printcharfun);
       printchar ('>', printcharfun);
       break;
 
diff --git a/src/process.c b/src/process.c
index 58347a154a..f923aff1cb 100644
--- a/src/process.c
+++ b/src/process.c
@@ -90,6 +90,7 @@ static struct rlimit nofile_limit;
 
 #include <c-ctype.h>
 #include <flexmember.h>
+#include <nproc.h>
 #include <sig2str.h>
 #include <verify.h>
 
@@ -682,6 +683,22 @@ clear_waiting_thread_info (void)
     }
 }
 
+/* Return TRUE if the keyboard descriptor is being monitored by the
+   current thread, FALSE otherwise.  */
+static bool
+kbd_is_ours (void)
+{
+  for (int fd = 0; fd <= max_desc; ++fd)
+    {
+      if (fd_callback_info[fd].waiting_thread != current_thread)
+       continue;
+      if ((fd_callback_info[fd].flags & (FOR_READ | KEYBOARD_FD))
+         == (FOR_READ | KEYBOARD_FD))
+       return true;
+    }
+  return false;
+}
+
 
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
@@ -2150,7 +2167,8 @@ create_process (Lisp_Object process, char **new_argv, 
Lisp_Object current_dir)
   p->pty_flag = pty_flag;
   pset_status (p, Qrun);
 
-  if (!EQ (p->command, Qt))
+  if (!EQ (p->command, Qt)
+      && !EQ (p->filter, Qt))
     add_process_read_fd (inchannel);
 
   ptrdiff_t count = SPECPDL_INDEX ();
@@ -2268,7 +2286,8 @@ create_pty (Lisp_Object process)
       pset_status (p, Qrun);
       setup_process_coding_systems (process);
 
-      add_process_read_fd (pty_fd);
+      if (!EQ (p->filter, Qt))
+       add_process_read_fd (pty_fd);
 
       pset_tty_name (p, build_string (pty_name));
     }
@@ -2377,7 +2396,8 @@ usage:  (make-pipe-process &rest ARGS)  */)
     pset_command (p, Qt);
   eassert (! p->pty_flag);
 
-  if (!EQ (p->command, Qt))
+  if (!EQ (p->command, Qt)
+      && !EQ (p->filter, Qt))
     add_process_read_fd (inchannel);
   p->adaptive_read_buffering
     = (NILP (Vprocess_adaptive_read_buffering) ? 0
@@ -3112,7 +3132,8 @@ usage:  (make-serial-process &rest ARGS)  */)
     pset_command (p, Qt);
   eassert (! p->pty_flag);
 
-  if (!EQ (p->command, Qt))
+  if (!EQ (p->command, Qt)
+      && !EQ (p->filter, Qt))
     add_process_read_fd (fd);
 
   update_process_mark (p);
@@ -4004,7 +4025,7 @@ usage: (make-network-process &rest ARGS)  */)
 
   if (!NILP (host))
     {
-      ptrdiff_t portstringlen ATTRIBUTE_UNUSED;
+      MAYBE_UNUSED ptrdiff_t portstringlen;
 
       /* SERVICE can either be a string or int.
         Convert to a C string for later use by getaddrinfo.  */
@@ -5311,13 +5332,13 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
               wait_reading_process_output_1 ();
         }
 
-      /* Cause C-g and alarm signals to take immediate action,
+      /* Cause C-g signals to take immediate action,
         and cause input available signals to zero out timeout.
 
         It is important that we do this before checking for process
         activity.  If we get a SIGCHLD after the explicit checks for
         process activity, timeout is the only way we will know.  */
-      if (read_kbd < 0)
+      if (read_kbd < 0 && kbd_is_ours ())
        set_waiting_for_input (&timeout);
 
       /* If status of something has changed, and no input is
@@ -5447,7 +5468,7 @@ wait_reading_process_output (intmax_t time_limit, int 
nsecs, int read_kbd,
        {
          clear_waiting_for_input ();
          redisplay_preserve_echo_area (11);
-         if (read_kbd < 0)
+         if (read_kbd < 0 && kbd_is_ours ())
            set_waiting_for_input (&timeout);
        }
 
@@ -8212,6 +8233,20 @@ integer or floating point values.
   return system_process_attributes (pid);
 }
 
+DEFUN ("num-processors", Fnum_processors, Snum_processors, 0, 1, 0,
+       doc: /* Return the number of processors, a positive integer.
+Each usable thread execution unit counts as a processor.
+By default, count the number of available processors,
+overridable via the OMP_NUM_THREADS environment variable.
+If optional argument QUERY is `current', ignore OMP_NUM_THREADS.
+If QUERY is `all', also count processors not available.  */)
+  (Lisp_Object query)
+{
+  return make_uint (num_processors (EQ (query, Qall) ? NPROC_ALL
+                                   : EQ (query, Qcurrent) ? NPROC_CURRENT
+                                   : NPROC_CURRENT_OVERRIDABLE));
+}
+
 #ifdef subprocesses
 /* Arrange to catch SIGCHLD if this hasn't already been arranged.
    Invoke this after init_process_emacs, and after glib and/or GNUstep
@@ -8472,6 +8507,8 @@ syms_of_process (void)
   DEFSYM (Qpcpu, "pcpu");
   DEFSYM (Qpmem, "pmem");
   DEFSYM (Qargs, "args");
+  DEFSYM (Qall, "all");
+  DEFSYM (Qcurrent, "current");
 
   DEFVAR_BOOL ("delete-exited-processes", delete_exited_processes,
               doc: /* Non-nil means delete processes immediately when they 
exit.
@@ -8633,4 +8670,5 @@ amounts of data in one go.  */);
   defsubr (&Sprocess_inherit_coding_system_flag);
   defsubr (&Slist_system_processes);
   defsubr (&Sprocess_attributes);
+  defsubr (&Snum_processors);
 }
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 8350e54b54..3224f65fa4 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -2407,7 +2407,7 @@ regex_compile (re_char *pattern, ptrdiff_t size,
 
                    if (lower_bound == 0)
                      {
-                       /* A succeed_n that starts with 0 is really a
+                       /* A succeed_n that starts with 0 is really
                           a simple on_failure_jump_loop.  */
                        INSERT_JUMP (on_failure_jump_loop, laststart,
                                     b + 3 + nbytes);
@@ -3828,7 +3828,7 @@ mutually_exclusive_p (struct re_pattern_buffer *bufp, 
re_char *p1,
 /* Matching routines.  */
 
 /* re_match_2 matches the compiled pattern in BUFP against the
-   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
    and SIZE2, respectively).  We start matching at POS, and stop
    matching at STOP.
 
diff --git a/src/search.c b/src/search.c
index 08f1e9474f..66e77d42b4 100644
--- a/src/search.c
+++ b/src/search.c
@@ -260,7 +260,7 @@ compile_pattern (Lisp_Object pattern, struct re_registers 
*regp,
 
 
 static Lisp_Object
-looking_at_1 (Lisp_Object string, bool posix)
+looking_at_1 (Lisp_Object string, bool posix, bool modify_data)
 {
   Lisp_Object val;
   unsigned char *p1, *p2;
@@ -278,11 +278,11 @@ looking_at_1 (Lisp_Object string, bool posix)
   CHECK_STRING (string);
 
   /* Snapshot in case Lisp changes the value.  */
-  bool preserve_match_data = NILP (Vinhibit_changing_match_data);
+  bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
 
   struct regexp_cache *cache_entry = compile_pattern (
     string,
-    preserve_match_data ? &search_regs : NULL,
+    modify_match_data ? &search_regs : NULL,
     (!NILP (BVAR (current_buffer, case_fold_search))
      ? BVAR (current_buffer, case_canon_table) : Qnil),
     posix,
@@ -316,7 +316,7 @@ looking_at_1 (Lisp_Object string, bool posix)
   re_match_object = Qnil;
   i = re_match_2 (&cache_entry->buf, (char *) p1, s1, (char *) p2, s2,
                  PT_BYTE - BEGV_BYTE,
-                 preserve_match_data ? &search_regs : NULL,
+                 modify_match_data ? &search_regs : NULL,
                  ZV_BYTE - BEGV_BYTE);
 
   if (i == -2)
@@ -326,7 +326,7 @@ looking_at_1 (Lisp_Object string, bool posix)
     }
 
   val = (i >= 0 ? Qt : Qnil);
-  if (preserve_match_data && i >= 0)
+  if (modify_match_data && i >= 0)
   {
     for (i = 0; i < search_regs.num_regs; i++)
       if (search_regs.start[i] >= 0)
@@ -343,35 +343,37 @@ looking_at_1 (Lisp_Object string, bool posix)
   return unbind_to (count, val);
 }
 
-DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 1, 0,
+DEFUN ("looking-at", Flooking_at, Slooking_at, 1, 2, 0,
        doc: /* Return t if text after point matches regular expression REGEXP.
-This function modifies the match data that `match-beginning',
-`match-end' and `match-data' access; save and restore the match
-data if you want to preserve them.  */)
-  (Lisp_Object regexp)
+By default, this function modifies the match data that
+`match-beginning', `match-end' and `match-data' access.  If
+INHIBIT-MODIFY is non-nil, don't modify the match data.  */)
+  (Lisp_Object regexp, Lisp_Object inhibit_modify)
 {
-  return looking_at_1 (regexp, 0);
+  return looking_at_1 (regexp, 0, NILP (inhibit_modify));
 }
 
-DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 1, 0,
+DEFUN ("posix-looking-at", Fposix_looking_at, Sposix_looking_at, 1, 2, 0,
        doc: /* Return t if text after point matches REGEXP according to Posix 
rules.
 Find the longest match, in accordance with Posix regular expression rules.
-This function modifies the match data that `match-beginning',
-`match-end' and `match-data' access; save and restore the match
-data if you want to preserve them.  */)
-  (Lisp_Object regexp)
+
+By default, this function modifies the match data that
+`match-beginning', `match-end' and `match-data' access.  If
+INHIBIT-MODIFY is non-nil, don't modify the match data.  */)
+  (Lisp_Object regexp, Lisp_Object inhibit_modify)
 {
-  return looking_at_1 (regexp, 1);
+  return looking_at_1 (regexp, 1, NILP (inhibit_modify));
 }
 
 static Lisp_Object
 string_match_1 (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
-               bool posix)
+               bool posix, bool modify_data)
 {
   ptrdiff_t val;
   struct re_pattern_buffer *bufp;
   EMACS_INT pos;
   ptrdiff_t pos_byte, i;
+  bool modify_match_data = NILP (Vinhibit_changing_match_data) && modify_data;
 
   if (running_asynch_code)
     save_search_regs ();
@@ -400,8 +402,7 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
                         BVAR (current_buffer, case_eqv_table));
 
   bufp = &compile_pattern (regexp,
-                           (NILP (Vinhibit_changing_match_data)
-                            ? &search_regs : NULL),
+                           (modify_match_data ? &search_regs : NULL),
                            (!NILP (BVAR (current_buffer, case_fold_search))
                             ? BVAR (current_buffer, case_canon_table) : Qnil),
                            posix,
@@ -410,18 +411,17 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
   val = re_search (bufp, SSDATA (string),
                   SBYTES (string), pos_byte,
                   SBYTES (string) - pos_byte,
-                  (NILP (Vinhibit_changing_match_data)
-                   ? &search_regs : NULL));
+                  (modify_match_data ? &search_regs : NULL));
 
   /* Set last_thing_searched only when match data is changed.  */
-  if (NILP (Vinhibit_changing_match_data))
+  if (modify_match_data)
     last_thing_searched = Qt;
 
   if (val == -2)
     matcher_overflow ();
   if (val < 0) return Qnil;
 
-  if (NILP (Vinhibit_changing_match_data))
+  if (modify_match_data)
     for (i = 0; i < search_regs.num_regs; i++)
       if (search_regs.start[i] >= 0)
        {
@@ -434,32 +434,42 @@ string_match_1 (Lisp_Object regexp, Lisp_Object string, 
Lisp_Object start,
   return make_fixnum (string_byte_to_char (string, val));
 }
 
-DEFUN ("string-match", Fstring_match, Sstring_match, 2, 3, 0,
+DEFUN ("string-match", Fstring_match, Sstring_match, 2, 4, 0,
        doc: /* Return index of start of first match for REGEXP in STRING, or 
nil.
 Matching ignores case if `case-fold-search' is non-nil.
 If third arg START is non-nil, start search at that index in STRING.
-For index of first char beyond the match, do (match-end 0).
-`match-end' and `match-beginning' also give indices of substrings
-matched by parenthesis constructs in the pattern.
 
-You can use the function `match-string' to extract the substrings
-matched by the parenthesis constructions in REGEXP. */)
-  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start)
+If INHIBIT-MODIFY is non-nil, match data is not changed.
+
+If INHIBIT-MODIFY is nil or missing, match data is changed, and
+`match-end' and `match-beginning' give indices of substrings matched
+by parenthesis constructs in the pattern.  You can use the function
+`match-string' to extract the substrings matched by the parenthesis
+constructions in REGEXP.  For index of first char beyond the match, do
+(match-end 0).  */)
+  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
+   Lisp_Object inhibit_modify)
 {
-  return string_match_1 (regexp, string, start, 0);
+  return string_match_1 (regexp, string, start, 0, NILP (inhibit_modify));
 }
 
-DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 3, 0,
+DEFUN ("posix-string-match", Fposix_string_match, Sposix_string_match, 2, 4, 0,
        doc: /* Return index of start of first match for Posix REGEXP in 
STRING, or nil.
 Find the longest match, in accord with Posix regular expression rules.
 Case is ignored if `case-fold-search' is non-nil in the current buffer.
-If third arg START is non-nil, start search at that index in STRING.
-For index of first char beyond the match, do (match-end 0).
-`match-end' and `match-beginning' also give indices of substrings
-matched by parenthesis constructs in the pattern.  */)
-  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start)
+
+If INHIBIT-MODIFY is non-nil, match data is not changed.
+
+If INHIBIT-MODIFY is nil or missing, match data is changed, and
+`match-end' and `match-beginning' give indices of substrings matched
+by parenthesis constructs in the pattern.  You can use the function
+`match-string' to extract the substrings matched by the parenthesis
+constructions in REGEXP.  For index of first char beyond the match, do
+(match-end 0).  */)
+  (Lisp_Object regexp, Lisp_Object string, Lisp_Object start,
+   Lisp_Object inhibit_modify)
 {
-  return string_match_1 (regexp, string, start, 1);
+  return string_match_1 (regexp, string, start, 1, NILP (inhibit_modify));
 }
 
 /* Match REGEXP against STRING using translation table TABLE,
diff --git a/src/sysstdio.h b/src/sysstdio.h
index d4df3d7456..d6ebfb455f 100644
--- a/src/sysstdio.h
+++ b/src/sysstdio.h
@@ -26,7 +26,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include "unlocked-io.h"
 
-extern FILE *emacs_fopen (char const *, char const *);
+extern FILE *emacs_fopen (char const *, char const *) ATTRIBUTE_MALLOC;
 extern void errputc (int);
 extern void errwrite (void const *, ptrdiff_t);
 extern void close_output_streams (void);
diff --git a/src/systhread.h b/src/systhread.h
index 0f47d7c1a8..601505f4f8 100644
--- a/src/systhread.h
+++ b/src/systhread.h
@@ -101,14 +101,11 @@ extern void sys_cond_signal (sys_cond_t *);
 extern void sys_cond_broadcast (sys_cond_t *);
 extern void sys_cond_destroy (sys_cond_t *);
 
-extern sys_thread_t sys_thread_self (void)
-  NODISCARD;
-extern bool sys_thread_equal (sys_thread_t, sys_thread_t)
-  NODISCARD;
-
-extern bool sys_thread_create (sys_thread_t *, thread_creation_function *,
-                               void *)
-  NODISCARD;
+NODISCARD extern sys_thread_t sys_thread_self (void);
+NODISCARD extern bool sys_thread_equal (sys_thread_t, sys_thread_t);
+
+NODISCARD extern bool sys_thread_create (sys_thread_t *,
+                                        thread_creation_function *, void *);
 
 extern void sys_thread_yield (void);
 extern void sys_thread_set_name (const char *);
diff --git a/src/term.c b/src/term.c
index 7d9fe8cee3..6f0b827cfc 100644
--- a/src/term.c
+++ b/src/term.c
@@ -549,13 +549,14 @@ encode_terminal_code (struct glyph *src, int src_len,
     {
       if (src->type == COMPOSITE_GLYPH)
        {
-         struct composition *cmp UNINIT;
+         struct composition *cmp;
          Lisp_Object gstring UNINIT;
          int i;
 
          nbytes = buf - encode_terminal_src;
          if (src->u.cmp.automatic)
            {
+             cmp = NULL;
              gstring = composition_gstring_from_id (src->u.cmp.id);
              required = src->slice.cmp.to - src->slice.cmp.from + 1;
            }
@@ -575,7 +576,7 @@ encode_terminal_code (struct glyph *src, int src_len,
              buf = encode_terminal_src + nbytes;
            }
 
-         if (src->u.cmp.automatic)
+         if (!cmp)
            for (i = src->slice.cmp.from; i <= src->slice.cmp.to; i++)
              {
                Lisp_Object g = LGSTRING_GLYPH (gstring, i);
diff --git a/src/termhooks.h b/src/termhooks.h
index 1d3cdc8fe8..e7539bbce2 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -255,6 +255,8 @@ enum event_kind
 #ifdef HAVE_XWIDGETS
   /* events generated by xwidgets*/
    , XWIDGET_EVENT
+   /* Event generated when WebKit asks us to display another widget.  */
+   , XWIDGET_DISPLAY_EVENT
 #endif
 
 #ifdef USE_FILE_NOTIFY
diff --git a/src/timefns.c b/src/timefns.c
index f0e2e97f55..a9921cdc10 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -19,6 +19,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+/* Work around GCC bug 102671.  */
+#if 10 <= __GNUC__
+# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
+#endif
+
 #include "systime.h"
 
 #include "blockinput.h"
diff --git a/src/unexcw.c b/src/unexcw.c
index 7a80b05963..157e9f4560 100644
--- a/src/unexcw.c
+++ b/src/unexcw.c
@@ -48,7 +48,7 @@ static exe_header_t *
 read_exe_header (int fd, exe_header_t * exe_header_buffer)
 {
   int i;
-  int ret ATTRIBUTE_UNUSED;
+  MAYBE_UNUSED int ret;
 
   assert (fd >= 0);
   assert (exe_header_buffer != 0);
@@ -111,7 +111,7 @@ fixup_executable (int fd)
   exe_header_t exe_header_buffer;
   exe_header_t *exe_header;
   int i;
-  int ret ATTRIBUTE_UNUSED;
+  MAYBE_UNUSED int ret;
   int found_data = 0;
   int found_bss = 0;
 
@@ -269,7 +269,7 @@ unexec (const char *outfile, const char *infile)
   int fd_in;
   int fd_out;
   int ret;
-  int ret2 ATTRIBUTE_UNUSED;
+  MAYBE_UNUSED int ret2;
 
   infile = add_exe_suffix_if_necessary (infile, infile_buffer);
   outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer);
diff --git a/src/verbose.mk.in b/src/verbose.mk.in
index 50d6ea3200..a5ff931ed0 100644
--- a/src/verbose.mk.in
+++ b/src/verbose.mk.in
@@ -25,6 +25,7 @@ AM_V_at =
 AM_V_CC =
 AM_V_CCLD =
 AM_V_ELC =
+AM_V_ELN =
 AM_V_GEN =
 AM_V_GLOBALS =
 AM_V_NO_PD =
@@ -37,11 +38,14 @@ AM_V_CCLD = @echo "  CCLD    " $@;
 ifeq ($(HAVE_NATIVE_COMP),yes)
 ifeq ($(NATIVE_DISABLED),1)
 AM_V_ELC = @echo "  ELC     " $@;
+AM_V_ELN =
 else
 AM_V_ELC = @echo "  ELC+ELN " $@;
+AM_V_ELN = @echo "  ELN " $@;
 endif
 else
 AM_V_ELC = @echo "  ELC     " $@;
+AM_V_ELN =
 endif
 AM_V_GEN = @echo "  GEN     " $@;
 AM_V_GLOBALS = @echo "  GEN     " globals.h;
diff --git a/src/vm-limit.c b/src/vm-limit.c
index b9058d0435..e0547651bb 100644
--- a/src/vm-limit.c
+++ b/src/vm-limit.c
@@ -126,7 +126,7 @@ get_lim_data (void)
 
   dos_memory_info (&totalram, &freeram, &totalswap, &freeswap);
   lim_data = freeram;
-  /* Don't believe they will give us more that 0.5 GB.   */
+  /* Don't believe they will give us more than 0.5 GB.   */
   if (lim_data > 512U * 1024U * 1024U)
     lim_data = 512U * 1024U * 1024U;
 }
diff --git a/src/w16select.c b/src/w16select.c
index 37239137cf..bbd2ed4bb9 100644
--- a/src/w16select.c
+++ b/src/w16select.c
@@ -87,7 +87,7 @@ static size_t clipboard_storage_size;
 /* C functions to access the Windows 3.1x clipboard from DOS apps.
 
    The information was obtained from the Microsoft Knowledge Base,
-   article Q67675 and can be found at:
+   article Q67675 and can be found at: [broken link  -- SK 2021-09-27]
    http://www.microsoft.com/kb/developr/win_dk/q67675.htm  */
 
 /* See also Ralf Brown's Interrupt List.
diff --git a/src/w32.c b/src/w32.c
index 0eb69d4b1d..e4b7ef3b95 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -39,6 +39,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <sys/time.h>
 #include <sys/utime.h>
 #include <math.h>
+#include <nproc.h>
 
 /* Include (most) CRT headers *before* ms-w32.h.  */
 #include <ms-w32.h>
@@ -1962,6 +1963,16 @@ w32_get_nproc (void)
   return num_of_processors;
 }
 
+/* Emulate Gnulib's 'num_processors'.  We cannot use the Gnulib
+   version because it unconditionally calls APIs that aren't available
+   on old MS-Windows versions.  */
+unsigned long
+num_processors (enum nproc_query query)
+{
+  /* We ignore QUERY.  */
+  return w32_get_nproc ();
+}
+
 static void
 sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
 {
@@ -2809,53 +2820,6 @@ sys_putenv (char *str)
 
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
-LPBYTE
-w32_get_resource (const char *key, LPDWORD lpdwtype)
-{
-  LPBYTE lpvalue;
-  HKEY hrootkey = NULL;
-  DWORD cbData;
-
-  /* Check both the current user and the local machine to see if
-     we have any resources.  */
-
-  if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == 
ERROR_SUCCESS)
-    {
-      lpvalue = NULL;
-
-      if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == 
ERROR_SUCCESS
-         && (lpvalue = xmalloc (cbData)) != NULL
-         && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) 
== ERROR_SUCCESS)
-       {
-          RegCloseKey (hrootkey);
-         return (lpvalue);
-       }
-
-      xfree (lpvalue);
-
-      RegCloseKey (hrootkey);
-    }
-
-  if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == 
ERROR_SUCCESS)
-    {
-      lpvalue = NULL;
-
-      if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == 
ERROR_SUCCESS
-         && (lpvalue = xmalloc (cbData)) != NULL
-         && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) 
== ERROR_SUCCESS)
-       {
-          RegCloseKey (hrootkey);
-         return (lpvalue);
-       }
-
-      xfree (lpvalue);
-
-      RegCloseKey (hrootkey);
-    }
-
-  return (NULL);
-}
-
 /* The argv[] array holds ANSI-encoded strings, and so this function
    works with ANS_encoded strings.  */
 void
@@ -3066,7 +3030,7 @@ init_environment (char ** argv)
            int dont_free = 0;
            char bufc[SET_ENV_BUF_SIZE];
 
-           if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
+           if ((lpval = w32_get_resource (REG_ROOT, env_vars[i].name, 
&dwType)) == NULL
                /* Also ignore empty environment variables.  */
                || *lpval == 0)
              {
diff --git a/src/w32.h b/src/w32.h
index ffa145b148..b31d66646c 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -155,14 +155,15 @@ extern unsigned int w32_get_short_filename (const char *, 
char *, int);
 
 /* Prepare our standard handles for proper inheritance by child processes.  */
 extern void prepare_standard_handles (int in, int out,
-                                     int err, HANDLE handles[4]);
+                                     int err, HANDLE handles[3]);
 
 /* Reset our standard handles to their original state.  */
 extern void reset_standard_handles (int in, int out,
-                                   int err, HANDLE handles[4]);
+                                   int err, HANDLE handles[3]);
 
-/* Return the string resource associated with KEY of type TYPE.  */
-extern LPBYTE w32_get_resource (const char * key, LPDWORD type);
+/* Query Windows Registry and return the resource associated
+   associated with KEY and NAME of type TYPE.  */
+extern LPBYTE w32_get_resource (const char * key, const char * name, LPDWORD 
type);
 
 extern void release_listen_threads (void);
 extern void init_ntproc (int);
diff --git a/src/w32fns.c b/src/w32fns.c
index 14d1154a2b..c1686beaaa 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -73,6 +73,20 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <imm.h>
 #include <windowsx.h>
 
+/*
+  Internal/undocumented constants for Windows Dark mode.
+  See: https://github.com/microsoft/WindowsAppSDK/issues/41
+*/
+#define DARK_MODE_APP_NAME L"DarkMode_Explorer"
+/* For Windows 10 version 1809, 1903, 1909. */
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_OLD
+#define DWMWA_USE_IMMERSIVE_DARK_MODE_OLD 19
+#endif
+/* For Windows 10 version 2004 and higher, and Windows 11. */
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
 #ifndef FOF_NO_CONNECTED_ELEMENTS
 #define FOF_NO_CONNECTED_ELEMENTS 0x2000
 #endif
@@ -185,6 +199,11 @@ typedef BOOL (WINAPI *IsDebuggerPresent_Proc) (void);
 typedef HRESULT (WINAPI *SetThreadDescription_Proc)
   (HANDLE hThread, PCWSTR lpThreadDescription);
 
+typedef HRESULT (WINAPI * SetWindowTheme_Proc)
+  (IN HWND hwnd, IN LPCWSTR pszSubAppName, IN LPCWSTR pszSubIdList);
+typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc)
+  (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute);
+
 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
 ImmGetContext_Proc get_ime_context_fn = NULL;
@@ -199,6 +218,8 @@ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
 GetTitleBarInfo_Proc get_title_bar_info_fn = NULL;
 IsDebuggerPresent_Proc is_debugger_present = NULL;
 SetThreadDescription_Proc set_thread_description = NULL;
+SetWindowTheme_Proc SetWindowTheme_fn = NULL;
+DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL;
 
 extern AppendMenuW_Proc unicode_append_menu;
 
@@ -252,6 +273,9 @@ int w32_major_version;
 int w32_minor_version;
 int w32_build_number;
 
+/* If the OS is set to use dark mode.  */
+BOOL w32_darkmode = FALSE;
+
 /* Distinguish between Windows NT and Windows 95.  */
 int os_subtype;
 
@@ -2279,10 +2303,36 @@ w32_init_class (HINSTANCE hinst)
     }
 }
 
+/* Applies the Windows system theme (light or dark) to the window
+   handle HWND.  */
+static void
+w32_applytheme (HWND hwnd)
+{
+  if (w32_darkmode)
+    {
+      /* Set window theme to that of a built-in Windows app (Explorer),
+        because it has dark scroll bars and other UI elements.  */
+      if (SetWindowTheme_fn)
+       SetWindowTheme_fn (hwnd, DARK_MODE_APP_NAME, NULL);
+
+      /* Set the titlebar to system dark mode.  */
+      if (DwmSetWindowAttribute_fn)
+       {
+         /* Windows 10 version 2004 and up, Windows 11.  */
+         DWORD attr = DWMWA_USE_IMMERSIVE_DARK_MODE;
+         /* Windows 10 older than 2004.  */
+         if (w32_build_number < 19041)
+           attr = DWMWA_USE_IMMERSIVE_DARK_MODE_OLD;
+         DwmSetWindowAttribute_fn (hwnd, attr,
+                                   &w32_darkmode, sizeof (w32_darkmode));
+       }
+    }
+}
+
 static HWND
 w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
 {
-  return CreateWindow ("SCROLLBAR", "",
+  HWND hwnd = CreateWindow ("SCROLLBAR", "",
                       /* Clip siblings so we don't draw over child
                          frames.  Apparently this is not always
                          sufficient so we also try to make bar windows
@@ -2291,12 +2341,15 @@ w32_createvscrollbar (struct frame *f, struct 
scroll_bar * bar)
                       /* Position and size of scroll bar.  */
                       bar->left, bar->top, bar->width, bar->height,
                       FRAME_W32_WINDOW (f), NULL, hinst, NULL);
+  if (hwnd)
+    w32_applytheme (hwnd);
+  return hwnd;
 }
 
 static HWND
 w32_createhscrollbar (struct frame *f, struct scroll_bar * bar)
 {
-  return CreateWindow ("SCROLLBAR", "",
+  HWND hwnd = CreateWindow ("SCROLLBAR", "",
                       /* Clip siblings so we don't draw over child
                          frames.  Apparently this is not always
                          sufficient so we also try to make bar windows
@@ -2305,6 +2358,9 @@ w32_createhscrollbar (struct frame *f, struct scroll_bar 
* bar)
                       /* Position and size of scroll bar.  */
                       bar->left, bar->top, bar->width, bar->height,
                       FRAME_W32_WINDOW (f), NULL, hinst, NULL);
+  if (hwnd)
+    w32_applytheme (hwnd);
+  return hwnd;
 }
 
 static void
@@ -2390,6 +2446,9 @@ w32_createwindow (struct frame *f, int *coords)
       /* Enable drag-n-drop.  */
       DragAcceptFiles (hwnd, TRUE);
 
+      /* Enable system light/dark theme.  */
+      w32_applytheme (hwnd);
+
       /* Do this to discard the default setting specified by our parent. */
       ShowWindow (hwnd, SW_HIDE);
 
@@ -10257,6 +10316,60 @@ to be converted to forward slashes by the caller.  */)
 }
 
 #endif /* WINDOWSNT */
+
+/* Query a value from the Windows Registry (under HKCU and HKLM),
+   where `key` is the registry key, `name` is the name, and `lpdwtype`
+   is a pointer to the return value's type. `lpwdtype` can be NULL if
+   you do not care about the type.
+
+   Returns: pointer to the value, or null pointer if the key/name does
+   not exist. */
+LPBYTE
+w32_get_resource (const char *key, const char *name, LPDWORD lpdwtype)
+{
+  LPBYTE lpvalue;
+  HKEY hrootkey = NULL;
+  DWORD cbData;
+
+  /* Check both the current user and the local machine to see if
+     we have any resources.  */
+
+  if (RegOpenKeyEx (HKEY_CURRENT_USER, key, 0, KEY_READ, &hrootkey) == 
ERROR_SUCCESS)
+    {
+      lpvalue = NULL;
+
+      if (RegQueryValueEx (hrootkey, name, NULL, NULL, NULL, &cbData) == 
ERROR_SUCCESS
+         && (lpvalue = xmalloc (cbData)) != NULL
+         && RegQueryValueEx (hrootkey, name, NULL, lpdwtype, lpvalue, &cbData) 
== ERROR_SUCCESS)
+       {
+          RegCloseKey (hrootkey);
+         return (lpvalue);
+       }
+
+      xfree (lpvalue);
+
+      RegCloseKey (hrootkey);
+    }
+
+  if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hrootkey) == 
ERROR_SUCCESS)
+    {
+      lpvalue = NULL;
+
+      if (RegQueryValueEx (hrootkey, name, NULL, NULL, NULL, &cbData) == 
ERROR_SUCCESS
+         && (lpvalue = xmalloc (cbData)) != NULL
+         && RegQueryValueEx (hrootkey, name, NULL, lpdwtype, lpvalue, &cbData) 
== ERROR_SUCCESS)
+       {
+          RegCloseKey (hrootkey);
+         return (lpvalue);
+       }
+
+      xfree (lpvalue);
+
+      RegCloseKey (hrootkey);
+    }
+
+  return (NULL);
+}
 
 /***********************************************************************
                            Initialization
@@ -11028,6 +11141,37 @@ globals_of_w32fns (void)
   set_thread_description = (SetThreadDescription_Proc)
     get_proc_addr (hm_kernel32, "SetThreadDescription");
 
+  /* Support OS dark mode on Windows 10 version 1809 and higher.
+     See `w32_applytheme` which uses appropriate APIs per version of Windows.
+     For future wretches who may need to understand Windows build numbers:
+     
https://docs.microsoft.com/en-us/windows/release-health/release-information
+  */
+  if (os_subtype == OS_SUBTYPE_NT
+      && w32_major_version >= 10 && w32_build_number >= 17763)
+    {
+      /* Load dwmapi.dll and uxtheme.dll, which will be needed to set
+        window themes.  */
+      HMODULE dwmapi_lib = LoadLibrary("dwmapi.dll");
+      DwmSetWindowAttribute_fn = (DwmSetWindowAttribute_Proc)
+       get_proc_addr (dwmapi_lib, "DwmSetWindowAttribute");
+      HMODULE uxtheme_lib = LoadLibrary("uxtheme.dll");
+      SetWindowTheme_fn = (SetWindowTheme_Proc)
+       get_proc_addr (uxtheme_lib, "SetWindowTheme");
+
+      /* Check Windows Registry for system theme and set w32_darkmode.
+        TODO: "Nice to have" would be to create a lisp setting (which
+        defaults to this Windows Registry value), then read that lisp
+        value here instead. This would allow the user to forcibly
+        override the system theme (which is also user-configurable in
+        Windows settings; see MS-Windows section in Emacs manual). */
+      LPBYTE val =
+       w32_get_resource 
("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
+                         "AppsUseLightTheme",
+                         NULL);
+      if (val && *val == 0)
+       w32_darkmode = TRUE;
+    }
+
   except_code = 0;
   except_addr = 0;
 #ifndef CYGWIN
diff --git a/src/w32font.c b/src/w32font.c
index 6b9ab0468c..4ceb4302ce 100644
--- a/src/w32font.c
+++ b/src/w32font.c
@@ -2000,11 +2000,11 @@ w32_encode_weight (int n)
 static Lisp_Object
 w32_to_fc_weight (int n)
 {
-  if (n >= FW_HEAVY)     return intern ("black");
+  if (n >= FW_HEAVY)     return Qblack;
   if (n >= FW_EXTRABOLD) return Qextra_bold;
   if (n >= FW_BOLD)      return Qbold;
   if (n >= FW_SEMIBOLD)  return intern ("demibold");
-  if (n >= FW_NORMAL)    return intern ("medium");
+  if (n >= FW_NORMAL)    return Qmedium;
   if (n >= FW_LIGHT)     return Qlight;
   if (n >= FW_EXTRALIGHT) return Qextra_light;
   return intern ("thin");
diff --git a/src/w32heap.c b/src/w32heap.c
index 0f228bfb22..a0d4c070be 100644
--- a/src/w32heap.c
+++ b/src/w32heap.c
@@ -189,6 +189,26 @@ malloc_fn the_malloc_fn;
 realloc_fn the_realloc_fn;
 free_fn the_free_fn;
 
+static void *
+heap_alloc (size_t size)
+{
+  void *p = size <= PTRDIFF_MAX ? HeapAlloc (heap, 0, size | !size) : NULL;
+  if (!p)
+    errno = ENOMEM;
+  return p;
+}
+
+static void *
+heap_realloc (void *ptr, size_t size)
+{
+  void *p = (size <= PTRDIFF_MAX
+            ? HeapReAlloc (heap, 0, ptr, size | !size)
+            : NULL);
+  if (!p)
+    errno = ENOMEM;
+  return p;
+}
+
 /* It doesn't seem to be useful to allocate from a file mapping.
    It would be if the memory was shared.
      
https://stackoverflow.com/questions/307060/what-is-the-purpose-of-allocating-pages-in-the-pagefile-with-createfilemapping
  */
@@ -346,7 +366,7 @@ void *
 malloc_after_dump (size_t size)
 {
   /* Use the new private heap.  */
-  void *p = HeapAlloc (heap, 0, size);
+  void *p = heap_alloc (size);
 
   /* After dump, keep track of the "brk value" for sbrk(0).  */
   if (p)
@@ -356,8 +376,6 @@ malloc_after_dump (size_t size)
       if (new_brk > data_region_end)
        data_region_end = new_brk;
     }
-  else
-    errno = ENOMEM;
   return p;
 }
 
@@ -373,9 +391,7 @@ malloc_before_dump (size_t size)
   if (size < MaxBlockSize)
     {
       /* Use the private heap if possible.  */
-      p = HeapAlloc (heap, 0, size);
-      if (!p)
-       errno = ENOMEM;
+      p = heap_alloc (size);
     }
   else
     {
@@ -433,18 +449,14 @@ realloc_after_dump (void *ptr, size_t size)
   if (FREEABLE_P (ptr))
     {
       /* Reallocate the block since it lies in the new heap.  */
-      p = HeapReAlloc (heap, 0, ptr, size);
-      if (!p)
-       errno = ENOMEM;
+      p = heap_realloc (ptr, size);
     }
   else
     {
       /* If the block lies in the dumped data, do not free it.  Only
          allocate a new one.  */
-      p = HeapAlloc (heap, 0, size);
-      if (!p)
-       errno = ENOMEM;
-      else if (ptr)
+      p = heap_alloc (size);
+      if (p && ptr)
        CopyMemory (p, ptr, size);
     }
   /* After dump, keep track of the "brk value" for sbrk(0).  */
@@ -467,9 +479,7 @@ realloc_before_dump (void *ptr, size_t size)
   if (dumped_data < (unsigned char *)ptr
       && (unsigned char *)ptr < bc_limit && size <= MaxBlockSize)
     {
-      p = HeapReAlloc (heap, 0, ptr, size);
-      if (!p)
-       errno = ENOMEM;
+      p = heap_realloc (ptr, size);
     }
   else
     {
diff --git a/src/w32proc.c b/src/w32proc.c
index 702ea122e6..360f45e9e1 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -3878,14 +3878,6 @@ w32_compare_strings (const char *s1, const char *s2, 
char *locname,
   return val - 2;
 }
 
-DEFUN ("w32-get-nproc", Fw32_get_nproc,
-       Sw32_get_nproc, 0, 0, 0,
-       doc: /* Return the number of system's processor execution units.  */)
-  (void)
-{
-  return make_fixnum (w32_get_nproc ());
-}
-
 
 void
 syms_of_ntproc (void)
@@ -3920,8 +3912,6 @@ syms_of_ntproc (void)
   defsubr (&Sw32_get_keyboard_layout);
   defsubr (&Sw32_set_keyboard_layout);
 
-  defsubr (&Sw32_get_nproc);
-
   DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args,
               doc: /* Non-nil enables quoting of process arguments to ensure 
correct parsing.
 Because Windows does not directly pass argv arrays to child processes,
diff --git a/src/w32term.c b/src/w32term.c
index 9cf250cd73..07a5cd3564 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -954,22 +954,6 @@ w32_set_cursor_gc (struct glyph_string *s)
 static void
 w32_set_mouse_face_gc (struct glyph_string *s)
 {
-  int face_id;
-  struct face *face;
-
-  /* What face has to be used last for the mouse face?  */
-  face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
-  face = FACE_FROM_ID_OR_NULL (s->f, face_id);
-  if (face == NULL)
-    face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-
-  if (s->first_glyph->type == CHAR_GLYPH)
-    face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
-  else
-    face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
-  s->face = FACE_FROM_ID (s->f, face_id);
-  prepare_face_for_display (s->f, s->face);
-
   /* If font in this face is same as S->font, use it.  */
   if (s->font == s->face->font)
     s->gc = s->face->gc;
diff --git a/src/window.c b/src/window.c
index a6e8ee0d53..e801ff821f 100644
--- a/src/window.c
+++ b/src/window.c
@@ -20,6 +20,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+/* Work around GCC bug 102671.  */
+#if 10 <= __GNUC__
+# pragma GCC diagnostic ignored "-Wanalyzer-null-dereference"
+#endif
+
 #include "lisp.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -760,6 +765,19 @@ selected one.  */)
 {
   return make_fixnum (decode_live_window (window)->use_time);
 }
+
+DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
+       Swindow_bump_use_time, 0, 1, 0,
+       doc: /* Mark WINDOW as having been most recently used.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  struct window *w = decode_live_window (window);
+
+  w->use_time = ++window_select_count;
+
+  return Qnil;
+}
 
 DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
        doc: /* Return the width of window WINDOW in pixels.
@@ -3194,8 +3212,10 @@ function in a program gives strange scrolling, make sure 
the
 window-start value is reasonable when this function is called.  */)
      (Lisp_Object window, Lisp_Object root)
 {
-  struct window *w, *r, *s;
-  struct frame *f;
+  struct window *w = decode_valid_window (window);
+  struct window *r, *s;
+  Lisp_Object frame = w->frame;
+  struct frame *f = XFRAME (frame);
   Lisp_Object sibling, pwindow, delta;
   Lisp_Object swindow UNINIT;
   ptrdiff_t startpos UNINIT, startbyte UNINIT;
@@ -3203,9 +3223,7 @@ window-start value is reasonable when this function is 
called.  */)
   int new_top;
   bool resize_failed = false;
 
-  w = decode_valid_window (window);
   XSETWINDOW (window, w);
-  f = XFRAME (w->frame);
 
   if (NILP (root))
     /* ROOT is the frame's root window.  */
@@ -3245,7 +3263,7 @@ window-start value is reasonable when this function is 
called.  */)
       /* Make sure WINDOW is the frame's selected window.  */
       if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
        {
-         if (EQ (selected_frame, w->frame))
+         if (EQ (selected_frame, frame))
            Fselect_window (window, Qnil);
          else
            /* Do not clear f->select_mini_window_flag here.  If the
@@ -3278,7 +3296,7 @@ window-start value is reasonable when this function is 
called.  */)
 
       if (!EQ (swindow, FRAME_SELECTED_WINDOW (f)))
        {
-         if (EQ (selected_frame, w->frame))
+         if (EQ (selected_frame, frame))
            Fselect_window (swindow, Qnil);
          else
            fset_selected_window (f, swindow);
@@ -3313,18 +3331,12 @@ window-start value is reasonable when this function is 
called.  */)
       w->top_line = r->top_line;
       resize_root_window (window, delta, Qnil, Qnil, Qt);
       if (window_resize_check (w, false))
-       {
-         window_resize_apply (w, false);
-         window_pixel_to_total (w->frame, Qnil);
-       }
+       window_resize_apply (w, false);
       else
        {
          resize_root_window (window, delta, Qnil, Qt, Qt);
          if (window_resize_check (w, false))
-           {
-             window_resize_apply (w, false);
-             window_pixel_to_total (w->frame, Qnil);
-           }
+           window_resize_apply (w, false);
          else
            resize_failed = true;
        }
@@ -3337,18 +3349,12 @@ window-start value is reasonable when this function is 
called.  */)
          XSETINT (delta, r->pixel_width - w->pixel_width);
          resize_root_window (window, delta, Qt, Qnil, Qt);
          if (window_resize_check (w, true))
-           {
-             window_resize_apply (w, true);
-             window_pixel_to_total (w->frame, Qt);
-           }
+           window_resize_apply (w, true);
          else
            {
              resize_root_window (window, delta, Qt, Qt, Qt);
              if (window_resize_check (w, true))
-               {
-                 window_resize_apply (w, true);
-                 window_pixel_to_total (w->frame, Qt);
-               }
+               window_resize_apply (w, true);
              else
                resize_failed = true;
            }
@@ -3390,6 +3396,12 @@ window-start value is reasonable when this function is 
called.  */)
     }
 
   replace_window (root, window, true);
+  /* Assign new total sizes to all windows on FRAME.  We can't do that
+     _before_ WINDOW replaces ROOT since 'window--pixel-to-total' works
+     on the whole frame and thus would work on the frame's old window
+     configuration (Bug#51007).  */
+  window_pixel_to_total (frame, Qnil);
+  window_pixel_to_total (frame, Qt);
 
   /* This must become SWINDOW anyway .......  */
   if (BUFFERP (w->contents) && !resize_failed)
@@ -8123,18 +8135,6 @@ and scrolling positions.  */)
     return Qt;
   return Qnil;
 }
-
-DEFUN ("window-bump-use-time", Fwindow_bump_use_time,
-       Swindow_bump_use_time, 1, 1, 0,
-       doc: /* Mark WINDOW as having been recently used.  */)
-  (Lisp_Object window)
-{
-  struct window *w = decode_valid_window (window);
-
-  w->use_time = ++window_select_count;
-  return Qnil;
-}
-
 
 
 static void init_window_once_for_pdumper (void);
diff --git a/src/xdisp.c b/src/xdisp.c
index b777d1b282..d7ad548917 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1179,7 +1179,13 @@ static void append_stretch_glyph (struct it *, 
Lisp_Object,
 static Lisp_Object get_it_property (struct it *, Lisp_Object);
 static Lisp_Object calc_line_height_property (struct it *, Lisp_Object,
                                              struct font *, int, bool);
-
+static int adjust_glyph_width_for_mouse_face (struct glyph *,
+                                             struct glyph_row *,
+                                             struct window *, struct face *,
+                                             struct face *);
+static void get_cursor_offset_for_mouse_face (struct window *w,
+                                             struct glyph_row *row,
+                                             int *offset);
 #endif /* HAVE_WINDOW_SYSTEM */
 
 static void produce_special_glyphs (struct it *, enum display_element_type);
@@ -7668,7 +7674,8 @@ get_next_display_element (struct it *it)
                  /* Merge `nobreak-space' into the current face.  */
                  face_id = merge_faces (it->w, Qnobreak_space, 0,
                                         it->face_id);
-                 XSETINT (it->ctl_chars[0], it->c);
+                 XSETINT (it->ctl_chars[0],
+                          nobreak_char_ascii_display ? ' ' : it->c);
                  ctl_len = 1;
                  goto display_control;
                }
@@ -7681,7 +7688,8 @@ get_next_display_element (struct it *it)
                  /* Merge `nobreak-space' into the current face.  */
                  face_id = merge_faces (it->w, Qnobreak_hyphen, 0,
                                         it->face_id);
-                 XSETINT (it->ctl_chars[0], it->c);
+                 XSETINT (it->ctl_chars[0],
+                          nobreak_char_ascii_display ? '-' : it->c);
                  ctl_len = 1;
                  goto display_control;
                }
@@ -10071,6 +10079,8 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int 
to_x, int to_y, int to_vpos
 
        case MOVE_NEWLINE_OR_CR:
          max_current_x = max (it->current_x, max_current_x);
+         if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+           it->override_ascent = -1;
          set_iterator_to_next (it, true);
          it->continuation_lines_width = 0;
          break;
@@ -10618,10 +10628,12 @@ in_display_vector_p (struct it *it)
 
 DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, 
Swindow_text_pixel_size, 0, 6, 0,
        doc: /* Return the size of the text of WINDOW's buffer in pixels.
-WINDOW must be a live window and defaults to the selected one.  The
+WINDOW can be any live window and defaults to the selected one.  The
 return value is a cons of the maximum pixel-width of any text line
 and the pixel-height of all the text lines in the accessible portion
 of buffer text.
+WINDOW can also be a buffer, in which case the selected window is used,
+and the function behaves as if that window was displaying this buffer.
 
 This function exists to allow Lisp programs to adjust the dimensions
 of WINDOW to the buffer text it needs to display.
@@ -10657,16 +10669,17 @@ position specified by TO.  Since calculating the text 
height of a
 large buffer can take some time, it makes sense to specify this
 argument if the size of the buffer is large or unknown.
 
-Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
-include the height of the mode- or header-line of WINDOW in the return
-value.  If it is either the symbol `mode-line' or `header-line', include
+Optional argument MODE-LINES nil or omitted means do not include the
+height of the mode-, tab- or header-line of WINDOW in the return value.
+If it is the symbol `mode-line', 'tab-line' or `header-line', include
 only the height of that line, if present, in the return value.  If t,
-include the height of both, if present, in the return value.  */)
+include the height of any of these, if present, in the return value.  */)
   (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit,
-   Lisp_Object y_limit, Lisp_Object mode_and_header_line)
+   Lisp_Object y_limit, Lisp_Object mode_lines)
 {
-  struct window *w = decode_live_window (window);
-  Lisp_Object buffer = w->contents;
+  struct window *w = BUFFERP (window) ? XWINDOW (selected_window)
+                     : decode_live_window (window);
+  Lisp_Object buffer = BUFFERP (window) ? window : w->contents;
   struct buffer *b;
   struct it it;
   struct buffer *old_b = NULL;
@@ -10837,20 +10850,42 @@ include the height of both, if present, in the return 
value.  */)
   if (y > max_y)
     y = max_y;
 
-  if (EQ (mode_and_header_line, Qtab_line)
-      || EQ (mode_and_header_line, Qt))
-    /* Re-add height of tab-line as requested.  */
-    y = y + WINDOW_TAB_LINE_HEIGHT (w);
+  if ((EQ (mode_lines, Qtab_line) || EQ (mode_lines, Qt))
+      && window_wants_tab_line (w))
+    /* Add height of tab-line as requested.  */
+    {
+      Lisp_Object window_tab_line_format
+       = window_parameter (w, Qtab_line_format);
 
-  if (EQ (mode_and_header_line, Qheader_line)
-      || EQ (mode_and_header_line, Qt))
-    /* Re-add height of header-line as requested.  */
-    y = y + WINDOW_HEADER_LINE_HEIGHT (w);
+      y = y + display_mode_line (w, TAB_LINE_FACE_ID,
+                                NILP (window_tab_line_format)
+                                ? BVAR (current_buffer, tab_line_format)
+                                : window_tab_line_format);
+    }
 
-  if (EQ (mode_and_header_line, Qmode_line)
-      || EQ (mode_and_header_line, Qt))
-    /* Add height of mode-line as requested.  */
-    y = y + WINDOW_MODE_LINE_HEIGHT (w);
+  if ((EQ (mode_lines, Qheader_line) || EQ (mode_lines, Qt))
+      && window_wants_header_line (w))
+    {
+      Lisp_Object window_header_line_format
+       = window_parameter (w, Qheader_line_format);
+
+      y = y + display_mode_line (w, HEADER_LINE_FACE_ID,
+                                NILP (window_header_line_format)
+                                ? BVAR (current_buffer, header_line_format)
+                                : window_header_line_format);
+    }
+
+  if ((EQ (mode_lines, Qmode_line) || EQ (mode_lines, Qt))
+      && window_wants_mode_line (w))
+    {
+      Lisp_Object window_mode_line_format
+       = window_parameter (w, Qmode_line_format);
+
+      y = y + display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w),
+                                NILP (window_mode_line_format)
+                                ? BVAR (current_buffer, mode_line_format)
+                                : window_mode_line_format);
+    }
 
   bidi_unshelve_cache (itdata, false);
 
@@ -13859,15 +13894,18 @@ note_tab_bar_highlight (struct frame *f, int x, int y)
   clear_mouse_face (hlinfo);
 
   bool mouse_down_p = false;
-#ifndef HAVE_NS
-  /* Mouse is down, but on different tab-bar item?  */
+  /* Mouse is down, but on different tab-bar item?  Or alternatively,
+     the mouse might've been pressed somewhere we don't know about,
+     and then have moved onto the tab bar.  In this case,
+     last_tab_bar_item is -1, so we DTRT and behave like other
+     programs by displaying the item as sunken. */
   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   mouse_down_p = (gui_mouse_grabbed (dpyinfo)
                  && f == dpyinfo->last_mouse_frame);
 
-  if (mouse_down_p && f->last_tab_bar_item != prop_idx)
+  if (mouse_down_p && f->last_tab_bar_item != prop_idx
+      && f->last_tab_bar_item != -1)
     return;
-#endif
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
 
   /* If tab-bar item is not enabled, don't highlight it.  */
@@ -24471,7 +24509,7 @@ See also `bidi-paragraph-direction'.  */)
 
 DEFUN ("bidi-find-overridden-directionality",
        Fbidi_find_overridden_directionality,
-       Sbidi_find_overridden_directionality, 2, 3, 0,
+       Sbidi_find_overridden_directionality, 3, 4, 0,
        doc: /* Return position between FROM and TO where directionality was 
overridden.
 
 This function returns the first character position in the specified
@@ -24490,12 +24528,18 @@ a buffer is preferable when the buffer is displayed 
in some window,
 because this function will then be able to correctly account for
 window-specific overlays, which can affect the results.
 
+Optional argument BASE-DIR specifies the base paragraph directory
+of the text.  It should be a symbol, either `left-to-right'
+or `right-to-left', and defaults to `left-to-right'.
+
 Strong directional characters `L', `R', and `AL' can have their
 intrinsic directionality overridden by directional override
-control characters RLO (u+202e) and LRO (u+202d).  See the
-function `get-char-code-property' for a way to inquire about
+control characters RLO (u+202E) and LRO (u+202D).  They can also
+have their directionality affected by other formatting control
+characters: LRE (u+202A), RLE (u+202B), LRI (u+2066), and RLI (u+2067).
+See the function `get-char-code-property' for a way to inquire about
 the `bidi-class' property of a character.  */)
-  (Lisp_Object from, Lisp_Object to, Lisp_Object object)
+  (Lisp_Object from, Lisp_Object to, Lisp_Object object, Lisp_Object base_dir)
 {
   struct buffer *buf = current_buffer;
   struct buffer *old = buf;
@@ -24592,10 +24636,9 @@ the `bidi-class' property of a character.  */)
     }
 
   ptrdiff_t found;
+  bidi_dir_t bdir = EQ (base_dir, Qright_to_left) ? R2L : L2R;
   do {
-    /* For the purposes of this function, the actual base direction of
-       the paragraph doesn't matter, so just set it to L2R.  */
-    bidi_paragraph_init (L2R, &itb, false);
+    bidi_paragraph_init (bdir, &itb, false);
     while ((found = bidi_find_first_overridden (&itb)) < from_pos)
       ;
   } while (found == ZV && itb.ch == '\n' && itb.charpos < to_pos);
@@ -25586,7 +25629,8 @@ display_mode_line (struct window *w, enum face_id 
face_id, Lisp_Object format)
   push_kboard (FRAME_KBOARD (it.f));
   record_unwind_save_match_data ();
 
-  if (NILP (Vmode_line_compact))
+  if (NILP (Vmode_line_compact)
+      || face_id == HEADER_LINE_FACE_ID || face_id == TAB_LINE_FACE_ID)
     {
       mode_line_target = MODE_LINE_DISPLAY;
       display_mode_element (&it, 0, 0, 0, format, Qnil, false);
@@ -28122,6 +28166,19 @@ fill_composite_glyph_string (struct glyph_string *s, 
struct face *base_face,
       s->font = s->face->font;
     }
 
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      int c = COMPOSITION_GLYPH (s->cmp, 0);
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+
+      s->face = FACE_FROM_ID (s->f, FACE_FOR_CHAR (s->f, s->face, c, -1, 
Qnil));
+      prepare_face_for_display (s->f, s->face);
+    }
+
   /* All glyph strings for the same composition has the same width,
      i.e. the width set for the first component of the composition.  */
   s->width = s->first_glyph->pixel_width;
@@ -28158,7 +28215,17 @@ fill_gstring_glyph_string (struct glyph_string *s, int 
face_id,
   s->cmp_id = glyph->u.cmp.id;
   s->cmp_from = glyph->slice.cmp.from;
   s->cmp_to = glyph->slice.cmp.to + 1;
-  s->face = FACE_FROM_ID (s->f, face_id);
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      prepare_face_for_display (s->f, s->face);
+    }
+  else
+    s->face = FACE_FROM_ID (s->f, face_id);
   lgstring = composition_gstring_from_id (s->cmp_id);
   s->font = XFONT_OBJECT (LGSTRING_FONT (lgstring));
   /* The width of a composition glyph string is the sum of the
@@ -28214,6 +28281,15 @@ fill_glyphless_glyph_string (struct glyph_string *s, 
int face_id,
   voffset = glyph->voffset;
   s->face = FACE_FROM_ID (s->f, face_id);
   s->font = s->face->font ? s->face->font : FRAME_FONT (s->f);
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      prepare_face_for_display (s->f, s->face);
+    }
   s->nchars = 1;
   s->width = glyph->pixel_width;
   glyph++;
@@ -28277,6 +28353,19 @@ fill_glyph_string (struct glyph_string *s, int face_id,
 
   s->font = s->face->font;
 
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      s->face
+        = FACE_FROM_ID (s->f, FACE_FOR_CHAR (s->f, s->face,
+                                            s->first_glyph->u.ch, -1, Qnil));
+      prepare_face_for_display (s->f, s->face);
+    }
+
   /* If the specified font could not be loaded, use the frame's font,
      but record the fact that we couldn't load it in
      S->font_not_found_p so that we can draw rectangles for the
@@ -28306,6 +28395,15 @@ fill_image_glyph_string (struct glyph_string *s)
   s->slice = s->first_glyph->slice.img;
   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
   s->font = s->face->font;
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      prepare_face_for_display (s->f, s->face);
+    }
   s->width = s->first_glyph->pixel_width;
 
   /* Adjust base line for subscript/superscript text.  */
@@ -28320,9 +28418,18 @@ fill_xwidget_glyph_string (struct glyph_string *s)
   eassert (s->first_glyph->type == XWIDGET_GLYPH);
   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
   s->font = s->face->font;
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      prepare_face_for_display (s->f, s->face);
+    }
   s->width = s->first_glyph->pixel_width;
   s->ybase += s->first_glyph->voffset;
-  s->xwidget = s->first_glyph->u.xwidget;
+  s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget);
 }
 #endif
 /* Fill glyph string S from a sequence of stretch glyphs.
@@ -28345,6 +28452,15 @@ fill_stretch_glyph_string (struct glyph_string *s, int 
start, int end)
   face_id = glyph->face_id;
   s->face = FACE_FROM_ID (s->f, face_id);
   s->font = s->face->font;
+  if (s->hl == DRAW_MOUSE_FACE
+      || (s->hl == DRAW_CURSOR && cursor_in_mouse_face_p (s->w)))
+    {
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (s->f);
+      s->face = FACE_FROM_ID_OR_NULL (s->f, hlinfo->mouse_face_face_id);
+      if (!s->face)
+       s->face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+      prepare_face_for_display (s->f, s->face);
+    }
   s->width = glyph->pixel_width;
   s->nchars = 1;
   voffset = glyph->voffset;
@@ -28592,7 +28708,12 @@ right_overwriting (struct glyph_string *s)
 
 /* Set background width of glyph string S.  START is the index of the
    first glyph following S.  LAST_X is the right-most x-position + 1
-   in the drawing area.  */
+   in the drawing area.
+
+   If S->hl is DRAW_CURSOR, S->f is a window system frame, and the
+   cursor in S's window is currently inside mouse face, also update
+   S->width to take into account potentially differing :box
+   properties between the original face and the mouse face.  */
 
 static void
 set_glyph_string_background_width (struct glyph_string *s, int start, int 
last_x)
@@ -28614,7 +28735,27 @@ set_glyph_string_background_width (struct glyph_string 
*s, int start, int last_x
   if (s->extends_to_end_of_line_p)
     s->background_width = last_x - s->x + 1;
   else
-    s->background_width = s->width;
+    {
+      s->background_width = s->width;
+#ifdef HAVE_WINDOW_SYSTEM
+      if (FRAME_WINDOW_P (s->f)
+         && s->hl == DRAW_CURSOR
+         && cursor_in_mouse_face_p (s->w))
+       {
+         /* Adjust the background width of the glyph string, because
+            if the glyph's face has the :box attribute, its
+            pixel_width might be different when it's displayed in the
+            mouse-face, if that also has the :box attribute.  */
+         struct glyph *g = s->first_glyph;
+         struct face *regular_face = FACE_FROM_ID (s->f, g->face_id);
+         s->background_width +=
+           adjust_glyph_width_for_mouse_face (g, s->row, s->w,
+                                              regular_face, s->face);
+         /* S->width is probably worth adjusting here as well.  */
+         s->width = s->background_width;
+        }
+#endif
+    }
 }
 
 
@@ -29163,7 +29304,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row 
*row,
   for (s = head; s; s = s->next)
     FRAME_RIF (f)->draw_glyph_string (s);
 
-#ifndef HAVE_NS
   /* When focus a sole frame and move horizontally, this clears on_p
      causing a failure to erase prev cursor position. */
   if (area == TEXT_AREA
@@ -29182,7 +29322,6 @@ draw_glyphs (struct window *w, int x, struct glyph_row 
*row,
       notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
                                 row->y, MATRIX_ROW_BOTTOM_Y (row));
     }
-#endif
 
   /* Value is the x-position up to which drawn, relative to AREA of W.
      This doesn't include parts drawn because of overhangs.  */
@@ -29515,6 +29654,8 @@ produce_image_glyph (struct it *it)
 
   if (face->box != FACE_NO_BOX)
     {
+      /* If you change the logic here, please change it in
+        get_cursor_offset_for_mouse_face as well. */
       if (face->box_horizontal_line_width > 0)
        {
          if (slice.y == 0)
@@ -29691,7 +29832,7 @@ produce_xwidget_glyph (struct it *it)
           glyph->padding_p = 0;
          glyph->glyph_not_available_p = 0;
          glyph->face_id = it->face_id;
-          glyph->u.xwidget = it->xwidget;
+          glyph->u.xwidget = it->xwidget->xwidget_id;
          glyph->font_type = FONT_TYPE_UNKNOWN;
          if (it->bidi_p)
            {
@@ -31816,6 +31957,20 @@ erase_phys_cursor (struct window *w)
       && cursor_row->used[TEXT_AREA] > hpos && hpos >= 0)
     mouse_face_here_p = true;
 
+#ifdef HAVE_WINDOW_SYSTEM
+  /* Since erasing the phys cursor will probably lead to corruption of
+     the mouse face display if the glyph's pixel_width is not kept up
+     to date with the :box property of the mouse face, just redraw the
+     mouse face.  */
+  if (FRAME_WINDOW_P (WINDOW_XFRAME (w)) && mouse_face_here_p)
+    {
+      w->phys_cursor_on_p = false;
+      w->phys_cursor_type = NO_CURSOR;
+      show_mouse_face (MOUSE_HL_INFO (WINDOW_XFRAME (w)), DRAW_MOUSE_FACE);
+      return;
+    }
+#endif
+
   /* Maybe clear the display under the cursor.  */
   if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
     {
@@ -32087,6 +32242,9 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum 
draw_glyphs_face draw)
       && hlinfo->mouse_face_end_row < w->current_matrix->nrows)
     {
       bool phys_cursor_on_p = w->phys_cursor_on_p;
+#ifdef HAVE_WINDOW_SYSTEM
+      int mouse_off = 0;
+#endif
       struct glyph_row *row, *first, *last;
 
       first = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
@@ -32160,6 +32318,15 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum 
draw_glyphs_face draw)
              row->mouse_face_p
                = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
            }
+#ifdef HAVE_WINDOW_SYSTEM
+         /* Compute the cursor offset due to mouse-highlight.  */
+         if ((MATRIX_ROW_VPOS (row, w->current_matrix) == w->phys_cursor.vpos)
+             /* But not when highlighting a pseudo window, such as
+                the toolbar, which can't have a cursor anyway.  */
+             && !w->pseudo_window_p
+             && draw == DRAW_MOUSE_FACE)
+           get_cursor_offset_for_mouse_face (w, row, &mouse_off);
+#endif
        }
 
       /* When we've written over the cursor, arrange for it to
@@ -32169,6 +32336,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum 
draw_glyphs_face draw)
        {
 #ifdef HAVE_WINDOW_SYSTEM
          int hpos = w->phys_cursor.hpos;
+         int old_phys_cursor_x = w->phys_cursor.x;
 
          /* When the window is hscrolled, cursor hpos can legitimately be
             out of bounds, but we draw the cursor at the corresponding
@@ -32180,7 +32348,11 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum 
draw_glyphs_face draw)
 
          block_input ();
          display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos,
-                                 w->phys_cursor.x, w->phys_cursor.y);
+                                 w->phys_cursor.x + mouse_off,
+                                 w->phys_cursor.y);
+         /* Restore the original cursor coordinates, perhaps modified
+            to account for mouse-highlight.  */
+         w->phys_cursor.x = old_phys_cursor_x;
          unblock_input ();
 #endif /* HAVE_WINDOW_SYSTEM */
        }
@@ -33643,7 +33815,21 @@ note_mouse_highlight (struct frame *f, int x, int y)
   if (EQ (window, f->tab_bar_window))
     {
       note_tab_bar_highlight (f, x, y);
-      return;
+      if (tab_bar__dragging_in_progress)
+       {
+         cursor = FRAME_OUTPUT_DATA (f)->hand_cursor;
+         goto set_cursor;
+       }
+      else
+       return;
+    }
+  else
+    {
+      /* The mouse might have pressed into the tab bar, but might
+        also have been released outside the tab bar, so
+        f->last_tab_bar_item must be reset, in order to make sure the
+        item can be still highlighted again in the future.  */
+      f->last_tab_bar_item = -1;
     }
 #endif
 
@@ -35034,6 +35220,26 @@ glyph followed by an ordinary space or hyphen.
 A value of nil means no special handling of these characters.  */);
   Vnobreak_char_display = Qt;
 
+  DEFVAR_BOOL ("nobreak-char-ascii-display", nobreak_char_ascii_display,
+    doc: /* Control display of non-ASCII space and hyphen chars.
+If the value of this variable is nil, the default, Emacs displays
+non-ASCII chars which have the same appearance as an ASCII space
+or hyphen as themselves, with the `nobreak-space' or `nobreak-hyphen'
+face, respectively.
+
+If the value is t, these characters are displayed as their ASCII
+counterparts: whitespace characters as ASCII space, hyphen characters
+as ASCII hyphen (a.k.a. \"dash\"), using the `nobreak-space' or
+the `nobreak-hyphen' face.
+
+This variable has effect only if `nobreak-char-display' is t;
+otherwise it is ignored.
+
+All of the non-ASCII characters in the Unicode horizontal whitespace
+character class, as well as U+00AD (soft hyphen), U+2010 (hyphen), and
+U+2011 (non-breaking hyphen) are affected.  */);
+  nobreak_char_ascii_display = false;
+
   DEFVAR_LISP ("void-text-area-pointer", Vvoid_text_area_pointer,
     doc: /* The pointer shape to show in void text areas.
 A value of nil means to show the text pointer.  Other options are
@@ -35753,6 +35959,10 @@ When nil, mouse-movement events will not be generated 
as long as the
 mouse stays within the extent of a single glyph (except for images).  */);
   mouse_fine_grained_tracking = false;
 
+  DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,
+    doc: /* Non-nil when maybe dragging tab bar item.  */);
+  tab_bar__dragging_in_progress = false;
+
   DEFVAR_BOOL ("redisplay-skip-initial-frame", redisplay_skip_initial_frame,
     doc: /* Non-nil to skip redisplay in initial frame.
 The initial frame is not displayed anywhere, so skipping it is
@@ -35932,4 +36142,121 @@ cancel_hourglass (void)
     }
 }
 
+/* Return a correction to be applied to G->pixel_width when it is
+   displayed in MOUSE_FACE.  This is needed for the first and the last
+   glyphs of text inside a face with :box when it is displayed with
+   MOUSE_FACE that has a different or no :box attribute.
+   ORIGINAL_FACE is the face G was originally drawn in, and MOUSE_FACE
+   is the face it will be drawn in now.  ROW is the G's glyph row and
+   W is its window.  */
+static int
+adjust_glyph_width_for_mouse_face (struct glyph *g, struct glyph_row *row,
+                                  struct window *w,
+                                  struct face *original_face,
+                                  struct face *mouse_face)
+{
+  int sum = 0;
+
+  bool do_left_box_p = g->left_box_line_p;
+  bool do_right_box_p = g->right_box_line_p;
+
+  /* This is required because we test some parameters of the image
+     slice before applying the box in produce_image_glyph.  */
+  if (g->type == IMAGE_GLYPH)
+    {
+      if (!row->reversed_p)
+       {
+         struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+                                            g->u.img_id);
+         do_left_box_p = g->left_box_line_p &&
+           g->slice.img.x == 0;
+         do_right_box_p = g->right_box_line_p &&
+           g->slice.img.x + g->slice.img.width == img->width;
+       }
+      else
+       {
+         struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+                                            g->u.img_id);
+         do_left_box_p = g->left_box_line_p &&
+           g->slice.img.x + g->slice.img.width == img->width;
+         do_right_box_p = g->right_box_line_p &&
+           g->slice.img.x == 0;
+       }
+    }
+
+  /* If the glyph has a left box line, subtract it from the offset.  */
+  if (do_left_box_p)
+    sum -= max (0, original_face->box_vertical_line_width);
+  /* Likewise with the right box line, as there may be a
+     box there as well.  */
+  if (do_right_box_p)
+    sum -= max (0, original_face->box_vertical_line_width);
+  /* Now add the line widths from the new face.  */
+  if (g->left_box_line_p)
+    sum += max (0, mouse_face->box_vertical_line_width);
+  if (g->right_box_line_p)
+    sum += max (0, mouse_face->box_vertical_line_width);
+
+  return sum;
+}
+
+/* Get the offset due to mouse-highlight to apply before drawing
+   phys_cursor, and return it in OFFSET.  ROW should be the row that
+   is under mouse face and contains the phys cursor.
+
+   This is required because the produce_XXX_glyph series of functions
+   add the width of the various vertical box lines to the total width
+   of the glyphs, but that must be updated when the row is put under
+   mouse face, which can have different box dimensions.  */
+static void
+get_cursor_offset_for_mouse_face (struct window *w, struct glyph_row *row,
+                                 int *offset)
+{
+  int sum = 0;
+  /* Return because the mode line can't possibly have a cursor. */
+  if (row->mode_line_p)
+    return;
+
+  block_input ();
+
+  struct frame *f = WINDOW_XFRAME (w);
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+  struct glyph *start, *end;
+  struct face *mouse_face = FACE_FROM_ID (f, hlinfo->mouse_face_face_id);
+  int hpos = w->phys_cursor.hpos;
+  end = &row->glyphs[TEXT_AREA][hpos];
+
+  if (!row->reversed_p)
+    {
+      if (MATRIX_ROW_VPOS (row, w->current_matrix) ==
+         hlinfo->mouse_face_beg_row)
+       start = &row->glyphs[TEXT_AREA][hlinfo->mouse_face_beg_col];
+      else
+       start = row->glyphs[TEXT_AREA];
+    }
+  else
+    {
+      if (MATRIX_ROW_VPOS (row, w->current_matrix) ==
+         hlinfo->mouse_face_end_row)
+       start = &row->glyphs[TEXT_AREA][hlinfo->mouse_face_end_col];
+      else
+       start = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
+    }
+
+  /* Calculate the offset by which to correct phys_cursor x if we are
+     drawing the cursor inside mouse-face highlighted text.  */
+
+  for ( ; row->reversed_p ? start > end : start < end;
+         row->reversed_p ? --start : ++start)
+    sum += adjust_glyph_width_for_mouse_face (start, row, w,
+                                             FACE_FROM_ID (f, start->face_id),
+                                             mouse_face);
+
+  if (row->reversed_p)
+    sum = -sum;
+
+  *offset = sum;
+
+  unblock_input ();
+}
 #endif /* HAVE_WINDOW_SYSTEM */
diff --git a/src/xfaces.c b/src/xfaces.c
index 5e63e87d75..a8cbf34790 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -5373,6 +5373,10 @@ DEFUN ("display-supports-face-attributes-p",
 The optional argument DISPLAY can be a display name, a frame, or
 nil (meaning the selected frame's display).
 
+For instance, to check whether the display supports underlining:
+
+  (display-supports-face-attributes-p \\='(:underline t))
+
 The definition of `supported' is somewhat heuristic, but basically means
 that a face containing all the attributes in ATTRIBUTES, when merged
 with the default face for display, can be represented in a way that's
@@ -6933,13 +6937,20 @@ syms_of_xfaces (void)
   DEFSYM (Qpressed_button, "pressed-button");
   DEFSYM (Qflat_button, "flat-button");
   DEFSYM (Qnormal, "normal");
+  DEFSYM (Qthin, "thin");
   DEFSYM (Qextra_light, "extra-light");
+  DEFSYM (Qultra_light, "ultra-light");
   DEFSYM (Qlight, "light");
   DEFSYM (Qsemi_light, "semi-light");
+  DEFSYM (Qmedium, "medium");
   DEFSYM (Qsemi_bold, "semi-bold");
+  DEFSYM (Qbook, "book");
   DEFSYM (Qbold, "bold");
   DEFSYM (Qextra_bold, "extra-bold");
   DEFSYM (Qultra_bold, "ultra-bold");
+  DEFSYM (Qheavy, "heavy");
+  DEFSYM (Qultra_heavy, "ultra-heavy");
+  DEFSYM (Qblack, "black");
   DEFSYM (Qoblique, "oblique");
   DEFSYM (Qitalic, "italic");
 
diff --git a/src/xfns.c b/src/xfns.c
index 0d0335c299..785ae3baca 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6222,7 +6222,7 @@ Otherwise, the return value is a vector with the 
following fields:
 static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
                            Lisp_Object, int, int, int *, int *);
 
-/* The frame of the currently visible tooltip.  */
+/* The frame of the currently visible tooltip, or nil if none.  */
 static Lisp_Object tip_frame;
 
 /* The window-system window corresponding to the frame of the
@@ -6710,7 +6710,7 @@ x_hide_tip (bool delete)
   if ((NILP (tip_last_frame) && NILP (tip_frame))
       || (!x_gtk_use_system_tooltips
          && !delete
-         && FRAMEP (tip_frame)
+         && !NILP (tip_frame)
          && FRAME_LIVE_P (XFRAME (tip_frame))
          && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
     /* Either there's no tooltip to hide or it's an already invisible
@@ -6727,7 +6727,7 @@ x_hide_tip (bool delete)
       specbind (Qinhibit_quit, Qt);
 
       /* Try to hide the GTK+ system tip first.  */
-      if (FRAMEP (tip_last_frame))
+      if (!NILP (tip_last_frame))
        {
          struct frame *f = XFRAME (tip_last_frame);
 
@@ -6745,7 +6745,7 @@ x_hide_tip (bool delete)
        tip_last_frame = Qnil;
 
       /* Now look whether there's an Emacs tip around.  */
-      if (FRAMEP (tip_frame))
+      if (!NILP (tip_frame))
        {
          struct frame *f = XFRAME (tip_frame);
 
@@ -6775,7 +6775,7 @@ x_hide_tip (bool delete)
 #else /* not USE_GTK */
   if (NILP (tip_frame)
       || (!delete
-         && FRAMEP (tip_frame)
+         && !NILP (tip_frame)
          && FRAME_LIVE_P (XFRAME (tip_frame))
          && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
     return Qnil;
@@ -6788,7 +6788,7 @@ x_hide_tip (bool delete)
       specbind (Qinhibit_redisplay, Qt);
       specbind (Qinhibit_quit, Qt);
 
-      if (FRAMEP (tip_frame))
+      if (!NILP (tip_frame))
        {
          struct frame *f = XFRAME (tip_frame);
 
@@ -6931,7 +6931,7 @@ Text larger than the specified size is clipped.  */)
     }
 #endif /* USE_GTK */
 
-  if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
+  if (!NILP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       if (FRAME_VISIBLE_P (XFRAME (tip_frame))
          && EQ (frame, tip_last_frame)
@@ -7016,7 +7016,7 @@ Text larger than the specified size is clipped.  */)
   tip_last_string = string;
   tip_last_parms = parms;
 
-  if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+  if (NILP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       /* Add default values to frame parameters.  */
       if (NILP (Fassq (Qname, parms)))
diff --git a/src/xmenu.c b/src/xmenu.c
index a6762236bc..ea2cbab203 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1603,6 +1603,14 @@ x_menu_show (struct frame *f, int x, int y, int 
menuflags,
                                  STRINGP (help) ? help : Qnil);
          if (prev_wv)
            prev_wv->next = wv;
+         else if (!save_wv)
+           {
+             /* This emacs_abort call pacifies gcc 11.2.1 when Emacs
+                is configured with --enable-gcc-warnings.  FIXME: If
+                save_wv can be null, do something better; otherwise,
+                explain why save_wv cannot be null.  */
+             emacs_abort ();
+           }
          else
            save_wv->contents = wv;
          if (!NILP (descrip))
diff --git a/src/xterm.c b/src/xterm.c
index ae3af598da..172abe919d 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1563,22 +1563,6 @@ x_set_cursor_gc (struct glyph_string *s)
 static void
 x_set_mouse_face_gc (struct glyph_string *s)
 {
-  int face_id;
-  struct face *face;
-
-  /* What face has to be used last for the mouse face?  */
-  face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id;
-  face = FACE_FROM_ID_OR_NULL (s->f, face_id);
-  if (face == NULL)
-    face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
-
-  if (s->first_glyph->type == CHAR_GLYPH)
-    face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
-  else
-    face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
-  s->face = FACE_FROM_ID (s->f, face_id);
-  prepare_face_for_display (s->f, s->face);
-
   if (s->font == s->face->font)
     s->gc = s->face->gc;
   else
@@ -4049,7 +4033,7 @@ x_delete_glyphs (struct frame *f, int n)
 /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
    If they are <= 0, this is probably an error.  */
 
-static ATTRIBUTE_UNUSED void
+MAYBE_UNUSED static void
 x_clear_area1 (Display *dpy, Window window,
                int x, int y, int width, int height, int exposures)
 {
@@ -4142,6 +4126,8 @@ x_show_hourglass (struct frame *f)
 
          XMapRaised (dpy, x->hourglass_window);
          XFlush (dpy);
+        /* Ensure that the spinning hourglass is shown.  */
+        flush_frame (f);
        }
     }
 }
@@ -4405,6 +4391,99 @@ x_scroll_run (struct window *w, struct run *run)
   /* Cursor off.  Will be switched on again in gui_update_window_end.  */
   gui_clear_cursor (w);
 
+#ifdef HAVE_XWIDGETS
+  /* "Copy" xwidget windows in the area that will be scrolled.  */
+  Display *dpy = FRAME_X_DISPLAY (f);
+  Window window = FRAME_X_WINDOW (f);
+
+  Window root, parent, *children;
+  unsigned int nchildren;
+
+  if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren))
+    {
+      /* Now find xwidget views situated between from_y and to_y, and
+        attached to w.  */
+      for (unsigned int i = 0; i < nchildren; ++i)
+       {
+         Window child = children[i];
+         struct xwidget_view *view = xwidget_view_from_window (child);
+
+         if (view && !view->hidden)
+           {
+             int window_y = view->y + view->clip_top;
+             int window_height = view->clip_bottom - view->clip_top;
+
+             Emacs_Rectangle r1, r2, result;
+             r1.x = w->pixel_left;
+             r1.y = from_y;
+             r1.width = w->pixel_width;
+             r1.height = height;
+             r2 = r1;
+             r2.y = window_y;
+             r2.height = window_height;
+
+             /* The window is offscreen, just unmap it.  */
+             if (window_height == 0)
+               {
+                 view->hidden = true;
+                 XUnmapWindow (dpy, child);
+                 continue;
+               }
+
+             bool intersects_p =
+               gui_intersect_rectangles (&r1, &r2, &result);
+
+             if (XWINDOW (view->w) == w && intersects_p)
+               {
+                 int y = view->y + (to_y - from_y);
+                 int text_area_x, text_area_y, text_area_width, 
text_area_height;
+                 int clip_top, clip_bottom;
+
+                 window_box (w, TEXT_AREA, &text_area_x, &text_area_y,
+                             &text_area_width, &text_area_height);
+
+                 view->y = y;
+
+                 clip_top = 0;
+                 clip_bottom = XXWIDGET (view->model)->height;
+
+                 if (y < text_area_y)
+                   clip_top = text_area_y - y;
+
+                 if ((y + clip_bottom) > (text_area_y + text_area_height))
+                   {
+                     clip_bottom -= (y + clip_bottom) - (text_area_y + 
text_area_height);
+                   }
+
+                 view->clip_top = clip_top;
+                 view->clip_bottom = clip_bottom;
+
+                 /* This means the view has moved offscreen.  Unmap
+                    it and hide it here.  */
+                 if ((view->clip_bottom - view->clip_top) <= 0)
+                   {
+                     view->hidden = true;
+                     XUnmapWindow (dpy, child);
+                   }
+                 else
+                   {
+                     XMoveResizeWindow (dpy, child, view->x + view->clip_left,
+                                        view->y + view->clip_top,
+                                        view->clip_right - view->clip_left,
+                                        view->clip_bottom - view->clip_top);
+                     cairo_xlib_surface_set_size (view->cr_surface,
+                                                  view->clip_right - 
view->clip_left,
+                                                  view->clip_bottom - 
view->clip_top);
+                   }
+                 xwidget_expose (view);
+                 XFlush (dpy);
+               }
+            }
+       }
+      XFree (children);
+    }
+#endif
+
 #ifdef USE_CAIRO
   if (FRAME_CR_CONTEXT (f))
     {
@@ -4578,8 +4657,9 @@ x_focus_changed (int type, int state, struct 
x_display_info *dpyinfo, struct fra
     }
 }
 
-/* Return the Emacs frame-object corresponding to an X window.
-   It could be the frame's main window or an icon window.  */
+/* Return the Emacs frame-object corresponding to an X window.  It
+   could be the frame's main window, an icon window, or an xwidget
+   window.  */
 
 static struct frame *
 x_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
@@ -4590,6 +4670,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int 
wdesc)
   if (wdesc == None)
     return NULL;
 
+#ifdef HAVE_XWIDGETS
+  struct xwidget_view *xvw = xwidget_view_from_window (wdesc);
+
+  if (xvw && xvw->frame)
+    return xvw->frame;
+#endif
+
   FOR_EACH_FRAME (tail, frame)
     {
       f = XFRAME (frame);
@@ -5012,7 +5099,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, 
int state)
             | ((state & dpyinfo->hyper_mod_mask)       ? mod_hyper     : 0));
 }
 
-static int
+int
 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state)
 {
   EMACS_INT mod_ctrl = ctrl_modifier;
@@ -8226,6 +8313,18 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
     case Expose:
       f = x_window_to_frame (dpyinfo, event->xexpose.window);
+#ifdef HAVE_XWIDGETS
+      {
+       struct xwidget_view *xv =
+         xwidget_view_from_window (event->xexpose.window);
+
+       if (xv)
+         {
+           xwidget_expose (xv);
+           goto OTHER;
+         }
+      }
+#endif
       if (f)
         {
           if (!FRAME_VISIBLE_P (f))
@@ -8806,6 +8905,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
       x_detect_focus_change (dpyinfo, any, event, &inev.ie);
 
+#ifdef HAVE_XWIDGETS
+      {
+       struct xwidget_view *xvw = xwidget_view_from_window 
(event->xcrossing.window);
+       Mouse_HLInfo *hlinfo;
+
+       if (xvw)
+         {
+           xwidget_motion_or_crossing (xvw, event);
+           hlinfo = MOUSE_HL_INFO (xvw->frame);
+
+           if (xvw->frame == hlinfo->mouse_face_mouse_frame)
+             {
+               clear_mouse_face (hlinfo);
+               hlinfo->mouse_face_mouse_frame = 0;
+             }
+
+           if (any_help_event_p)
+             {
+               do_help = -1;
+             }
+           goto OTHER;
+         }
+      }
+#endif
+
       f = any;
 
       if (f && x_mouse_click_focus_ignore_position)
@@ -8849,6 +8973,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       goto OTHER;
 
     case LeaveNotify:
+#ifdef HAVE_XWIDGETS
+      {
+       struct xwidget_view *xvw = xwidget_view_from_window 
(event->xcrossing.window);
+
+       if (xvw)
+         {
+           xwidget_motion_or_crossing (xvw, event);
+           goto OTHER;
+         }
+      }
+#endif
       x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
       x_detect_focus_change (dpyinfo, any, event, &inev.ie);
 
@@ -8898,6 +9033,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_GTK
         if (f && xg_event_is_for_scrollbar (f, event))
           f = 0;
+#endif
+#ifdef HAVE_XWIDGETS
+       struct xwidget_view *xvw = xwidget_view_from_window 
(event->xmotion.window);
+
+       if (xvw)
+         xwidget_motion_or_crossing (xvw, event);
 #endif
         if (f)
           {
@@ -9153,6 +9294,24 @@ handle_one_xevent (struct x_display_info *dpyinfo,
     case ButtonRelease:
     case ButtonPress:
       {
+#ifdef HAVE_XWIDGETS
+       struct xwidget_view *xvw = xwidget_view_from_window 
(event->xmotion.window);
+
+       if (xvw)
+         {
+           xwidget_button (xvw, event->type == ButtonPress,
+                           event->xbutton.x, event->xbutton.y,
+                           event->xbutton.button, event->xbutton.state,
+                           event->xbutton.time);
+
+           if (!EQ (selected_window, xvw->w))
+             {
+               inev.ie.kind = SELECT_WINDOW_EVENT;
+               inev.ie.frame_or_window = xvw->w;
+             }
+           goto OTHER;
+         }
+#endif
         /* If we decide we want to generate an event to be seen
            by the rest of Emacs, we put it here.  */
         Lisp_Object tab_bar_arg = Qnil;
@@ -10133,8 +10292,9 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
          frame on it. */
       dpyinfo->reference_count++;
       dpyinfo->terminal->reference_count++;
+      if (ioerror)
+       dpyinfo->display = 0;
     }
-  if (ioerror) dpyinfo->display = 0;
 
   /* First delete frames whose mini-buffers are on frames
      that are on the dead display.  */
@@ -12122,6 +12282,10 @@ x_free_frame_resources (struct frame *f)
        xfree (f->shell_position);
 #else  /* !USE_X_TOOLKIT */
 
+#ifdef HAVE_XWIDGETS
+      kill_frame_xwidget_views (f);
+#endif
+
 #ifdef USE_GTK
       xg_free_frame_widgets (f);
 #endif /* USE_GTK */
diff --git a/src/xterm.h b/src/xterm.h
index de6ea50385..9d9534dd62 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1108,6 +1108,7 @@ extern void x_mouse_leave (struct x_display_info *);
 extern int x_dispatch_event (XEvent *, Display *);
 #endif
 extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
+extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t);
 #ifdef USE_CAIRO
 extern void x_cr_destroy_frame_context (struct frame *);
 extern void x_cr_update_surface_desired_size (struct frame *, int, int);
diff --git a/src/xwidget.c b/src/xwidget.c
index e4b42e6e0c..d3a8d5eb82 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -19,6 +19,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include "buffer.h"
 #include "xwidget.h"
 
 #include "lisp.h"
@@ -35,10 +36,24 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #ifdef USE_GTK
 #include <webkit2/webkit2.h>
 #include <JavaScriptCore/JavaScript.h>
+#include <cairo.h>
+#include <X11/Xlib.h>
 #elif defined NS_IMPL_COCOA
 #include "nsxwidget.h"
 #endif
 
+static Lisp_Object id_to_xwidget_map;
+static uint32_t xwidget_counter = 0;
+
+#ifdef USE_GTK
+static Lisp_Object x_window_to_xwv_map;
+static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
+static void synthesize_focus_in_event (GtkWidget *);
+static GdkDevice *find_suitable_keyboard (struct frame *);
+static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *,
+                                        gpointer);
+#endif
+
 static struct xwidget *
 allocate_xwidget (void)
 {
@@ -64,18 +79,32 @@ static void webkit_javascript_finished_cb (GObject *,
                                            GAsyncResult *,
                                            gpointer);
 static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, 
gpointer);
-
+static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, 
gpointer);
 static gboolean
 webkit_decide_policy_cb (WebKitWebView *,
                          WebKitPolicyDecision *,
                          WebKitPolicyDecisionType,
                          gpointer);
+static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *);
+
+struct widget_search_data
+{
+  int x;
+  int y;
+  bool foundp;
+  bool first;
+  GtkWidget *data;
+};
+
+static void find_widget (GtkWidget *t, struct widget_search_data *);
+static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, 
guint,
+                                 gpointer);
 #endif
 
 
 DEFUN ("make-xwidget",
        Fmake_xwidget, Smake_xwidget,
-       5, 6, 0,
+       4, 7, 0,
        doc: /* Make an xwidget of TYPE.
 If BUFFER is nil, use the current buffer.
 If BUFFER is a string and no such buffer exists, create it.
@@ -83,10 +112,13 @@ TYPE is a symbol which can take one of the following 
values:
 
 - webkit
 
-Returns the newly constructed xwidget, or nil if construction fails.  */)
+RELATED is nil, or an xwidget.  When constructing a WebKit widget, it
+will share the same settings and internal subprocess as RELATED.
+Returns the newly constructed xwidget, or nil if construction
+fails.  */)
   (Lisp_Object type,
    Lisp_Object title, Lisp_Object width, Lisp_Object height,
-   Lisp_Object arguments, Lisp_Object buffer)
+   Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related)
 {
 #ifdef USE_GTK
   if (!xg_gtk_initialized)
@@ -96,6 +128,9 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
   CHECK_FIXNAT (width);
   CHECK_FIXNAT (height);
 
+  if (!EQ (type, Qwebkit))
+    error ("Bad xwidget type");
+
   struct xwidget *xw = allocate_xwidget ();
   Lisp_Object val;
   xw->type = type;
@@ -108,13 +143,19 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
   XSETXWIDGET (val, xw);
   Vxwidget_list = Fcons (val, Vxwidget_list);
   xw->plist = Qnil;
+  xw->xwidget_id = ++xwidget_counter;
+  xw->find_text = NULL;
+
+  Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map);
 
 #ifdef USE_GTK
   xw->widgetwindow_osr = NULL;
   xw->widget_osr = NULL;
+  xw->hit_result = 0;
   if (EQ (xw->type, Qwebkit))
     {
       block_input ();
+      WebKitSettings *settings;
       WebKitWebContext *webkit_context = webkit_web_context_get_default ();
 
 # if WEBKIT_CHECK_VERSION (2, 26, 0)
@@ -128,18 +169,33 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
 
       if (EQ (xw->type, Qwebkit))
         {
-          xw->widget_osr = webkit_web_view_new ();
-
-          /* webkitgtk uses GSubprocess which sets sigaction causing
-             Emacs to not catch SIGCHLD with its usual handle setup in
-             catch_child_signal().  This resets the SIGCHLD
-             sigaction.  */
-          struct sigaction old_action;
-          sigaction (SIGCHLD, NULL, &old_action);
-          webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr),
-                                   "about:blank");
-          sigaction (SIGCHLD, &old_action, NULL);
-        }
+         WebKitWebView *related_view;
+
+         if (NILP (related)
+             || !XWIDGETP (related)
+             || !EQ (XXWIDGET (related)->type, Qwebkit))
+           {
+             xw->widget_osr = webkit_web_view_new ();
+
+             /* webkitgtk uses GSubprocess which sets sigaction causing
+                Emacs to not catch SIGCHLD with its usual handle setup in
+                'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
+             struct sigaction old_action;
+             sigaction (SIGCHLD, NULL, &old_action);
+             webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
+                                       "about:blank");
+             sigaction (SIGCHLD, &old_action, NULL);
+           }
+         else
+           {
+             related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
+             xw->widget_osr = webkit_web_view_new_with_related_view 
(related_view);
+           }
+
+         /* Enable the developer extras.  */
+         settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW 
(xw->widget_osr));
+         g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, 
NULL);
+       }
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
@@ -157,6 +213,7 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
 
       gtk_widget_show (xw->widget_osr);
       gtk_widget_show (xw->widgetwindow_osr);
+      synthesize_focus_in_event (xw->widgetwindow_osr);
 
       /* Store some xwidget data in the gtk widgets for convenient
          retrieval in the event handlers.  */
@@ -179,8 +236,24 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
                             G_CALLBACK
                             (webkit_decide_policy_cb),
                             xw);
+
+         g_signal_connect (G_OBJECT (xw->widget_osr),
+                           "mouse-target-changed",
+                           G_CALLBACK (mouse_target_changed),
+                           xw);
+         g_signal_connect (G_OBJECT (xw->widget_osr),
+                           "create",
+                           G_CALLBACK (webkit_create_cb),
+                           xw);
+         g_signal_connect (G_OBJECT (xw->widget_osr),
+                           "script-dialog",
+                           G_CALLBACK (webkit_script_dialog_cb),
+                           NULL);
         }
 
+      g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
+                       G_CALLBACK (offscreen_damage_event), xw);
+
       unblock_input ();
     }
 #elif defined NS_IMPL_COCOA
@@ -190,6 +263,156 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
   return val;
 }
 
+#ifdef USE_GTK
+static void
+set_widget_if_text_view (GtkWidget *widget, void *data)
+{
+  GtkWidget **pointer = data;
+
+  if (GTK_IS_TEXT_VIEW (widget))
+    *pointer = widget;
+}
+#endif
+
+DEFUN ("xwidget-perform-lispy-event",
+       Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event,
+       2, 3, 0, doc: /* Send a lispy event to XWIDGET.
+EVENT should be the event that will be sent.  FRAME should be the
+frame which generated the event, and defaults to the selected frame.
+On X11, modifier keys will not be processed if FRAME is nil and the
+selected frame is not an X-Windows frame.  */)
+  (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame)
+{
+  struct xwidget *xw;
+  struct frame *f = NULL;
+  int character = -1, keycode = -1;
+  int modifiers = 0;
+
+#ifdef USE_GTK
+  GdkEvent *xg_event;
+  GtkContainerClass *klass;
+  GtkWidget *widget;
+  GtkWidget *temp = NULL;
+#endif
+
+  CHECK_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  if (!NILP (frame))
+    f = decode_window_system_frame (frame);
+  else if (FRAME_X_P (SELECTED_FRAME ()))
+    f = SELECTED_FRAME ();
+
+#ifdef USE_GTK
+  widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr));
+
+  if (!widget)
+    widget = xw->widget_osr;
+
+  if (RANGED_FIXNUMP (0, event, INT_MAX))
+    {
+      character = XFIXNUM (event);
+
+      if (character < 32)
+       modifiers |= ctrl_modifier;
+
+      modifiers |= character & meta_modifier;
+      modifiers |= character & hyper_modifier;
+      modifiers |= character & super_modifier;
+      modifiers |= character & shift_modifier;
+      modifiers |= character & ctrl_modifier;
+
+      character = character & ~(1 << 21);
+
+      if (character < 32)
+       character += '_';
+
+      if (f)
+       modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
+      else
+       modifiers = 0;
+    }
+  else if (SYMBOLP (event))
+    {
+      Lisp_Object decoded = parse_modifiers (event);
+      Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded));
+
+      int off = 0;
+      bool found = false;
+
+      while (off < 256)
+       {
+         if (lispy_function_keys[off]
+             && !strcmp (lispy_function_keys[off],
+                         SSDATA (decoded_name)))
+           {
+             found = true;
+             break;
+           }
+         ++off;
+       }
+
+      if (f)
+       modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
+                                           XFIXNUM (XCAR (XCDR (decoded))));
+      else
+       modifiers = 0;
+
+      if (found)
+       keycode = off + 0xff00;
+    }
+
+  if (character == -1 && keycode == -1)
+    return Qnil;
+
+  block_input ();
+  xg_event = gdk_event_new (GDK_KEY_PRESS);
+  xg_event->any.window = gtk_widget_get_window (xw->widget_osr);
+  g_object_ref (xg_event->any.window);
+
+  if (character > -1)
+    keycode = gdk_unicode_to_keyval (character);
+
+  xg_event->key.keyval = keycode;
+  xg_event->key.state = modifiers;
+
+  if (keycode > -1)
+    {
+      /* WebKitGTK internals abuse follows.  */
+      if (WEBKIT_IS_WEB_VIEW (widget))
+       {
+         /* WebKitGTK relies on an internal GtkTextView object to
+            "translate" keys such as backspace.  We must find that
+            widget and activate its binding to this key if any.  */
+         klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget));
+
+         klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE,
+                        set_widget_if_text_view, &temp);
+
+         if (GTK_IS_WIDGET (temp))
+           {
+             if (!gtk_widget_get_realized (temp))
+               gtk_widget_realize (temp);
+
+             gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers);
+           }
+       }
+    }
+
+  if (f)
+    gdk_event_set_device (xg_event,
+                         find_suitable_keyboard (SELECTED_FRAME ()));
+
+  gtk_main_do_event (xg_event);
+  xg_event->type = GDK_KEY_RELEASE;
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
        1, 1, 0,
        doc: /* Return a list of xwidgets associated with BUFFER.
@@ -221,16 +444,397 @@ xwidget_hidden (struct xwidget_view *xv)
   return xv->hidden;
 }
 
+struct xwidget *
+xwidget_from_id (uint32_t id)
+{
+  Lisp_Object key = make_fixnum (id);
+  Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil);
+
+  if (NILP (xwidget))
+    emacs_abort ();
+
+  return XXWIDGET (xwidget);
+}
+
 #ifdef USE_GTK
+
+static GdkDevice *
+find_suitable_pointer (struct frame *f)
+{
+  GdkSeat *seat = gdk_display_get_default_seat
+    (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
+
+  if (!seat)
+    return NULL;
+
+  return gdk_seat_get_pointer (seat);
+}
+
+static GdkDevice *
+find_suitable_keyboard (struct frame *f)
+{
+  GdkSeat *seat = gdk_display_get_default_seat
+    (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
+
+  if (!seat)
+    return NULL;
+
+  return gdk_seat_get_keyboard (seat);
+}
+
+static void
+find_widget_cb (GtkWidget *widget, void *user)
+{
+  find_widget (widget, user);
+}
+
+static void
+find_widget (GtkWidget *widget,
+            struct widget_search_data *data)
+{
+  GtkAllocation new_allocation;
+  GdkWindow *window;
+  int x_offset = 0;
+  int y_offset = 0;
+
+  gtk_widget_get_allocation (widget, &new_allocation);
+
+  if (gtk_widget_get_has_window (widget))
+    {
+      new_allocation.x = 0;
+      new_allocation.y = 0;
+    }
+
+  if (gtk_widget_get_parent (widget) && !data->first)
+    {
+      window = gtk_widget_get_window (widget);
+      while (window != gtk_widget_get_window (gtk_widget_get_parent (widget)))
+       {
+         gint tx, ty, twidth, theight;
+
+         if (!window)
+           return;
+
+         twidth = gdk_window_get_width (window);
+         theight = gdk_window_get_height (window);
+
+         if (new_allocation.x < 0)
+           {
+             new_allocation.width += new_allocation.x;
+             new_allocation.x = 0;
+           }
+
+         if (new_allocation.y < 0)
+           {
+             new_allocation.height += new_allocation.y;
+             new_allocation.y = 0;
+           }
+
+         if (new_allocation.x + new_allocation.width > twidth)
+           new_allocation.width = twidth - new_allocation.x;
+         if (new_allocation.y + new_allocation.height > theight)
+           new_allocation.height = theight - new_allocation.y;
+
+         gdk_window_get_position (window, &tx, &ty);
+         new_allocation.x += tx;
+         x_offset += tx;
+         new_allocation.y += ty;
+         y_offset += ty;
+
+         window = gdk_window_get_parent (window);
+       }
+    }
+
+  if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
+      (data->x < new_allocation.x + new_allocation.width) &&
+      (data->y < new_allocation.y + new_allocation.height))
+    {
+      /* First, check if the drag is in a valid drop site in one of
+        our children.  */
+      if (GTK_IS_CONTAINER (widget))
+       {
+         struct widget_search_data new_data = *data;
+
+         new_data.x -= x_offset;
+         new_data.y -= y_offset;
+         new_data.foundp = false;
+         new_data.first = false;
+
+         gtk_container_forall (GTK_CONTAINER (widget),
+                               find_widget_cb, &new_data);
+
+         data->foundp = new_data.foundp;
+         if (data->foundp)
+           data->data = new_data.data;
+       }
+
+      /* If not, and this widget is registered as a drop site, check
+        to emit "drag_motion" to check if we are actually in a drop
+        site.  */
+      if (!data->foundp)
+       {
+         data->foundp = true;
+         data->data = widget;
+       }
+    }
+}
+
+static GtkWidget *
+find_widget_at_pos (GtkWidget *w, int x, int y,
+                   int *new_x, int *new_y)
+{
+  struct widget_search_data data;
+
+  data.x = x;
+  data.y = y;
+  data.foundp = false;
+  data.first = true;
+
+  find_widget (w, &data);
+
+  if (data.foundp)
+    {
+      gtk_widget_translate_coordinates (w, data.data, x,
+                                       y, new_x, new_y);
+      return data.data;
+    }
+
+  *new_x = x;
+  *new_y = y;
+
+  return NULL;
+}
+
+static Emacs_Cursor
+cursor_for_hit (guint result, struct frame *frame)
+{
+  Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor;
+
+  if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
+      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)
+      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
+    cursor = FRAME_X_OUTPUT (frame)->text_cursor;
+
+  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR)
+    cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor;
+
+  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+    cursor = FRAME_X_OUTPUT (frame)->hand_cursor;
+
+  return cursor;
+}
+
+static void
+define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
+{
+  struct xwidget_view *xvw;
+
+  xw->hit_result = webkit_hit_test_result_get_context (res);
+
+  for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem);
+       tem = XCDR (tem))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tem)))
+       {
+         xvw = XXWIDGET_VIEW (XCAR (tem));
+
+         if (XXWIDGET (xvw->model) == xw)
+           {
+             xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame);
+             if (xvw->wdesc != None)
+               XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor);
+           }
+       }
+    }
+}
+
+static void
+mouse_target_changed (WebKitWebView *webview,
+                     WebKitHitTestResult *hitresult,
+                     guint modifiers, gpointer xw)
+{
+  define_cursors (xw, hitresult);
+}
+
+
+static void
+xwidget_button_1 (struct xwidget_view *view,
+                 bool down_p, int x, int y, int button,
+                 int modifier_state, Time time)
+{
+  GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : 
GDK_BUTTON_RELEASE);
+  struct xwidget *model = XXWIDGET (view->model);
+  GtkWidget *target;
+
+  /* X and Y should be relative to the origin of view->wdesc.  */
+  x += view->clip_left;
+  y += view->clip_top;
+
+  target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
+
+  if (!target)
+    target = model->widget_osr;
+
+  xg_event->any.window = gtk_widget_get_window (target);
+  g_object_ref (xg_event->any.window); /* The window will be unrefed
+                                         later by gdk_event_free.  */
+
+  xg_event->button.x = x;
+  xg_event->button.x_root = x;
+  xg_event->button.y = y;
+  xg_event->button.y_root = y;
+  xg_event->button.button = button;
+  xg_event->button.state = modifier_state;
+  xg_event->button.time = time;
+  xg_event->button.device = find_suitable_pointer (view->frame);
+
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+}
+
+void
+xwidget_button (struct xwidget_view *view,
+               bool down_p, int x, int y, int button,
+               int modifier_state, Time time)
+{
+  if (button < 4 || button > 8)
+    xwidget_button_1 (view, down_p, x, y, button, modifier_state, time);
+  else
+    {
+      GdkEvent *xg_event = gdk_event_new (GDK_SCROLL);
+      struct xwidget *model = XXWIDGET (view->model);
+      GtkWidget *target;
+
+      x += view->clip_left;
+      y += view->clip_top;
+
+      target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
+
+      if (!target)
+       target = model->widget_osr;
+
+      xg_event->any.window = gtk_widget_get_window (target);
+      g_object_ref (xg_event->any.window); /* The window will be unrefed
+                                             later by gdk_event_free.  */
+      if (button == 4)
+       xg_event->scroll.direction = GDK_SCROLL_UP;
+      else if (button == 5)
+       xg_event->scroll.direction = GDK_SCROLL_DOWN;
+      else if (button == 6)
+       xg_event->scroll.direction = GDK_SCROLL_LEFT;
+      else
+       xg_event->scroll.direction = GDK_SCROLL_RIGHT;
+
+      xg_event->scroll.device = find_suitable_pointer (view->frame);
+
+      xg_event->scroll.x = x;
+      xg_event->scroll.x_root = x;
+      xg_event->scroll.y = y;
+      xg_event->scroll.y_root = y;
+      xg_event->scroll.state = modifier_state;
+      xg_event->scroll.time = time;
+
+      xg_event->scroll.delta_x = 0;
+      xg_event->scroll.delta_y = 0;
+
+      gtk_main_do_event (xg_event);
+      gdk_event_free (xg_event);
+    }
+}
+
+void
+xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
+{
+  GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify
+                                     ? GDK_MOTION_NOTIFY
+                                     : (event->type == LeaveNotify
+                                        ? GDK_LEAVE_NOTIFY
+                                        : GDK_ENTER_NOTIFY));
+  struct xwidget *model = XXWIDGET (view->model);
+  int x;
+  int y;
+  GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr,
+                                         (event->type == MotionNotify
+                                          ? event->xmotion.x + view->clip_left
+                                          : event->xcrossing.x + 
view->clip_left),
+                                         (event->type == MotionNotify
+                                          ? event->xmotion.y + view->clip_top
+                                          : event->xcrossing.y + 
view->clip_top),
+                                         &x, &y);
+
+  if (!target)
+    target = model->widget_osr;
+
+  xg_event->any.window = gtk_widget_get_window (target);
+  g_object_ref (xg_event->any.window); /* The window will be unrefed
+                                         later by gdk_event_free.  */
+
+  if (event->type == MotionNotify)
+    {
+      xg_event->motion.x = x;
+      xg_event->motion.y = y;
+      xg_event->motion.x_root = event->xmotion.x_root;
+      xg_event->motion.y_root = event->xmotion.y_root;
+      xg_event->motion.time = event->xmotion.time;
+      xg_event->motion.state = event->xmotion.state;
+      xg_event->motion.device = find_suitable_pointer (view->frame);
+    }
+  else
+    {
+      xg_event->crossing.detail = min (5, event->xcrossing.detail);
+      xg_event->crossing.time = event->xcrossing.time;
+      xg_event->crossing.x = x;
+      xg_event->crossing.y = y;
+      xg_event->crossing.x_root = event->xcrossing.x_root;
+      xg_event->crossing.y_root = event->xcrossing.y_root;
+      gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
+    }
+
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+}
+
+static void
+synthesize_focus_in_event (GtkWidget *offscreen_window)
+{
+  GdkWindow *wnd;
+  GdkEvent *focus_event;
+
+  if (!gtk_widget_get_realized (offscreen_window))
+    gtk_widget_realize (offscreen_window);
+
+  wnd = gtk_widget_get_window (offscreen_window);
+
+  focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
+  focus_event->any.window = wnd;
+  focus_event->focus_change.in = TRUE;
+  g_object_ref (wnd);
+
+  gtk_main_do_event (focus_event);
+  gdk_event_free (focus_event);
+}
+
+struct xwidget_view *
+xwidget_view_from_window (Window wdesc)
+{
+  Lisp_Object key = make_fixnum (wdesc);
+  Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil);
+
+  if (NILP (xwv))
+    return NULL;
+
+  return XXWIDGET_VIEW (xwv);
+}
+
 static void
 xwidget_show_view (struct xwidget_view *xv)
 {
   xv->hidden = false;
-  gtk_widget_show (xv->widgetwindow);
-  gtk_fixed_move (GTK_FIXED (xv->emacswindow),
-                  xv->widgetwindow,
-                  xv->x + xv->clip_left,
-                  xv->y + xv->clip_top);
+  XMoveWindow (xv->dpy, xv->wdesc,
+              xv->x + xv->clip_left,
+              xv->y + xv->clip_top);
+  XMapWindow (xv->dpy, xv->wdesc);
+  XFlush (xv->dpy);
 }
 
 /* Hide an xwidget view.  */
@@ -238,28 +842,64 @@ static void
 xwidget_hide_view (struct xwidget_view *xv)
 {
   xv->hidden = true;
-  gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
-                  10000, 10000);
+  XUnmapWindow (xv->dpy, xv->wdesc);
+  XFlush (xv->dpy);
+}
+
+static void
+xv_do_draw (struct xwidget_view *xw, struct xwidget *w)
+{
+  GtkOffscreenWindow *wnd;
+  cairo_surface_t *surface;
+  block_input ();
+  wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
+  surface = gtk_offscreen_window_get_surface (wnd);
+
+  cairo_save (xw->cr_context);
+  if (surface)
+    {
+      cairo_translate (xw->cr_context, -xw->clip_left, -xw->clip_top);
+      cairo_set_source_surface (xw->cr_context, surface, 0, 0);
+      cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE);
+      cairo_paint (xw->cr_context);
+    }
+  cairo_restore (xw->cr_context);
+
+  unblock_input ();
 }
 
 /* When the off-screen webkit master view changes this signal is called.
    It copies the bitmap from the off-screen instance.  */
 static gboolean
 offscreen_damage_event (GtkWidget *widget, GdkEvent *event,
-                        gpointer xv_widget)
-{
-  /* Queue a redraw of onscreen widget.
-     There is a guard against receiving an invalid widget,
-     which should only happen if we failed to remove the
-     specific signal handler for the damage event.  */
-  if (GTK_IS_WIDGET (xv_widget))
-    gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
-  else
-    message ("Warning, offscreen_damage_event received invalid xv 
pointer:%p\n",
-             xv_widget);
+                        gpointer xwidget)
+{
+  block_input ();
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail)))
+       {
+         struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail));
+
+         if (view->wdesc && XXWIDGET (view->model) == xwidget)
+           xv_do_draw (view, XXWIDGET (view->model));
+       }
+    }
+
+  unblock_input ();
 
   return FALSE;
 }
+
+void
+xwidget_expose (struct xwidget_view *xv)
+{
+  struct xwidget *xw = XXWIDGET (xv->model);
+
+  xv_do_draw (xv, xw);
+}
 #endif /* USE_GTK */
 
 void
@@ -313,22 +953,108 @@ store_xwidget_js_callback_event (struct xwidget *xw,
 
 
 #ifdef USE_GTK
+static void
+store_xwidget_display_event (struct xwidget *xw)
+{
+  struct input_event evt;
+  Lisp_Object val;
+
+  XSETXWIDGET (val, xw);
+  EVENT_INIT (evt);
+  evt.kind = XWIDGET_DISPLAY_EVENT;
+  evt.frame_or_window = Qnil;
+  evt.arg = val;
+  kbd_buffer_store_event (&evt);
+}
+
+static void
+webkit_ready_to_show (WebKitWebView *new_view,
+                     gpointer user_data)
+{
+  Lisp_Object tem;
+  struct xwidget *xw;
+
+  for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem))
+    {
+      if (XWIDGETP (XCAR (tem)))
+       {
+         xw = XXWIDGET (XCAR (tem));
+
+         if (EQ (xw->type, Qwebkit)
+             && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view)
+           store_xwidget_display_event (xw);
+       }
+    }
+}
+
+static GtkWidget *
+webkit_create_cb_1 (WebKitWebView *webview,
+                   struct xwidget_view *xv)
+{
+  Lisp_Object related;
+  Lisp_Object xwidget;
+  GtkWidget *widget;
+
+  XSETXWIDGET (related, xv);
+  xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
+                          make_fixnum (0), Qnil,
+                          build_string (" *detached xwidget buffer*"),
+                          related);
+
+  if (NILP (xwidget))
+    return NULL;
+
+  widget = XXWIDGET (xwidget)->widget_osr;
+
+  g_signal_connect (G_OBJECT (widget), "ready-to-show",
+                   G_CALLBACK (webkit_ready_to_show), NULL);
+
+  return widget;
+}
+
+static GtkWidget *
+webkit_create_cb (WebKitWebView *webview,
+                 WebKitNavigationAction *nav_action,
+                 gpointer user_data)
+{
+  switch (webkit_navigation_action_get_navigation_type (nav_action))
+    {
+    case WEBKIT_NAVIGATION_TYPE_OTHER:
+      return webkit_create_cb_1 (webview, user_data);
+
+    case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
+    case WEBKIT_NAVIGATION_TYPE_RELOAD:
+    case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
+    case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
+    case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
+    default:
+      return NULL;
+    }
+}
+
 void
 webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
                              WebKitLoadEvent load_event,
                              gpointer data)
 {
-  switch (load_event) {
-  case WEBKIT_LOAD_FINISHED:
+  struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
+                                         XG_XWIDGET);
+
+  switch (load_event)
     {
-      struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
-                                              XG_XWIDGET);
-      store_xwidget_event_string (xw, "load-changed", "");
+    case WEBKIT_LOAD_FINISHED:
+      store_xwidget_event_string (xw, "load-changed", "load-finished");
+      break;
+    case WEBKIT_LOAD_STARTED:
+      store_xwidget_event_string (xw, "load-changed", "load-started");
+      break;
+    case WEBKIT_LOAD_REDIRECTED:
+      store_xwidget_event_string (xw, "load-changed", "load-redirected");
+      break;
+    case WEBKIT_LOAD_COMMITTED:
+      store_xwidget_event_string (xw, "load-changed", "load-committed");
       break;
     }
-  default:
-    break;
-  }
 }
 
 /* Recursively convert a JavaScript value to a Lisp value. */
@@ -479,6 +1205,33 @@ webkit_decide_policy_cb (WebKitWebView *webView,
       break;
     }
   case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
+    {
+      WebKitNavigationPolicyDecision *navigation_decision =
+        WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+      WebKitNavigationAction *navigation_action =
+        webkit_navigation_policy_decision_get_navigation_action 
(navigation_decision);
+      WebKitURIRequest *request =
+        webkit_navigation_action_get_request (navigation_action);
+      WebKitWebView *newview;
+      struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+      Lisp_Object val, new_xwidget;
+
+      XSETXWIDGET (val, xw);
+
+      new_xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
+                                  make_fixnum (0), Qnil,
+                                  build_string (" *detached xwidget buffer*"),
+                                  val);
+
+      if (NILP (new_xwidget))
+       return FALSE;
+
+      newview = WEBKIT_WEB_VIEW (XXWIDGET (new_xwidget)->widget_osr);
+      webkit_web_view_load_request (newview, request);
+
+      store_xwidget_display_event (XXWIDGET (new_xwidget));
+      return TRUE;
+    }
   case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
     {
       WebKitNavigationPolicyDecision *navigation_decision =
@@ -499,49 +1252,64 @@ webkit_decide_policy_cb (WebKitWebView *webView,
   }
 }
 
-
-/* For gtk3 offscreen rendered widgets.  */
 static gboolean
-xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
+webkit_script_dialog_cb (WebKitWebView *webview,
+                        WebKitScriptDialog *script_dialog,
+                        gpointer user)
 {
-  struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
-  struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget),
-                                               XG_XWIDGET_VIEW);
+  struct frame *f = SELECTED_FRAME ();
+  WebKitScriptDialogType type;
+  GtkWidget *widget;
+  GtkWidget *dialog;
+  GtkWidget *entry;
+  GtkWidget *content_area;
+  const gchar *content;
+  const gchar *message;
+  gint result;
+
+  /* Return TRUE to prevent WebKit from showing the default script
+     dialog in the offscreen window, which runs a nested main loop
+     Emacs can't respond to, and as such can't pass X events to.  */
+  if (!FRAME_WINDOW_P (f))
+    return TRUE;
+
+  type = webkit_script_dialog_get_dialog_type (script_dialog);;
+  widget = FRAME_GTK_OUTER_WIDGET (f);
+  content = webkit_script_dialog_get_message (script_dialog);
+
+  if (type == WEBKIT_SCRIPT_DIALOG_ALERT)
+    dialog = gtk_dialog_new_with_buttons (content, GTK_WINDOW (widget),
+                                         GTK_DIALOG_MODAL,
+                                         "Dismiss", 1, NULL);
+  else
+    dialog = gtk_dialog_new_with_buttons (content, GTK_WINDOW (widget),
+                                         GTK_DIALOG_MODAL,
+                                         "OK", 0, "Cancel", 1, NULL);
 
-  cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom);
-  cairo_clip (cr);
+  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
+    {
+      entry = gtk_entry_new ();
+      message = webkit_script_dialog_prompt_get_default_text (script_dialog);
+      content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
-  gtk_widget_draw (xw->widget_osr, cr);
-  return FALSE;
-}
+      gtk_widget_show (entry);
+      gtk_entry_set_text (GTK_ENTRY (entry), message);
+      gtk_container_add (GTK_CONTAINER (content_area), entry);
+    }
 
-static gboolean
-xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event,
-                          gpointer user_data)
-{
-  /* Copy events that arrive at the outer widget to the offscreen widget.  */
-  struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
-  GdkEvent *eventcopy = gdk_event_copy (event);
-  eventcopy->any.window = gtk_widget_get_window (xw->widget_osr);
+  result = gtk_dialog_run (GTK_DIALOG (dialog));
 
-  /* TODO: This might leak events.  They should be deallocated later,
-     perhaps in xwgir_event_cb.  */
-  gtk_main_do_event (eventcopy);
+  if (type == WEBKIT_SCRIPT_DIALOG_CONFIRM
+      || type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM)
+    webkit_script_dialog_confirm_set_confirmed (script_dialog, result == 0);
 
-  /* Don't propagate this event further.  */
-  return TRUE;
-}
+  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
+    webkit_script_dialog_prompt_set_text (script_dialog,
+                                         gtk_entry_get_text (GTK_ENTRY 
(entry)));
 
-static gboolean
-xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event,
-                               gpointer data)
-{
-  struct xwidget_view *xv = data;
-  struct xwidget *xww = XXWIDGET (xv->model);
-  gdk_offscreen_window_set_embedder (gtk_widget_get_window
-                                    (xww->widgetwindow_osr),
-                                     gtk_widget_get_window (xv->widget));
-  return FALSE;
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+
+  return TRUE;
 }
 #endif /* USE_GTK */
 
@@ -568,63 +1336,19 @@ xwidget_init_view (struct xwidget *xww,
   XSETXWIDGET (xv->model, xww);
 
 #ifdef USE_GTK
-  if (EQ (xww->type, Qwebkit))
-    {
-      xv->widget = gtk_drawing_area_new ();
-      /* Expose event handling.  */
-      gtk_widget_set_app_paintable (xv->widget, TRUE);
-      gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
+  xv->dpy = FRAME_X_DISPLAY (s->f);
 
-      /* Draw the view on damage-event.  */
-      g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
-                        G_CALLBACK (offscreen_damage_event), xv->widget);
-
-      if (EQ (xww->type, Qwebkit))
-        {
-          g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
-                            G_CALLBACK (xwidget_osr_event_forward), NULL);
-          g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
-                            G_CALLBACK (xwidget_osr_event_forward), NULL);
-          g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
-                            G_CALLBACK (xwidget_osr_event_forward), NULL);
-        }
-      else
-        {
-          /* xwgir debug, orthogonal to forwarding.  */
-          g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
-                            G_CALLBACK (xwidget_osr_event_set_embedder), xv);
-        }
-      g_signal_connect (G_OBJECT (xv->widget), "draw",
-                        G_CALLBACK (xwidget_osr_draw_cb), NULL);
-    }
-
-  /* Widget realization.
-
-     Make container widget first, and put the actual widget inside the
-     container later.  Drawing should crop container window if necessary
-     to handle case where xwidget is partially obscured by other Emacs
-     windows.  Other containers than gtk_fixed where explored, but
-     gtk_fixed had the most predictable behavior so far.  */
-
-  xv->emacswindow = FRAME_GTK_WIDGET (s->f);
-  xv->widgetwindow = gtk_fixed_new ();
-  gtk_widget_set_has_window (xv->widgetwindow, TRUE);
-  gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
-
-  /* Store some xwidget data in the gtk widgets.  */
-  g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f);
-  g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww);
-  g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv);
-  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww);
-  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv);
-
-  gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
-                               xww->height);
-  gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
-  gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
   xv->x = x;
   xv->y = y;
-  gtk_widget_show_all (xv->widgetwindow);
+
+  xv->clip_left = 0;
+  xv->clip_right = xww->width;
+  xv->clip_top = 0;
+  xv->clip_bottom = xww->height;
+
+  xv->wdesc = None;
+  xv->frame = s->f;
+  xv->cursor = cursor_for_hit (xww->hit_result, s->f);
 #elif defined NS_IMPL_COCOA
   nsxwidget_init_view (xv, xww, s, x, y);
   nsxwidget_resize_view(xv, xww->width, xww->height);
@@ -681,19 +1405,6 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
   window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y,
               &text_area_width, &text_area_height);
 
-  /* Resize xwidget webkit if its container window size is changed in
-     some ways, for example, a buffer became hidden in small split
-     window, then it can appear front in merged whole window.  */
-  if (EQ (xww->type, Qwebkit)
-      && (xww->width != text_area_width || xww->height != text_area_height))
-    {
-      Lisp_Object xwl;
-      XSETXWIDGET (xwl, xww);
-      Fxwidget_resize (xwl,
-                       make_int (text_area_width),
-                       make_int (text_area_height));
-    }
-
   clip_left = max (0, text_area_x - x);
   clip_right = max (clip_left,
                    min (xww->width, text_area_x + text_area_width - x));
@@ -711,15 +1422,51 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
      later.  */
   bool moved = (xv->x + xv->clip_left != x + clip_left
                || xv->y + xv->clip_top != y + clip_top);
+
+#ifdef USE_GTK
+  bool wdesc_was_none = xv->wdesc == None;
+#endif
   xv->x = x;
   xv->y = y;
 
+#ifdef USE_GTK
+  block_input ();
+  if (xv->wdesc == None)
+    {
+      Lisp_Object xvw;
+      XSETXWIDGET_VIEW (xvw, xv);
+      XSetWindowAttributes a;
+      a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask
+                     | PointerMotionMask | EnterWindowMask | LeaveWindowMask);
+
+      xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f),
+                                x + clip_left, y + clip_top,
+                                clip_right - clip_left,
+                                clip_bottom - clip_top, 0,
+                                CopyFromParent, CopyFromParent,
+                                CopyFromParent, CWEventMask, &a);
+      XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
+      xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
+                                                 xv->wdesc,
+                                                 FRAME_DISPLAY_INFO 
(s->f)->visual,
+                                                 clip_right - clip_left,
+                                                 clip_bottom - clip_top);
+      xv->cr_context = cairo_create (xv->cr_surface);
+      Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map);
+
+      moved = false;
+    }
+#endif
+
   /* Has it moved?  */
   if (moved)
     {
 #ifdef USE_GTK
-      gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
-                      xv->widgetwindow, x + clip_left, y + clip_top);
+      XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
+                        clip_right - clip_left, clip_bottom - clip_top);
+      XFlush (xv->dpy);
+      cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+                                  clip_bottom - clip_top);
 #elif defined NS_IMPL_COCOA
       nsxwidget_move_view (xv, x + clip_left, y + clip_top);
 #endif
@@ -735,10 +1482,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
       || xv->clip_top != clip_top || xv->clip_left != clip_left)
     {
 #ifdef USE_GTK
-      gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left,
-                                   clip_bottom - clip_top);
-      gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
-                      -clip_top);
+      if (!wdesc_was_none && !moved)
+       {
+         XResizeWindow (xv->dpy, xv->wdesc, clip_right - clip_left,
+                        clip_bottom - clip_top);
+         XFlush (xv->dpy);
+         cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
+                                      clip_bottom - clip_top);
+       }
 #elif defined NS_IMPL_COCOA
       nsxwidget_resize_view (xv, clip_right - clip_left,
                              clip_bottom - clip_top);
@@ -758,12 +1509,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
   if (!xwidget_hidden (xv))
     {
 #ifdef USE_GTK
-      gtk_widget_queue_draw (xv->widgetwindow);
-      gtk_widget_queue_draw (xv->widget);
+      gtk_widget_queue_draw (xww->widget_osr);
 #elif defined NS_IMPL_COCOA
       nsxwidget_set_needsdisplay (xv);
 #endif
     }
+
+#ifdef USE_GTK
+  unblock_input ();
+#endif
 }
 
 static bool
@@ -839,7 +1593,11 @@ DEFUN ("xwidget-webkit-goto-uri",
 DEFUN ("xwidget-webkit-goto-history",
        Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
        2, 2, 0,
-       doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse 
history.  */)
+       doc: /* Make the XWIDGET webkit the REL-POSth element in load history.
+
+If REL-POS is 0, the widget will be just reload the current element in
+history.  If REL-POS is more or less than 0, the widget will load the
+REL-POSth element around the current spot in the load history. */)
   (Lisp_Object xwidget, Lisp_Object rel_pos)
 {
   WEBKIT_FN_INIT ();
@@ -849,11 +1607,20 @@ DEFUN ("xwidget-webkit-goto-history",
 
 #ifdef USE_GTK
   WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
-  switch (XFIXNAT (rel_pos))
+  WebKitBackForwardList *list;
+  WebKitBackForwardListItem *it;
+
+  if (XFIXNUM (rel_pos) == 0)
+    webkit_web_view_reload (wkwv);
+  else
     {
-    case -1: webkit_web_view_go_back (wkwv); break;
-    case 0: webkit_web_view_reload (wkwv); break;
-    case 1: webkit_web_view_go_forward (wkwv); break;
+      list = webkit_web_view_get_back_forward_list (wkwv);
+      it = webkit_back_forward_list_get_nth_item (list, XFIXNUM (rel_pos));
+
+      if (!it)
+       error ("There is no item at this index");
+
+      webkit_web_view_go_to_back_forward_list_item (wkwv, it);
     }
 #elif defined NS_IMPL_COCOA
   nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
@@ -960,9 +1727,10 @@ DEFUN ("xwidget-resize", Fxwidget_resize, 
Sxwidget_resize, 3, 3, 0,
     {
       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
                          xw->height);
-      gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
+
+      gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
     }
 #elif defined NS_IMPL_COCOA
   nsxwidget_resize (xw);
@@ -975,16 +1743,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, 
Sxwidget_resize, 3, 3, 0,
           struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
           if (XXWIDGET (xv->model) == xw)
             {
-#ifdef USE_GTK
-              gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
-                                           xw->height);
-#elif defined NS_IMPL_COCOA
-              nsxwidget_resize_view(xv, xw->width, xw->height);
-#endif
+             wset_redisplay (XWINDOW (xv->w));
             }
         }
     }
 
+  redisplay ();
+
   return Qnil;
 }
 
@@ -1084,13 +1849,15 @@ DEFUN ("delete-xwidget-view",
   CHECK_XWIDGET_VIEW (xwidget_view);
   struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
 #ifdef USE_GTK
-  gtk_widget_destroy (xv->widgetwindow);
-  /* xv->model still has signals pointing to the view.  There can be
-     several views.  Find the matching signals and delete them all.  */
-  g_signal_handlers_disconnect_matched  (XXWIDGET 
(xv->model)->widgetwindow_osr,
-                                         G_SIGNAL_MATCH_DATA,
-                                         0, 0, 0, 0,
-                                         xv->widget);
+  if (xv->wdesc != None)
+    {
+      block_input ();
+      cairo_destroy (xv->cr_context);
+      cairo_surface_destroy (xv->cr_surface);
+      XDestroyWindow (xv->dpy, xv->wdesc);
+      Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
+      unblock_input ();
+    }
 #elif defined NS_IMPL_COCOA
   nsxwidget_delete_view (xv);
 #endif
@@ -1145,6 +1912,19 @@ DEFUN ("xwidget-buffer",
   return XXWIDGET (xwidget)->buffer;
 }
 
+DEFUN ("set-xwidget-buffer",
+       Fset_xwidget_buffer, Sset_xwidget_buffer,
+       2, 2, 0,
+       doc: /* Set XWIDGET's buffer to BUFFER.  */)
+  (Lisp_Object xwidget, Lisp_Object buffer)
+{
+  CHECK_XWIDGET (xwidget);
+  CHECK_BUFFER (buffer);
+
+  XXWIDGET (xwidget)->buffer = buffer;
+  return Qnil;
+}
+
 DEFUN ("set-xwidget-plist",
        Fset_xwidget_plist, Sset_xwidget_plist,
        2, 2, 0,
@@ -1183,6 +1963,166 @@ DEFUN ("xwidget-query-on-exit-flag",
   return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
 }
 
+DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
+       2, 5, 0,
+       doc: /* Begin an incremental search operation in an xwidget.
+QUERY should be a string containing the text to search for.  XWIDGET
+should be a WebKit xwidget where the search will take place.  When the
+search operation is complete, callers should also call
+`xwidget-webkit-finish-search' to complete the search operation.
+
+CASE-INSENSITIVE, when non-nil, will cause the search to ignore the
+case of characters inside QUERY.  BACKWARDS, when non-nil, will cause
+the search to proceed towards the beginning of the widget's contents.
+WRAP-AROUND, when nil, will cause the search to stop upon hitting the
+end of the widget's contents.
+
+It is OK to call this function even when a search is already in
+progress.  In that case, the previous search query will be replaced
+with QUERY.  */)
+  (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive,
+   Lisp_Object backwards, Lisp_Object wrap_around)
+{
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+  WebKitFindOptions opt;
+  struct xwidget *xw;
+  gchar *g_query;
+#endif
+
+  CHECK_STRING (query);
+  CHECK_XWIDGET (xwidget);
+
+#ifdef USE_GTK
+  xw = XXWIDGET (xwidget);
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  query = ENCODE_UTF_8 (query);
+  opt = WEBKIT_FIND_OPTIONS_NONE;
+  g_query = xstrdup (SSDATA (query));
+
+  if (!NILP (case_insensitive))
+    opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
+  if (!NILP (backwards))
+    opt |= WEBKIT_FIND_OPTIONS_BACKWARDS;
+  if (!NILP (wrap_around))
+    opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
+
+  if (xw->find_text)
+    xfree (xw->find_text);
+  xw->find_text = g_query;
+
+  block_input ();
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search (controller, g_query, opt, G_MAXUINT);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
+       Sxwidget_webkit_next_result, 1, 1, 0,
+       doc: /* Show the next result matching the current search query.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_next (controller);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
+       Sxwidget_webkit_previous_result, 1, 1, 0,
+       doc: /* Show the previous result matching the current search query.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_previous (controller);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
+       Sxwidget_webkit_finish_search, 1, 1, 0,
+       doc: /* Finish XWIDGET's search operation.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_finish (controller);
+
+  if (xw->find_text)
+    {
+      xfree (xw->find_text);
+      xw->find_text = NULL;
+    }
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
 void
 syms_of_xwidget (void)
 {
@@ -1215,6 +2155,12 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_plist);
   defsubr (&Sxwidget_buffer);
   defsubr (&Sset_xwidget_plist);
+  defsubr (&Sxwidget_perform_lispy_event);
+  defsubr (&Sxwidget_webkit_search);
+  defsubr (&Sxwidget_webkit_finish_search);
+  defsubr (&Sxwidget_webkit_next_result);
+  defsubr (&Sxwidget_webkit_previous_result);
+  defsubr (&Sset_xwidget_buffer);
 
   DEFSYM (QCxwidget, ":xwidget");
   DEFSYM (QCtitle, ":title");
@@ -1236,6 +2182,15 @@ syms_of_xwidget (void)
   Vxwidget_view_list = Qnil;
 
   Fprovide (intern ("xwidget-internal"), Qnil);
+
+  id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq);
+  staticpro (&id_to_xwidget_map);
+
+#ifdef USE_GTK
+  x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq);
+
+  staticpro (&x_window_to_xwv_map);
+#endif
 }
 
 
@@ -1374,7 +2329,7 @@ xwidget_end_redisplay (struct window *w, struct 
glyph_matrix *matrix)
                  /* The only call to xwidget_end_redisplay is in dispnew.
                     xwidget_end_redisplay (w->current_matrix);  */
                  struct xwidget_view *xv
-                   = xwidget_view_lookup (glyph->u.xwidget, w);
+                   = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), 
w);
 #ifdef USE_GTK
                  /* FIXME: Is it safe to assume xwidget_view_lookup
                     always succeeds here?  If so, this comment can be removed.
@@ -1424,6 +2379,25 @@ xwidget_end_redisplay (struct window *w, struct 
glyph_matrix *matrix)
     }
 }
 
+#ifdef USE_GTK
+void
+kill_frame_xwidget_views (struct frame *f)
+{
+  Lisp_Object rem = Qnil;
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail))
+         && XXWIDGET_VIEW (XCAR (tail))->frame == f)
+       rem = Fcons (XCAR (tail), rem);
+    }
+
+  for (; CONSP (rem); rem = XCDR (rem))
+    Fdelete_xwidget_view (XCAR (rem));
+}
+#endif
+
 /* Kill all xwidget in BUFFER.  */
 void
 kill_buffer_xwidgets (Lisp_Object buffer)
@@ -1437,12 +2411,15 @@ kill_buffer_xwidgets (Lisp_Object buffer)
       {
         CHECK_XWIDGET (xwidget);
         struct xwidget *xw = XXWIDGET (xwidget);
+       Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map);
 #ifdef USE_GTK
         if (xw->widget_osr && xw->widgetwindow_osr)
           {
             gtk_widget_destroy (xw->widget_osr);
             gtk_widget_destroy (xw->widgetwindow_osr);
           }
+       if (xw->find_text)
+         xfree (xw->find_text);
        if (!NILP (xw->script_callbacks))
          for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++)
            {
diff --git a/src/xwidget.h b/src/xwidget.h
index 591f23489d..ad8b7c039c 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -32,6 +32,8 @@ struct window;
 
 #if defined (USE_GTK)
 #include <gtk/gtk.h>
+#include <X11/Xlib.h>
+#include "xterm.h"
 #elif defined (NS_IMPL_COCOA) && defined (__OBJC__)
 #import <AppKit/NSView.h>
 #import "nsxwidget.h"
@@ -59,11 +61,14 @@ struct xwidget
 
   int height;
   int width;
+  uint32_t xwidget_id;
+  char *find_text;
 
 #if defined (USE_GTK)
   /* For offscreen widgets, unused if not osr.  */
   GtkWidget *widget_osr;
   GtkWidget *widgetwindow_osr;
+  guint hit_result;
 #elif defined (NS_IMPL_COCOA)
 # ifdef __OBJC__
   /* For offscreen widgets, unused if not osr.  */
@@ -98,9 +103,13 @@ struct xwidget_view
   bool hidden;
 
 #if defined (USE_GTK)
-  GtkWidget *widget;
-  GtkWidget *widgetwindow;
-  GtkWidget *emacswindow;
+  Display *dpy;
+  Window wdesc;
+  Emacs_Cursor cursor;
+  struct frame *frame;
+
+  cairo_surface_t *cr_surface;
+  cairo_t *cr_context;
 #elif defined (NS_IMPL_COCOA)
 # ifdef __OBJC__
   XvWindow *xvWindow;
@@ -162,6 +171,18 @@ void store_xwidget_download_callback_event (struct xwidget 
*xw,
 void store_xwidget_js_callback_event (struct xwidget *xw,
                                       Lisp_Object proc,
                                       Lisp_Object argument);
+
+extern struct xwidget *xwidget_from_id (uint32_t id);
+
+#ifdef HAVE_X_WINDOWS
+struct xwidget_view *xwidget_view_from_window (Window wdesc);
+void xwidget_expose (struct xwidget_view *xv);
+extern void kill_frame_xwidget_views (struct frame *f);
+extern void xwidget_button (struct xwidget_view *, bool, int,
+                           int, int, int, Time);
+extern void xwidget_motion_or_crossing (struct xwidget_view *,
+                                       const XEvent *);
+#endif
 #else
 INLINE_HEADER_BEGIN
 INLINE void syms_of_xwidget (void) {}
diff --git a/test/Makefile.in b/test/Makefile.in
index e0a2b7799a..7bef1c3660 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -77,9 +77,14 @@ EMACSOPT = --no-init-file --no-site-file --no-site-lisp -L 
"$(SEPCHAR)$(srcdir)"
 # Prevent any settings in the user environment causing problems.
 unexport EMACSDATA EMACSDOC EMACSPATH GREP_OPTIONS XDG_CONFIG_HOME
 
-## To run tests under a debugger, set this to eg: "gdb --args".
+# To run tests under a debugger, set this to eg: "gdb --args".
 GDB =
 
+# Whether a timeout shall be given, writing possibly a core dump.
+ifneq (${EMACS_TEST_TIMEOUT},)
+TEST_TIMEOUT = timeout -s ABRT ${EMACS_TEST_TIMEOUT}
+endif
+
 # Set this to 'yes' to run the tests in an interactive instance.
 TEST_INTERACTIVE ?= no
 
@@ -117,7 +122,7 @@ endif
 # and prevent locals to influence the text of the errors we expect to receive.
 emacs = LANG=C EMACSLOADPATH=             \
  EMACS_TEST_DIRECTORY=$(abspath $(srcdir)) \
- $(GDB) "$(EMACS)" $(MODULES_EMACSOPT) $(EMACSOPT)
+ $(GDB) $(TEST_TIMEOUT) "$(EMACS)" $(MODULES_EMACSOPT) $(EMACSOPT)
 
 # Set HOME to a nonexistent directory to prevent tests from accessing
 # it accidentally (e.g., popping up a gnupg dialog if ~/.authinfo.gpg
@@ -167,7 +172,7 @@ lisp/net/tramp-tests.log \
 : WRITE_LOG = 2>&1 | tee $@
 endif
 ifdef EMACS_EMBA_CI
-lisp/filenotify-tests.log lisp/net/tramp-tests.log \
+lisp/filenotify-tests.log lisp/net/tramp-tests.log src/emacs-module-tests.log \
 : WRITE_LOG = 2>&1 | tee $@
 endif
 
diff --git a/test/README b/test/README
index 97611cf864..4d447c9bf1 100644
--- a/test/README
+++ b/test/README
@@ -22,6 +22,10 @@ following tags are recognized:
   to run on a regular basis by users.  Instead, it runs on demand
   only, or during regression tests.
 
+* :nativecomp
+  The test runs only if Emacs is configured with Lisp native compiler
+  support.
+
 * :unstable
   The test is under development.  It shall run on demand only.
 
@@ -136,6 +140,11 @@ these test environments.
 $EMACS_HYDRA_CI indicates the hydra environment, and $EMACS_EMBA_CI
 indicates the emba environment, respectively.
 
+If tests on these premises take too long, and it is needed to create a
+core dump for further analysis, the environment variable
+$EMACS_TEST_TIMEOUT could set a limit (in seconds) when this shall
+happen.
+
 
 (Also, see etc/compilation.txt for compilation mode font lock tests
 and etc/grep.txt for grep mode font lock tests.)
diff --git a/test/data/image/black.gif b/test/data/image/black.gif
new file mode 100644
index 0000000000..6ab623e367
Binary files /dev/null and b/test/data/image/black.gif differ
diff --git a/test/data/image/black.webp b/test/data/image/black.webp
new file mode 100644
index 0000000000..5dbe716415
Binary files /dev/null and b/test/data/image/black.webp differ
diff --git a/test/infra/Dockerfile.emba b/test/infra/Dockerfile.emba
index e79f370f17..aef68c6e81 100644
--- a/test/infra/Dockerfile.emba
+++ b/test/infra/Dockerfile.emba
@@ -28,13 +28,15 @@ FROM debian:stretch as emacs-base
 
 RUN apt-get update && \
     apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \
-      libc-dev gcc g++ make autoconf automake libncurses-dev gnutls-dev git 
texinfo \
+      libc-dev gcc g++ make autoconf automake libncurses-dev gnutls-dev \
+      libdbus-1-dev libacl1-dev acl git texinfo gdb \
     && rm -rf /var/lib/apt/lists/*
 
 FROM emacs-base as emacs-inotify
 
 RUN apt-get update && \
-    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 
inotify-tools \
+    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \
+      inotify-tools \
     && rm -rf /var/lib/apt/lists/*
 
 COPY . /checkout
@@ -43,7 +45,6 @@ RUN ./autogen.sh autoconf
 RUN ./configure
 # 'make -j4 bootstrap' does not work reliably.
 RUN make bootstrap
-RUN make -j4
 
 FROM emacs-base as emacs-filenotify-gio
 
@@ -57,12 +58,12 @@ WORKDIR /checkout
 RUN ./autogen.sh autoconf
 RUN ./configure --with-file-notification=gfile
 RUN make bootstrap
-RUN make -j4
 
 FROM emacs-base as emacs-gnustep
 
 RUN apt-get update && \
-    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 
gnustep-devel \
+    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \
+      gnustep-devel \
     && rm -rf /var/lib/apt/lists/*
 
 COPY . /checkout
@@ -70,19 +71,35 @@ WORKDIR /checkout
 RUN ./autogen.sh autoconf
 RUN ./configure --with-ns
 RUN make bootstrap
-RUN make -j4
 
-FROM emacs-base as emacs-native-comp-speed0
+FROM emacs-base as emacs-native-comp
 
 RUN apt-get update && \
-    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 
libgccjit-6-dev \
+    apt-get install -y --no-install-recommends -o=Dpkg::Use-Pty=0 \
+      libgccjit-6-dev \
     && rm -rf /var/lib/apt/lists/*
 
-ARG make_bootstrap_params=""
+FROM emacs-native-comp as emacs-native-comp-speed0
+
+COPY . /checkout
+WORKDIR /checkout
+RUN ./autogen.sh autoconf
+RUN ./configure --with-native-compilation
+RUN make bootstrap -j2 \
+      NATIVE_FULL_AOT=1 BYTE_COMPILE_EXTRA_FLAGS='--eval "(setq comp-speed 0)"'
+
+FROM emacs-native-comp as emacs-native-comp-speed1
+
+COPY . /checkout
+WORKDIR /checkout
+RUN ./autogen.sh autoconf
+RUN ./configure --with-native-compilation
+RUN make bootstrap -j2 BYTE_COMPILE_EXTRA_FLAGS='--eval "(setq comp-speed 1)"'
+
+FROM emacs-native-comp as emacs-native-comp-speed2
 
 COPY . /checkout
 WORKDIR /checkout
 RUN ./autogen.sh autoconf
 RUN ./configure --with-native-compilation
-RUN make bootstrap -j2 NATIVE_FULL_AOT=1 BYTE_COMPILE_EXTRA_FLAGS='--eval 
"(setq comp-speed 0)"'
-RUN make -j4
+RUN make bootstrap -j2
diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml
index 0b12f96f4c..001c779572 100644
--- a/test/infra/gitlab-ci.yml
+++ b/test/infra/gitlab-ci.yml
@@ -44,13 +44,18 @@ workflow:
 variables:
   GIT_STRATEGY: fetch
   EMACS_EMBA_CI: 1
+  # Three hours, see below.
+  EMACS_TEST_TIMEOUT: 10800
   EMACS_TEST_VERBOSE: 1
   # # Use TLS 
https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
   # DOCKER_HOST: tcp://docker:2376
   # DOCKER_TLS_CERTDIR: "/certs"
-  # Put the configuration for each run in a separate directory to avoid 
conflicts
+  # Put the configuration for each run in a separate directory to
+  # avoid conflicts.
   DOCKER_CONFIG: "/.docker-config-${CI_COMMIT_SHA}"
-  # We don't use ${CI_COMMIT_SHA} to be able to do one bootstrap across 
multiple builds
+  DOCKER_BUILDKIT: 1
+  # We don't use ${CI_COMMIT_SHA} to be able to do one bootstrap
+  # across multiple builds.
   BUILD_TAG: ${CI_COMMIT_REF_SLUG}
 
 default:
@@ -66,57 +71,61 @@ default:
     test_name: ${CI_JOB_NAME}-${CI_COMMIT_SHORT_SHA}
   rules:
     - changes:
-        - "**/Makefile.in"
+        - "**Makefile.in"
         - .gitlab-ci.yml
         - aclocal.m4
         - autogen.sh
         - configure.ac
         - lib/*.{h,c}
-        - lisp/**/*.el
+        - lisp/**.el
         - src/*.{h,c}
         - test/infra/*
         - test/lib-src/*.el
-        - test/lisp/**/*.el
+        - test/lisp/**.el
+        - test/misc/*.el
         - test/src/*.el
     - changes:
         # gfilemonitor, kqueue
         - src/gfilenotify.c
         - src/kqueue.c
         # MS Windows
-        - "**/w32*"
+        - "**w32*"
         # GNUstep
         - lisp/term/ns-win.el
         - src/ns*.{h,m}
         - src/macfont.{h,m}
       when: never
-  # these will be cached across builds
+  # These will be cached across builds.
   cache:
     key: ${CI_COMMIT_SHA}
     paths: []
     policy: pull-push
-  # these will be saved for followup builds
+  # These will be saved for followup builds.
   artifacts:
     expire_in: 24 hrs
     paths: []
-  # using the variables for each job
+  # Using the variables for each job.
   script:
     - docker pull ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG}
-    # TODO: with make -j4 several of the tests were failing, for example 
shadowfile-tests, but passed without it
+    # TODO: with make -j4 several of the tests were failing, for
+    # example shadowfile-tests, but passed without it.
     - 'export PWD=$(pwd)'
-    - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} --volumes-from $(docker 
ps -q -f "label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name 
${test_name} ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git 
fetch ${PWD} HEAD && echo checking out these updated files && git diff 
--name-only FETCH_HEAD && ( git diff --name-only FETCH_HEAD | xargs git 
checkout -f FETCH_HEAD ) && make -j4 && make ${make_params}"'
+    - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e 
EMACS_TEST_TIMEOUT=${EMACS_TEST_TIMEOUT} -e 
EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f 
"label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} 
${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD 
&& echo checking out these updated files && git diff --name-only FETCH_HEAD && 
( git diff --name-only FETCH_HEAD | xargs git checkout -f FETCH_HEAD ) && make 
- [...]
   after_script:
     # - docker ps -a
     # - printenv
     # - test -n "$(docker ps -aq -f name=${test_name})" && ( docker export 
${test_name} | tar -tvf - )
     - test -n "$(docker ps -aq -f name=${test_name})" && docker cp 
${test_name}:checkout/test ${test_name}
     - test -n "$(docker ps -aq -f name=${test_name})" && docker rm ${test_name}
+    # - ls -alR ${test_name}
 
 .build-template:
+  needs: []
   rules:
     - if: '$CI_PIPELINE_SOURCE == "web"'
       when: always
     - changes:
-        - "**/Makefile.in"
+        - "**Makefile.in"
         - .gitlab-ci.yml
         - aclocal.m4
         - autogen.sh
@@ -130,7 +139,7 @@ default:
         - src/gfilenotify.c
         - src/kqueue.c
         # MS Windows
-        - "**/w32*"
+        - "**w32*"
         # GNUstep
         - lisp/term/ns-win.el
         - src/ns*.{h,m}
@@ -141,7 +150,7 @@ default:
     - docker push ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG}
 
 .test-template:
-  # Do not run fast and normal test jobs when scheduled
+  # Do not run fast and normal test jobs when scheduled.
   rules:
     - if: '$CI_JOB_STAGE =~ "fast|normal" && $CI_PIPELINE_SOURCE == "schedule"'
       when: never
@@ -151,20 +160,23 @@ default:
     public: true
     expire_in: 1 week
     paths:
-      - "${test_name}/**/*.log"
+      - ${test_name}/**/*.log
+      - ${test_name}/**/core
+      - ${test_name}/core
+    when: always
 
 .gnustep-template:
   rules:
     - if: '$CI_PIPELINE_SOURCE == "web"'
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
       changes:
-        - "**/Makefile.in"
+        - "**Makefile.in"
         - .gitlab-ci.yml
         - configure.ac
         - src/ns*.{h,m}
         - src/macfont.{h,m}
         - lisp/term/ns-win.el
-        - nextstep/**/*
+        - nextstep/**
         - test/infra/*
 
 .filenotify-gio-template:
@@ -172,7 +184,7 @@ default:
     - if: '$CI_PIPELINE_SOURCE == "web"'
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
       changes:
-        - "**/Makefile.in"
+        - "**Makefile.in"
         - .gitlab-ci.yml
         - lisp/autorevert.el
         - lisp/filenotify.el
@@ -187,7 +199,7 @@ default:
     - if: '$CI_PIPELINE_SOURCE == "web"'
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
       changes:
-        - "**/Makefile.in"
+        - "**Makefile.in"
         - .gitlab-ci.yml
         - lisp/emacs-lisp/comp.el
         - lisp/emacs-lisp/comp-cstr.el
@@ -198,7 +210,6 @@ default:
   timeout: 8 hours
 
 stages:
-  - prep-images
   - build-images
 #  - fast
   - normal
@@ -208,18 +219,13 @@ stages:
   - native-comp
   - slow
 
-prep-image-base:
-  stage: prep-images
-  extends: [.job-template, .build-template]
-  variables:
-    target: emacs-base
-
 build-image-inotify:
   stage: build-images
   extends: [.job-template, .build-template]
-  needs: [prep-image-base]
   variables:
     target: emacs-inotify
+# Temporarily.
+  timeout: 8 hours
 
 # test-fast-inotify:
 #   stage: fast
@@ -245,14 +251,12 @@ test-lisp-net-inotify:
 build-image-filenotify-gio:
   stage: platform-images
   extends: [.job-template, .build-template, .filenotify-gio-template]
-  needs: [prep-image-base]
   variables:
     target: emacs-filenotify-gio
 
 build-image-gnustep:
   stage: platform-images
   extends: [.job-template, .build-template, .gnustep-template]
-  needs: [prep-image-base]
   variables:
     target: emacs-gnustep
 
@@ -266,7 +270,7 @@ test-filenotify-gio:
     make_params: "-k -C test autorevert-tests.log filenotify-tests.log"
 
 test-gnustep:
-  # This tests the GNUstep build process
+  # This tests the GNUstep build process.
   stage: platforms
   needs: [build-image-gnustep]
   extends: [.job-template, .gnustep-template]
@@ -274,56 +278,48 @@ test-gnustep:
     target: emacs-gnustep
     make_params: install
 
-build-native-bootstrap-speed0:
+build-native-comp-speed0:
   stage: native-comp-images
   extends: [.job-template, .build-template, .native-comp-template]
-  needs: [prep-image-base]
   variables:
     target: emacs-native-comp-speed0
 
-# build-native-bootstrap-speed0:
-#   # Test a full native bootstrap
-#   # Run for now only speed 0 to limit memory usage and compilation time.
-#   stage: native-comp-images
-#   # Uncomment the following to run it only when scheduled.
-#   # only:
-#   #   - schedules
-#   script:
-#     - DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends -y 
-qq -o=Dpkg::Use-Pty=0 libgccjit-6-dev
-#     - ./autogen.sh autoconf
-#     - ./configure --with-native-compilation
-#     - make bootstrap NATIVE_FULL_AOT=1 BYTE_COMPILE_EXTRA_FLAGS='--eval 
"(setq comp-speed 0)"' -j2
-#   timeout: 8 hours
+build-native-comp-speed1:
+  stage: native-comp-images
+  extends: [.job-template, .build-template, .native-comp-template]
+  variables:
+    target: emacs-native-comp-speed1
 
-# build-native-bootstrap-speed1:
-#   stage: native-comp-images
-#   script:
-#     - DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends -y 
-qq -o=Dpkg::Use-Pty=0 libgccjit-6-dev
-#     - ./autogen.sh autoconf
-#     - ./configure --with-native-compilation
-#     - make bootstrap BYTE_COMPILE_EXTRA_FLAGS='--eval "(setq comp-speed 1)"'
-#   timeout: 8 hours
+build-native-comp-speed2:
+  stage: native-comp-images
+  extends: [.job-template, .build-template, .native-comp-template]
+  variables:
+    target: emacs-native-comp-speed2
 
-# build-native-bootstrap-speed2:
-#   stage: native-comp-images
-#   script:
-#     - DEBIAN_FRONTEND=noninteractive apt install --no-install-recommends -y 
-qq -o=Dpkg::Use-Pty=0 libgccjit-6-dev
-#     - ./autogen.sh autoconf
-#     - ./configure --with-native-compilation
-#     - make bootstrap
-#   timeout: 8 hours
+test-native-comp-speed0:
+  stage: native-comp
+  needs: [build-native-comp-speed0]
+  extends: [.job-template, .test-template, .native-comp-template]
+  variables:
+    target: emacs-native-comp-speed0
+    make_params: >-
+      -C test check EXCLUDE_TESTS=%emacs-module-tests.el
+         SELECTOR='(not (tag :unstable))'
 
 test-all-inotify:
   # This tests also file monitor libraries inotify and inotifywatch.
   stage: slow
+  needs: [build-image-inotify]
   extends: [.job-template, .test-template]
   rules:
-    # note there's no "changes" section, so this always runs on a schedule
+    # Note there's no "changes" section, so this always runs on a schedule.
     - if: '$CI_PIPELINE_SOURCE == "web"'
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
   variables:
     target: emacs-inotify
-    make_params: check-expensive
+    make_params: check-expensive EXCLUDE_TESTS=%emacs-module-tests.el
+    # Two hours.
+    EMACS_TEST_TIMEOUT: 7200
 
 # Local Variables:
 # add-log-current-defun-header-regexp: "^\\([-_.[:alnum:]]+\\)[ \t]*:"
diff --git a/test/lisp/abbrev-tests.el b/test/lisp/abbrev-tests.el
index 2dcfb1c309..863806af7b 100644
--- a/test/lisp/abbrev-tests.el
+++ b/test/lisp/abbrev-tests.el
@@ -28,6 +28,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'abbrev)
 (require 'seq)
 
@@ -236,44 +237,41 @@
 
 (ert-deftest read-write-abbrev-file-test ()
   "Test reading and writing abbrevs from file."
-  (let ((temp-test-file (make-temp-file "ert-abbrev-test"))
-        (ert-test-abbrevs (setup-test-abbrev-table)))
-    (write-abbrev-file temp-test-file)
-    (clear-abbrev-table ert-test-abbrevs)
-    (should (abbrev-table-empty-p ert-test-abbrevs))
-    (read-abbrev-file temp-test-file)
-    (should (equal "abbrev-ert-test" (abbrev-expansion "a-e-t" 
ert-test-abbrevs)))
-    (delete-file temp-test-file)))
+  (ert-with-temp-file temp-test-file
+    (let ((ert-test-abbrevs (setup-test-abbrev-table)))
+      (write-abbrev-file temp-test-file)
+      (clear-abbrev-table ert-test-abbrevs)
+      (should (abbrev-table-empty-p ert-test-abbrevs))
+      (read-abbrev-file temp-test-file)
+      (should (equal "abbrev-ert-test" (abbrev-expansion "a-e-t" 
ert-test-abbrevs))))))
 
 (ert-deftest read-write-abbrev-file-test-with-props ()
   "Test reading and writing abbrevs from file."
-  (let ((temp-test-file (make-temp-file "ert-abbrev-test"))
-        (ert-test-abbrevs (setup-test-abbrev-table-with-props)))
-    (write-abbrev-file temp-test-file)
-    (clear-abbrev-table ert-test-abbrevs)
-    (should (abbrev-table-empty-p ert-test-abbrevs))
-    (read-abbrev-file temp-test-file)
-    (should (equal "fooBar" (abbrev-expansion "fb" ert-test-abbrevs)))
-    (delete-file temp-test-file)))
+  (ert-with-temp-file temp-test-file
+    (let ((ert-test-abbrevs (setup-test-abbrev-table-with-props)))
+      (write-abbrev-file temp-test-file)
+      (clear-abbrev-table ert-test-abbrevs)
+      (should (abbrev-table-empty-p ert-test-abbrevs))
+      (read-abbrev-file temp-test-file)
+      (should (equal "fooBar" (abbrev-expansion "fb" ert-test-abbrevs))))))
 
 (ert-deftest abbrev-edit-save-to-file-test ()
   "Test saving abbrev definitions in buffer to file."
   (defvar ert-save-test-table nil)
-  (let ((temp-test-file (make-temp-file "ert-abbrev-test"))
-        (ert-test-abbrevs (setup-test-abbrev-table)))
-    (with-temp-buffer
-      (goto-char (point-min))
-      (insert "(ert-save-test-table)\n")
-      (insert "\n" "\"s-a-t\"\t" "0\t" "\"save-abbrevs-test\"\n")
-      (should (equal "abbrev-ert-test"
-                     (abbrev-expansion "a-e-t" ert-test-abbrevs)))
-      ;; clears abbrev tables
-      (abbrev-edit-save-to-file temp-test-file)
-      (should-not (abbrev-expansion "a-e-t" ert-test-abbrevs))
-      (read-abbrev-file temp-test-file)
-      (should (equal "save-abbrevs-test"
-                     (abbrev-expansion "s-a-t" ert-save-test-table)))
-      (delete-file temp-test-file))))
+  (ert-with-temp-file temp-test-file
+    (let ((ert-test-abbrevs (setup-test-abbrev-table)))
+      (with-temp-buffer
+        (goto-char (point-min))
+        (insert "(ert-save-test-table)\n")
+        (insert "\n" "\"s-a-t\"\t" "0\t" "\"save-abbrevs-test\"\n")
+        (should (equal "abbrev-ert-test"
+                       (abbrev-expansion "a-e-t" ert-test-abbrevs)))
+        ;; clears abbrev tables
+        (abbrev-edit-save-to-file temp-test-file)
+        (should-not (abbrev-expansion "a-e-t" ert-test-abbrevs))
+        (read-abbrev-file temp-test-file)
+        (should (equal "save-abbrevs-test"
+                       (abbrev-expansion "s-a-t" ert-save-test-table)))))))
 
 (ert-deftest inverse-add-abbrev-skips-trailing-nonword ()
   "Test that adding an inverse abbrev skips trailing nonword characters."
diff --git a/test/lisp/ansi-color-tests.el b/test/lisp/ansi-color-tests.el
index 107dc8e400..14a14ca4f0 100644
--- a/test/lisp/ansi-color-tests.el
+++ b/test/lisp/ansi-color-tests.el
@@ -3,7 +3,6 @@
 ;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
 
 ;; Author: Pablo Barbáchano <pablob@amazon.com>
-;; Keywords: ansi
 
 ;; This file is part of GNU Emacs.
 
@@ -25,24 +24,154 @@
 ;;; Code:
 
 (require 'ansi-color)
+(eval-when-compile (require 'cl-lib))
 
-(defvar test-strings '(("\e[33mHello World\e[0m" . "Hello World")
-                       ("\e[1m\e[3m\e[5mbold italics blink\e[0m" . "bold 
italics blink")))
+(defvar ansi-color-tests--strings
+  (let ((bright-yellow (face-foreground 'ansi-color-bright-yellow nil 
'default))
+        (yellow (face-foreground 'ansi-color-yellow nil 'default))
+        (custom-color "#87FFFF"))
+    `(("Hello World" "Hello World")
+      ("\e[33mHello World\e[0m" "Hello World"
+       (:foreground ,yellow))
+      ("\e[43mHello World\e[0m" "Hello World"
+       (:background ,yellow))
+      ("\e[93mHello World\e[0m" "Hello World"
+       (:foreground ,bright-yellow))
+      ("\e[103mHello World\e[0m" "Hello World"
+       (:background ,bright-yellow))
+      ("\e[1;33mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:foreground ,yellow))
+       (ansi-color-bold (:foreground ,bright-yellow)))
+      ("\e[33;1mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:foreground ,yellow))
+       (ansi-color-bold (:foreground ,bright-yellow)))
+      ("\e[1m\e[33mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:foreground ,yellow))
+       (ansi-color-bold (:foreground ,bright-yellow)))
+      ("\e[33m\e[1mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:foreground ,yellow))
+       (ansi-color-bold (:foreground ,bright-yellow)))
+      ("\e[1m\e[3m\e[5mbold italics blink\e[0m" "bold italics blink"
+       (ansi-color-bold ansi-color-italic ansi-color-slow-blink))
+      ("\e[10munrecognized\e[0m" "unrecognized")
+      ("\e[38;5;3;1mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:foreground ,yellow))
+       (ansi-color-bold (:foreground ,bright-yellow)))
+      ("\e[48;5;123;1mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:background ,custom-color)))
+      ("\e[48;2;135;255;255;1mHello World\e[0m" "Hello World"
+       (ansi-color-bold (:background ,custom-color))))))
+
+(defun ansi-color-tests-equal-props (o1 o2)
+  "Return t if two Lisp objects have similar structure and contents.
+While `equal-including-properties' compares text properties of
+strings with `eq', this function compares them with `equal'."
+  (or (equal-including-properties o1 o2)
+      (and (stringp o1)
+           (equal o1 o2)
+           (cl-loop for i below (length o1)
+                    always (equal (text-properties-at i o1)
+                                  (text-properties-at i o2))))))
 
 (ert-deftest ansi-color-apply-on-region-test ()
-    (dolist (pair test-strings)
-      (with-temp-buffer
-        (insert (car pair))
+  (pcase-dolist (`(,input ,text ,face) ansi-color-tests--strings)
+    (with-temp-buffer
+      (insert input)
+      (ansi-color-apply-on-region (point-min) (point-max))
+      (should (equal (buffer-string) text))
+      (should (equal (get-char-property (point-min) 'face) face))
+      (when face
+        (should (overlays-at (point-min)))))))
+
+(ert-deftest ansi-color-apply-on-region-bold-is-bright-test ()
+  (pcase-dolist (`(,input ,text ,normal-face ,bright-face)
+                 ansi-color-tests--strings)
+    (with-temp-buffer
+      (let ((ansi-color-bold-is-bright t)
+            (face (or bright-face normal-face)))
+        (insert input)
         (ansi-color-apply-on-region (point-min) (point-max))
-        (should (equal (buffer-string) (cdr pair)))
-        (should (not (equal (overlays-at (point-min)) nil))))))
+        (should (equal (buffer-string) text))
+        (should (equal (get-char-property (point-min) 'face) face))
+        (when face
+          (should (overlays-at (point-min))))))))
 
 (ert-deftest ansi-color-apply-on-region-preserving-test ()
-    (dolist (pair test-strings)
-      (with-temp-buffer
-        (insert (car pair))
-        (ansi-color-apply-on-region (point-min) (point-max) t)
-        (should (equal (buffer-string) (car pair))))))
+  (dolist (pair ansi-color-tests--strings)
+    (with-temp-buffer
+      (insert (car pair))
+      (ansi-color-apply-on-region (point-min) (point-max) t)
+      (should (equal (buffer-string) (car pair))))))
+
+(ert-deftest ansi-color-incomplete-sequences-test ()
+  (let* ((strs (list "\e[" "2;31m Hello World "
+                     "\e" "[108;5;12" "3m" "Greetings"
+                     "\e[0m\e[35;6m" "Hello"))
+         (complete-str (apply #'concat strs))
+         (filtered-str)
+         (propertized-str)
+         (ansi-color-apply-face-function
+          #'ansi-color-apply-text-property-face)
+         (ansi-filt (lambda (str) (ansi-color-filter-apply
+                                   (copy-sequence str))))
+         (ansi-app (lambda (str) (ansi-color-apply
+                                  (copy-sequence str)))))
+
+    (with-temp-buffer
+      (setq filtered-str
+            (replace-regexp-in-string "\e\\[.*?m" "" complete-str))
+      (setq propertized-str (funcall ansi-app complete-str))
+
+      (should-not (ansi-color-tests-equal-props
+                   filtered-str propertized-str))
+      (should (equal filtered-str propertized-str)))
+
+    ;; Tests for `ansi-color-filter-apply'
+    (with-temp-buffer
+      (should (equal-including-properties
+               filtered-str
+               (funcall ansi-filt complete-str))))
+
+    (with-temp-buffer
+      (should (equal-including-properties
+               filtered-str
+               (mapconcat ansi-filt strs ""))))
+
+    ;; Tests for `ansi-color-filter-region'
+    (with-temp-buffer
+      (insert complete-str)
+      (ansi-color-filter-region (point-min) (point-max))
+      (should (equal-including-properties
+               filtered-str (buffer-string))))
+
+    (with-temp-buffer
+      (dolist (str strs)
+        (let ((opoint (point)))
+          (insert str)
+          (ansi-color-filter-region opoint (point))))
+      (should (equal-including-properties
+               filtered-str (buffer-string))))
+
+    ;; Test for `ansi-color-apply'
+    (with-temp-buffer
+      (should (ansi-color-tests-equal-props
+               propertized-str
+               (mapconcat ansi-app strs ""))))
+
+    ;; Tests for `ansi-color-apply-on-region'
+    (with-temp-buffer
+      (insert complete-str)
+      (ansi-color-apply-on-region (point-min) (point-max))
+      (should (ansi-color-tests-equal-props
+               propertized-str (buffer-string))))
+
+    (with-temp-buffer
+      (dolist (str strs)
+        (let ((opoint (point)))
+          (insert str)
+          (ansi-color-apply-on-region opoint (point))))
+      (should (ansi-color-tests-equal-props
+               propertized-str (buffer-string))))))
 
 (provide 'ansi-color-tests)
 
diff --git a/test/lisp/auth-source-pass-tests.el 
b/test/lisp/auth-source-pass-tests.el
index a0a97eca5e..3da6f3e9b7 100644
--- a/test/lisp/auth-source-pass-tests.el
+++ b/test/lisp/auth-source-pass-tests.el
@@ -97,7 +97,8 @@ This function is intended to be set to `auth-source-debug'."
 (defun auth-source-pass--explain-match-entry-p (entry hostname &optional user 
port)
   "Explainer function for `auth-source-pass-match-entry-p'.
 
-ENTRY, HOSTNAME, USER and PORT are the same as in 
`auth-source-pass-match-entry-p'."
+ENTRY, HOSTNAME, USER and PORT are the same as in
+`auth-source-pass-match-entry-p'."
   `(entry
     ,entry
     store
@@ -122,7 +123,8 @@ HOSTNAME, USER and PORT are passed unchanged to
 (defun auth-source-pass--explain-includes-sorted-entries (entries hostname 
&optional user port)
   "Explainer function for `auth-source-pass--includes-sorted-entries'.
 
-ENTRIES, HOSTNAME, USER and PORT are the same as in 
`auth-source-pass--includes-sorted-entries'."
+ENTRIES, HOSTNAME, USER and PORT are the same as in
+`auth-source-pass--includes-sorted-entries'."
   `(store
     ,(auth-source-pass-entries)
     matching-entries
diff --git a/test/lisp/auth-source-tests.el b/test/lisp/auth-source-tests.el
index 5140970b0b..34c68b421c 100644
--- a/test/lisp/auth-source-tests.el
+++ b/test/lisp/auth-source-tests.el
@@ -27,6 +27,7 @@
 ;;; Code:
 
 (require 'ert)
+(eval-when-compile (require 'ert-x))
 (require 'cl-lib)
 (require 'auth-source)
 (require 'secrets)
@@ -277,34 +278,33 @@
                    "((:host \"a1\" :port \"a2\" :user \"a3\" :secret \"a4\") 
(:host \"b1\" :port \"b2\" :user \"b3\" :secret \"b4\") (:host \"c1\" :port 
\"c2\" :user \"c3\" :secret \"c4\"))"
                    :host t :max 4)
                   ("host b1, default max is 1"
-                  "((:host \"b1\" :port \"b2\" :user \"b3\" :secret \"b4\"))"
+                   "((:host \"b1\" :port \"b2\" :user \"b3\" :secret \"b4\"))"
                    :host "b1")
                   ("host b1, port b2, user b3, default max is 1"
-                  "((:host \"b1\" :port \"b2\" :user \"b3\" :secret \"b4\"))"
+                   "((:host \"b1\" :port \"b2\" :user \"b3\" :secret \"b4\"))"
                    :host "b1" :port "b2" :user "b3")
-                  ))
-
-         (netrc-file (make-temp-file "auth-source-test" nil nil
-                                     (mapconcat 'identity entries "\n")))
-         (auth-sources (list netrc-file))
-         (auth-source-do-cache nil)
-         found found-as-string)
-
-    (dolist (test tests)
-      (cl-destructuring-bind (testname needed &rest parameters) test
-        (setq found (apply #'auth-source-search parameters))
-        (when (listp found)
-          (dolist (f found)
-            (setf f (plist-put f :secret
-                              (let ((secret (plist-get f :secret)))
-                                (if (functionp secret)
-                                    (funcall secret)
-                                  secret))))))
-
-        (setq found-as-string (format "%s: %S" testname found))
-        ;; (message "With parameters %S found: [%s] needed: [%s]" parameters 
found-as-string needed)
-        (should (equal found-as-string (concat testname ": " needed)))))
-    (delete-file netrc-file)))
+                  )))
+    (ert-with-temp-file netrc-file
+      :text (mapconcat 'identity entries "\n")
+      (let ((auth-sources (list netrc-file))
+            (auth-source-do-cache nil)
+            found found-as-string)
+
+        (dolist (test tests)
+          (cl-destructuring-bind (testname needed &rest parameters) test
+            (setq found (apply #'auth-source-search parameters))
+            (when (listp found)
+              (dolist (f found)
+                (setf f (plist-put f :secret
+                                   (let ((secret (plist-get f :secret)))
+                                     (if (functionp secret)
+                                         (funcall secret)
+                                       secret))))))
+
+            (setq found-as-string (format "%s: %S" testname found))
+            ;; (message "With parameters %S found: [%s] needed: [%s]"
+            ;;          parameters found-as-string needed)
+            (should (equal found-as-string (concat testname ": " 
needed)))))))))
 
 (ert-deftest auth-source-test-secrets-create-secret ()
   (skip-unless secrets-enabled)
@@ -360,77 +360,73 @@
        (format "%s@%s" (plist-get auth-info :user) (plist-get auth-info 
:host))))))
 
 (ert-deftest auth-source-test-netrc-create-secret ()
-  (let* ((netrc-file (make-temp-file "auth-source-test"))
-         (auth-sources (list netrc-file))
-         (auth-source-save-behavior t)
-         host auth-info auth-passwd)
-    (unwind-protect
-        (dolist (passwd '("foo" "" nil))
-          ;; Redefine `read-*' in order to avoid interactive input.
-          (cl-letf (((symbol-function 'read-passwd) (lambda (_) passwd))
-                    ((symbol-function 'read-string)
-                     (lambda (_prompt &optional _initial _history default
-                                      _inherit-input-method)
-                       default)))
-            (setq host
-                  (md5 (concat (prin1-to-string process-environment) passwd))
-                  auth-info
-                  (car (auth-source-search
-                        :max 1 :host host :require '(:user :secret) :create t))
-                 auth-passwd (plist-get auth-info :secret)
-                 auth-passwd (if (functionp auth-passwd)
-                                 (funcall auth-passwd)
-                               auth-passwd))
-            (should (string-equal (plist-get auth-info :user) 
(user-login-name)))
-            (should (string-equal (plist-get auth-info :host) host))
-            (should (equal auth-passwd passwd))
-            (when (functionp (plist-get auth-info :save-function))
-              (funcall (plist-get auth-info :save-function)))
-
-            ;; Check, that the item has been created indeed.
-            (auth-source-forget+ :host t)
-            (setq auth-source-netrc-cache nil)
-            (setq auth-info (car (auth-source-search :host host))
-                 auth-passwd (plist-get auth-info :secret)
-                 auth-passwd (if (functionp auth-passwd)
-                                 (funcall auth-passwd)
-                               auth-passwd))
-            (with-temp-buffer
-              (insert-file-contents netrc-file)
-              (if (zerop (length passwd))
-                  (progn
-                    (should-not (plist-get auth-info :user))
-                    (should-not (plist-get auth-info :host))
-                    (should-not auth-passwd)
-                    (should-not (search-forward host nil 'noerror)))
-                (should
-                 (string-equal (plist-get auth-info :user) (user-login-name)))
-                (should (string-equal (plist-get auth-info :host) host))
-                (should (string-equal auth-passwd passwd))
-                (should (search-forward host nil 'noerror))))))
-
-      ;; Cleanup.
-      (delete-file netrc-file))))
+  (ert-with-temp-file netrc-file
+    :suffix "auth-source-test"
+    (let* ((auth-sources (list netrc-file))
+           (auth-source-save-behavior t)
+           host auth-info auth-passwd)
+      (dolist (passwd '("foo" "" nil))
+        ;; Redefine `read-*' in order to avoid interactive input.
+        (cl-letf (((symbol-function 'read-passwd) (lambda (_) passwd))
+                  ((symbol-function 'read-string)
+                   (lambda (_prompt &optional _initial _history default
+                               _inherit-input-method)
+                     default)))
+          (setq host
+                (md5 (concat (prin1-to-string process-environment) passwd))
+                auth-info
+                (car (auth-source-search
+                      :max 1 :host host :require '(:user :secret) :create t))
+                auth-passwd (plist-get auth-info :secret)
+                auth-passwd (if (functionp auth-passwd)
+                                (funcall auth-passwd)
+                              auth-passwd))
+          (should (string-equal (plist-get auth-info :user) (user-login-name)))
+          (should (string-equal (plist-get auth-info :host) host))
+          (should (equal auth-passwd passwd))
+          (when (functionp (plist-get auth-info :save-function))
+            (funcall (plist-get auth-info :save-function)))
+
+          ;; Check, that the item has been created indeed.
+          (auth-source-forget+ :host t)
+          (setq auth-source-netrc-cache nil)
+          (setq auth-info (car (auth-source-search :host host))
+                auth-passwd (plist-get auth-info :secret)
+                auth-passwd (if (functionp auth-passwd)
+                                (funcall auth-passwd)
+                              auth-passwd))
+          (with-temp-buffer
+            (insert-file-contents netrc-file)
+            (if (zerop (length passwd))
+                (progn
+                  (should-not (plist-get auth-info :user))
+                  (should-not (plist-get auth-info :host))
+                  (should-not auth-passwd)
+                  (should-not (search-forward host nil 'noerror)))
+              (should
+               (string-equal (plist-get auth-info :user) (user-login-name)))
+              (should (string-equal (plist-get auth-info :host) host))
+              (should (string-equal auth-passwd passwd))
+              (should (search-forward host nil 'noerror)))))))))
 
 (ert-deftest auth-source-delete ()
-  (let* ((netrc-file (make-temp-file "auth-source-test" nil nil "\
+  (ert-with-temp-file netrc-file
+    :suffix "auth-source-test" :text "\
 machine a1 port a2 user a3 password a4
 machine b1 port b2 user b3 password b4
-machine c1 port c2 user c3 password c4\n"))
-         (auth-sources (list netrc-file))
-         (auth-source-do-cache nil)
-         (expected '((:host "a1" :port "a2" :user "a3" :secret "a4")))
-         (parameters '(:max 1 :host t)))
-    (unwind-protect
-        (let ((found (apply #'auth-source-delete parameters)))
-          (dolist (f found)
-            (let ((s (plist-get f :secret)))
-              (setf f (plist-put f :secret
-                                 (if (functionp s) (funcall s) s)))))
-          ;; Note: The netrc backend doesn't delete anything, so
-          ;; this is actually the same as `auth-source-search'.
-          (should (equal found expected)))
-      (delete-file netrc-file))))
+machine c1 port c2 user c3 password c4\n"
+    (let* ((auth-sources (list netrc-file))
+           (auth-source-do-cache nil)
+           (expected '((:host "a1" :port "a2" :user "a3" :secret "a4")))
+           (parameters '(:max 1 :host t))
+           (found (apply #'auth-source-delete parameters)))
+      (dolist (f found)
+        (let ((s (plist-get f :secret)))
+          (setf f (plist-put f :secret
+                             (if (functionp s) (funcall s) s)))))
+      ;; Note: The netrc backend doesn't delete anything, so
+      ;; this is actually the same as `auth-source-search'.
+      (should (equal found expected)))))
 
 (provide 'auth-source-tests)
 ;;; auth-source-tests.el ends here
diff --git a/test/lisp/autoinsert-tests.el b/test/lisp/autoinsert-tests.el
index 7ec4bf6379..b264323ca1 100644
--- a/test/lisp/autoinsert-tests.el
+++ b/test/lisp/autoinsert-tests.el
@@ -28,6 +28,7 @@
 
 (require 'autoinsert)
 (require 'ert)
+(require 'ert-x)
 
 (ert-deftest autoinsert-tests-auto-insert-skeleton ()
   (let ((auto-insert-alist '((text-mode nil "f" _ "oo")))
@@ -39,16 +40,14 @@
       (should (equal (point) (+ (point-min) 1))))))
 
 (ert-deftest autoinsert-tests-auto-insert-file ()
-  (let ((temp-file (make-temp-file "autoinsert-tests" nil nil "foo")))
-    (unwind-protect
-        (let ((auto-insert-alist `((text-mode . ,temp-file)))
-              (auto-insert-query nil))
-          (with-temp-buffer
-            (text-mode)
-            (auto-insert)
-            (should (equal (buffer-string) "foo"))))
-      (when (file-exists-p temp-file)
-        (delete-file temp-file)))))
+  (ert-with-temp-file temp-file
+    :text "foo"
+    (let ((auto-insert-alist `((text-mode . ,temp-file)))
+          (auto-insert-query nil))
+      (with-temp-buffer
+        (text-mode)
+        (auto-insert)
+        (should (equal (buffer-string) "foo"))))))
 
 (ert-deftest autoinsert-tests-auto-insert-function ()
   (let ((auto-insert-alist '((text-mode . (lambda () (insert "foo")))))
diff --git a/test/lisp/autorevert-tests.el b/test/lisp/autorevert-tests.el
index 96169c75d3..b9d45324cb 100644
--- a/test/lisp/autorevert-tests.el
+++ b/test/lisp/autorevert-tests.el
@@ -174,42 +174,41 @@ This expects `auto-revert--messages' to be bound by
   ;; `auto-revert-buffers' runs every 5".  And we must wait, until the
   ;; file has been reverted.
   (with-auto-revert-test
-   (let ((tmpfile (make-temp-file "auto-revert-test"))
-         (times '(60 30 15))
-         buf)
-     (unwind-protect
-         (progn
-           (auto-revert-tests--write-file "any text" tmpfile (pop times))
-           (setq buf (find-file-noselect tmpfile))
-           (with-current-buffer buf
-             (ert-with-message-capture auto-revert--messages
-               (should (string-equal (buffer-string) "any text"))
-               ;; `buffer-stale--default-function' checks for
-               ;; `verify-visited-file-modtime'.  We must ensure that it
-               ;; returns nil.
-               (auto-revert-mode 1)
-               (should auto-revert-mode)
-
-               (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
-
-               ;; Check, that the buffer has been reverted.
-               (auto-revert--wait-for-revert buf))
-             (should (string-match "another text" (buffer-string)))
-
-             ;; When the buffer is modified, it shall not be reverted.
-             (ert-with-message-capture auto-revert--messages
-               (set-buffer-modified-p t)
-               (auto-revert-tests--write-file "any text" tmpfile (pop times))
-
-               ;; Check, that the buffer hasn't been reverted.
-               (auto-revert--wait-for-revert buf))
-             (should-not (string-match "any text" (buffer-string)))))
-
-       ;; Exit.
-       (ignore-errors
-         (with-current-buffer buf (set-buffer-modified-p nil))
-         (kill-buffer buf))
-       (ignore-errors (delete-file tmpfile))))))
+   (ert-with-temp-file tmpfile
+     (let ((times '(60 30 15))
+           buf)
+       (unwind-protect
+           (progn
+             (auto-revert-tests--write-file "any text" tmpfile (pop times))
+             (setq buf (find-file-noselect tmpfile))
+             (with-current-buffer buf
+               (ert-with-message-capture auto-revert--messages
+                 (should (string-equal (buffer-string) "any text"))
+                 ;; `buffer-stale--default-function' checks for
+                 ;; `verify-visited-file-modtime'.  We must ensure that it
+                 ;; returns nil.
+                 (auto-revert-mode 1)
+                 (should auto-revert-mode)
+
+                 (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
+
+                 ;; Check, that the buffer has been reverted.
+                 (auto-revert--wait-for-revert buf))
+               (should (string-match "another text" (buffer-string)))
+
+               ;; When the buffer is modified, it shall not be reverted.
+               (ert-with-message-capture auto-revert--messages
+                 (set-buffer-modified-p t)
+                 (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+                 ;; Check, that the buffer hasn't been reverted.
+                 (auto-revert--wait-for-revert buf))
+               (should-not (string-match "any text" (buffer-string)))))
+
+         ;; Exit.
+         (ignore-errors
+           (with-current-buffer buf (set-buffer-modified-p nil))
+           (kill-buffer buf)))))))
 
 (auto-revert--deftest-remote auto-revert-test00-auto-revert-mode
   "Check autorevert for a remote file.")
@@ -219,63 +218,61 @@ This expects `auto-revert--messages' to be bound by
   "Check autorevert for several files at once."
   (skip-unless (executable-find "cp" (file-remote-p temporary-file-directory)))
 
-  (with-auto-revert-test
-   (let* ((cp (executable-find "cp" (file-remote-p temporary-file-directory)))
-          (tmpdir1 (make-temp-file "auto-revert-test" 'dir))
-          (tmpdir2 (make-temp-file "auto-revert-test" 'dir))
-          (tmpfile1
-           (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
-          (tmpfile2
-           (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
-          (times '(120 60 30 15))
-          buf1 buf2)
-     (unwind-protect
-         (ert-with-message-capture auto-revert--messages
-           (auto-revert-tests--write-file "any text" tmpfile1 (pop times))
-           (setq buf1 (find-file-noselect tmpfile1))
-           (auto-revert-tests--write-file "any text" tmpfile2 (pop times))
-           (setq buf2 (find-file-noselect tmpfile2))
-
-           (dolist (buf (list buf1 buf2))
-             (with-current-buffer buf
-               (should (string-equal (buffer-string) "any text"))
-               ;; `buffer-stale--default-function' checks for
-               ;; `verify-visited-file-modtime'.  We must ensure that
-               ;; it returns nil.
-               (auto-revert-mode 1)
-               (should auto-revert-mode)))
-
-           ;; Modify files.  We wait for a second, in order to have
-           ;; another timestamp.
-           (auto-revert-tests--write-file
-            "another text"
-            (expand-file-name (file-name-nondirectory tmpfile1) tmpdir2)
-            (pop times))
-           (auto-revert-tests--write-file
-            "another text"
-            (expand-file-name (file-name-nondirectory tmpfile2) tmpdir2)
-            (pop times))
-           ;;(copy-directory tmpdir2 tmpdir1 nil 'copy-contents)
-           ;; Strange, that `copy-directory' does not work as expected.
-           ;; The following shell command is not portable on all
-           ;; platforms, unfortunately.
-           (shell-command
-            (format "%s -f %s/* %s"
-                    cp (file-local-name tmpdir2) (file-local-name tmpdir1)))
-
-           ;; Check, that the buffers have been reverted.
-           (dolist (buf (list buf1 buf2))
-             (with-current-buffer buf
-               (auto-revert--wait-for-revert buf)
-               (should (string-match "another text" (buffer-string))))))
-
-       ;; Exit.
-       (ignore-errors
-         (dolist (buf (list buf1 buf2))
-           (with-current-buffer buf (set-buffer-modified-p nil))
-           (kill-buffer buf)))
-       (ignore-errors (delete-directory tmpdir1 'recursive))
-       (ignore-errors (delete-directory tmpdir2 'recursive))))))
+  (ert-with-temp-directory tmpdir1
+    (ert-with-temp-directory tmpdir2
+      (ert-with-temp-file tmpfile1
+        :prefix (expand-file-name "auto-revert-test" tmpdir1)
+        (ert-with-temp-file tmpfile2
+          :prefix (expand-file-name "auto-revert-test" tmpdir1)
+          (with-auto-revert-test
+           (let* ((cp (executable-find "cp" (file-remote-p 
temporary-file-directory)))
+                  (times '(120 60 30 15))
+                  buf1 buf2)
+             (unwind-protect
+                 (ert-with-message-capture auto-revert--messages
+                   (auto-revert-tests--write-file "any text" tmpfile1 (pop 
times))
+                   (setq buf1 (find-file-noselect tmpfile1))
+                   (auto-revert-tests--write-file "any text" tmpfile2 (pop 
times))
+                   (setq buf2 (find-file-noselect tmpfile2))
+
+                   (dolist (buf (list buf1 buf2))
+                     (with-current-buffer buf
+                       (should (string-equal (buffer-string) "any text"))
+                       ;; `buffer-stale--default-function' checks for
+                       ;; `verify-visited-file-modtime'.  We must ensure that
+                       ;; it returns nil.
+                       (auto-revert-mode 1)
+                       (should auto-revert-mode)))
+
+                   ;; Modify files.  We wait for a second, in order to have
+                   ;; another timestamp.
+                   (auto-revert-tests--write-file
+                    "another text"
+                    (expand-file-name (file-name-nondirectory tmpfile1) 
tmpdir2)
+                    (pop times))
+                   (auto-revert-tests--write-file
+                    "another text"
+                    (expand-file-name (file-name-nondirectory tmpfile2) 
tmpdir2)
+                    (pop times))
+                   ;;(copy-directory tmpdir2 tmpdir1 nil 'copy-contents)
+                   ;; Strange, that `copy-directory' does not work as expected.
+                   ;; The following shell command is not portable on all
+                   ;; platforms, unfortunately.
+                   (shell-command
+                    (format "%s -f %s/* %s"
+                            cp (file-local-name tmpdir2) (file-local-name 
tmpdir1)))
+
+                   ;; Check, that the buffers have been reverted.
+                   (dolist (buf (list buf1 buf2))
+                     (with-current-buffer buf
+                       (auto-revert--wait-for-revert buf)
+                       (should (string-match "another text" 
(buffer-string))))))
+
+               ;; Exit.
+               (ignore-errors
+                 (dolist (buf (list buf1 buf2))
+                   (with-current-buffer buf (set-buffer-modified-p nil))
+                   (kill-buffer buf)))))))))))
 
 (auto-revert--deftest-remote auto-revert-test01-auto-revert-several-files
   "Check autorevert for several remote files at once.")
@@ -285,79 +282,78 @@ This expects `auto-revert--messages' to be bound by
   "Check autorevert for a deleted file."
   ;; Repeated unpredictable failures, bug#32645.
   ;; Unlikely to be hydra-specific?
-;  (skip-unless (not (getenv "EMACS_HYDRA_CI")))
+                                        ;  (skip-unless (not (getenv 
"EMACS_HYDRA_CI")))
   :tags '(:unstable)
   (with-auto-revert-test
-   (let ((tmpfile (make-temp-file "auto-revert-test"))
-         ;; Try to catch bug#32645.
-         (auto-revert-debug (getenv "EMACS_HYDRA_CI"))
-         (file-notify-debug (getenv "EMACS_HYDRA_CI"))
-         (times '(120 60 30 15))
-         buf desc)
-     (unwind-protect
-         (progn
-           (auto-revert-tests--write-file "any text" tmpfile (pop times))
-           (setq buf (find-file-noselect tmpfile))
-           (with-current-buffer buf
-             (should-not
-              (file-notify-valid-p auto-revert-notify-watch-descriptor))
-             (should (string-equal (buffer-string) "any text"))
-             ;; `buffer-stale--default-function' checks for
-             ;; `verify-visited-file-modtime'.  We must ensure that
-             ;; it returns nil.
-             (auto-revert-mode 1)
-             (should auto-revert-mode)
-             (setq desc auto-revert-notify-watch-descriptor)
-
-             ;; Remove file while reverting.  We simulate this by
-             ;; modifying `before-revert-hook'.
-             (add-hook
-              'before-revert-hook
-              (lambda ()
-                (when auto-revert-debug
-                  (message "%s deleted" buffer-file-name))
-                (delete-file buffer-file-name))
-              nil t)
-
-             (ert-with-message-capture auto-revert--messages
-               (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
-               (auto-revert--wait-for-revert buf))
-             ;; Check, that the buffer hasn't been reverted.  File
-             ;; notification should be disabled, falling back to
-             ;; polling.
-             (should (string-match "any text" (buffer-string)))
-             ;; With w32notify, and on emba, the `stopped' events are not sent.
-             (or (eq file-notify--library 'w32notify)
-                 (getenv "EMACS_EMBA_CI")
-                 (should-not
-                  (file-notify-valid-p auto-revert-notify-watch-descriptor)))
-
-             ;; Once the file has been recreated, the buffer shall be
-             ;; reverted.
-             (kill-local-variable 'before-revert-hook)
-             (ert-with-message-capture auto-revert--messages
-               (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
-               (auto-revert--wait-for-revert buf))
-             ;; Check, that the buffer has been reverted.
-             (should (string-match "another text" (buffer-string)))
-             ;; When file notification is used, it must be reenabled
-             ;; after recreation of the file.  We cannot expect that
-             ;; the descriptor is the same, so we just check the
-             ;; existence.
-             (should (eq (null desc) (null 
auto-revert-notify-watch-descriptor)))
-
-             ;; An empty file shall still be reverted.
-             (ert-with-message-capture auto-revert--messages
-               (auto-revert-tests--write-file "" tmpfile (pop times))
-               (auto-revert--wait-for-revert buf))
-             ;; Check, that the buffer has been reverted.
-             (should (string-equal "" (buffer-string)))))
-
-       ;; Exit.
-       (ignore-errors
-         (with-current-buffer buf (set-buffer-modified-p nil))
-         (kill-buffer buf))
-       (ignore-errors (delete-file tmpfile))))))
+   (ert-with-temp-file tmpfile
+     (let (;; Try to catch bug#32645.
+           (auto-revert-debug (getenv "EMACS_HYDRA_CI"))
+           (file-notify-debug (getenv "EMACS_HYDRA_CI"))
+           (times '(120 60 30 15))
+           buf desc)
+       (unwind-protect
+           (progn
+             (auto-revert-tests--write-file "any text" tmpfile (pop times))
+             (setq buf (find-file-noselect tmpfile))
+             (with-current-buffer buf
+               (should-not
+                (file-notify-valid-p auto-revert-notify-watch-descriptor))
+               (should (string-equal (buffer-string) "any text"))
+               ;; `buffer-stale--default-function' checks for
+               ;; `verify-visited-file-modtime'.  We must ensure that
+               ;; it returns nil.
+               (auto-revert-mode 1)
+               (should auto-revert-mode)
+               (setq desc auto-revert-notify-watch-descriptor)
+
+               ;; Remove file while reverting.  We simulate this by
+               ;; modifying `before-revert-hook'.
+               (add-hook
+                'before-revert-hook
+                (lambda ()
+                  (when auto-revert-debug
+                    (message "%s deleted" buffer-file-name))
+                  (delete-file buffer-file-name))
+                nil t)
+
+               (ert-with-message-capture auto-revert--messages
+                 (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
+                 (auto-revert--wait-for-revert buf))
+               ;; Check, that the buffer hasn't been reverted.  File
+               ;; notification should be disabled, falling back to
+               ;; polling.
+               (should (string-match "any text" (buffer-string)))
+               ;; With w32notify, and on emba, the `stopped' events are not 
sent.
+               (or (eq file-notify--library 'w32notify)
+                   (getenv "EMACS_EMBA_CI")
+                   (should-not
+                    (file-notify-valid-p auto-revert-notify-watch-descriptor)))
+
+               ;; Once the file has been recreated, the buffer shall be
+               ;; reverted.
+               (kill-local-variable 'before-revert-hook)
+               (ert-with-message-capture auto-revert--messages
+                 (auto-revert-tests--write-file "another text" tmpfile (pop 
times))
+                 (auto-revert--wait-for-revert buf))
+               ;; Check, that the buffer has been reverted.
+               (should (string-match "another text" (buffer-string)))
+               ;; When file notification is used, it must be reenabled
+               ;; after recreation of the file.  We cannot expect that
+               ;; the descriptor is the same, so we just check the
+               ;; existence.
+               (should (eq (null desc) (null 
auto-revert-notify-watch-descriptor)))
+
+               ;; An empty file shall still be reverted.
+               (ert-with-message-capture auto-revert--messages
+                 (auto-revert-tests--write-file "" tmpfile (pop times))
+                 (auto-revert--wait-for-revert buf))
+               ;; Check, that the buffer has been reverted.
+               (should (string-equal "" (buffer-string)))))
+
+         ;; Exit.
+         (ignore-errors
+           (with-current-buffer buf (set-buffer-modified-p nil))
+           (kill-buffer buf)))))))
 
 (auto-revert--deftest-remote auto-revert-test02-auto-revert-deleted-file
   "Check autorevert for a deleted remote file.")
@@ -366,34 +362,33 @@ This expects `auto-revert--messages' to be bound by
   "Check autorevert tail mode."
   ;; `auto-revert-buffers' runs every 5".  And we must wait, until the
   ;; file has been reverted.
-  (let ((tmpfile (make-temp-file "auto-revert-test"))
-        (times '(30 15))
-        buf)
-    (unwind-protect
-        (ert-with-message-capture auto-revert--messages
-          (auto-revert-tests--write-file "any text" tmpfile (pop times))
-         (setq buf (find-file-noselect tmpfile))
-         (with-current-buffer buf
-            ;; `buffer-stale--default-function' checks for
-            ;; `verify-visited-file-modtime'.  We must ensure that it
-            ;; returns nil.
-           (auto-revert-tail-mode 1)
-           (should auto-revert-tail-mode)
-            (erase-buffer)
-            (insert "modified text\n")
-            (set-buffer-modified-p nil)
-
-            ;; Modify file.
-            (auto-revert-tests--write-file "another text" tmpfile (pop times) 
'append)
-
-           ;; Check, that the buffer has been reverted.
-            (auto-revert--wait-for-revert buf)
-            (should
-             (string-match "modified text\nanother text" (buffer-string)))))
-
-      ;; Exit.
-      (ignore-errors (kill-buffer buf))
-      (ignore-errors (delete-file tmpfile)))))
+  (ert-with-temp-file tmpfile
+    (let ((times '(30 15))
+          buf)
+      (unwind-protect
+          (ert-with-message-capture auto-revert--messages
+            (auto-revert-tests--write-file "any text" tmpfile (pop times))
+            (setq buf (find-file-noselect tmpfile))
+            (with-current-buffer buf
+              ;; `buffer-stale--default-function' checks for
+              ;; `verify-visited-file-modtime'.  We must ensure that it
+              ;; returns nil.
+              (auto-revert-tail-mode 1)
+              (should auto-revert-tail-mode)
+              (erase-buffer)
+              (insert "modified text\n")
+              (set-buffer-modified-p nil)
+
+              ;; Modify file.
+              (auto-revert-tests--write-file "another text" tmpfile (pop 
times) 'append)
+
+              ;; Check, that the buffer has been reverted.
+              (auto-revert--wait-for-revert buf)
+              (should
+               (string-match "modified text\nanother text" (buffer-string)))))
+
+        ;; Exit.
+        (ignore-errors (kill-buffer buf))))))
 
 (auto-revert--deftest-remote auto-revert-test03-auto-revert-tail-mode
   "Check remote autorevert tail mode.")
@@ -403,46 +398,45 @@ This expects `auto-revert--messages' to be bound by
   ;; `auto-revert-buffers' runs every 5".  And we must wait, until the
   ;; file has been reverted.
   (with-auto-revert-test
-   (let* ((tmpfile (make-temp-file "auto-revert-test"))
-          (name (file-name-nondirectory tmpfile))
-          (times '(30))
-          buf)
-     (unwind-protect
-         (progn
-           (setq buf (dired-noselect temporary-file-directory))
-           (with-current-buffer buf
-             ;; `buffer-stale--default-function' checks for
-             ;; `verify-visited-file-modtime'.  We must ensure that it
-             ;; returns nil.
-             (auto-revert-mode 1)
-             (should auto-revert-mode)
-             (should
-              (string-match name (substring-no-properties (buffer-string))))
-
-             (ert-with-message-capture auto-revert--messages
-               ;; Delete file.
-               (delete-file tmpfile)
-               (auto-revert--wait-for-revert buf))
-             ;; Check, that the buffer has been reverted.
-             (should-not
-              (string-match name (substring-no-properties (buffer-string))))
-
-             (ert-with-message-capture auto-revert--messages
-               ;; Make dired buffer modified.  Check, that the buffer has
-               ;; been still reverted.
-               (set-buffer-modified-p t)
-               (auto-revert-tests--write-file "any text" tmpfile (pop times))
-
-               (auto-revert--wait-for-revert buf))
-             ;; Check, that the buffer has been reverted.
-             (should
-              (string-match name (substring-no-properties (buffer-string))))))
-
-       ;; Exit.
-       (ignore-errors
-         (with-current-buffer buf (set-buffer-modified-p nil))
-         (kill-buffer buf))
-       (ignore-errors (delete-file tmpfile))))))
+   (ert-with-temp-file tmpfile
+     (let* ((name (file-name-nondirectory tmpfile))
+            (times '(30))
+            buf)
+       (unwind-protect
+           (progn
+             (setq buf (dired-noselect temporary-file-directory))
+             (with-current-buffer buf
+               ;; `buffer-stale--default-function' checks for
+               ;; `verify-visited-file-modtime'.  We must ensure that it
+               ;; returns nil.
+               (auto-revert-mode 1)
+               (should auto-revert-mode)
+               (should
+                (string-match name (substring-no-properties (buffer-string))))
+
+               (ert-with-message-capture auto-revert--messages
+                 ;; Delete file.
+                 (delete-file tmpfile)
+                 (auto-revert--wait-for-revert buf))
+               ;; Check, that the buffer has been reverted.
+               (should-not
+                (string-match name (substring-no-properties (buffer-string))))
+
+               (ert-with-message-capture auto-revert--messages
+                 ;; Make dired buffer modified.  Check, that the buffer has
+                 ;; been still reverted.
+                 (set-buffer-modified-p t)
+                 (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+                 (auto-revert--wait-for-revert buf))
+               ;; Check, that the buffer has been reverted.
+               (should
+                (string-match name (substring-no-properties 
(buffer-string))))))
+
+         ;; Exit.
+         (ignore-errors
+           (with-current-buffer buf (set-buffer-modified-p nil))
+           (kill-buffer buf)))))))
 
 (auto-revert--deftest-remote auto-revert-test04-auto-revert-mode-dired
   "Check remote autorevert for dired.")
@@ -469,86 +463,114 @@ This expects `auto-revert--messages' to be bound by
    (lambda () (string-equal (auto-revert-test--buffer-string buffer) string))
    max-wait))
 
+(defun auto-revert-test--instrument-kill-buffer-hook (buffer)
+  "Instrument local `kill-buffer-hook' with messages."
+  (when auto-revert-debug
+    (with-current-buffer buffer
+      (add-hook
+       'kill-buffer-hook
+       (lambda ()
+         (message
+          "%s killed\n%s" (current-buffer) (with-output-to-string 
(backtrace))))
+       nil 'local))))
+
 (ert-deftest auto-revert-test05-global-notify ()
   "Test `global-auto-revert-mode' without polling."
   (skip-unless (or file-notify--library
                    (file-remote-p temporary-file-directory)))
   (with-auto-revert-test
-   (let* ((auto-revert-use-notify t)
-          (auto-revert-avoid-polling t)
-          (was-in-global-auto-revert-mode global-auto-revert-mode)
-          (file-1 (make-temp-file "global-auto-revert-test-1"))
-          (file-2 (make-temp-file "global-auto-revert-test-2"))
-          (file-3 (make-temp-file "global-auto-revert-test-3"))
-          (file-2b (concat file-2 "-b"))
-          require-final-newline buf-1 buf-2 buf-3)
-     (unwind-protect
-         (progn
-           (setq buf-1 (find-file-noselect file-1))
-           (setq buf-2 (find-file-noselect file-2))
-           (auto-revert-test--write-file "1-a" file-1)
-           (should (equal (auto-revert-test--buffer-string buf-1) ""))
-
-           (global-auto-revert-mode 1)   ; Turn it on.
-
-           (should (buffer-local-value
-                    'auto-revert-notify-watch-descriptor buf-1))
-           (should (buffer-local-value
-                    'auto-revert-notify-watch-descriptor buf-2))
-
-           ;; buf-1 should have been reverted immediately when the mode
-           ;; was enabled.
-           (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
-
-           ;; Alter a file.
-           (auto-revert-test--write-file "2-a" file-2)
-           ;; Allow for some time to handle notification events.
-           (auto-revert-test--wait-for-buffer-text buf-2 "2-a" 1)
-           (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
-
-           ;; Visit a file, and modify it on disk.
-           (setq buf-3 (find-file-noselect file-3))
-           ;; Newly opened buffers won't be use notification until the
-           ;; first poll cycle; wait for it.
-           (auto-revert-test--wait-for
-            (lambda () (buffer-local-value
-                   'auto-revert-notify-watch-descriptor buf-3))
-            (auto-revert--timeout))
-           (should (buffer-local-value
-                    'auto-revert-notify-watch-descriptor buf-3))
-           (auto-revert-test--write-file "3-a" file-3)
-           (auto-revert-test--wait-for-buffer-text buf-3 "3-a" 1)
-           (should (equal (auto-revert-test--buffer-string buf-3) "3-a"))
-
-           ;; Delete a visited file, and re-create it with new contents.
-           (delete-file file-1)
-           (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
-           (auto-revert-test--write-file "1-b" file-1)
-           (auto-revert-test--wait-for-buffer-text
-            buf-1 "1-b" (auto-revert--timeout))
-           ;; On emba, `buf-1' is a killed buffer.
-           (when (buffer-live-p buf-1)
-             (should (buffer-local-value
-                      'auto-revert-notify-watch-descriptor buf-1)))
-
-           ;; Write a buffer to a new file, then modify the new file on disk.
-           (with-current-buffer buf-2
-             (write-file file-2b))
-           (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
-           (auto-revert-test--write-file "2-b" file-2b)
-           (auto-revert-test--wait-for-buffer-text
-            buf-2 "2-b" (auto-revert--timeout))
-           (should (buffer-local-value
-                    'auto-revert-notify-watch-descriptor buf-2)))
-
-       ;; Clean up.
-       (unless was-in-global-auto-revert-mode
-         (global-auto-revert-mode 0))    ; Turn it off.
-       (dolist (buf (list buf-1 buf-2 buf-3))
-         (ignore-errors (kill-buffer buf)))
-       (dolist (file (list file-1 file-2 file-2b file-3))
-         (ignore-errors (delete-file file)))
-       ))))
+   (ert-with-temp-file file-1
+     (ert-with-temp-file file-2
+       (ert-with-temp-file file-3
+         (let* ((auto-revert-use-notify t)
+                (auto-revert-avoid-polling t)
+                (auto-revert-debug (getenv "EMACS_EMBA_CI"))
+                (file-notify-debug (getenv "EMACS_EMBA_CI"))
+                (was-in-global-auto-revert-mode global-auto-revert-mode)
+                (file-2b (concat file-2 "-b"))
+                require-final-newline buf-1 buf-2 buf-3)
+           (unwind-protect
+               (progn
+                 (setq buf-1 (find-file-noselect file-1))
+                 (auto-revert-test--instrument-kill-buffer-hook buf-1)
+                 (setq buf-2 (find-file-noselect file-2))
+                 (auto-revert-test--instrument-kill-buffer-hook buf-2)
+                 (auto-revert-test--write-file "1-a" file-1)
+                 (should (equal (auto-revert-test--buffer-string buf-1) ""))
+
+                 (global-auto-revert-mode 1) ; Turn it on.
+
+                 (should (buffer-local-value
+                          'auto-revert-notify-watch-descriptor buf-1))
+                 (should (buffer-local-value
+                          'auto-revert-notify-watch-descriptor buf-2))
+
+                 ;; buf-1 should have been reverted immediately when the mode
+                 ;; was enabled.
+                 (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
+
+                 ;; Alter a file.
+                 (auto-revert-test--write-file "2-a" file-2)
+                 ;; Allow for some time to handle notification events.
+                 (auto-revert-test--wait-for-buffer-text buf-2 "2-a" 1)
+                 (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
+
+                 ;; Visit a file, and modify it on disk.
+                 (setq buf-3 (find-file-noselect file-3))
+                 (auto-revert-test--instrument-kill-buffer-hook buf-3)
+                 ;; Newly opened buffers won't be use notification until the
+                 ;; first poll cycle; wait for it.
+                 (auto-revert-test--wait-for
+                  (lambda () (buffer-local-value
+                              'auto-revert-notify-watch-descriptor buf-3))
+                  (auto-revert--timeout))
+                 (should (buffer-local-value
+                          'auto-revert-notify-watch-descriptor buf-3))
+                 (auto-revert-test--write-file "3-a" file-3)
+                 (auto-revert-test--wait-for-buffer-text buf-3 "3-a" 1)
+                 (should (equal (auto-revert-test--buffer-string buf-3) "3-a"))
+
+                 ;; Delete a visited file, and re-create it with new contents.
+                 (when auto-revert-debug (message "Hallo0"))
+                 (delete-file file-1)
+                 (when auto-revert-debug (message "Hallo1"))
+                 (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
+                 (when auto-revert-debug (message "Hallo2"))
+                 (auto-revert-test--write-file "1-b" file-1)
+                 (when auto-revert-debug (message "Hallo3"))
+                 (auto-revert-test--wait-for-buffer-text
+                  buf-1 "1-b" (auto-revert--timeout))
+                 ;; On emba, `buf-1' is a killed buffer.
+                 (when auto-revert-debug
+                   (message
+                    "Hallo4 %s %s %s %s %s %s %s"
+                    buf-1 (buffer-name buf-1) (buffer-live-p buf-1)
+                    file-1 (get-file-buffer file-1)
+                    (buffer-name (get-file-buffer file-1))
+                    (buffer-live-p (get-file-buffer file-1)))
+                   (with-current-buffer buf-1
+                     (message "Hallo5\n%s" (buffer-local-variables))))
+                 (should (buffer-local-value
+                          'auto-revert-notify-watch-descriptor buf-1))
+                 (when auto-revert-debug (message "Hallo6"))
+
+                 ;; Write a buffer to a new file, then modify the new file on 
disk.
+                 (with-current-buffer buf-2
+                   (write-file file-2b))
+                 (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
+                 (auto-revert-test--write-file "2-b" file-2b)
+                 (auto-revert-test--wait-for-buffer-text
+                  buf-2 "2-b" (auto-revert--timeout))
+                 (should (buffer-local-value
+                          'auto-revert-notify-watch-descriptor buf-2)))
+
+             ;; Clean up.
+             (unless was-in-global-auto-revert-mode
+               (global-auto-revert-mode 0)) ; Turn it off.
+             (dolist (buf (list buf-1 buf-2 buf-3))
+               (with-current-buffer buf (setq-local kill-buffer-hook nil))
+               (ignore-errors (kill-buffer buf)))
+             (ignore-errors (delete-file file-2b)))))))))
 
 (auto-revert--deftest-remote auto-revert-test05-global-notify
   "Test `global-auto-revert-mode' without polling for remote buffers.")
@@ -558,31 +580,30 @@ This expects `auto-revert--messages' to be bound by
   (skip-unless (or file-notify--library
                    (file-remote-p temporary-file-directory)))
   (with-auto-revert-test
-   (let* ((auto-revert-use-notify t)
-          (file-1 (make-temp-file "auto-revert-test"))
-          (file-2 (concat file-1 "-2"))
-          require-final-newline buf)
-     (unwind-protect
-         (progn
-           (setq buf (find-file-noselect file-1))
-           (with-current-buffer buf
-             (insert "A")
-             (save-buffer)
+   (ert-with-temp-file file-1
+     (let* ((auto-revert-use-notify t)
+            (file-2 (concat file-1 "-2"))
+            require-final-newline buf)
+       (unwind-protect
+           (progn
+             (setq buf (find-file-noselect file-1))
+             (with-current-buffer buf
+               (insert "A")
+               (save-buffer)
 
-             (auto-revert-mode 1)
+               (auto-revert-mode 1)
 
-             (insert "B")
-             (write-file file-2)
+               (insert "B")
+               (write-file file-2)
 
-             (auto-revert-test--write-file "C" file-2)
-             (auto-revert-test--wait-for-buffer-text
-              buf "C" (auto-revert--timeout))
-             (should (equal (buffer-string) "C"))))
+               (auto-revert-test--write-file "C" file-2)
+               (auto-revert-test--wait-for-buffer-text
+                buf "C" (auto-revert--timeout))
+               (should (equal (buffer-string) "C"))))
 
-       ;; Clean up.
-       (ignore-errors (kill-buffer buf))
-       (ignore-errors (delete-file file-1))
-       (ignore-errors (delete-file file-2))))))
+         ;; Clean up.
+         (ignore-errors (kill-buffer buf))
+         (ignore-errors (delete-file file-2)))))))
 
 (auto-revert--deftest-remote auto-revert-test06-write-file
   "Test `write-file' in `auto-revert-mode' for remote buffers.")
@@ -591,82 +612,81 @@ This expects `auto-revert--messages' to be bound by
 (ert-deftest auto-revert-test07-auto-revert-several-buffers ()
   "Check autorevert for several buffers visiting the same file."
   ;; (with-auto-revert-test
-   (let ((auto-revert-use-notify t)
-         (tmpfile (make-temp-file "auto-revert-test"))
-         (times '(120 60 30 15))
-         (num-buffers 10)
-         require-final-newline buffers)
-
-     (unwind-protect
-         ;; Check indirect buffers.
-         (ert-with-message-capture auto-revert--messages
-           (auto-revert-tests--write-file "any text" tmpfile (pop times))
-           (push (find-file-noselect tmpfile) buffers)
-           (with-current-buffer (car buffers)
-             (should (string-equal (buffer-string) "any text"))
-             ;; `buffer-stale--default-function' checks for
-             ;; `verify-visited-file-modtime'.  We must ensure that
-             ;; it returns nil.
-             (auto-revert-mode 1)
-             (should auto-revert-mode))
-
-           (dotimes (i num-buffers)
-             (push (make-indirect-buffer
-                    (car buffers)
-                    (format "%s-%d" (buffer-file-name (car buffers)) i)
-                    'clone)
-                   buffers))
-           (setq buffers (nreverse buffers))
-           (dolist (buf buffers)
-             (with-current-buffer buf
-               (should (string-equal (buffer-string) "any text"))
-               (should auto-revert-mode)))
-
-           (auto-revert-tests--write-file "another text" tmpfile (pop times))
-           ;; Check, that the buffer has been reverted.
-           (auto-revert--wait-for-revert (car buffers))
-           (dolist (buf buffers)
-             (with-current-buffer buf
-               (should (string-equal (buffer-string) "another text")))))
-
-       ;; Exit.
-       (ignore-errors
-         (dolist (buf buffers)
-           (with-current-buffer buf (set-buffer-modified-p nil))
-           (kill-buffer buf)))
-       (setq buffers nil)
-       (ignore-errors (delete-file tmpfile)))
-
-     ;; Check direct buffers.
-     (unwind-protect
-         (ert-with-message-capture auto-revert--messages
-           (auto-revert-tests--write-file "any text" tmpfile (pop times))
-
-           (dotimes (i num-buffers)
-             (push (generate-new-buffer
-                    (format "%s-%d" (file-name-nondirectory tmpfile) i))
-                   buffers))
-           (setq buffers (nreverse buffers))
-           (dolist (buf buffers)
-             (with-current-buffer buf
-               (insert-file-contents tmpfile 'visit)
-               (should (string-equal (buffer-string) "any text"))
-               (auto-revert-mode 1)
-               (should auto-revert-mode)))
-
-           (auto-revert-tests--write-file "another text" tmpfile (pop times))
-           ;; Check, that the buffers have been reverted.
-           (dolist (buf buffers)
-             (auto-revert--wait-for-revert buf)
-             (with-current-buffer buf
-               (should (string-equal (buffer-string) "another text")))))
-
-       ;; Exit.
-       (ignore-errors
-         (dolist (buf buffers)
-           (with-current-buffer buf (set-buffer-modified-p nil))
-           (kill-buffer buf)))
-       (ignore-errors (delete-file tmpfile)))));)
+  (ert-with-temp-file tmpfile
+    (let ((auto-revert-use-notify t)
+          (times '(120 60 30 15))
+          (num-buffers 10)
+          require-final-newline buffers)
+
+      (unwind-protect
+          ;; Check indirect buffers.
+          (ert-with-message-capture auto-revert--messages
+            (auto-revert-tests--write-file "any text" tmpfile (pop times))
+            (push (find-file-noselect tmpfile) buffers)
+            (with-current-buffer (car buffers)
+              (should (string-equal (buffer-string) "any text"))
+              ;; `buffer-stale--default-function' checks for
+              ;; `verify-visited-file-modtime'.  We must ensure that
+              ;; it returns nil.
+              (auto-revert-mode 1)
+              (should auto-revert-mode))
+
+            (dotimes (i num-buffers)
+              (push (make-indirect-buffer
+                     (car buffers)
+                     (format "%s-%d" (buffer-file-name (car buffers)) i)
+                     'clone)
+                    buffers))
+            (setq buffers (nreverse buffers))
+            (dolist (buf buffers)
+              (with-current-buffer buf
+                (should (string-equal (buffer-string) "any text"))
+                (should auto-revert-mode)))
+
+            (auto-revert-tests--write-file "another text" tmpfile (pop times))
+            ;; Check, that the buffer has been reverted.
+            (auto-revert--wait-for-revert (car buffers))
+            (dolist (buf buffers)
+              (with-current-buffer buf
+                (should (string-equal (buffer-string) "another text")))))
+
+        ;; Exit.
+        (ignore-errors
+          (dolist (buf buffers)
+            (with-current-buffer buf (set-buffer-modified-p nil))
+            (kill-buffer buf)))
+        (setq buffers nil)
+        (ignore-errors (delete-file tmpfile)))
+
+      ;; Check direct buffers.
+      (unwind-protect
+          (ert-with-message-capture auto-revert--messages
+            (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+            (dotimes (i num-buffers)
+              (push (generate-new-buffer
+                     (format "%s-%d" (file-name-nondirectory tmpfile) i))
+                    buffers))
+            (setq buffers (nreverse buffers))
+            (dolist (buf buffers)
+              (with-current-buffer buf
+                (insert-file-contents tmpfile 'visit)
+                (should (string-equal (buffer-string) "any text"))
+                (auto-revert-mode 1)
+                (should auto-revert-mode)))
+
+            (auto-revert-tests--write-file "another text" tmpfile (pop times))
+            ;; Check, that the buffers have been reverted.
+            (dolist (buf buffers)
+              (auto-revert--wait-for-revert buf)
+              (with-current-buffer buf
+                (should (string-equal (buffer-string) "another text")))))
+
+        ;; Exit.
+        (ignore-errors
+          (dolist (buf buffers)
+            (with-current-buffer buf (set-buffer-modified-p nil))
+            (kill-buffer buf)))))));)
 
 (auto-revert--deftest-remote auto-revert-test07-auto-revert-several-buffers
   "Check autorevert for several buffers visiting the same remote file.")
@@ -685,4 +705,4 @@ This expects `auto-revert--messages' to be bound by
     (ert-run-tests-batch "^auto-revert-")))
 
 (provide 'auto-revert-tests)
-;;; auto-revert-tests.el ends here
+;;; autorevert-tests.el ends here
diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el
index 9c33a27288..dc2dec68ee 100644
--- a/test/lisp/bookmark-tests.el
+++ b/test/lisp/bookmark-tests.el
@@ -371,16 +371,14 @@ Same as `with-bookmark-test' but also sets a temporary
 `bookmark-default-file', evaluates BODY, and then runs the test
 that saves and then loads the bookmark file."
   `(with-bookmark-test
-    (let ((file (make-temp-file "bookmark-tests-")))
-      (unwind-protect
-          (let ((bookmark-default-file file)
-                (old-alist bookmark-alist))
-            ,@body
-            (bookmark-save nil file t)
-            (setq bookmark-alist nil)
-            (bookmark-load file nil t)
-            (should (equal bookmark-alist old-alist)))
-        (delete-file file)))))
+    (ert-with-temp-file file
+      (let ((bookmark-default-file file)
+            (old-alist bookmark-alist))
+        ,@body
+        (bookmark-save nil file t)
+        (setq bookmark-alist nil)
+        (bookmark-load file nil t)
+        (should (equal bookmark-alist old-alist))))))
 
 (defvar bookmark-tests-non-ascii-data
   (concat "Здра́вствуйте!" "中文,普通话,汉语" "åäöøñ"
diff --git a/test/lisp/buff-menu-tests.el b/test/lisp/buff-menu-tests.el
index 18c988656d..b223a64308 100644
--- a/test/lisp/buff-menu-tests.el
+++ b/test/lisp/buff-menu-tests.el
@@ -24,19 +24,20 @@
 ;;; Code:
 
 (require 'ert)
+(eval-when-compile (require 'ert-x))
 
 (ert-deftest buff-menu-24962 ()
   "Test for https://debbugs.gnu.org/24962 ."
-  (let* ((file (make-temp-file "foo"))
-         (buf (find-file file)))
-    (unwind-protect
-        (progn
-          (rename-buffer " foo")
-          (list-buffers)
-          (with-current-buffer "*Buffer List*"
-            (should (string= " foo" (buffer-name (Buffer-menu-buffer))))))
-      (and (buffer-live-p buf) (kill-buffer buf))
-      (and (file-exists-p file) (delete-file file)))))
+  (ert-with-temp-file file
+    :suffix "foo"
+    (let ((buf (find-file file)))
+      (unwind-protect
+          (progn
+            (rename-buffer " foo")
+            (list-buffers)
+            (with-current-buffer "*Buffer List*"
+              (should (string= " foo" (buffer-name (Buffer-menu-buffer))))))
+        (and (buffer-live-p buf) (kill-buffer buf))))))
 
 (provide 'buff-menu-tests)
 
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index 13dd228d3b..3eb6b34c13 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -53,7 +53,7 @@ A and B should be calc expressions."
 
 (defun calc-tests-simple (fun string &rest args)
   "Push STRING on the calc stack, then call FUN and return the new top.
-The result is a calc (i.e., lisp) expression, not its string representation.
+The result is a calc (i.e., Lisp) expression, not its string representation.
 Also pop the entire stack afterwards.
 An existing calc stack is reused, otherwise a new one is created."
   (calc-eval string 'push)
@@ -448,7 +448,7 @@ An existing calc stack is reused, otherwise a new one is 
created."
     ;; Generalisation for any n, integral k≥0: use falling product
     (/ (apply '* (number-sequence n (- n (1- k)) -1))
        (calc-tests--fac k)))
-   (t (error "case not covered"))))
+   (t (error "Case not covered"))))
 
 (defun calc-tests--calc-to-number (x)
   "Convert a Calc object to a Lisp number."
@@ -810,6 +810,12 @@ An existing calc stack is reused, otherwise a new one is 
created."
   (should (equal (calcFunc-test6 3) (* (* 3 2) (- 3 1))))
   (should (equal (calcFunc-test7 3) (* 3 2))))
 
+(ert-deftest calc-nth-root ()
+  ;; bug#51209
+  (let* ((calc-display-working-message nil)
+         (x (calc-tests--calc-to-number (math-pow 8 '(frac 1 6)))))
+    (should (< (abs (- x (sqrt 2.0))) 1.0e-10))))
+
 (provide 'calc-tests)
 ;;; calc-tests.el ends here
 
diff --git a/test/lisp/calculator-tests.el b/test/lisp/calculator-tests.el
index 9551b1a4c6..f24ca97310 100644
--- a/test/lisp/calculator-tests.el
+++ b/test/lisp/calculator-tests.el
@@ -48,4 +48,4 @@
          (should (equal (calculator-string-to-number str) expected)))))))
 
 (provide 'calculator-tests)
-;; calculator-tests.el ends here
+;;; calculator-tests.el ends here
diff --git a/test/lisp/calendar/cal-french-tests.el 
b/test/lisp/calendar/cal-french-tests.el
index ab62c1e6fc..1de5dea088 100644
--- a/test/lisp/calendar/cal-french-tests.el
+++ b/test/lisp/calendar/cal-french-tests.el
@@ -111,3 +111,4 @@
     (should (equal (calendar-french-date-string (list m d y)) str))))
 
 (provide 'cal-french-tests)
+;;; cal-french-tests.el ends here
diff --git a/test/lisp/calendar/icalendar-tests.el 
b/test/lisp/calendar/icalendar-tests.el
index de2a891758..9e8a8e7b47 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -698,17 +698,18 @@ and ISO style input data must use english month names."
   "Actually perform export test.
 Argument INPUT input diary string.
 Argument EXPECTED-OUTPUT expected iCalendar result string."
-  (let ((temp-file (make-temp-file "icalendar-tests-ics")))
+  (ert-with-temp-file temp-file
+    :suffix "icalendar-tests-ics"
     (unwind-protect
-       (progn
-         (with-temp-buffer
-           (insert input)
-           (icalendar-export-region (point-min) (point-max) temp-file))
-         (save-excursion
-           (find-file temp-file)
-           (goto-char (point-min))
-           (cond (expected-output
-                  (should (re-search-forward "^\\s-*BEGIN:VCALENDAR
+        (progn
+          (with-temp-buffer
+            (insert input)
+            (icalendar-export-region (point-min) (point-max) temp-file))
+          (save-excursion
+            (find-file temp-file)
+            (goto-char (point-min))
+            (cond (expected-output
+                   (should (re-search-forward "^\\s-*BEGIN:VCALENDAR
 PRODID:-//Emacs//NONSGML icalendar.el//EN
 VERSION:2.0
 BEGIN:VEVENT
@@ -717,23 +718,22 @@ UID:emacs[0-9]+
 END:VEVENT
 END:VCALENDAR
 \\s-*$"
-                                             nil t))
-                  (should (string-match
-                           (concat "^\\s-*"
-                                   (regexp-quote 
(buffer-substring-no-properties
-                                                  (match-beginning 1) 
(match-end 1)))
-                                   "\\s-*$")
-                           expected-output)))
-                 (t
-                  (should (re-search-forward "^\\s-*BEGIN:VCALENDAR
+                                              nil t))
+                   (should (string-match
+                            (concat "^\\s-*"
+                                    (regexp-quote 
(buffer-substring-no-properties
+                                                   (match-beginning 1) 
(match-end 1)))
+                                    "\\s-*$")
+                            expected-output)))
+                  (t
+                   (should (re-search-forward "^\\s-*BEGIN:VCALENDAR
 PRODID:-//Emacs//NONSGML icalendar.el//EN
 VERSION:2.0
 END:VCALENDAR
 \\s-*$"
-                                             nil t))))))
+                                              nil t))))))
       ;; cleanup!!
-      (kill-buffer (find-buffer-visiting temp-file))
-      (delete-file temp-file))))
+      (kill-buffer (find-buffer-visiting temp-file)))))
 
 (ert-deftest icalendar-export-ordinary-no-time ()
   "Perform export test."
@@ -1031,7 +1031,8 @@ During import test the timezone is set to Central 
European Time."
 (defun icalendar-tests--do-test-import (expected-output)
   "Actually perform import test.
 Argument EXPECTED-OUTPUT file containing expected diary string."
-  (let ((temp-file (make-temp-file "icalendar-test-diary")))
+  (ert-with-temp-file temp-file
+    :suffix "icalendar-test-diary"
     ;; Test the Catch-the-mysterious-coding-header logic below.
     ;; Ruby-mode adds an after-save-hook which inserts the header!
     ;; (save-excursion
@@ -1061,8 +1062,7 @@ Argument EXPECTED-OUTPUT file containing expected diary 
string."
 
       (let ((result (buffer-substring-no-properties (point-min) (point-max))))
         (should (string= expected-output result)))
-      (kill-buffer (find-buffer-visiting temp-file))
-      (delete-file temp-file))))
+      (kill-buffer (find-buffer-visiting temp-file)))))
 
 (ert-deftest icalendar-import-non-recurring ()
   "Perform standard import tests."
@@ -1240,35 +1240,33 @@ Argument INPUT icalendar event string."
 
 (defun icalendar-tests--do-test-cycle ()
   "Actually perform import/export cycle test."
-  (let ((temp-diary (make-temp-file "icalendar-test-diary"))
-        (temp-ics (make-temp-file "icalendar-test-ics"))
-        (org-input (buffer-substring-no-properties (point-min) (point-max))))
-
-    (unwind-protect
-       (progn
-         ;; step 1: import
-         (icalendar-import-buffer temp-diary t t)
-
-         ;; step 2: export what was just imported
-         (save-excursion
-           (find-file temp-diary)
-           (icalendar-export-region (point-min) (point-max) temp-ics))
-
-         ;; compare the output of step 2 with the input of step 1
-         (save-excursion
-           (find-file temp-ics)
-           (goto-char (point-min))
-           ;;(when (re-search-forward "\nUID:.*\n" nil t)
-           ;;(replace-match "\n"))
-           (let ((cycled (buffer-substring-no-properties (point-min) 
(point-max))))
-             (should (string= org-input cycled)))))
-      ;; clean up
-      (kill-buffer (find-buffer-visiting temp-diary))
-      (with-current-buffer (find-buffer-visiting temp-ics)
-       (set-buffer-modified-p nil)
-       (kill-buffer (current-buffer)))
-      (delete-file temp-diary)
-      (delete-file temp-ics))))
+  (ert-with-temp-file temp-diary
+    (ert-with-temp-file temp-ics
+      (let ((org-input (buffer-substring-no-properties (point-min) 
(point-max))))
+
+        (unwind-protect
+            (progn
+              ;; step 1: import
+              (icalendar-import-buffer temp-diary t t)
+
+              ;; step 2: export what was just imported
+              (save-excursion
+                (find-file temp-diary)
+                (icalendar-export-region (point-min) (point-max) temp-ics))
+
+              ;; compare the output of step 2 with the input of step 1
+              (save-excursion
+                (find-file temp-ics)
+                (goto-char (point-min))
+                ;;(when (re-search-forward "\nUID:.*\n" nil t)
+                ;;(replace-match "\n"))
+                (let ((cycled (buffer-substring-no-properties (point-min) 
(point-max))))
+                  (should (string= org-input cycled)))))
+          ;; clean up
+          (kill-buffer (find-buffer-visiting temp-diary))
+          (with-current-buffer (find-buffer-visiting temp-ics)
+            (set-buffer-modified-p nil)
+            (kill-buffer (current-buffer))))))))
 
 (ert-deftest icalendar-cycle ()
   "Perform cycling tests.
@@ -1636,7 +1634,7 @@ SUMMARY:NNN Wwwwwwww Wwwww - Aaaaaa Pppppppp rrrrrr ddd 
oo Nnnnnnnn 30
     (format-time-string "%FT%T%z" (encode-time time) 0)))
 
 (defun icalendar-tests--decode-isodatetime (_ical-string)
-  "Test icalendar--decode-isodatetime."
+  "Test `icalendar--decode-isodatetime'."
   (should (equal (icalendar-test--format "20040917T050910-0200")
                  "2004-09-17T03:09:10+0000"))
   (should (equal (icalendar-test--format "20040917T050910")
diff --git a/test/lisp/calendar/solar-tests.el 
b/test/lisp/calendar/solar-tests.el
index 337deb8ce9..921be1d2d4 100644
--- a/test/lisp/calendar/solar-tests.el
+++ b/test/lisp/calendar/solar-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'solar)
 
@@ -42,3 +44,5 @@
       (should (< (abs (- sunset 17.72)) epsilon)))))
 
 (provide 'solar-tests)
+
+;;; solar-tests.el ends here
diff --git a/test/lisp/calendar/todo-mode-tests.el 
b/test/lisp/calendar/todo-mode-tests.el
index 6fa2b9d7c3..79978a2041 100644
--- a/test/lisp/calendar/todo-mode-tests.el
+++ b/test/lisp/calendar/todo-mode-tests.el
@@ -35,27 +35,26 @@
   "Todo Archive mode test file.")
 
 (defmacro with-todo-test (&rest body)
-  "Set up an isolated todo-mode test environment."
+  "Set up an isolated `todo-mode' test environment."
   (declare (debug (body)))
-  `(let* ((todo-test-home (make-temp-file "todo-test-home-" t))
-          ;; Since we change HOME, clear this to avoid a conflict
-          ;; e.g. if Emacs runs within the user's home directory.
-          (abbreviated-home-dir nil)
-          (process-environment (cons (format "HOME=%s" todo-test-home)
-                                     process-environment))
-          (todo-directory (ert-resource-directory))
-          (todo-default-todo-file (todo-short-file-name
-                                  (car (funcall todo-files-function)))))
-     (unwind-protect
-         (progn ,@body)
-       ;; Restore pre-test-run state of test files.
-       (dolist (f (directory-files todo-directory))
-         (let ((buf (get-file-buffer f)))
-           (when buf
-             (with-current-buffer buf
-               (restore-buffer-modified-p nil)
-               (kill-buffer)))))
-       (delete-directory todo-test-home t))))
+  `(ert-with-temp-directory todo-test-home
+     (let* (;; Since we change HOME, clear this to avoid a conflict
+            ;; e.g. if Emacs runs within the user's home directory.
+            (abbreviated-home-dir nil)
+            (process-environment (cons (format "HOME=%s" todo-test-home)
+                                       process-environment))
+            (todo-directory (ert-resource-directory))
+            (todo-default-todo-file (todo-short-file-name
+                                 (car (funcall todo-files-function)))))
+       (unwind-protect
+           (progn ,@body)
+         ;; Restore pre-test-run state of test files.
+         (dolist (f (directory-files todo-directory))
+           (let ((buf (get-file-buffer f)))
+             (when buf
+               (with-current-buffer buf
+                 (restore-buffer-modified-p nil)
+                 (kill-buffer)))))))))
 
 (defun todo-test--show (num &optional archive)
   "Display category NUM of test todo file.
@@ -567,7 +566,7 @@ The remaining arguments (except _ARG, which is ignored) 
specify
 item insertion parameters.  This provides a noninteractive API
 for todo-insert-item for use in automatic testing."
   (cl-letf (((symbol-function 'read-from-minibuffer)
-             (lambda (_prompt) item))
+             (lambda (_prompt &rest _) item))
             ((symbol-function 'read-number) ; For todo-set-item-priority
              (lambda (_prompt &optional _default) (or priority 1))))
     (todo-insert-item--basic nil diary-type date-type time where)))
diff --git a/test/lisp/cedet/semantic-utest-c.el 
b/test/lisp/cedet/semantic-utest-c.el
index d08c79cad3..c5eb5b0ec0 100644
--- a/test/lisp/cedet/semantic-utest-c.el
+++ b/test/lisp/cedet/semantic-utest-c.el
@@ -60,7 +60,7 @@
              (semantic-fetch-tags))))
       (when (or (not tags-expected) (not tags-actual))
         (message "Tried to find test files in: %s" 
semantic-utest-c-test-directory)
-        (error "Failed:  Discovered no tags in test files or test file not 
found."))
+        (error "Failed:  Discovered no tags in test files or test file not 
found"))
 
       ;; Now that we have the tags, compare them for SPP accuracy.
       (dolist (tag tags-actual)
diff --git a/test/lisp/cedet/semantic-utest-ia.el 
b/test/lisp/cedet/semantic-utest-ia.el
index 122c431d47..6ea4ca1a16 100644
--- a/test/lisp/cedet/semantic-utest-ia.el
+++ b/test/lisp/cedet/semantic-utest-ia.el
@@ -489,4 +489,4 @@ tag that contains point, and return that."
 
 (provide 'semantic-ia-utest)
 
-;;; semantic-ia-utest.el ends here
+;;; semantic-utest-ia.el ends here
diff --git a/test/lisp/cedet/semantic-utest.el 
b/test/lisp/cedet/semantic-utest.el
index 172ab62f89..3e4cfb0f0c 100644
--- a/test/lisp/cedet/semantic-utest.el
+++ b/test/lisp/cedet/semantic-utest.el
@@ -29,6 +29,8 @@
 (require 'cedet)
 (require 'semantic)
 
+;;; Code:
+
 (defvar cedet-utest-directory
   (let* ((C (file-name-directory (locate-library "cedet")))
          (D (expand-file-name "../../test/manual/cedet/" C)))
@@ -103,7 +105,7 @@ int calc_sv(int);
 (defvar semantic-utest-C-filename-h
   (concat (file-name-sans-extension semantic-utest-C-filename)
          ".h")
-  "Header file filename for C")
+  "Header file filename for C.")
 
 
 (defvar semantic-utest-C-name-contents
@@ -424,8 +426,7 @@ class aClass {
      nil
      (overlay 135 262 "phptest.php"))
     )
-  "Expected results from the PHP Unit test"
-  )
+  "Expected results from the PHP Unit test.")
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/test/lisp/cedet/semantic/bovine/gcc-tests.el 
b/test/lisp/cedet/semantic/bovine/gcc-tests.el
index 93677d6c87..d049f95b4c 100644
--- a/test/lisp/cedet/semantic/bovine/gcc-tests.el
+++ b/test/lisp/cedet/semantic/bovine/gcc-tests.el
@@ -124,6 +124,11 @@ gcc version 2.95.2 19991024 (release)"
   "Test the output parser against the machine currently running Emacs."
   (skip-unless (executable-find "gcc"))
   (let ((semantic-gcc-test-strings (list (semantic-gcc-query "gcc" "-v"))))
-    (semantic-gcc-test-output-parser)))
+    ;; Some macOS machines run llvm when you type gcc.  (!)
+    ;; We can't even check if it's a symlink; it's a binary placed in
+    ;; "/usr/bin/gcc".  So check the output and just skip this test if
+    ;; it says "Apple LLVM".
+    (unless (string-match "Apple LLVM" (car semantic-gcc-test-strings))
+        (semantic-gcc-test-output-parser))))
 
 ;;; gcc-tests.el ends here
diff --git a/test/lisp/cedet/semantic/fw-tests.el 
b/test/lisp/cedet/semantic/fw-tests.el
index 7b1cd21bd1..6a5f3c85fc 100644
--- a/test/lisp/cedet/semantic/fw-tests.el
+++ b/test/lisp/cedet/semantic/fw-tests.el
@@ -42,4 +42,4 @@
       ;; retrieve cached data
       (should (equal (semantic-get-cache-data 'moose) data)))))
 
-;;; gw-tests.el ends here
+;;; fw-tests.el ends here
diff --git a/test/lisp/comint-tests.el b/test/lisp/comint-tests.el
index 8a9a41f452..0bd5c1e9d1 100644
--- a/test/lisp/comint-tests.el
+++ b/test/lisp/comint-tests.el
@@ -1,4 +1,4 @@
-;;; comint-tests.el  -*- lexical-binding:t -*-
+;;; comint-tests.el --- Tests for comint.el  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
@@ -43,6 +43,11 @@
     "PIN for user:"        ; Bug#35523
     "Password (again):"
     "Enter password:"
+    "(user@host) Password: " ; openssh-8.6p1
+    "Current password:"    ; "passwd" (to change password) in Debian.
+    "Enter encryption key: " ; ccrypt
+    "Enter decryption key: " ; ccrypt
+    "Enter encryption key: (repeat) " ; ccrypt
     "Enter Auth Password:" ; OpenVPN (Bug#35724)
     "Verify password: "    ; zip -e zipfile.zip ... (Bug#47209)
     "Mot de Passe :" ; localized (Bug#29729)
@@ -94,4 +99,4 @@ password flow if it returns a nil value."
 ;; no-byte-compile: t
 ;; End:
 
-;;; comint-testsuite.el ends here
+;;; comint-tests.el ends here
diff --git a/test/lisp/cus-edit-tests.el b/test/lisp/cus-edit-tests.el
index 97b3349000..f7d5283437 100644
--- a/test/lisp/cus-edit-tests.el
+++ b/test/lisp/cus-edit-tests.el
@@ -37,7 +37,7 @@
 
 ;;;; showing/hiding obsolete options
 
-(defgroup cus-edit-tests nil "test"
+(defgroup cus-edit-tests nil "Test."
   :group 'test-group)
 
 (defcustom cus-edit-tests--obsolete-option-tag nil
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
index f4c43b0a14..769db6ceab 100644
--- a/test/lisp/custom-tests.el
+++ b/test/lisp/custom-tests.el
@@ -25,20 +25,9 @@
 (require 'wid-edit)
 (require 'cus-edit)
 
-(defmacro custom-tests--with-temp-dir (&rest body)
-  "Eval BODY with `temporary-file-directory' bound to a fresh directory.
-Ensure the directory is recursively deleted after the fact."
-  (declare (debug t) (indent 0))
-  (let ((dir (make-symbol "dir")))
-    `(let ((,dir (file-name-as-directory (make-temp-file "custom-tests-" t))))
-       (unwind-protect
-           (let ((temporary-file-directory ,dir))
-             ,@body)
-         (delete-directory ,dir t)))))
-
 (ert-deftest custom-theme--load-path ()
   "Test `custom-theme--load-path' behavior."
-  (custom-tests--with-temp-dir
+  (ert-with-temp-directory temporary-file-directory
     ;; Path is empty.
     (let ((custom-theme-load-path ()))
       (should (null (custom-theme--load-path))))
@@ -50,28 +39,28 @@ Ensure the directory is recursively deleted after the fact."
       (should (null (custom-theme--load-path))))
 
     ;; Path comprises existing file.
-    (let* ((file (make-temp-file "file"))
-           (custom-theme-load-path (list file)))
-      (should (file-exists-p file))
-      (should (not (file-directory-p file)))
-      (should (null (custom-theme--load-path))))
+    (ert-with-temp-file file
+      (let* ((custom-theme-load-path (list file)))
+        (should (file-exists-p file))
+        (should (not (file-directory-p file)))
+        (should (null (custom-theme--load-path)))))
 
     ;; Path comprises existing directory.
-    (let* ((dir (make-temp-file "dir" t))
-           (custom-theme-load-path (list dir)))
-      (should (file-directory-p dir))
-      (should (equal (custom-theme--load-path) custom-theme-load-path)))
+    (ert-with-temp-directory dir
+      (let* ((custom-theme-load-path (list dir)))
+        (should (file-directory-p dir))
+        (should (equal (custom-theme--load-path) custom-theme-load-path))))
 
     ;; Expand `custom-theme-directory' path element.
     (let ((custom-theme-load-path '(custom-theme-directory)))
       (let ((custom-theme-directory (make-temp-name temporary-file-directory)))
         (should (not (file-exists-p custom-theme-directory)))
         (should (null (custom-theme--load-path))))
-      (let ((custom-theme-directory (make-temp-file "file")))
+      (ert-with-temp-file custom-theme-directory
         (should (file-exists-p custom-theme-directory))
         (should (not (file-directory-p custom-theme-directory)))
         (should (null (custom-theme--load-path))))
-      (let ((custom-theme-directory (make-temp-file "dir" t)))
+      (ert-with-temp-directory custom-theme-directory
         (should (file-directory-p custom-theme-directory))
         (should (equal (custom-theme--load-path)
                        (list custom-theme-directory)))))
@@ -97,7 +86,7 @@ Ensure the directory is recursively deleted after the fact."
 (ert-deftest custom-tests-require-theme ()
   "Test `require-theme'."
   (require 'warnings)
-  (custom-tests--with-temp-dir
+  (ert-with-temp-directory temporary-file-directory
     (let* ((default-directory temporary-file-directory)
            (custom-theme-load-path (list default-directory))
            (load-path ()))
diff --git a/test/lisp/dabbrev-tests.el b/test/lisp/dabbrev-tests.el
index 0b20dcf921..d3fe78b618 100644
--- a/test/lisp/dabbrev-tests.el
+++ b/test/lisp/dabbrev-tests.el
@@ -29,16 +29,15 @@
 
 (ert-deftest dabbrev-expand-test ()
   "Test for bug#1948.
-When DABBREV-ELIMINATE-NEWLINES is non-nil (the default),
-repeated calls to DABBREV-EXPAND can result in the source of
+When `dabbrev-eliminate-newlines' is non-nil (the default),
+repeated calls to `dabbrev-expand' can result in the source of
 first expansion being replaced rather than the destination."
   (with-temp-buffer
    (insert "ab  x\na\nab  y")
    (goto-char 8)
    (save-window-excursion
      (set-window-buffer nil (current-buffer))
-     ;; M-/ SPC M-/ M-/
-     (execute-kbd-macro "\257 \257\257"))
+     (execute-kbd-macro (kbd "M-/ SPC M-/ M-/")))
    (should (string= (buffer-string) "ab  x\nab y\nab  y"))))
 
 (ert-deftest dabbrev-completion-test ()
@@ -52,8 +51,7 @@ buffers unless a prefix argument is used."
       (goto-char 6)
       (save-window-excursion
         (set-window-buffer nil (current-buffer))
-        ;; C-M-/
-        (execute-kbd-macro [201326639]))
+        (execute-kbd-macro (kbd "C-M-/")))
       (should (string= (buffer-string) "abc\nabc")))))
 
 (ert-deftest dabbrev-completion-test-with-argument ()
@@ -67,6 +65,7 @@ multiple expansions."
       (goto-char 6)
       (save-window-excursion
         (set-window-buffer nil (current-buffer))
-        ;; C-u C-u C-M-/
-        (execute-kbd-macro [21 21 201326639]))
+        (execute-kbd-macro (kbd "C-u C-u C-M-/")))
       (should (string= (buffer-string) "abc\na")))))
+
+;;; dabbrev-tests.el ends here
diff --git a/test/lisp/descr-text-tests.el b/test/lisp/descr-text-tests.el
index 2052dc0e38..715fafa44c 100644
--- a/test/lisp/descr-text-tests.el
+++ b/test/lisp/descr-text-tests.el
@@ -91,4 +91,4 @@
 
 (provide 'descr-text-test)
 
-;;; descr-text-test.el ends here
+;;; descr-text-tests.el ends here
diff --git a/test/lisp/dired-aux-tests.el b/test/lisp/dired-aux-tests.el
index 7f1743f88d..374164f1f9 100644
--- a/test/lisp/dired-aux-tests.el
+++ b/test/lisp/dired-aux-tests.el
@@ -19,26 +19,25 @@
 
 ;;; Code:
 (require 'ert)
+(require 'ert-x)
 (require 'dired-aux)
 (eval-when-compile (require 'cl-lib))
 
 (ert-deftest dired-test-bug27496 ()
   "Test for https://debbugs.gnu.org/27496 ."
   (skip-unless (executable-find shell-file-name))
-  (let* ((foo (make-temp-file "foo"))
-         (files (list foo)))
-    (unwind-protect
-        (cl-letf (((symbol-function 'read-char-from-minibuffer) 'error))
-          (dired temporary-file-directory)
-          (dired-goto-file foo)
-          ;; `dired-do-shell-command' returns nil on success.
-          (should-error (dired-do-shell-command "ls ? ./?" nil files))
-          (should-error (dired-do-shell-command "ls ./? ?" nil files))
-          (should-not (dired-do-shell-command "ls ? ?" nil files))
-          (should-error (dired-do-shell-command "ls * ./*" nil files))
-          (should-not (dired-do-shell-command "ls * *" nil files))
-          (should-not (dired-do-shell-command "ls ? ./`?`" nil files)))
-      (delete-file foo))))
+  (ert-with-temp-file foo
+    (let* ((files (list foo)))
+      (cl-letf (((symbol-function 'read-char-from-minibuffer) 'error))
+        (dired temporary-file-directory)
+        (dired-goto-file foo)
+        ;; `dired-do-shell-command' returns nil on success.
+        (should-error (dired-do-shell-command "ls ? ./?" nil files))
+        (should-error (dired-do-shell-command "ls ./? ?" nil files))
+        (should-not (dired-do-shell-command "ls ? ?" nil files))
+        (should-error (dired-do-shell-command "ls * ./*" nil files))
+        (should-not (dired-do-shell-command "ls * *" nil files))
+        (should-not (dired-do-shell-command "ls ? ./`?`" nil files))))))
 
 ;; Auxiliary macro for `dired-test-bug28834': it binds
 ;; `dired-create-destination-dirs' to CREATE-DIRS and execute BODY.
@@ -47,24 +46,21 @@
 (defmacro with-dired-bug28834-test (create-dirs yes-or-no &rest body)
   (declare (debug (form symbolp body)))
   (let ((foo (make-symbol "foo")))
-    `(let* ((,foo (make-temp-file "foo" 'dir))
-            (dired-create-destination-dirs ,create-dirs))
-       (setq from (make-temp-file "from"))
-       (setq to-cp
-             (expand-file-name
-              "foo-cp" (file-name-as-directory (expand-file-name "bar" ,foo))))
-       (setq to-mv
-             (expand-file-name
-              "foo-mv" (file-name-as-directory (expand-file-name "qux" ,foo))))
-       (unwind-protect
-           (if ,yes-or-no
-               (cl-letf (((symbol-function 'yes-or-no-p)
-                          (lambda (_prompt) (eq ,yes-or-no 'yes))))
-                 ,@body)
-             ,@body)
-         ;; clean up
-         (delete-directory ,foo 'recursive)
-         (delete-file from)))))
+    `(ert-with-temp-directory ,foo
+       (ert-with-temp-file from
+         (let* ((dired-create-destination-dirs ,create-dirs))
+           (setq to-cp
+                 (expand-file-name
+                  "foo-cp" (file-name-as-directory (expand-file-name "bar" 
,foo))))
+           (setq to-mv
+                 (expand-file-name
+                  "foo-mv" (file-name-as-directory (expand-file-name "qux" 
,foo))))
+           (unwind-protect
+               (if ,yes-or-no
+                   (cl-letf (((symbol-function 'yes-or-no-p)
+                              (lambda (_prompt) (eq ,yes-or-no 'yes))))
+                     ,@body)
+                 ,@body)))))))
 
 (ert-deftest dired-test-bug28834 ()
   "test for https://debbugs.gnu.org/28834 ."
@@ -159,4 +155,4 @@
     (dired-test--check-highlighting (nth 0 lines) '(8))))
 
 (provide 'dired-aux-tests)
-;; dired-aux-tests.el ends here
+;;; dired-aux-tests.el ends here
diff --git a/test/lisp/dired-tests.el b/test/lisp/dired-tests.el
index aac78c64c6..ad1bca923d 100644
--- a/test/lisp/dired-tests.el
+++ b/test/lisp/dired-tests.el
@@ -19,6 +19,7 @@
 
 ;;; Code:
 (require 'ert)
+(require 'ert-x)
 (require 'dired)
 
 (ert-deftest dired-autoload ()
@@ -141,116 +142,113 @@
 
 (ert-deftest dired-test-bug27243-01 ()
   "Test for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27243#5 ."
-  (let* ((test-dir (file-name-as-directory (make-temp-file "test-dir-" t)))
-         (save-pos (lambda ()
-                     (with-current-buffer (car (dired-buffers-for-dir 
test-dir))
-                       (dired-save-positions))))
-         (dired-auto-revert-buffer t) buffers)
-    ;; On MS-Windows, get rid of 8+3 short names in test-dir, if the
-    ;; corresponding long file names exist, otherwise such names trip
-    ;; dired-buffers-for-dir.
-    (if (eq system-type 'windows-nt)
-        (setq test-dir (file-truename test-dir)))
-    (should-not (dired-buffers-for-dir test-dir))
-    (with-current-buffer (find-file-noselect test-dir)
-      (make-directory "test-subdir"))
-    (message "Saved pos: %S" (funcall save-pos))
-    ;; Point must be at end-of-buffer.
-    (with-current-buffer (car (dired-buffers-for-dir test-dir))
-      (should (eobp)))
-    (push (dired test-dir) buffers)
-    (message "Saved pos: %S" (funcall save-pos))
-    ;; Previous dired call shouldn't create a new buffer: must visit the one
-    ;; created by `find-file-noselect' above.
-    (should (eq 1 (length (dired-buffers-for-dir test-dir))))
-    (unwind-protect
-        (let ((buf (current-buffer))
-              (pt1 (point))
-              (test-file (concat (file-name-as-directory "test-subdir")
-                                 "test-file")))
-          (message "Saved pos: %S" (funcall save-pos))
-          (write-region "Test" nil test-file nil 'silent nil 'excl)
-          (message "Saved pos: %S" (funcall save-pos))
-          ;; Sanity check: point should now be on the subdirectory.
-          (should (equal (dired-file-name-at-point)
-                         (concat test-dir (file-name-as-directory 
"test-subdir"))))
-          (message "Saved pos: %S" (funcall save-pos))
-          (push (dired-find-file) buffers)
-          (let ((pt2 (point)))          ; Point is on test-file.
-            (pop-to-buffer-same-window buf)
-            ;; Sanity check: point should now be back on the subdirectory.
-            (should (eq (point) pt1))
+  (ert-with-temp-directory test-dir
+    (let* ((save-pos (lambda ()
+                       (with-current-buffer (car (dired-buffers-for-dir 
test-dir))
+                         (dired-save-positions))))
+           (dired-auto-revert-buffer t) buffers)
+      ;; On MS-Windows, get rid of 8+3 short names in test-dir, if the
+      ;; corresponding long file names exist, otherwise such names trip
+      ;; dired-buffers-for-dir.
+      (if (eq system-type 'windows-nt)
+          (setq test-dir (file-truename test-dir)))
+      (should-not (dired-buffers-for-dir test-dir))
+      (with-current-buffer (find-file-noselect test-dir)
+        (make-directory "test-subdir"))
+      (message "Saved pos: %S" (funcall save-pos))
+      ;; Point must be at end-of-buffer.
+      (with-current-buffer (car (dired-buffers-for-dir test-dir))
+        (should (eobp)))
+      (push (dired test-dir) buffers)
+      (message "Saved pos: %S" (funcall save-pos))
+      ;; Previous dired call shouldn't create a new buffer: must visit the one
+      ;; created by `find-file-noselect' above.
+      (should (eq 1 (length (dired-buffers-for-dir test-dir))))
+      (unwind-protect
+          (let ((buf (current-buffer))
+                (pt1 (point))
+                (test-file (concat (file-name-as-directory "test-subdir")
+                                   "test-file")))
+            (message "Saved pos: %S" (funcall save-pos))
+            (write-region "Test" nil test-file nil 'silent nil 'excl)
+            (message "Saved pos: %S" (funcall save-pos))
+            ;; Sanity check: point should now be on the subdirectory.
+            (should (equal (dired-file-name-at-point)
+                           (concat test-dir (file-name-as-directory 
"test-subdir"))))
+            (message "Saved pos: %S" (funcall save-pos))
             (push (dired-find-file) buffers)
-            (should (eq (point) pt2))))
-      (dolist (buf buffers)
-        (when (buffer-live-p buf) (kill-buffer buf)))
-      (delete-directory test-dir t))))
+            (let ((pt2 (point)))         ; Point is on test-file.
+              (pop-to-buffer-same-window buf)
+              ;; Sanity check: point should now be back on the subdirectory.
+              (should (eq (point) pt1))
+              (push (dired-find-file) buffers)
+              (should (eq (point) pt2))))
+        (dolist (buf buffers)
+          (when (buffer-live-p buf) (kill-buffer buf)))))))
 
 (ert-deftest dired-test-bug27243-02 ()
   "Test for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27243#28 ."
-  (let ((test-dir (make-temp-file "test-dir-" t))
-        (dired-auto-revert-buffer t) buffers)
-    ;; On MS-Windows, get rid of 8+3 short names in test-dir, if the
-    ;; corresponding long file names exist, otherwise such names trip
-    ;; string comparisons below.
-    (if (eq system-type 'windows-nt)
-        (setq test-dir (file-truename test-dir)))
-    (with-current-buffer (find-file-noselect test-dir)
-      (make-directory "test-subdir"))
-    (push (dired test-dir) buffers)
-    (unwind-protect
-        (let ((buf (current-buffer))
-              (pt1 (point))
-              (test-file (concat (file-name-as-directory "test-subdir")
-                                 "test-file")))
-          (write-region "Test" nil test-file nil 'silent nil 'excl)
-          ;; Sanity check: point should now be on the subdirectory.
-          (should (equal (dired-file-name-at-point)
-                         (concat (file-name-as-directory test-dir)
-                                 (file-name-as-directory "test-subdir"))))
-          (push (dired-find-file) buffers)
-          ;; Point is on test-file.
-          (switch-to-buffer buf)
-          ;; Sanity check: point should now be back on the subdirectory.
-          (should (eq (point) pt1))
-          (push (dired test-dir) buffers)
-          (should (eq (point) pt1)))
-      (dolist (buf buffers)
-        (when (buffer-live-p buf) (kill-buffer buf)))
-      (delete-directory test-dir t))))
+  (ert-with-temp-directory test-dir
+    (let ((dired-auto-revert-buffer t) buffers)
+      ;; On MS-Windows, get rid of 8+3 short names in test-dir, if the
+      ;; corresponding long file names exist, otherwise such names trip
+      ;; string comparisons below.
+      (if (eq system-type 'windows-nt)
+          (setq test-dir (file-truename test-dir)))
+      (with-current-buffer (find-file-noselect test-dir)
+        (make-directory "test-subdir"))
+      (push (dired test-dir) buffers)
+      (unwind-protect
+          (let ((buf (current-buffer))
+                (pt1 (point))
+                (test-file (concat (file-name-as-directory "test-subdir")
+                                   "test-file")))
+            (write-region "Test" nil test-file nil 'silent nil 'excl)
+            ;; Sanity check: point should now be on the subdirectory.
+            (should (equal (dired-file-name-at-point)
+                           (concat (file-name-as-directory test-dir)
+                                   (file-name-as-directory "test-subdir"))))
+            (push (dired-find-file) buffers)
+            ;; Point is on test-file.
+            (switch-to-buffer buf)
+            ;; Sanity check: point should now be back on the subdirectory.
+            (should (eq (point) pt1))
+            (push (dired test-dir) buffers)
+            (should (eq (point) pt1)))
+        (dolist (buf buffers)
+          (when (buffer-live-p buf) (kill-buffer buf)))))))
 
 (ert-deftest dired-test-bug27243-03 ()
   "Test for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=27243#61 ."
-  (let ((test-dir (make-temp-file "test-dir-" t))
-        (dired-auto-revert-buffer t)
-        allbufs)
-    (unwind-protect
-        (progn
-          (with-current-buffer (find-file-noselect test-dir)
-            (push (current-buffer) allbufs)
-            (make-directory "test-subdir1")
-            (make-directory "test-subdir2")
-            (let ((test-file1 "test-file1")
-                  (test-file2 "test-file2"))
-              (with-current-buffer (find-file-noselect "test-subdir1")
-                (push (current-buffer) allbufs)
-                (write-region "Test1" nil test-file1 nil 'silent nil 'excl))
-              (with-current-buffer (find-file-noselect "test-subdir2")
-                (push (current-buffer) allbufs)
-                (write-region "Test2" nil test-file2 nil 'silent nil 'excl))))
-          ;; Call find-file with a wild card and test point in each file.
-          (let ((buffers (find-file (concat (file-name-as-directory test-dir)
-                                            "*")
-                                    t)))
-            (dolist (buf buffers)
-              (let ((pt (with-current-buffer buf (point))))
-                (switch-to-buffer (find-file-noselect test-dir))
-                (find-file (buffer-name buf))
-                (should (equal (point) pt))))
-            (append buffers allbufs)))
-      (dolist (buf allbufs)
-        (when (buffer-live-p buf) (kill-buffer buf)))
-      (delete-directory test-dir t))))
+  (ert-with-temp-directory test-dir
+    (let ((dired-auto-revert-buffer t)
+          allbufs)
+      (unwind-protect
+          (progn
+            (with-current-buffer (find-file-noselect test-dir)
+              (push (current-buffer) allbufs)
+              (make-directory "test-subdir1")
+              (make-directory "test-subdir2")
+              (let ((test-file1 "test-file1")
+                    (test-file2 "test-file2"))
+                (with-current-buffer (find-file-noselect "test-subdir1")
+                  (push (current-buffer) allbufs)
+                  (write-region "Test1" nil test-file1 nil 'silent nil 'excl))
+                (with-current-buffer (find-file-noselect "test-subdir2")
+                  (push (current-buffer) allbufs)
+                  (write-region "Test2" nil test-file2 nil 'silent nil 
'excl))))
+            ;; Call find-file with a wild card and test point in each file.
+            (let ((buffers (find-file (concat (file-name-as-directory test-dir)
+                                              "*")
+                                      t)))
+              (dolist (buf buffers)
+                (let ((pt (with-current-buffer buf (point))))
+                  (switch-to-buffer (find-file-noselect test-dir))
+                  (find-file (buffer-name buf))
+                  (should (equal (point) pt))))
+              (append buffers allbufs)))
+        (dolist (buf allbufs)
+          (when (buffer-live-p buf) (kill-buffer buf)))))))
 
 (ert-deftest dired-test-bug7131 ()
   "Test for https://debbugs.gnu.org/7131 ."
@@ -274,22 +272,21 @@
   ;; ls-lisp-tests.el and em-ls-tests.el.
   (skip-unless (and (not (featurep 'ls-lisp))
                     (not (featurep 'eshell))))
-  (let* ((dir (make-temp-file "bug27631" 'dir))
-         (dir1 (expand-file-name "dir1" dir))
-         (dir2 (expand-file-name "dir2" dir))
-         (default-directory dir)
-         buf)
-    (unwind-protect
-        (progn
-          (make-directory dir1)
-          (make-directory dir2)
-          (with-temp-file (expand-file-name "a.txt" dir1))
-          (with-temp-file (expand-file-name "b.txt" dir2))
-          (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
-          (dired-toggle-marks)
-          (should (cdr (dired-get-marked-files))))
-      (delete-directory dir 'recursive)
-      (when (buffer-live-p buf) (kill-buffer buf)))))
+  (ert-with-temp-directory dir
+    (let* ((dir1 (expand-file-name "dir1" dir))
+           (dir2 (expand-file-name "dir2" dir))
+           (default-directory dir)
+           buf)
+      (unwind-protect
+          (progn
+            (make-directory dir1)
+            (make-directory dir2)
+            (with-temp-file (expand-file-name "a.txt" dir1))
+            (with-temp-file (expand-file-name "b.txt" dir2))
+            (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
+            (dired-toggle-marks)
+            (should (cdr (dired-get-marked-files))))
+        (when (buffer-live-p buf) (kill-buffer buf))))))
 
 (ert-deftest dired-test-bug27899 ()
   "Test for https://debbugs.gnu.org/27899 ."
@@ -310,72 +307,69 @@
 
 (ert-deftest dired-test-bug27968 ()
   "Test for https://debbugs.gnu.org/27968 ."
-  (let* ((top-dir (make-temp-file "top-dir" t))
-         (subdir (expand-file-name "subdir" top-dir))
-         (header-len-fn (lambda ()
-                          (save-excursion
-                            (goto-char 1)
-                            (forward-line 1)
-                            (- (point-at-eol) (point)))))
-         orig-len len diff pos line-nb)
-    (make-directory subdir 'parents)
-    (unwind-protect
-        (with-current-buffer (dired-noselect subdir)
-          (setq orig-len (funcall header-len-fn)
-                pos (point)
-                line-nb (line-number-at-pos))
-          ;; Bug arises when the header line changes its length; this may
-          ;; happen if the used space has changed: for instance, with the
-          ;; creation of additional files.
-          (make-directory "subdir" t)
-          (dired-revert)
-          ;; Change the header line.
-          (save-excursion
-            (goto-char 1)
-            (forward-line 1)
-            (let ((inhibit-read-only t)
-                  (new-header "  test-bug27968"))
-              (delete-region (point) (point-at-eol))
-              (when (= orig-len (length new-header))
-                ;; Wow lucky guy! I must buy lottery today.
-                (setq new-header (concat new-header " :-)")))
-              (insert new-header)))
-          (setq len (funcall header-len-fn)
-                diff (- len orig-len))
-          (should-not (zerop diff)) ; Header length has changed.
-          ;; If diff > 0, then the point moves back.
-          ;; If diff < 0, then the point moves forward.
-          ;; If diff = 0, then the point doesn't move.
-          ;; Sometimes this point movement causes
-          ;; line-nb != (line-number-at-pos pos), so that we get
-          ;; an unexpected file at point if we store buffer points.
-          ;; Note that the line number before/after revert
-          ;; doesn't change.
-          (should (= line-nb
-                     (line-number-at-pos)
-                     (line-number-at-pos (+ pos diff))))
-          ;; After revert, the point must be in 'subdir' line.
-          (should (equal "subdir" (dired-get-filename 'local t))))
-      (delete-directory top-dir t))))
+  (ert-with-temp-directory top-dir
+    (let* ((subdir (expand-file-name "subdir" top-dir))
+           (header-len-fn (lambda ()
+                            (save-excursion
+                              (goto-char 1)
+                              (forward-line 1)
+                              (- (point-at-eol) (point)))))
+           orig-len len diff pos line-nb)
+      (make-directory subdir 'parents)
+      (with-current-buffer (dired-noselect subdir)
+        (setq orig-len (funcall header-len-fn)
+              pos (point)
+              line-nb (line-number-at-pos))
+        ;; Bug arises when the header line changes its length; this may
+        ;; happen if the used space has changed: for instance, with the
+        ;; creation of additional files.
+        (make-directory "subdir" t)
+        (dired-revert)
+        ;; Change the header line.
+        (save-excursion
+          (goto-char 1)
+          (forward-line 1)
+          (let ((inhibit-read-only t)
+                (new-header "  test-bug27968"))
+            (delete-region (point) (point-at-eol))
+            (when (= orig-len (length new-header))
+              ;; Wow lucky guy! I must buy lottery today.
+              (setq new-header (concat new-header " :-)")))
+            (insert new-header)))
+        (setq len (funcall header-len-fn)
+              diff (- len orig-len))
+        (should-not (zerop diff))    ; Header length has changed.
+        ;; If diff > 0, then the point moves back.
+        ;; If diff < 0, then the point moves forward.
+        ;; If diff = 0, then the point doesn't move.
+        ;; Sometimes this point movement causes
+        ;; line-nb != (line-number-at-pos pos), so that we get
+        ;; an unexpected file at point if we store buffer points.
+        ;; Note that the line number before/after revert
+        ;; doesn't change.
+        (should (= line-nb
+                   (line-number-at-pos)
+                   (line-number-at-pos (+ pos diff))))
+        ;; After revert, the point must be in 'subdir' line.
+        (should (equal "subdir" (dired-get-filename 'local t)))))))
 
 
 (defmacro dired-test-with-temp-dirs (just-empty-dirs &rest body)
   "Helper macro for Bug#27940 test."
   (declare (indent 1) (debug body))
   (let ((dir (make-symbol "dir")))
-    `(let* ((,dir (make-temp-file "bug27940" t))
-            (dired-deletion-confirmer (lambda (_) "yes")) ; Suppress prompts.
-            (inhibit-message t)
-            (default-directory ,dir))
-       (dotimes (i 5) (make-directory (format "empty-dir-%d" i)))
-       (unless ,just-empty-dirs
-         (dotimes (i 5) (make-directory (format "non-empty-%d/foo" i) 
'parents)))
-       (make-directory "zeta-empty-dir")
-       (unwind-protect
-           (progn
-             ,@body)
-         (delete-directory ,dir t)
-         (kill-buffer (current-buffer))))))
+    `(ert-with-temp-directory ,dir
+       (let* ((dired-deletion-confirmer (lambda (_) "yes")) ; Suppress prompts.
+              (inhibit-message t)
+              (default-directory ,dir))
+         (dotimes (i 5) (make-directory (format "empty-dir-%d" i)))
+         (unless ,just-empty-dirs
+           (dotimes (i 5) (make-directory (format "non-empty-%d/foo" i) 
'parents)))
+         (make-directory "zeta-empty-dir")
+         (unwind-protect
+             (progn
+               ,@body)
+           (kill-buffer (current-buffer)))))))
 
 (ert-deftest dired-test-bug27940 ()
   "Test for https://debbugs.gnu.org/27940 ."
@@ -518,4 +512,4 @@
         (delete-directory testdir t)))))
 
 (provide 'dired-tests)
-;; dired-tests.el ends here
+;;; dired-tests.el ends here
diff --git a/test/lisp/dired-x-tests.el b/test/lisp/dired-x-tests.el
index 003923d60f..fe4b9711d4 100644
--- a/test/lisp/dired-x-tests.el
+++ b/test/lisp/dired-x-tests.el
@@ -19,6 +19,7 @@
 
 ;;; Code:
 (require 'ert)
+(require 'ert-x)
 (require 'dired-x)
 
 
@@ -31,23 +32,20 @@
            (append (copy-sequence dirs)
                    (delete "c" (copy-sequence files)))
            #'string<))
-         (dir (make-temp-file "Bug25942" 'dir))
          (extension "c"))
-    (unwind-protect
-        (progn
-          (dolist (d dirs)
-            (make-directory (expand-file-name d dir)))
-          (dolist (f files)
-            (write-region nil nil (expand-file-name f dir)))
-          (dired dir)
-          (dired-mark-extension extension)
-          (should (equal '("bar.c" "foo.c")
-                         (sort (dired-get-marked-files 'local) #'string<)))
-          (dired-unmark-all-marks)
-          (dired-mark-suffix extension)
-          (should (equal all-but-c
-                         (sort (dired-get-marked-files 'local) #'string<))))
-      (delete-directory dir 'recursive))))
+    (ert-with-temp-directory dir
+      (dolist (d dirs)
+        (make-directory (expand-file-name d dir)))
+      (dolist (f files)
+        (write-region nil nil (expand-file-name f dir)))
+      (dired dir)
+      (dired-mark-extension extension)
+      (should (equal '("bar.c" "foo.c")
+                     (sort (dired-get-marked-files 'local) #'string<)))
+      (dired-unmark-all-marks)
+      (dired-mark-suffix extension)
+      (should (equal all-but-c
+                     (sort (dired-get-marked-files 'local) #'string<))))))
 
 (ert-deftest dired-guess-default ()
   (let ((dired-guess-shell-alist-user nil)
@@ -63,4 +61,4 @@
                    nil))))
 
 (provide 'dired-x-tests)
-;; dired-x-tests.el ends here
+;;; dired-x-tests.el ends here
diff --git a/test/lisp/edmacro-tests.el b/test/lisp/edmacro-tests.el
new file mode 100644
index 0000000000..974f506a36
--- /dev/null
+++ b/test/lisp/edmacro-tests.el
@@ -0,0 +1,47 @@
+;;; edmacro-tests.el --- Tests for edmacro.el  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'edmacro)
+
+(ert-deftest edmacro-test-edmacro-parse-keys ()
+  (should (equal (edmacro-parse-keys "") ""))
+  (should (equal (edmacro-parse-keys "x") "x"))
+  (should (equal (edmacro-parse-keys "C-a") "\C-a"))
+
+  ;; comments
+  (should (equal (edmacro-parse-keys ";; foobar") ""))
+  (should (equal (edmacro-parse-keys ";;;") ""))
+  (should (equal (edmacro-parse-keys "; ; ;") ";;;"))
+  (should (equal (edmacro-parse-keys "REM foobar") ""))
+  (should (equal (edmacro-parse-keys "x ;; foobar") "x"))
+  (should (equal (edmacro-parse-keys "x REM foobar") "x"))
+  (should (equal (edmacro-parse-keys "<<goto-line>>")
+                 [134217848 103 111 116 111 45 108 105 110 101 13]))
+
+  ;; repetitions
+  (should (equal (edmacro-parse-keys "3*x") "xxx"))
+  (should (equal (edmacro-parse-keys "3*C-m") "\C-m\C-m\C-m"))
+  (should (equal (edmacro-parse-keys "10*foo") 
"foofoofoofoofoofoofoofoofoofoo")))
+
+;;; edmacro-tests.el ends here
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 46bcbfce30..1e32dbfb60 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -54,17 +54,18 @@
                                        expected-point mode bindings
                                        fixture-fn &optional doc-string)
   (with-temp-buffer
-    (funcall mode)
-    (insert fixture)
-    (save-electric-modes
-      (let ((last-command-event char)
-            (transient-mark-mode 'lambda))
-        (goto-char where)
-        (funcall fixture-fn)
-        (cl-progv
-            (mapcar #'car bindings)
-            (mapcar #'cdr bindings)
-          (call-interactively (key-binding `[,last-command-event])))))
+    (dlet ((python-indent-guess-indent-offset-verbose nil))
+      (funcall mode)
+      (insert fixture)
+      (save-electric-modes
+       (let ((last-command-event char)
+             (transient-mark-mode 'lambda))
+         (goto-char where)
+         (funcall fixture-fn)
+         (cl-progv
+             (mapcar #'car bindings)
+             (mapcar #'cdr bindings)
+           (call-interactively (key-binding `[,last-command-event]))))))
     (when
         (and doc-string
              (not
@@ -98,21 +99,22 @@
                       ;; FIXME: avoid `eval'
                       (mapcar #'car (eval bindings))
                       (mapcar #'cdr (eval bindings))
-                    (funcall mode)
-                    (insert fixture)
-                    (goto-char (1+ pos))
-                    (insert char)
-                    (cond ((eq (aref skip-pair-string pos)
-                               ?p)
-                           (insert (cadr (electric-pair-syntax-info char)))
-                           (backward-char 1))
-                          ((eq (aref skip-pair-string pos)
-                               ?s)
-                           (delete-char -1)
-                           (forward-char 1)))
-                    (list
-                     (buffer-substring-no-properties (point-min) (point-max))
-                     (point))))
+                    (dlet ((python-indent-guess-indent-offset-verbose nil))
+                      (funcall mode)
+                      (insert fixture)
+                      (goto-char (1+ pos))
+                      (insert char)
+                      (cond ((eq (aref skip-pair-string pos)
+                                 ?p)
+                             (insert (cadr (electric-pair-syntax-info char)))
+                             (backward-char 1))
+                            ((eq (aref skip-pair-string pos)
+                                 ?s)
+                             (delete-char -1)
+                             (forward-char 1)))
+                      (list
+                       (buffer-substring-no-properties (point-min) (point-max))
+                       (point)))))
               (list expected-string expected-point)))
            (expected-string (car expected-string-and-point))
            (expected-point (cadr expected-string-and-point))
@@ -174,7 +176,7 @@ The buffer's contents should %s:
           expected-string
           expected-point
           bindings
-          (modes '(quote (ruby-mode js-mode python-mode)))
+          (modes '(quote (ruby-mode js-mode python-mode c-mode)))
           (test-in-comments t)
           (test-in-strings t)
           (test-in-code t)
@@ -191,11 +193,13 @@ The buffer's contents should %s:
          for (prefix suffix extra-desc) in
          (append (if test-in-comments
                      `((,(with-temp-buffer
-                           (funcall mode)
-                           (insert "z")
-                           (comment-region (point-min) (point-max))
-                           (buffer-substring-no-properties (point-min)
-                                                           (1- (point-max))))
+                           (dlet ((python-indent-guess-indent-offset-verbose
+                                   nil))
+                             (funcall mode)
+                             (insert "z")
+                             (comment-region (point-min) (point-max))
+                             (buffer-substring-no-properties (point-min)
+                                                             (1- 
(point-max)))))
                         ""
                         "-in-comments")))
                  (if test-in-strings
@@ -424,7 +428,9 @@ baz\"\""
   :bindings '((electric-pair-skip-whitespace . chomp))
   :test-in-strings nil
   :test-in-code nil
-  :test-in-comments t)
+  :test-in-comments t
+  :fixture-fn (lambda () (when (eq major-mode 'c-mode)
+                           (c-toggle-comment-style -1))))
 
 (define-electric-pair-test whitespace-skipping-for-quotes-not-outside
   "  \"  \"" "\"-----" :expected-string "\"\"  \"  \""
@@ -871,7 +877,7 @@ baz\"\""
     (local-set-key (vector key) 'self-insert-command)))
 
 (defun electric-layout-for-c-style-du-jour (inserted)
-  "A function to use in `electric-layout-rules'"
+  "A function to use in `electric-layout-rules'."
   (when (memq inserted '(?\{ ?\}))
     (save-excursion
       (backward-char 2) (c-point-syntax) (forward-char) ; silly, but needed
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el 
b/test/lisp/emacs-lisp/bytecomp-tests.el
index 2832dd0246..dbc0aa3db4 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -1,4 +1,4 @@
-;;; bytecomp-tests.el  -*- lexical-binding:t -*-
+;;; bytecomp-tests.el --- Tests for bytecomp.el  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
 
@@ -41,6 +41,24 @@
   "Identity, but hidden from some optimisations."
   x)
 
+(defmacro bytecomp-test-loop (outer1 outer2 inner1 inner2)
+  "Exercise constant propagation inside `while' loops.
+OUTER1, OUTER2, INNER1 and INNER2 are forms placed in the outer and
+inner loops respectively."
+  `(let ((x 1) (i 3) (res nil))
+     (while (> i 0)
+       (let ((y 2) (j 2))
+         (setq res (cons (list 'outer x y) res))
+         (while (> j 0)
+           (setq res (cons (list 'inner x y) res))
+           ,inner1
+           ,inner2
+           (setq j (1- j)))
+         ,outer1
+         ,outer2)
+       (setq i (1- i)))
+     res))
+
 (defconst bytecomp-tests--test-cases
   '(
     ;; some functional tests
@@ -454,6 +472,25 @@
                       (setq x 10))))
      4)
 
+    ;; Loop constprop: set the inner and outer variables in the inner
+    ;; and outer loops, all combinations.
+    (bytecomp-test-loop nil        nil        nil        nil       )
+    (bytecomp-test-loop nil        nil        nil        (setq x 6))
+    (bytecomp-test-loop nil        nil        (setq x 5) nil       )
+    (bytecomp-test-loop nil        nil        (setq x 5) (setq x 6))
+    (bytecomp-test-loop nil        (setq x 4) nil        nil       )
+    (bytecomp-test-loop nil        (setq x 4) nil        (setq x 6))
+    (bytecomp-test-loop nil        (setq x 4) (setq x 5) nil       )
+    (bytecomp-test-loop nil        (setq x 4) (setq x 5) (setq x 6))
+    (bytecomp-test-loop (setq x 3) nil        nil        nil       )
+    (bytecomp-test-loop (setq x 3) nil        nil        (setq x 6))
+    (bytecomp-test-loop (setq x 3) nil        (setq x 5) nil       )
+    (bytecomp-test-loop (setq x 3) nil        (setq x 5) (setq x 6))
+    (bytecomp-test-loop (setq x 3) (setq x 4) nil        nil       )
+    (bytecomp-test-loop (setq x 3) (setq x 4) nil        (setq x 6))
+    (bytecomp-test-loop (setq x 3) (setq x 4) (setq x 5) nil       )
+    (bytecomp-test-loop (setq x 3) (setq x 4) (setq x 5) (setq x 6))
+
     ;; No error, no success handler.
     (condition-case x
         (list 42)
@@ -536,6 +573,14 @@
     (let ((_a 1)
           (_b 2))
       'z)
+    (let (x y)
+      y)
+    (let* (x y)
+      y)
+    (let (x y)
+      'a)
+    (let* (x y)
+      'a)
 
     ;; Check empty-list optimisations.
     (mapcar (lambda (x) (member x nil)) '("a" 2 nil))
@@ -595,6 +640,9 @@
            (f (list (lambda (x) (setq a x)))))
       (funcall (car f) 3)
       (list a b))
+
+    (cond)
+    (mapcar (lambda (x) (cond ((= x 0)))) '(0 1))
     )
   "List of expressions for cross-testing interpreted and compiled code.")
 
@@ -645,24 +693,19 @@ byte-compiled.  Run with dynamic binding."
 
 (defun test-byte-comp-compile-and-load (compile &rest forms)
   (declare (indent 1))
-  (let ((elfile nil)
-        (elcfile nil))
-    (unwind-protect
-         (progn
-           (setf elfile (make-temp-file "test-bytecomp" nil ".el"))
-           (when compile
-             (setf elcfile (make-temp-file "test-bytecomp" nil ".elc")))
-           (with-temp-buffer
-             (dolist (form forms)
-               (print form (current-buffer)))
-             (write-region (point-min) (point-max) elfile nil 'silent))
-           (if compile
-               (let ((byte-compile-dest-file-function
-                      (lambda (e) elcfile)))
-                 (byte-compile-file elfile)))
-           (load elfile nil 'nomessage))
-      (when elfile (delete-file elfile))
-      (when elcfile (delete-file elcfile)))))
+  (ert-with-temp-file elfile
+    :suffix ".el"
+    (ert-with-temp-file elcfile
+      :suffix ".elc"
+      (with-temp-buffer
+        (dolist (form forms)
+          (print form (current-buffer)))
+        (write-region (point-min) (point-max) elfile nil 'silent))
+      (if compile
+          (let ((byte-compile-dest-file-function
+                 (lambda (e) elcfile)))
+            (byte-compile-file elfile)))
+      (load elfile nil 'nomessage))))
 
 (ert-deftest test-byte-comp-macro-expansion ()
   (test-byte-comp-compile-and-load t
@@ -892,10 +935,9 @@ byte-compiled.  Run with dynamic binding."
  "warn-wide-docstring-define-obsolete-variable-alias.el"
  "defvaralias .foo. docstring wider than .* characters")
 
-;; TODO: We don't yet issue warnings for defuns.
 (bytecomp--define-warning-file-test
  "warn-wide-docstring-defun.el"
- "wider than .* characters" 'reverse)
+ "wider than .* characters")
 
 (bytecomp--define-warning-file-test
  "warn-wide-docstring-defvar.el"
@@ -969,10 +1011,9 @@ byte-compiled.  Run with dynamic binding."
 (defmacro bytecomp-tests--with-temp-file (file-name-var &rest body)
   (declare (indent 1))
   (cl-check-type file-name-var symbol)
-  `(let ((,file-name-var (make-temp-file "emacs")))
+  `(ert-with-temp-file ,file-name-var
      (unwind-protect
          (progn ,@body)
-       (delete-file ,file-name-var)
        (let ((elc (concat ,file-name-var ".elc")))
          (if (file-exists-p elc) (delete-file elc))))))
 
@@ -1199,25 +1240,25 @@ literals (Bug#20852)."
 (ert-deftest bytecomp-tests--not-writable-directory ()
   "Test that byte compilation works if the output directory isn't
 writable (Bug#44631)."
-  (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
-    (unwind-protect
-        (let* ((input-file (expand-file-name "test.el" directory))
-               (output-file (expand-file-name "test.elc" directory))
-               (byte-compile-dest-file-function
-                (lambda (_) output-file))
-               (byte-compile-error-on-warn t))
-          (write-region "" nil input-file nil nil nil 'excl)
-          (write-region "" nil output-file nil nil nil 'excl)
-          (set-file-modes input-file #o400)
-          (set-file-modes output-file #o200)
-          (set-file-modes directory #o500)
-          (should (byte-compile-file input-file))
-          (should (file-regular-p output-file))
-          (should (cl-plusp (file-attribute-size
-                             (file-attributes output-file)))))
-      (with-demoted-errors "Error cleaning up directory: %s"
-        (set-file-modes directory #o700)
-        (delete-directory directory :recursive)))))
+  (ert-with-temp-directory directory
+    (let* ((input-file (expand-file-name "test.el" directory))
+           (output-file (expand-file-name "test.elc" directory))
+           (byte-compile-dest-file-function
+            (lambda (_) output-file))
+           (byte-compile-error-on-warn t))
+      (unwind-protect
+          (progn
+            (write-region "" nil input-file nil nil nil 'excl)
+            (write-region "" nil output-file nil nil nil 'excl)
+            (set-file-modes input-file #o400)
+            (set-file-modes output-file #o200)
+            (set-file-modes directory #o500)
+            (should (byte-compile-file input-file))
+            (should (file-regular-p output-file))
+            (should (cl-plusp (file-attribute-size
+                               (file-attributes output-file)))))
+        ;; Allow the directory to be deleted.
+        (set-file-modes directory #o777)))))
 
 (ert-deftest bytecomp-tests--dest-mountpoint ()
   "Test that byte compilation works if the destination file is a
@@ -1229,56 +1270,53 @@ mountpoint (Bug#44631)."
     (skip-unless (not (file-remote-p bwrap)))
     (skip-unless (file-executable-p emacs))
     (skip-unless (not (file-remote-p emacs)))
-    (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
-      (unwind-protect
-          (let* ((input-file (expand-file-name "test.el" directory))
-                 (output-file (expand-file-name "test.elc" directory))
-                 (unquoted-file (file-name-unquote output-file))
-                 (byte-compile-dest-file-function
-                  (lambda (_) output-file))
-                 (byte-compile-error-on-warn t))
-            (should-not (file-remote-p input-file))
-            (should-not (file-remote-p output-file))
-            (write-region "" nil input-file nil nil nil 'excl)
-            (write-region "" nil output-file nil nil nil 'excl)
-            (set-file-modes input-file #o400)
-            (set-file-modes output-file #o200)
-            (set-file-modes directory #o500)
-            (with-temp-buffer
-              (let ((status (call-process
-                             bwrap nil t nil
-                             "--ro-bind" "/" "/"
-                             "--bind" unquoted-file unquoted-file
-                             emacs "--quick" "--batch" "--load=bytecomp"
-                             (format "--eval=%S"
-                                     `(setq byte-compile-dest-file-function
-                                            (lambda (_) ,output-file)
-                                            byte-compile-error-on-warn t))
-                             "--funcall=batch-byte-compile" input-file)))
-                (unless (eql status 0)
-                  (ert-fail `((status . ,status)
-                              (output . ,(buffer-string)))))))
-            (should (file-regular-p output-file))
-            (should (cl-plusp (file-attribute-size
-                               (file-attributes output-file)))))
-        (with-demoted-errors "Error cleaning up directory: %s"
-          (set-file-modes directory #o700)
-          (delete-directory directory :recursive))))))
+    (ert-with-temp-directory directory
+      (let* ((input-file (expand-file-name "test.el" directory))
+             (output-file (expand-file-name "test.elc" directory))
+             (unquoted-file (file-name-unquote output-file))
+             (byte-compile-dest-file-function
+              (lambda (_) output-file))
+             (byte-compile-error-on-warn t))
+        (should-not (file-remote-p input-file))
+        (should-not (file-remote-p output-file))
+        (write-region "" nil input-file nil nil nil 'excl)
+        (write-region "" nil output-file nil nil nil 'excl)
+        (unwind-protect
+            (progn
+              (set-file-modes input-file #o400)
+              (set-file-modes output-file #o200)
+              (set-file-modes directory #o500)
+              (with-temp-buffer
+                (let ((status (call-process
+                               bwrap nil t nil
+                               "--ro-bind" "/" "/"
+                               "--bind" unquoted-file unquoted-file
+                               emacs "--quick" "--batch" "--load=bytecomp"
+                               (format "--eval=%S"
+                                       `(setq byte-compile-dest-file-function
+                                              (lambda (_) ,output-file)
+                                              byte-compile-error-on-warn t))
+                               "--funcall=batch-byte-compile" input-file)))
+                  (unless (eql status 0)
+                    (ert-fail `((status . ,status)
+                                (output . ,(buffer-string)))))))
+              (should (file-regular-p output-file))
+              (should (cl-plusp (file-attribute-size
+                                 (file-attributes output-file)))))
+          ;; Allow the directory to be deleted.
+          (set-file-modes directory #o777))))))
 
 (ert-deftest bytecomp-tests--target-file-no-directory ()
   "Check that Bug#45287 is fixed."
-  (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
-    (unwind-protect
-        (let* ((default-directory directory)
-               (byte-compile-dest-file-function (lambda (_) "test.elc"))
-               (byte-compile-error-on-warn t))
-          (write-region "" nil "test.el" nil nil nil 'excl)
-          (should (byte-compile-file "test.el"))
-          (should (file-regular-p "test.elc"))
-          (should (cl-plusp (file-attribute-size
-                             (file-attributes "test.elc")))))
-      (with-demoted-errors "Error cleaning up directory: %s"
-        (delete-directory directory :recursive)))))
+  (ert-with-temp-directory directory
+    (let* ((default-directory directory)
+           (byte-compile-dest-file-function (lambda (_) "test.elc"))
+           (byte-compile-error-on-warn t))
+      (write-region "" nil "test.el" nil nil nil 'excl)
+      (should (byte-compile-file "test.el"))
+      (should (file-regular-p "test.elc"))
+      (should (cl-plusp (file-attribute-size
+                         (file-attributes "test.elc")))))))
 
 (defun bytecomp-tests--get-vars ()
   (list (ignore-errors (symbol-value 'bytecomp-tests--var1))
@@ -1425,9 +1463,33 @@ compiled correctly."
     (load-file (concat file "c"))
     (should (equal (bc-test-alpha-f 'a) '(nil a)))))
 
+(ert-deftest bytecomp-tests-byte-compile--wide-docstring-p/func-arg-list ()
+  (should-not (byte-compile--wide-docstring-p "\
+\(dbus-register-property BUS SERVICE PATH INTERFACE PROPERTY ACCESS \
+[TYPE] VALUE &optional EMITS-SIGNAL DONT-REGISTER-SERVICE)" fill-column))
+  (should-not (byte-compile--wide-docstring-p "\
+(fn CMD FLAGS FIS &key (BUF (cvs-temp-buffer)) DONT-CHANGE-DISC CVSARGS \
+POSTPROC)" fill-column))
+  ;; Bug#49007
+  (should-not (byte-compile--wide-docstring-p "\
+(fn (THIS rudel-protocol-backend) TRANSPORT \
+INFO INFO-CALLBACK &optional PROGRESS-CALLBACK)" fill-column))
+  (should-not (byte-compile--wide-docstring-p "\
+\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \
+[:tags \\='(TAG...)] BODY...)" fill-column))
+  (should-not (byte-compile--wide-docstring-p "\
+(make-soap-xs-element &key NAME NAMESPACE-TAG ID TYPE^ OPTIONAL? MULTIPLE? \
+REFERENCE SUBSTITUTION-GROUP ALTERNATIVES IS-GROUP)" fill-column))
+  (should-not (byte-compile--wide-docstring-p "\
+(fn NAME FIXTURE INPUT &key SKIP-PAIR-STRING EXPECTED-STRING \
+EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode python-mode)) \
+(TEST-IN-COMMENTS t) (TEST-IN-STRINGS t) (TEST-IN-CODE t) \
+(FIXTURE-FN \\='#\\='electric-pair-mode))" fill-column)))
+
+
 ;; Local Variables:
 ;; no-byte-compile: t
 ;; End:
 
 (provide 'bytecomp-tests)
-;; bytecomp-tests.el ends here.
+;;; bytecomp-tests.el ends here
diff --git a/test/lisp/emacs-lisp/cconv-tests.el 
b/test/lisp/emacs-lisp/cconv-tests.el
index 5aeed0cc15..4290571735 100644
--- a/test/lisp/emacs-lisp/cconv-tests.el
+++ b/test/lisp/emacs-lisp/cconv-tests.el
@@ -1,4 +1,4 @@
-;;; cconv-tests.el -*- lexical-binding: t -*-
+;;; cconv-tests.el --- Tests for cconv.el  -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
@@ -19,6 +19,8 @@
 
 ;;; Commentary:
 
+;;; Code:
+
 (require 'ert)
 (require 'cl-lib)
 
@@ -204,4 +206,4 @@
           42)))
 
 (provide 'cconv-tests)
-;; cconv-tests.el ends here.
+;;; cconv-tests.el ends here
diff --git a/test/lisp/emacs-lisp/check-declare-tests.el 
b/test/lisp/emacs-lisp/check-declare-tests.el
index 276530fb4d..5c9d847e34 100644
--- a/test/lisp/emacs-lisp/check-declare-tests.el
+++ b/test/lisp/emacs-lisp/check-declare-tests.el
@@ -28,6 +28,7 @@
 
 (require 'check-declare)
 (require 'ert)
+(require 'ert-x)
 (eval-when-compile (require 'subr-x))
 
 (ert-deftest check-declare-tests-locate ()
@@ -36,62 +37,53 @@
    (string-prefix-p "ext:" (check-declare-locate "ext:foo" ""))))
 
 (ert-deftest check-declare-tests-scan ()
-  (let ((file (make-temp-file "check-declare-tests-")))
-    (unwind-protect
-        (progn
-          (with-temp-file file
-            (insert
-             (string-join
-              '(";; foo comment"
-                "(declare-function ring-insert \"ring\" (ring item))"
-                "(let ((foo 'code)) foo)")
-              "\n")))
-          (let ((res (check-declare-scan file)))
-            (should (= (length res) 1))
-            (pcase-let ((`((,fnfile ,fn ,arglist ,fileonly)) res))
-              (should (string-match-p "ring" fnfile))
-              (should (equal "ring-insert" fn))
-              (should (equal '(ring item) arglist))
-              (should-not fileonly))))
-      (delete-file file))))
+  (ert-with-temp-file file
+    (with-temp-file file
+      (insert
+       (string-join
+        '(";; foo comment"
+          "(declare-function ring-insert \"ring\" (ring item))"
+          "(let ((foo 'code)) foo)")
+        "\n")))
+    (let ((res (check-declare-scan file)))
+      (should (= (length res) 1))
+      (pcase-let ((`((,fnfile ,fn ,arglist ,fileonly)) res))
+        (should (string-match-p "ring" fnfile))
+        (should (equal "ring-insert" fn))
+        (should (equal '(ring item) arglist))
+        (should-not fileonly)))))
 
 (ert-deftest check-declare-tests-verify ()
-  (let ((file (make-temp-file "check-declare-tests-")))
-    (unwind-protect
-        (progn
-          (with-temp-file file
-            (insert
-             (string-join
-              '(";; foo comment"
-                "(defun foo-fun ())"
-                "(defun ring-insert (ring item)"
-                "\"Insert onto ring RING the item ITEM.\""
-                "nil)")
-              "\n")))
-          (should-not
-           (check-declare-verify
-            file '(("foo.el" "ring-insert" (ring item))))))
-      (delete-file file))))
+  (ert-with-temp-file file
+    (with-temp-file file
+      (insert
+       (string-join
+        '(";; foo comment"
+          "(defun foo-fun ())"
+          "(defun ring-insert (ring item)"
+          "\"Insert onto ring RING the item ITEM.\""
+          "nil)")
+        "\n")))
+    (should-not
+     (check-declare-verify
+      file '(("foo.el" "ring-insert" (ring item)))))))
 
 (ert-deftest check-declare-tests-verify-mismatch ()
-  (let ((file (make-temp-file "check-declare-tests-")))
-    (unwind-protect
-        (progn
-          (with-temp-file file
-            (insert
-             (string-join
-              '(";; foo comment"
-                "(defun foo-fun ())"
-                "(defun ring-insert (ring)"
-                "\"Insert onto ring RING the item ITEM.\""
-                "nil)")
-              "\n")))
-          (should
-           (equal
-            (check-declare-verify
-             file '(("foo.el" "ring-insert" (ring item))))
-            '(("foo.el" "ring-insert" "arglist mismatch")))))
-      (delete-file file))))
+  (ert-with-temp-file file
+    (with-temp-file file
+      (insert
+       (string-join
+        '(";; foo comment"
+          "(defun foo-fun ())"
+          "(defun ring-insert (ring)"
+          "\"Insert onto ring RING the item ITEM.\""
+          "nil)")
+        "\n")))
+    (should
+     (equal
+      (check-declare-verify
+       file '(("foo.el" "ring-insert" (ring item))))
+      '(("foo.el" "ring-insert" "arglist mismatch"))))))
 
 (ert-deftest check-declare-tests-sort ()
   (should-not (check-declare-sort '()))
diff --git a/test/lisp/emacs-lisp/checkdoc-tests.el 
b/test/lisp/emacs-lisp/checkdoc-tests.el
index 3eb7da3d4a..ef49e71599 100644
--- a/test/lisp/emacs-lisp/checkdoc-tests.el
+++ b/test/lisp/emacs-lisp/checkdoc-tests.el
@@ -122,29 +122,71 @@ See the comments in Bug#24998."
     (should (looking-at-p "\"baz\")"))
     (should-not (checkdoc-next-docstring))))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p ()
+(defun checkdoc-tests--abbrev-test (buffer-contents goto-string)
   (with-temp-buffer
     (emacs-lisp-mode)
-    (insert "foo bar e.g. baz")
+    (insert buffer-contents)
     (goto-char (point-min))
-    (re-search-forward "e.g")
-    (should (checkdoc-in-abbreviation-p (point)))))
+    (re-search-forward goto-string)
+    (checkdoc-in-abbreviation-p (point))))
+
+(ert-deftest checkdoc-tests-in-abbrevation-p/basic-case ()
+  (should (checkdoc-tests--abbrev-test "foo bar e.g. baz" "e.g"))
+  (should (checkdoc-tests--abbrev-test "behavior/errors etc. that" "etc"))
+  (should (checkdoc-tests--abbrev-test "foo vs. bar" "vs"))
+  (should (checkdoc-tests--abbrev-test "spy a.k.a. spy" "a.k.a")))
 
 (ert-deftest checkdoc-tests-in-abbrevation-p/with-parens ()
-  (with-temp-buffer
-    (emacs-lisp-mode)
-    (insert "foo bar (e.g. baz)")
-    (goto-char (point-min))
-    (re-search-forward "e.g")
-    (should (checkdoc-in-abbreviation-p (point)))))
+  (should (checkdoc-tests--abbrev-test "foo bar (e.g. baz)" "e.g")))
 
 (ert-deftest checkdoc-tests-in-abbrevation-p/with-escaped-parens ()
-  (with-temp-buffer
-    (emacs-lisp-mode)
-    (insert "foo\n\\(e.g. baz)")
-    (goto-char (point-min))
-    (re-search-forward "e.g")
-    (should (checkdoc-in-abbreviation-p (point)))))
+  (should (checkdoc-tests--abbrev-test "foo\n\\(e.g. baz)" "e.g")))
+
+(ert-deftest checkdoc-tests-in-abbrevation-p/single-char ()
+  (should (checkdoc-tests--abbrev-test "a. foo bar" "a")))
+
+(ert-deftest checkdoc-tests-in-abbrevation-p/with-em-dash ()
+  (should (checkdoc-tests--abbrev-test "foo bar baz---e.g." "e.g")))
+
+(ert-deftest checkdoc-tests-in-abbrevation-p/incorrect-abbreviation ()
+  (should-not (checkdoc-tests--abbrev-test "foo bar a.b.c." "a.b.c")))
+
+(defun checkdoc-test-error-format-is-good (msg &optional reverse literal)
+  (with-temp-buffer
+    (erase-buffer)
+    (emacs-lisp-mode)
+    (let ((standard-output (current-buffer)))
+      (if literal
+          (print (format "(error \"%s\")" msg))
+        (prin1 `(error ,msg))))
+    (goto-char (length "(error \""))
+    (if reverse
+         (should (checkdoc--error-bad-format-p))
+       (should-not (checkdoc--error-bad-format-p)))))
+
+(defun checkdoc-test-error-format-is-bad (msg &optional literal)
+  (checkdoc-test-error-format-is-good msg t literal))
+
+(ert-deftest checkdoc-tests-error-message-bad-format-p ()
+  (checkdoc-test-error-format-is-good "Foo")
+  (checkdoc-test-error-format-is-good "Foo: bar baz")
+  (checkdoc-test-error-format-is-good "some-symbol: Foo")
+  (checkdoc-test-error-format-is-good "`some-symbol' foo bar")
+  (checkdoc-test-error-format-is-good "%sfoo")
+  (checkdoc-test-error-format-is-good "avl-tree-enter:\\
+ Updated data does not match existing data" nil 'literal))
+
+(ert-deftest checkdoc-tests-error-message-bad-format-p/defined-symbols ()
+  (defvar checkdoc-tests--var-symbol nil)
+  (checkdoc-test-error-format-is-good "checkdoc-tests--var-symbol foo bar baz")
+  (defun checkdoc-tests--fun-symbol ())
+  (checkdoc-test-error-format-is-good "checkdoc-tests--fun-symbol foo bar 
baz"))
+
+(ert-deftest checkdoc-tests-error-message-bad-format-p/not-capitalized ()
+  (checkdoc-test-error-format-is-bad "foo")
+  (checkdoc-test-error-format-is-bad "some-symbol: foo")
+  (checkdoc-test-error-format-is-bad "avl-tree-enter:\
+ updated data does not match existing data"))
 
 (ert-deftest checkdoc-tests-fix-y-or-n-p ()
   (with-temp-buffer
diff --git a/test/lisp/emacs-lisp/cl-macs-tests.el 
b/test/lisp/emacs-lisp/cl-macs-tests.el
index f4e2e46a01..033764a7f9 100644
--- a/test/lisp/emacs-lisp/cl-macs-tests.el
+++ b/test/lisp/emacs-lisp/cl-macs-tests.el
@@ -637,17 +637,26 @@ collection clause."
                        (/ 1 (logand n 1))
                      (arith-error (len3 (cdr xs) (1+ n)))
                      (:success (len3 (cdr xs) (+ n k))))
-                 n)))
+                 n))
+
+         ;; Tail calls in `cond'.
+         (len4 (xs n)
+           (cond (xs (cond (nil 'nevertrue)
+                           ((len4 (cdr xs) (1+ n)))))
+                 (t n))))
       (should (equal (len nil 0) 0))
       (should (equal (len2 nil 0) 0))
       (should (equal (len3 nil 0) 0))
+      (should (equal (len4 nil 0) 0))
       (should (equal (len list-42 0) 42))
       (should (equal (len2 list-42 0) 42))
       (should (equal (len3 list-42 0) 42))
+      (should (equal (len4 list-42 0) 42))
       ;; Should not bump into stack depth limits.
       (should (equal (len list-42k 0) 42000))
       (should (equal (len2 list-42k 0) 42000))
-      (should (equal (len3 list-42k 0) 42000))))
+      (should (equal (len3 list-42k 0) 42000))
+      (should (equal (len4 list-42k 0) 42000))))
 
   ;; Check that non-recursive functions are handled more efficiently.
   (should (pcase (macroexpand '(cl-labels ((f (x) (+ x 1))) (f 5)))
diff --git a/test/lisp/emacs-lisp/edebug-tests.el 
b/test/lisp/emacs-lisp/edebug-tests.el
index f8fa223da4..9285b2c945 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -107,27 +107,27 @@ back to the top level.")
   "Set up the environment for an Edebug test BODY, run it, and clean up."
   (declare (debug (body)))
   `(edebug-tests-with-default-config
-    (let ((edebug-tests-failure-in-post-command nil)
-          (edebug-tests-temp-file (make-temp-file "edebug-tests-" nil ".el"))
-          (find-file-suppress-same-file-warnings t))
-      (edebug-tests-setup-code-file edebug-tests-temp-file)
-      (ert-with-message-capture
-       edebug-tests-messages
-       (unwind-protect
-           (with-current-buffer (find-file edebug-tests-temp-file)
-             (read-only-mode)
-             (setq lexical-binding t)
-             (eval-buffer)
-             ,@body
-             (when edebug-tests-failure-in-post-command
-               (signal (car edebug-tests-failure-in-post-command)
-                       (cdr edebug-tests-failure-in-post-command))))
-         (unload-feature 'edebug-test-code)
-         (with-current-buffer (find-file-noselect edebug-tests-temp-file)
-           (set-buffer-modified-p nil))
-         (ignore-errors (kill-buffer (find-file-noselect
-                                      edebug-tests-temp-file)))
-         (ignore-errors (delete-file edebug-tests-temp-file)))))))
+    (ert-with-temp-file edebug-tests-temp-file
+      :suffix ".el"
+      (let ((edebug-tests-failure-in-post-command nil)
+            (find-file-suppress-same-file-warnings t))
+        (edebug-tests-setup-code-file edebug-tests-temp-file)
+        (ert-with-message-capture
+            edebug-tests-messages
+          (unwind-protect
+              (with-current-buffer (find-file edebug-tests-temp-file)
+                (read-only-mode)
+                (setq lexical-binding t)
+                (eval-buffer)
+                ,@body
+                (when edebug-tests-failure-in-post-command
+                  (signal (car edebug-tests-failure-in-post-command)
+                          (cdr edebug-tests-failure-in-post-command))))
+            (unload-feature 'edebug-test-code)
+            (with-current-buffer (find-file-noselect edebug-tests-temp-file)
+              (set-buffer-modified-p nil))
+            (ignore-errors (kill-buffer (find-file-noselect
+                                         edebug-tests-temp-file)))))))))
 
 ;; The following macro and its support functions implement an extension
 ;; to keyboard macros to allow interleaving of keyboard macro
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el 
b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
index 9f9bb73133..d1da066dc4 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
@@ -22,22 +22,22 @@
 
 ;;; Commentary:
 ;;
-;; Test method invocation order.  From the common lisp reference
-;; manual:
+;; Test method invocation order.  From the Common Lisp Reference
+;; Manual:
 ;;
 ;; QUOTE:
 ;; - All the :before methods are called, in most-specific-first
 ;;   order.  Their values are ignored.  An error is signaled if
 ;;   call-next-method is used in a :before method.
 ;;
-;; - The most specific primary method is called. Inside the body of a
+;; - The most specific primary method is called.  Inside the body of a
 ;;   primary method, call-next-method may be used to call the next
-;;   most specific primary method. When that method returns, the
+;;   most specific primary method.  When that method returns, the
 ;;   previous primary method can execute more code, perhaps based on
-;;   the returned value or values. The generic function no-next-method
+;;   the returned value or values.  The generic function no-next-method
 ;;   is invoked if call-next-method is used and there are no more
-;;   applicable primary methods. The function next-method-p may be
-;;   used to determine whether a next method exists. If
+;;   applicable primary methods.  The function next-method-p may be
+;;   used to determine whether a next method exists.  If
 ;;   call-next-method is not used, only the most specific primary
 ;;   method is called.
 ;;
@@ -46,12 +46,14 @@
 ;;   call-next-method is used in a :after method.
 ;;
 ;;
-;; Also test behavior of `call-next-method'. From clos.org:
+;; Also test behavior of `call-next-method'.  From clos.org:
 ;;
 ;; QUOTE:
 ;; When call-next-method is called with no arguments, it passes the
 ;; current method's original arguments to the next method.
 
+;;; Code:
+
 (require 'eieio)
 (require 'ert)
 
@@ -403,3 +405,5 @@
   (should (equal (eieio-test--1 (make-instance 'CNM-2) 5)
                  '("CNM-1-1" "CNM-1-2" "CNM-0" 7 5)))
   (should (equal (eieio-test--1 'CNM-2 6) '("subclass CNM-1-2" CNM-2 6))))
+
+;;; eieio-test-methodinvoke.el ends here
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el 
b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
index ddbef02c35..fd044ff373 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
@@ -165,9 +165,9 @@ Assume SLOTVALUE is a symbol of some sort."
   ((slot1 :initarg :slot1
          :initform 1)
    (slot2 :initform 2))
-  "Class for testing persistent saving of an object that isn't
-persistent.  This class is instead used as a slot value in a
-persistent class.")
+  "Class for testing persistent saving of an object that isn't persistent.
+This class is instead used as a slot value in a persistent
+class.")
 
 (defclass persistent-with-objs-slot (eieio-persistent)
   ((pnp :initarg :pnp
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el 
b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
index 3ec4234344..ba2e5f7be4 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
@@ -48,13 +48,13 @@
         :type (or null class-a)
         :documentation "Test self referencing types.")
    )
-  "Class A")
+  "Class A.")
 
 (defclass class-b ()
   ((land :initform "Sc"
         :type string
         :documentation "Detail about land."))
-  "Class B")
+  "Class B.")
 
 (defclass class-ab (class-a class-b)
   ((amphibian :initform "frog"
@@ -160,7 +160,7 @@
   ;; error
   (should-error (abstract-class)))
 
-(defgeneric generic1 () "First generic function")
+(defgeneric generic1 () "First generic function.")
 
 (ert-deftest eieio-test-03-generics ()
   (defun anormalfunction () "A plain function for error testing." nil)
@@ -901,12 +901,12 @@ Subclasses to override slot attributes.")
 
 (defclass opt-test1 ()
   ()
-  "Abstract base class"
+  "Abstract base class."
   :abstract t)
 
 (defclass opt-test2 (opt-test1)
   ()
-  "Instantiable child")
+  "Instantiable child.")
 
 (ert-deftest eieio-test-36-build-class-alist ()
   (should (= (length (eieio-build-class-alist 'opt-test1 nil)) 2))
@@ -969,6 +969,18 @@ Subclasses to override slot attributes.")
     (should (eieio-instance-inheritor-slot-boundp C :b))
     (should-not (eieio-instance-inheritor-slot-boundp C :c))))
 
+;;;; Interaction with defstruct
+
+(cl-defstruct eieio-test--struct a b c)
+
+(ert-deftest eieio-test-defstruct-slot-value ()
+  (let ((x (make-eieio-test--struct :a 'A :b 'B :c 'C)))
+    (should (eq (eieio-test--struct-a x)
+                (slot-value x 'a)))
+    (should (eq (eieio-test--struct-b x)
+                (slot-value x 'b)))
+    (should (eq (eieio-test--struct-c x)
+                (slot-value x 'c)))))
 
 (provide 'eieio-tests)
 
diff --git a/test/lisp/emacs-lisp/ert-tests.el 
b/test/lisp/emacs-lisp/ert-tests.el
index 5c9696105e..79576d2403 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -695,49 +695,40 @@ This macro is used to test if macroexpansion in `should' 
works."
   (should (equal (ert--abbreviate-string "bar" 0 t) "")))
 
 (ert-deftest ert-test-explain-equal-string-properties ()
-  (should
-   (equal (ert--explain-equal-including-properties #("foo" 0 1 (a b))
-                                                   "foo")
-          '(char 0 "f"
-                 (different-properties-for-key a (different-atoms b nil))
-                 context-before ""
-                 context-after "oo")))
-  (should (equal (ert--explain-equal-including-properties
+  (should-not (ert--explain-equal-including-properties-rec "foo" "foo"))
+  (should-not (ert--explain-equal-including-properties-rec
+               #("foo" 0 3 (a b))
+               (propertize "foo" 'a 'b)))
+  (should-not (ert--explain-equal-including-properties-rec
+               #("foo" 0 3 (a b c d))
+               (propertize "foo" 'a 'b 'c 'd)))
+  (should-not (ert--explain-equal-including-properties-rec
+               #("foo" 0 3 (a (t)))
+               (propertize "foo" 'a (list t))))
+
+  (should (equal (ert--explain-equal-including-properties-rec
+                  #("foo" 0 3 (a b c e))
+                  (propertize "foo" 'a 'b 'c 'd))
+                 '(char 0 "f" (different-properties-for-key c (different-atoms 
e d))
+                        context-before ""
+                        context-after "oo")))
+  (should (equal (ert--explain-equal-including-properties-rec
+                  #("foo" 0 1 (a b))
+                  "foo")
+                 '(char 0 "f"
+                        (different-properties-for-key a (different-atoms b 
nil))
+                        context-before ""
+                        context-after "oo")))
+  (should (equal (ert--explain-equal-including-properties-rec
                   #("foo" 1 3 (a b))
                   #("goo" 0 1 (c d)))
                  '(array-elt 0 (different-atoms (?f "#x66" "?f")
                                                 (?g "#x67" "?g")))))
-  (should
-   (equal (ert--explain-equal-including-properties
-           #("foo" 0 1 (a b c d) 1 3 (a b))
-           #("foo" 0 1 (c d a b) 1 2 (a foo)))
-          '(char 1 "o" (different-properties-for-key a (different-atoms b foo))
-                 context-before "f" context-after "o"))))
-
-(ert-deftest ert-test-equal-including-properties ()
-  (should (equal-including-properties "foo" "foo"))
-  (should (ert-equal-including-properties "foo" "foo"))
-
-  (should (equal-including-properties #("foo" 0 3 (a b))
-                                      (propertize "foo" 'a 'b)))
-  (should (ert-equal-including-properties #("foo" 0 3 (a b))
-                                          (propertize "foo" 'a 'b)))
-
-  (should (equal-including-properties #("foo" 0 3 (a b c d))
-                                      (propertize "foo" 'a 'b 'c 'd)))
-  (should (ert-equal-including-properties #("foo" 0 3 (a b c d))
-                                          (propertize "foo" 'a 'b 'c 'd)))
-
-  (should-not (equal-including-properties #("foo" 0 3 (a b c e))
-                                          (propertize "foo" 'a 'b 'c 'd)))
-  (should-not (ert-equal-including-properties #("foo" 0 3 (a b c e))
-                                              (propertize "foo" 'a 'b 'c 'd)))
-
-  ;; This is bug 6581.
-  (should-not (equal-including-properties #("foo" 0 3 (a (t)))
-                                          (propertize "foo" 'a (list t))))
-  (should (ert-equal-including-properties #("foo" 0 3 (a (t)))
-                                          (propertize "foo" 'a (list t)))))
+  (should (equal (ert--explain-equal-including-properties-rec
+                  #("foo" 0 1 (a b c d) 1 3 (a b))
+                  #("foo" 0 1 (c d a b) 1 2 (a foo)))
+                 '(char 1 "o" (different-properties-for-key a (different-atoms 
b foo))
+                        context-before "f" context-after "o"))))
 
 (ert-deftest ert-test-stats-set-test-and-result ()
   (let* ((test-1 (make-ert-test :name 'test-1
@@ -816,6 +807,10 @@ This macro is used to test if macroexpansion in `should' 
works."
     (should (equal (ert-test-failed-condition result)
                    '(ert-test-failed "Boo")))))
 
+(ert-deftest ert-test-deftest-lexical-binding-t ()
+  "Check that `lexical-binding' in `ert-deftest' has the file value."
+  (should (equal lexical-binding t)))
+
 
 (provide 'ert-tests)
 
diff --git a/test/lisp/emacs-lisp/ert-x-tests.el 
b/test/lisp/emacs-lisp/ert-x-tests.el
index 9f40a18d34..9baa994158 100644
--- a/test/lisp/emacs-lisp/ert-x-tests.el
+++ b/test/lisp/emacs-lisp/ert-x-tests.el
@@ -90,10 +90,10 @@
                  "foo  baz")))
 
 (ert-deftest ert-propertized-string ()
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (ert-propertized-string "a" '(a b) "b" '(c t) "cd")
            #("abcd" 1 2 (a b) 2 4 (c t))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (ert-propertized-string "foo " '(face italic) "bar" " baz" nil
                                    " quux")
            #("foo bar baz quux" 4 11 (face italic)))))
@@ -166,7 +166,7 @@
                                          "1 skipped"))))
               (with-current-buffer buffer-name
                 (font-lock-mode 0)
-                (should (ert-equal-including-properties
+                (should (equal-including-properties
                          (ert-filter-string (buffer-string)
                                             '("Started at:\\(.*\\)$" 1)
                                             '("Finished at:\\(.*\\)$" 1))
@@ -175,7 +175,7 @@
                 ;; pretend we are.
                 (let ((noninteractive nil))
                   (font-lock-mode 1))
-                (should (ert-equal-including-properties
+                (should (equal-including-properties
                          (ert-filter-string (buffer-string)
                                             '("Started at:\\(.*\\)$" 1)
                                             '("Finished at:\\(.*\\)$" 1))
@@ -271,6 +271,62 @@ desired effect."
     (cl-loop for x in '(0 1 2 3 4 t) do
              (should (equal (c x) (lisp x))))))
 
+(ert-deftest ert-x-tests--with-temp-file-generate-suffix ()
+  (should (equal (ert--with-temp-file-generate-suffix "foo.el") "-foo"))
+  (should (equal (ert--with-temp-file-generate-suffix "foo-test.el") "-foo"))
+  (should (equal (ert--with-temp-file-generate-suffix "foo-tests.el") "-foo"))
+  (should (equal (ert--with-temp-file-generate-suffix "foo-bar-baz.el")
+                 "-foo-bar-baz"))
+  (should (equal (ert--with-temp-file-generate-suffix "/foo/bar/baz.el")
+                 "-baz")))
+
+(ert-deftest ert-x-tests-with-temp-file ()
+  (let (saved)
+    (ert-with-temp-file fil
+      (setq saved fil)
+      (should (file-exists-p fil))
+      (should (file-regular-p fil)))
+    (should-not (file-exists-p saved))))
+
+(ert-deftest ert-x-tests-with-temp-file/handle-error ()
+  (let (saved)
+    (ignore-errors
+      (ert-with-temp-file fil
+        (setq saved fil)
+        (error "foo")))
+    (should-not (file-exists-p saved))))
+
+(ert-deftest ert-x-tests-with-temp-file/prefix-and-suffix-kwarg ()
+  (ert-with-temp-file fil
+    :prefix "foo"
+    :suffix "bar"
+    (should (string-match "foo.*bar" fil))))
+
+(ert-deftest ert-x-tests-with-temp-file/text-kwarg ()
+  (ert-with-temp-file fil
+    :text "foobar3"
+    (let ((buf (find-file-noselect fil)))
+      (unwind-protect
+          (with-current-buffer buf
+            (should (equal (buffer-string) "foobar3")))
+        (kill-buffer buf)))))
+
+(ert-deftest ert-x-tests-with-temp-file/unknown-kwarg-signals-error ()
+  (should-error
+   (ert-with-temp-file fil :foo "foo" nil)))
+
+(ert-deftest ert-x-tests-with-temp-directory ()
+  (let (saved)
+    (ert-with-temp-directory dir
+      (setq saved dir)
+      (should (file-exists-p dir))
+      (should (file-directory-p dir))
+      (should (equal dir (file-name-as-directory dir))))
+    (should-not (file-exists-p saved))))
+
+(ert-deftest ert-x-tests-with-temp-directory/text-signals-error ()
+  (should-error
+   (ert-with-temp-directory dir :text "foo" nil)))
 
 (provide 'ert-x-tests)
 
diff --git 
a/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el 
b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
index 3303e7b178..9fe5fe9218 100644
--- a/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
+++ b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
@@ -22,7 +22,7 @@
 
 ;;; Commentary:
 
-;; Support file for `faceup-test-basics.el'. This file is used to test
+;; Support file for `faceup-test-basics.el'.  This file is used to test
 ;; `faceup-this-file-directory' in various contexts.
 
 ;;; Code:
diff --git a/test/lisp/emacs-lisp/find-func-tests.el 
b/test/lisp/emacs-lisp/find-func-tests.el
index 28a9a7ecda..987e4047d3 100644
--- a/test/lisp/emacs-lisp/find-func-tests.el
+++ b/test/lisp/emacs-lisp/find-func-tests.el
@@ -26,7 +26,7 @@
 
 ;;; Code:
 
-(require 'ert-x)                        ;For `ert-run-keys'.
+(require 'ert-x)                        ;For `ert-simulate-keys'.
 (require 'find-func)
 
 (ert-deftest find-func-tests--library-completion () ;bug#43393
diff --git a/test/lisp/emacs-lisp/generator-tests.el 
b/test/lisp/emacs-lisp/generator-tests.el
index a1b9f64fdb..c81d3d09e7 100644
--- a/test/lisp/emacs-lisp/generator-tests.el
+++ b/test/lisp/emacs-lisp/generator-tests.el
@@ -271,7 +271,7 @@ identical output."
                      (unwind-protect
                           (progn
                             (iter-yield 1)
-                            (error "test")
+                            (error "Test")
                             (iter-yield 2))
                        (cl-incf nr-unwound))))))
     (should (equal (iter-next iter) 1))
diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el
index b9850eca8b..6ee274ae10 100644
--- a/test/lisp/emacs-lisp/gv-tests.el
+++ b/test/lisp/emacs-lisp/gv-tests.el
@@ -21,22 +21,21 @@
 
 (require 'edebug)
 (require 'ert)
+(require 'ert-x)
 (eval-when-compile (require 'cl-lib))
 
 (cl-defmacro gv-tests--in-temp-dir ((elvar elcvar)
                                     (&rest filebody)
                                     &rest body)
   (declare (indent 2))
-  `(let ((default-directory (make-temp-file "gv-test" t)))
-     (unwind-protect
-         (let ((,elvar "gv-test-deffoo.el")
-               (,elcvar "gv-test-deffoo.elc"))
-           (with-temp-file ,elvar
-             (insert ";; -*- lexical-binding: t; -*-\n")
-             (dolist (form ',filebody)
-               (pp form (current-buffer))))
-           ,@body)
-       (delete-directory default-directory t))))
+  `(ert-with-temp-directory default-directory
+     (let ((,elvar "gv-test-deffoo.el")
+           (,elcvar "gv-test-deffoo.elc"))
+       (with-temp-file ,elvar
+         (insert ";; -*- lexical-binding: t; -*-\n")
+         (dolist (form ',filebody)
+           (pp form (current-buffer))))
+       ,@body)))
 
 (ert-deftest gv-define-expander-in-file ()
   (gv-tests--in-temp-dir (el elc)
diff --git a/test/lisp/emacs-lisp/let-alist-tests.el 
b/test/lisp/emacs-lisp/let-alist-tests.el
index d856696da2..88e689c80b 100644
--- a/test/lisp/emacs-lisp/let-alist-tests.el
+++ b/test/lisp/emacs-lisp/let-alist-tests.el
@@ -100,4 +100,4 @@ See Bug#24641."
                    `[,(+ .a) ,(+ .a .b .b)])
                  [1 5])))
 
-;;; let-alist.el ends here
+;;; let-alist-tests.el ends here
diff --git a/test/lisp/emacs-lisp/lisp-mnt-tests.el 
b/test/lisp/emacs-lisp/lisp-mnt-tests.el
index 84cdc7205f..d77804fbe6 100644
--- a/test/lisp/emacs-lisp/lisp-mnt-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mnt-tests.el
@@ -32,5 +32,13 @@
                  '(("Bob Weiner" . "rsw@gnu.org")
                    ("Mats Lidell" . "matsl@gnu.org")))))
 
+(ert-deftest lm--tests-lm-website ()
+  (with-temp-buffer
+    (insert ";; URL: https://example.org/foo";)
+    (should (string= (lm-website) "https://example.org/foo";)))
+  (with-temp-buffer
+    (insert  ";; X-URL: <https://example.org/foo>")
+    (should (string= (lm-website) "https://example.org/foo";))))
+
 (provide 'lisp-mnt-tests)
 ;;; lisp-mnt-tests.el ends here
diff --git a/test/lisp/emacs-lisp/memory-report-tests.el 
b/test/lisp/emacs-lisp/memory-report-tests.el
index e352dd165f..d37f09b34f 100644
--- a/test/lisp/emacs-lisp/memory-report-tests.el
+++ b/test/lisp/emacs-lisp/memory-report-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'memory-report)
 
diff --git a/test/lisp/emacs-lisp/nadvice-tests.el 
b/test/lisp/emacs-lisp/nadvice-tests.el
index 358d9025ad..ee33bb0fa4 100644
--- a/test/lisp/emacs-lisp/nadvice-tests.el
+++ b/test/lisp/emacs-lisp/nadvice-tests.el
@@ -208,4 +208,4 @@ function being an around advice."
 ;; no-byte-compile: t
 ;; End:
 
-;;; advice-tests.el ends here.
+;;; nadvice-tests.el ends here
diff --git a/test/lisp/emacs-lisp/package-resources/key.pub 
b/test/lisp/emacs-lisp/package-resources/key.pub
index 5e2ebc55d3..99965723ba 100644
--- a/test/lisp/emacs-lisp/package-resources/key.pub
+++ b/test/lisp/emacs-lisp/package-resources/key.pub
@@ -1,20 +1,17 @@
 -----BEGIN PGP PUBLIC KEY BLOCK-----
 
-mI0EX48EbAEEANrsWXyZ4MRZRjVbLAh5jX/+1+31oB/aJ/q/5DkH1qUHJf0La9LC
-sykUSM3H2u5VWLytX/ozrxIRYX13GR2xBxyJlUkDWB209AAVLFrjSp1yUX/Sb5SU
-Kb7p421ZAeHiOxfnLRuErFZkTfzY19mUCyw4cdamw430V3mUC9uns/d9ABEBAAG0
-LUouIFJhbmRvbSBIYWNrZXIgKFRFU1QgS0VZKSA8anJoQGV4YW1wbGUub3JnPojO
-BBMBCgA4FiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwMFCwkIBwIGFQoJ
-CAsCBBYCAwECHgECF4AACgkQMKdkJgeTYhq9MQP7BYkCk8r5G777Ilp8kWjsEIo3
-aDX9jORiNfMAGys/aLjjEajHFAlTQKfSLm/VXLDYtK28c8ACjThQagaDF46MRWqQ
-rFFiH4IAZRgj2ELj+/j1ljQZjGjKR2Yx4BCDhbumz8zeMSPL6yFT5+8LOMUAtdv4
-lEPWXW0AycylbdbE7024jQRfjwRsAQQApjTw9kONmSVouCi8ZIQwwYiA9tLzbSZv
-CYxbJ6KH0icRhBLfdb1hL/Kn8x3k+xll9A0c/ABVkMxRcbQkY98xsFck7E2GcvnC
-sY+w/NdcUUZJYMB3l2MH5ojCbOk5jSAZzxzeFcJhNAhmLqomMHg2LI6KDVey6iYU
-FxyIpIQ3SlkAEQEAAYi2BBgBCgAgFiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+P
-BGwCGwwACgkQMKdkJgeTYhrtywQAhoCR/skBSQWWBI10N0qhtdlNxbpvK8ErSPKw
-wS74Pq407Zv0VD9ual/HC3Uet2z8LeG9ZwU4Jd23g96fmJt7AM9CQWrOhC242JYr
-YSqWxANyek8otsvppJNHtt2Stmknv7XbJFFB1JDC8WKo8lVo9/MkmzROxuEFEvOU
-Yn923VI=
-=NRtx
+mQGiBGFQyDcRBACmAI6cfY3fM02vb9JtC1BS19boKXbBsDoVrD9qRf8tDFROOpO3
+ZMlbuz+O9Vnljo6Y4WZGnyeWWAMqCditMOfr1cLbux77wSrmAVgZ9exwtGzkmUhM
+xcptzKuyod8NuhghXbJgVbfJZ6HlBkk4kiWv98iJQwUBZJfjBUfIv+acjwCg4M2i
+Ifu2A3UYl9VqF7qfcDOZudEEAI7V35yfsBDnr9ndKqdGYNw0alX9BEG3KwnAe0fF
+O1jDVW12Y/bwnyyrRTrz6o1G8dj7M4XVZQb5PpT9mpNzOSZ6yxqhg+foeJwn2JkD
+vyP+kMYU7SZ/tWuMOCdzN95Ki1rf+ti7pLnSMqKx+t3vOWwQbtnsbI6RCLLwETPA
+esghA/0X3Dw7cdiE5Xq4TRaPSGViCWP4ekL2KYKqmKv6M/4f2pgFNJY7C+2SIiiP
+T62zFlIjs5tF2Df34/M5mh4Vx6E8341r55+XO++kfFWJ5QjLiydRAY6ochG9IFgB
+xyBCkCNpiby9PpKyPodedBScdMxIAe4eJR7rG/j9gFC1MypBurQnSm9obm55IFJv
+Y2tldHMgPGpvaG5ueS5yb2NrZXRzQGdmeS5vcmc+iHgEExECADgWIQRIVz1DPzm4
+REDIXNtltQG5ACv6lwUCYVDINwIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAK
+CRBltQG5ACv6l4iZAKCqldroRYH7vUzVV0Uv1NcDVcpLngCgmEoLVxGLKSwDEXNq
+qjRDzDRpReg=
+=/l51
 -----END PGP PUBLIC KEY BLOCK-----
diff --git a/test/lisp/emacs-lisp/package-resources/key.sec 
b/test/lisp/emacs-lisp/package-resources/key.sec
index dbc80f43cb..5bbac1226a 100644
--- a/test/lisp/emacs-lisp/package-resources/key.sec
+++ b/test/lisp/emacs-lisp/package-resources/key.sec
@@ -1,35 +1,17 @@
 -----BEGIN PGP PRIVATE KEY BLOCK-----
 
-lQIGBF+PBGwBBADa7Fl8meDEWUY1WywIeY1//tft9aAf2if6v+Q5B9alByX9C2vS
-wrMpFEjNx9ruVVi8rV/6M68SEWF9dxkdsQcciZVJA1gdtPQAFSxa40qdclF/0m+U
-lCm+6eNtWQHh4jsX5y0bhKxWZE382NfZlAssOHHWpsON9Fd5lAvbp7P3fQARAQAB
-/gcDAngNw4ppSPBe/w734cz++xNEv0TDgwxGBWp2wGSwWao04Nl1U4LkjiIy+dkc
-uUPwEZMvxXwMcq10PPH26ifP8Xfi/zANXUoLJ0DsG6rtE3BcSC9MPFe3EJENtcIP
-a0jFLsbi72aBzolNEDCZCv93znXFPekaXw/RAeeFLJz8GR2Sx6bHbTJKklXgWPHw
-C5Dw6xr/kEZktgjlhjkx280STpLGaFO4jiiGZ4Obp5ePp7kyOzDUzaimdZgJwClT
-VbZDNQMTzgQrBOP8doXlo9euW4Wo1IYBIOwgeYieM3ZA9YjJAmp4lFnk/KFYt0Ak
-0H9IWzDU8VERcU4B04PSXahzvB1Ii7C7bbHxPyuu6sAfMK8DRkrGjwgAlrhuWNLX
-M07acT/E9Pm+mBlDcdkyKB2LfwgaVb9F3C25sfcFSvc5p+sqgZp1Zx7Qg9pOhQjw
-U7Ln+96c0bUl+iQKdm3TGjOXAFUHYXbRkx2cJ4gxnMVNj0D68xBtBSm0LUouIFJh
-bmRvbSBIYWNrZXIgKFRFU1QgS0VZKSA8anJoQGV4YW1wbGUub3JnPojOBBMBCgA4
-FiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwMFCwkIBwIGFQoJCAsCBBYC
-AwECHgECF4AACgkQMKdkJgeTYhq9MQP7BYkCk8r5G777Ilp8kWjsEIo3aDX9jORi
-NfMAGys/aLjjEajHFAlTQKfSLm/VXLDYtK28c8ACjThQagaDF46MRWqQrFFiH4IA
-ZRgj2ELj+/j1ljQZjGjKR2Yx4BCDhbumz8zeMSPL6yFT5+8LOMUAtdv4lEPWXW0A
-ycylbdbE702dAgYEX48EbAEEAKY08PZDjZklaLgovGSEMMGIgPbS820mbwmMWyei
-h9InEYQS33W9YS/yp/Md5PsZZfQNHPwAVZDMUXG0JGPfMbBXJOxNhnL5wrGPsPzX
-XFFGSWDAd5djB+aIwmzpOY0gGc8c3hXCYTQIZi6qJjB4NiyOig1XsuomFBcciKSE
-N0pZABEBAAH+BwMCXeUOBwcOsxb/AY6rnHmgACNTGwIa5vgelw0qfET0ms/YzVrN
-ufikyV9dEWVxJyuTKav978wanPu7VcCh0pTjL2nTm2nZWyRJN4gb3UIC0MA1xfB2
-yPLTCmsGeJhVOqi4Af/r06mk+NOQ96ivOA2CJuw1LSpcUtuYxB5t/grGyEojYjRP
-s0Htvf2bfN9KbFJ26DGsfYzC8bCxm9szPFHBQjw4NboCigUSAHmkoTW01aWZU9Vq
-brY4cWhdmCqHgfmsQgzP3LfaAQ6kJ/bkuKef7z57lz5XmlyjMQGWcZWp5xf2n81p
-BV6unaIPyavzkKVAXizVfNiHNJgK9PoVoEOJkPLjRfMxVmFSGN/oF7lVTRWfOIwo
-68rtNPhr6UzE4ArGHYv/pK3kijUp5daWmfrySWPcwoVAaR3mIIVs/1rhd9aZrwn6
-Q07Yo5u11rH9b8anZQF3BdTcrnU9pUzLYlFPnfhtyGqhikQILtPTf0iwr8hpG9b2
-Zoi2BBgBCgAgFiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwwACgkQMKdk
-JgeTYhrtywQAhoCR/skBSQWWBI10N0qhtdlNxbpvK8ErSPKwwS74Pq407Zv0VD9u
-al/HC3Uet2z8LeG9ZwU4Jd23g96fmJt7AM9CQWrOhC242JYrYSqWxANyek8otsvp
-pJNHtt2Stmknv7XbJFFB1JDC8WKo8lVo9/MkmzROxuEFEvOUYn923VI=
-=2DW8
+lQG7BGFQyDcRBACmAI6cfY3fM02vb9JtC1BS19boKXbBsDoVrD9qRf8tDFROOpO3
+ZMlbuz+O9Vnljo6Y4WZGnyeWWAMqCditMOfr1cLbux77wSrmAVgZ9exwtGzkmUhM
+xcptzKuyod8NuhghXbJgVbfJZ6HlBkk4kiWv98iJQwUBZJfjBUfIv+acjwCg4M2i
+Ifu2A3UYl9VqF7qfcDOZudEEAI7V35yfsBDnr9ndKqdGYNw0alX9BEG3KwnAe0fF
+O1jDVW12Y/bwnyyrRTrz6o1G8dj7M4XVZQb5PpT9mpNzOSZ6yxqhg+foeJwn2JkD
+vyP+kMYU7SZ/tWuMOCdzN95Ki1rf+ti7pLnSMqKx+t3vOWwQbtnsbI6RCLLwETPA
+esghA/0X3Dw7cdiE5Xq4TRaPSGViCWP4ekL2KYKqmKv6M/4f2pgFNJY7C+2SIiiP
+T62zFlIjs5tF2Df34/M5mh4Vx6E8341r55+XO++kfFWJ5QjLiydRAY6ochG9IFgB
+xyBCkCNpiby9PpKyPodedBScdMxIAe4eJR7rG/j9gFC1MypBugAAn0mvGeJi+oSo
+5jXAeXBhRiTyI5WPCuK0J0pvaG5ueSBSb2NrZXRzIDxqb2hubnkucm9ja2V0c0Bn
+Znkub3JnPoh4BBMRAgA4FiEESFc9Qz85uERAyFzbZbUBuQAr+pcFAmFQyDcCGwMF
+CwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQZbUBuQAr+peImQCgqpXa6EWB+71M
+1VdFL9TXA1XKS54AoJhKC1cRiyksAxFzaqo0Q8w0aUXo
+=cyQm
 -----END PGP PRIVATE KEY BLOCK-----
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin-aux.el
 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin-aux.el
new file mode 100644
index 0000000000..724f88ec9e
--- /dev/null
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin-aux.el
@@ -0,0 +1,12 @@
+;;; macro-builtin-aux.el --- laksd                                  -*- 
lexical-binding: t; -*-
+
+;; Author: Artur Malabarba <emacs@endlessparentheses.com>
+
+;;; Code:
+
+(defun macro-builtin-aux-1 ( &rest forms)
+  "Description"
+  `(progn ,@forms))
+
+(provide 'macro-builtin-aux)
+;;; macro-builtin-aux.el ends here
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin.el
 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin.el
new file mode 100644
index 0000000000..828968a057
--- /dev/null
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-1.0/macro-builtin.el
@@ -0,0 +1,21 @@
+;;; macro-builtin.el --- laksd                                  -*- 
lexical-binding: t; -*-
+
+;; Author: Artur Malabarba <emacs@endlessparentheses.com>
+;; Keywords: tools
+;; Version: 1.0
+
+;;; Code:
+
+(require 'macro-builtin-aux)
+
+(defmacro macro-builtin-1 ( &rest forms)
+  "Description"
+  `(progn ,@forms))
+
+(defun macro-builtin-func ()
+  ""
+  (macro-builtin-1 'a 'b)
+  (macro-builtin-aux-1 'a 'b))
+
+(provide 'macro-builtin)
+;;; macro-builtin.el ends here
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin-aux.el
 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin-aux.el
new file mode 100644
index 0000000000..9f257d9d22
--- /dev/null
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin-aux.el
@@ -0,0 +1,16 @@
+;;; macro-builtin-aux.el --- laksd                                  -*- 
lexical-binding: t; -*-
+
+;; Author: Artur Malabarba <emacs@endlessparentheses.com>
+
+;;; Code:
+
+(defmacro macro-builtin-aux-1 ( &rest forms)
+  "Description"
+  `(progn ,@forms))
+
+(defmacro macro-builtin-aux-3 ( &rest _)
+  "Description"
+  90)
+
+(provide 'macro-builtin-aux)
+;;; macro-builtin-aux.el ends here
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin.el
 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin.el
new file mode 100644
index 0000000000..5d241c082d
--- /dev/null
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-builtin-package-2.0/macro-builtin.el
@@ -0,0 +1,30 @@
+;;; macro-builtin.el --- laksd                                  -*- 
lexical-binding: t; -*-
+
+;; Author: Artur Malabarba <emacs@endlessparentheses.com>
+;; Keywords: tools
+;; Version: 2.0
+
+;;; Code:
+
+(require 'macro-builtin-aux)
+
+(defmacro macro-builtin-1 ( &rest forms)
+  "Description"
+  `(progn ,(cadr (car forms))))
+
+
+(defun macro-builtin-func ()
+  ""
+  (list (macro-builtin-1 '1 'b)
+        (macro-builtin-aux-1 'a 'b)))
+
+(defmacro macro-builtin-3 (&rest _)
+  "Description"
+  10)
+
+(defun macro-builtin-10-and-90 ()
+  ""
+  (list (macro-builtin-3 haha) (macro-builtin-aux-3 hehe)))
+
+(provide 'macro-builtin)
+;;; macro-builtin.el ends here
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-aux.el 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-aux.el
index f43232224a..ad20a3507a 100644
--- 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-aux.el
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-aux.el
@@ -5,7 +5,7 @@
 ;;; Code:
 
 (defun macro-aux-1 ( &rest forms)
-  "Description"
+  "Description."
   `(progn ,@forms))
 
 (provide 'macro-aux)
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-problem.el
 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-problem.el
index 0533b1bd9c..6e5e54e54f 100644
--- 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-problem.el
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-1.0/macro-problem.el
@@ -9,11 +9,11 @@
 (require 'macro-aux)
 
 (defmacro macro-problem-1 ( &rest forms)
-  "Description"
+  "Description."
   `(progn ,@forms))
 
 (defun macro-problem-func ()
-  ""
+  "Description."
   (macro-problem-1 'a 'b)
   (macro-aux-1 'a 'b))
 
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-aux.el 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-aux.el
index 6a55a40e3b..814d77183a 100644
--- 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-aux.el
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-aux.el
@@ -5,11 +5,11 @@
 ;;; Code:
 
 (defmacro macro-aux-1 ( &rest forms)
-  "Description"
+  "Description."
   `(progn ,@forms))
 
 (defmacro macro-aux-3 ( &rest _)
-  "Description"
+  "Description."
   90)
 
 (provide 'macro-aux)
diff --git 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-problem.el
 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-problem.el
index cad4ed93f1..aef5eda7c6 100644
--- 
a/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-problem.el
+++ 
b/test/lisp/emacs-lisp/package-resources/macro-problem-package-2.0/macro-problem.el
@@ -9,21 +9,21 @@
 (require 'macro-aux)
 
 (defmacro macro-problem-1 ( &rest forms)
-  "Description"
+  "Description."
   `(progn ,(cadr (car forms))))
 
 
 (defun macro-problem-func ()
-  ""
+  "Description."
   (list (macro-problem-1 '1 'b)
         (macro-aux-1 'a 'b)))
 
 (defmacro macro-problem-3 (&rest _)
-  "Description"
+  "Description."
   10)
 
 (defun macro-problem-10-and-90 ()
-  ""
+  "Description."
   (list (macro-problem-3 haha) (macro-aux-3 hehe)))
 
 (provide 'macro-problem)
diff --git 
a/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el 
b/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
index 301993deb3..be6bedf8a1 100644
--- a/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
+++ b/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
@@ -7,14 +7,14 @@
 ;;; Commentary:
 
 ;; This package provides a minor mode to frobnicate and/or bifurcate
-;; any flanges you desire. To activate it, type "C-M-r M-3 butterfly"
+;; any flanges you desire.  To activate it, type "C-M-r M-3 butterfly"
 ;; and all your dreams will come true.
 ;;
 ;; This is a new, updated version.
 
 ;;; Code:
 
-(defgroup simple-single nil "Simply a file"
+(defgroup simple-single nil "Simply a file."
   :group 'lisp)
 
 (defcustom simple-single-super-sunday nil
@@ -29,7 +29,7 @@ Default changed to nil."
 
 ;;;###autoload
 (define-minor-mode simple-single-mode
-  "It does good things to stuff")
+  "It does good things to stuff.")
 
 (provide 'simple-single)
 
diff --git a/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig 
b/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig
index dac168b0e4..b40620a0e8 100644
Binary files 
a/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig and 
b/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig differ
diff --git a/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el 
b/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
index ff070c6526..781077251e 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
@@ -8,12 +8,12 @@
 ;;; Commentary:
 
 ;; This package provides a minor mode to frobnicate and/or bifurcate
-;; any flanges you desire. To activate it, type "C-M-r M-3 butterfly"
+;; any flanges you desire.  To activate it, type "C-M-r M-3 butterfly"
 ;; and all your dreams will come true.
 
 ;;; Code:
 
-(defgroup signed-bad nil "Simply a file"
+(defgroup signed-bad nil "Simply a file."
   :group 'lisp)
 
 (defcustom signed-bad-super-sunday t
@@ -26,7 +26,7 @@
 
 ;;;###autoload
 (define-minor-mode signed-bad-mode
-  "It does good things to stuff")
+  "It does good things to stuff.")
 
 (provide 'signed-bad)
 
diff --git a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el 
b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
index 60b1b8663d..8a408c1f30 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
@@ -8,12 +8,12 @@
 ;;; Commentary:
 
 ;; This package provides a minor mode to frobnicate and/or bifurcate
-;; any flanges you desire. To activate it, type "C-M-r M-3 butterfly"
+;; any flanges you desire.  To activate it, type "C-M-r M-3 butterfly"
 ;; and all your dreams will come true.
 
 ;;; Code:
 
-(defgroup signed-good nil "Simply a file"
+(defgroup signed-good nil "Simply a file."
   :group 'lisp)
 
 (defcustom signed-good-super-sunday t
@@ -26,7 +26,7 @@
 
 ;;;###autoload
 (define-minor-mode signed-good-mode
-  "It does good things to stuff")
+  "It does good things to stuff.")
 
 (provide 'signed-good)
 
diff --git 
a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig 
b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig
index 5b1c721e32..1109241160 100644
Binary files 
a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig and 
b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig differ
diff --git a/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el 
b/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
index cb003905bb..f1ee862761 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
@@ -12,6 +12,6 @@
 ;;; Code:
 
 (defvar simple-depend "Value"
-  "Some trivial code")
+  "Some trivial code.")
 
 ;;; simple-depend.el ends here
diff --git a/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el 
b/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
index 9c3f427ff4..459801d78c 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
@@ -8,12 +8,12 @@
 ;;; Commentary:
 
 ;; This package provides a minor mode to frobnicate and/or bifurcate
-;; any flanges you desire. To activate it, type "C-M-r M-3 butterfly"
+;; any flanges you desire.  To activate it, type "C-M-r M-3 butterfly"
 ;; and all your dreams will come true.
 
 ;;; Code:
 
-(defgroup simple-single nil "Simply a file"
+(defgroup simple-single nil "Simply a file."
   :group 'lisp)
 
 (defcustom simple-single-super-sunday t
@@ -26,7 +26,7 @@
 
 ;;;###autoload
 (define-minor-mode simple-single-mode
-  "It does good things to stuff")
+  "It does good things to stuff.")
 
 (provide 'simple-single)
 
diff --git a/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el 
b/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
index a0a9607350..8de6141d67 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
@@ -12,6 +12,6 @@
 ;;; Code:
 
 (defvar simple-two-depend "Value"
-  "Some trivial code")
+  "Some trivial code.")
 
 ;;; simple-two-depend.el ends here
diff --git a/test/lisp/emacs-lisp/package-tests.el 
b/test/lisp/emacs-lisp/package-tests.el
index 2943579955..0f0ed029c3 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -115,57 +115,55 @@
                                 &rest body)
   "Set up temporary locations and variables for testing."
   (declare (indent 1) (debug (([&rest form]) body)))
-  `(let* ((package-test-user-dir (make-temp-file "pkg-test-user-dir-" t))
-          (process-environment (cons (format "HOME=%s" package-test-user-dir)
-                                     process-environment))
-          (package-user-dir package-test-user-dir)
-          (package-gnupghome-dir (expand-file-name "gnupg" package-user-dir))
-          (package-archives `(("gnu" . ,(or ,location package-test-data-dir))))
-          (default-directory package-test-file-dir)
-          abbreviated-home-dir
-          package--initialized
-          package-alist
-          ,@(if update-news
-                '(package-update-news-on-upload t)
-              (list (cl-gensym)))
-          ,@(if upload-base
-                '((package-test-archive-upload-base (make-temp-file 
"pkg-archive-base-" t))
-                  (package-archive-upload-base 
package-test-archive-upload-base))
-              (list (cl-gensym)))) ;; Dummy value so `let' doesn't try to bind 
nil
-     (let ((buf (get-buffer "*Packages*")))
-       (when (buffer-live-p buf)
-         (kill-buffer buf)))
-     (unwind-protect
-         (progn
-           ,(if basedir `(cd ,basedir))
-           (unless (file-directory-p package-user-dir)
-             (mkdir package-user-dir))
-           (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest _) t))
-                     ((symbol-function 'y-or-n-p)    (lambda (&rest _) t)))
-             ,@(when install
-                 `((package-initialize)
-                   (package-refresh-contents)
-                   (mapc 'package-install ,install)))
-             (with-temp-buffer
-               ,(if file
-                    `(insert-file-contents ,file))
-               ,@body)))
-
-       (when ,upload-base
-         (dolist (f '("archive-contents"
-                      "simple-single-1.3.el"
-                      "simple-single-1.4.el"
-                      "simple-single-readme.txt"))
-           (ignore-errors
-             (delete-file
-              (expand-file-name f package-test-archive-upload-base))))
-         (delete-directory package-test-archive-upload-base))
-       (when (file-directory-p package-test-user-dir)
-         (delete-directory package-test-user-dir t))
-
-       (when (and (boundp 'package-test-archive-upload-base)
-                  (file-directory-p package-test-archive-upload-base))
-         (delete-directory package-test-archive-upload-base t)))))
+  `(ert-with-temp-directory package-test-user-dir
+     (let* ((process-environment (cons (format "HOME=%s" package-test-user-dir)
+                                       process-environment))
+            (package-user-dir package-test-user-dir)
+            (package-gnupghome-dir (expand-file-name "gnupg" package-user-dir))
+            (package-archives `(("gnu" . ,(or ,location 
package-test-data-dir))))
+            (default-directory package-test-file-dir)
+            abbreviated-home-dir
+            package--initialized
+            package-alist
+            ,@(if update-news
+                  '(package-update-news-on-upload t)
+                (list (cl-gensym)))
+            ,@(if upload-base
+                  '((package-test-archive-upload-base (make-temp-file 
"pkg-archive-base-" t))
+                    (package-archive-upload-base 
package-test-archive-upload-base))
+                (list (cl-gensym)))) ;; Dummy value so `let' doesn't try to 
bind nil
+       (let ((buf (get-buffer "*Packages*")))
+         (when (buffer-live-p buf)
+           (kill-buffer buf)))
+       (unwind-protect
+           (progn
+             ,(if basedir `(cd ,basedir))
+             (unless (file-directory-p package-user-dir)
+               (mkdir package-user-dir))
+             (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest _) t))
+                       ((symbol-function 'y-or-n-p)    (lambda (&rest _) t)))
+               ,@(when install
+                   `((package-initialize)
+                     (package-refresh-contents)
+                     (mapc 'package-install ,install)))
+               (with-temp-buffer
+                 ,(if file
+                      `(insert-file-contents ,file))
+                 ,@body)))
+
+         (when ,upload-base
+           (dolist (f '("archive-contents"
+                        "simple-single-1.3.el"
+                        "simple-single-1.4.el"
+                        "simple-single-readme.txt"))
+             (ignore-errors
+               (delete-file
+                (expand-file-name f package-test-archive-upload-base))))
+           (delete-directory package-test-archive-upload-base))
+
+         (when (and (boundp 'package-test-archive-upload-base)
+                    (file-directory-p package-test-archive-upload-base))
+           (delete-directory package-test-archive-upload-base t))))))
 
 (defmacro with-fake-help-buffer (&rest body)
   "Execute BODY in a temp buffer which is treated as the \"*Help*\" buffer."
@@ -180,7 +178,7 @@
   (replace-regexp-in-string "-pkg\\.el\\'" "" (package--description-file dir)))
 
 (defun package-test-suffix-matches (base suffix-list)
-  "Return file names matching BASE concatenated with each item in SUFFIX-LIST"
+  "Return file names matching BASE concatenated with each item in SUFFIX-LIST."
   (mapcan (lambda (item) (file-expand-wildcards (concat base item)))
           suffix-list))
 
@@ -342,9 +340,13 @@ but with a different end of line convention (bug#48137)."
 
 (declare-function macro-problem-func "macro-problem" ())
 (declare-function macro-problem-10-and-90 "macro-problem" ())
+(declare-function macro-builtin-func "macro-builtin" ())
+(declare-function macro-builtin-10-and-90 "macro-builtin" ())
 
 (ert-deftest package-test-macro-compilation ()
-  "Install a package which includes a dependency."
+  "\"Activation has to be done before compilation, so that if we're
+   upgrading and macros have changed we load the new definitions
+   before compiling.\" -- package.el"
   (with-package-test (:basedir (ert-resource-directory))
     (package-install-file (expand-file-name "macro-problem-package-1.0/"))
     (require 'macro-problem)
@@ -357,6 +359,32 @@ but with a different end of line convention (bug#48137)."
     ;; `macro-problem-10-and-90' depends on an entirely new macro from 
`macro-aux'.
     (should (equal (macro-problem-10-and-90) '(10 90)))))
 
+(ert-deftest package-test-macro-compilation-gz ()
+  "Built-in's can be superseded as well."
+  (with-package-test (:basedir (ert-resource-directory))
+    (let ((dir (expand-file-name "macro-builtin-package-1.0")))
+      (unwind-protect
+          (let ((load-path load-path))
+            (add-to-list 'load-path (directory-file-name dir))
+            (byte-recompile-directory dir 0 t)
+            (mapc (lambda (f) (rename-file f (concat f ".gz")))
+                  (directory-files-recursively dir "\\`[^\\.].*\\.el\\'"))
+            (require 'macro-builtin)
+            (should (member (expand-file-name "macro-builtin-aux.elc" dir)
+                            (mapcar #'car load-history)))
+            ;; `macro-builtin-func' uses a macro from `macro-aux'.
+            (should (equal (macro-builtin-func) '(progn a b)))
+            (package-install-file (expand-file-name 
"macro-builtin-package-2.0/"))
+            ;; After upgrading, `macro-builtin-func' depends on a new version
+            ;; of the macro from `macro-builtin-aux'.
+            (should (equal (macro-builtin-func) '(1 b)))
+            ;; `macro-builtin-10-and-90' depends on an entirely new macro from 
`macro-aux'.
+            (should (equal (macro-builtin-10-and-90) '(10 90))))
+        (mapc #'delete-file
+              (directory-files-recursively dir "\\`[^\\.].*\\.elc\\'"))
+        (mapc (lambda (f) (rename-file f (file-name-sans-extension f)))
+              (directory-files-recursively dir "\\`[^\\.].*\\.el.gz\\'"))))))
+
 (ert-deftest package-test-install-two-dependencies ()
   "Install a package which includes a dependency."
   (with-package-test ()
@@ -636,7 +664,7 @@ but with a different end of line convention (bug#48137)."
      (save-excursion (should (re-search-forward "Status: Installed in 
['`‘]simple-single-1.3/['’] (unsigned)." nil t)))
      (save-excursion (should (search-forward "Version: 1.3" nil t)))
      (save-excursion (should (search-forward "Summary: A single-file package 
with no dependencies" nil t)))
-     (save-excursion (should (search-forward "Homepage: http://doodles.au"; nil 
t)))
+     (save-excursion (should (search-forward "Website: http://doodles.au"; nil 
t)))
      (save-excursion (should (re-search-forward "Keywords: \\[?frobnicate\\]?" 
nil t)))
      (save-excursion (should (search-forward "This package provides a minor 
mode to frobnicate"
                                              nil t)))
@@ -652,7 +680,7 @@ but with a different end of line convention (bug#48137)."
     (with-fake-help-buffer
      (describe-package 'multi-file)
      (goto-char (point-min))
-     (should (search-forward "Homepage: http://puddles.li"; nil t))
+     (should (search-forward "Website: http://puddles.li"; nil t))
      (should (search-forward "This is a bare-bones readme file for the 
multi-file"
                              nil t)))))
 
@@ -665,7 +693,7 @@ but with a different end of line convention (bug#48137)."
     (with-fake-help-buffer
      (describe-package 'simple-single)
      (goto-char (point-min))
-     (should (search-forward "Homepage: http://doodles.au"; nil t))
+     (should (search-forward "Website: http://doodles.au"; nil t))
      (should (search-forward "This package provides a minor mode to frobnicate"
                              nil t)))))
 
@@ -678,32 +706,30 @@ but with a different end of line convention (bug#48137)."
     (with-fake-help-buffer
      (describe-package 'multi-file)
      (goto-char (point-min))
-     (should (search-forward "Homepage: http://puddles.li"; nil t))
+     (should (search-forward "Website: http://puddles.li"; nil t))
      (should (search-forward "This is a bare-bones readme file for the 
multi-file"
                              nil t)))))
 
 (defvar epg-config--program-alist) ; Silence byte-compiler.
 (ert-deftest package-test-signed ()
   "Test verifying package signature."
-  (skip-unless (let ((homedir (make-temp-file "package-test" t)))
-                (unwind-protect
-                    (let ((process-environment
-                           (cons (concat "HOME=" homedir)
-                                 process-environment)))
-                       (require 'epg-config)
-                       (defvar epg-config--program-alist)
-                      (epg-find-configuration
-                        'OpenPGP nil
-                        ;; By default we require gpg2 2.1+ due to some
-                        ;; practical problems with pinentry.  But this
-                        ;; test works fine with 2.0 as well.
-                        (let ((prog-alist (copy-tree 
epg-config--program-alist)))
-                          (setf (alist-get "gpg2"
-                                           (alist-get 'OpenPGP prog-alist)
-                                           nil nil #'equal)
-                                "2.0")
-                          prog-alist)))
-                  (delete-directory homedir t))))
+  (skip-unless (ert-with-temp-directory homedir
+                 (let ((process-environment
+                        (cons (concat "HOME=" homedir)
+                              process-environment)))
+                   (require 'epg-config)
+                   (defvar epg-config--program-alist)
+                   (epg-find-configuration
+                    'OpenPGP nil
+                    ;; By default we require gpg2 2.1+ due to some
+                    ;; practical problems with pinentry.  But this
+                    ;; test works fine with 2.0 as well.
+                    (let ((prog-alist (copy-tree epg-config--program-alist)))
+                      (setf (alist-get "gpg2"
+                                       (alist-get 'OpenPGP prog-alist)
+                                       nil nil #'equal)
+                            "2.0")
+                      prog-alist)))))
   (let* ((keyring (expand-file-name "key.pub" package-test-data-dir))
          (package-test-data-dir (ert-resource-file "signed")))
     (with-package-test ()
diff --git a/test/lisp/emacs-lisp/pp-resources/code-formats.erts 
b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
new file mode 100644
index 0000000000..2b2001d096
--- /dev/null
+++ b/test/lisp/emacs-lisp/pp-resources/code-formats.erts
@@ -0,0 +1,124 @@
+Code:
+  (lambda ()
+    (emacs-lisp-mode)
+    (let ((code (read (current-buffer))))
+      (erase-buffer)
+      (pp-emacs-lisp-code code)
+      (untabify (point-min) (point-max))))
+
+Name: code-formats1
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2))
+    (zot 1 2 (funcall bar 2))))
+=-=-=
+
+
+Name: code-formats2
+
+=-=
+(defun pp-emacs-lisp-code (sexp)
+  "Insert SEXP into the current buffer, formatted as Emacs Lisp code."
+  (require 'edebug)
+  (let ((start (point))
+        (standard-output (current-buffer)))
+    (pp--insert-lisp sexp)
+    (insert "\n")
+    (goto-char start)
+    (indent-sexp)))
+=-=-=
+
+
+Name: code-formats3
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2))
+    (zot-zot-zot-zot-zot-zot 1 2 (funcall
+                                  bar-bar-bar-bar-bar-bar-bar-bar-bar-bar
+                                  2))))
+=-=-=
+
+
+Name: code-formats4
+
+=-=
+(defun foo (bar)
+  "Yes."
+  (let ((a 1)
+        (b 2)
+        foo bar zotfoo bar zotfoo bar zotfoo bar zotfoo bar zotfoo bar zotfoo
+        bar zot)
+    (zot 1 2 (funcall bar 2))))
+=-=-=
+
+
+Name: code-formats5
+
+=-=
+(defgroup pp ()
+  "Pretty printer for Emacs Lisp."
+  :prefix "pp-"
+  :group 'lisp)
+=-=-=
+
+Name: code-formats6
+
+=-=
+(defcustom pp-escape-newlines t
+  "Value of `print-escape-newlines' used by pp-* functions."
+  :type 'boolean
+  :group 'pp)
+=-=-=
+
+Name: code-formats7
+
+=-=
+(defun pp (object &optional stream)
+  (princ (pp-to-string object) (or stream standard-output)))
+=-=-=
+
+
+Name: code-formats8
+
+=-=
+(defun pp-eval-expression (expression)
+  "Evaluate EXPRESSION and pretty-print its value.
+Also add the value to the front of the list in the variable `values'."
+  (interactive (list (read--expression "Eval: ")))
+  (message "Evaluating...")
+  (let ((result (eval expression lexical-binding)))
+    (values--store-value result)
+    (pp-display-expression result "*Pp Eval Output*")))
+=-=-=
+
+Name: code-formats9
+
+=-=
+(lambda ()
+  (interactive)
+  1)
+=-=-=
+
+
+Name: code-formats10
+
+=-=
+(funcall foo (concat "zot" (if (length> site 0) site
+                             "bar")
+                     "+"
+                     (string-replace " " "+" query)))
+=-=-=
+
+
+Name: code-formats11
+
+=-=
+(lambda ()
+  [(foo bar) (foo bar)])
+=-=-=
diff --git a/test/lisp/emacs-lisp/pp-tests.el b/test/lisp/emacs-lisp/pp-tests.el
index b04030cc43..4cae1a7377 100644
--- a/test/lisp/emacs-lisp/pp-tests.el
+++ b/test/lisp/emacs-lisp/pp-tests.el
@@ -20,6 +20,7 @@
 ;;; Code:
 
 (require 'pp)
+(require 'ert-x)
 
 (ert-deftest pp-print-quote ()
   (should (string= (pp-to-string 'quote) "quote"))
@@ -32,4 +33,7 @@
   (should (string= (pp-to-string '(quotefoo)) "(quotefoo)\n"))
   (should (string= (pp-to-string '(a b)) "(a b)\n")))
 
+(ert-deftest test-indentation ()
+  (ert-test-erts-file (ert-resource-file "code-formats.erts")))
+
 ;;; pp-tests.el ends here.
diff --git a/test/lisp/emacs-lisp/regexp-opt-tests.el 
b/test/lisp/emacs-lisp/regexp-opt-tests.el
index 940feb5e82..65494e20df 100644
--- a/test/lisp/emacs-lisp/regexp-opt-tests.el
+++ b/test/lisp/emacs-lisp/regexp-opt-tests.el
@@ -66,4 +66,4 @@
 
   (should (equal (regexp-opt-charset '()) regexp-unmatchable)))
 
-;;; regexp-tests.el ends here.
+;;; regexp-opt-tests.el ends here
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el
index 4828df0de9..3bc35feb6d 100644
--- a/test/lisp/emacs-lisp/rx-tests.el
+++ b/test/lisp/emacs-lisp/rx-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'rx)
 
@@ -583,3 +585,5 @@
            "\\(?3:.+$\\)")))
 
 (provide 'rx-tests)
+
+;;; rx-tests.el ends here
diff --git a/test/lisp/emacs-lisp/shortdoc-tests.el 
b/test/lisp/emacs-lisp/shortdoc-tests.el
index 3bb3185649..cfb0b4244b 100644
--- a/test/lisp/emacs-lisp/shortdoc-tests.el
+++ b/test/lisp/emacs-lisp/shortdoc-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'shortdoc)
 
@@ -43,3 +45,5 @@
             (setq props (cddr props))))))))
 
 (provide 'shortdoc-tests)
+
+;;; shortdoc-tests.el ends here
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el 
b/test/lisp/emacs-lisp/subr-x-tests.el
index 1d19496ba4..f9cfea888c 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -638,5 +638,43 @@
   (should (equal (string-chop-newline "foo\nbar\n") "foo\nbar"))
   (should (equal (string-chop-newline "foo\nbar") "foo\nbar")))
 
+(ert-deftest subr-ensure-empty-lines ()
+  (should
+   (equal
+    (with-temp-buffer
+      (insert "foo")
+      (goto-char (point-min))
+      (ensure-empty-lines 2)
+      (buffer-string))
+    "\n\nfoo"))
+  (should
+   (equal
+    (with-temp-buffer
+      (insert "foo")
+      (ensure-empty-lines 2)
+      (buffer-string))
+    "foo\n\n\n"))
+  (should
+   (equal
+    (with-temp-buffer
+      (insert "foo\n")
+      (ensure-empty-lines 2)
+      (buffer-string))
+    "foo\n\n\n"))
+  (should
+   (equal
+    (with-temp-buffer
+      (insert "foo\n\n\n\n\n")
+      (ensure-empty-lines 2)
+      (buffer-string))
+    "foo\n\n\n"))
+  (should
+   (equal
+    (with-temp-buffer
+      (insert "foo\n\n\n")
+      (ensure-empty-lines 0)
+      (buffer-string))
+    "foo\n")))
+
 (provide 'subr-x-tests)
 ;;; subr-x-tests.el ends here
diff --git a/test/lisp/emacs-lisp/tabulated-list-test.el 
b/test/lisp/emacs-lisp/tabulated-list-tests.el
similarity index 63%
rename from test/lisp/emacs-lisp/tabulated-list-test.el
rename to test/lisp/emacs-lisp/tabulated-list-tests.el
index 679afda394..e376d2f328 100644
--- a/test/lisp/emacs-lisp/tabulated-list-test.el
+++ b/test/lisp/emacs-lisp/tabulated-list-tests.el
@@ -1,4 +1,4 @@
-;;; tabulated-list-test.el --- Tests for emacs-lisp/tabulated-list.el  -*- 
lexical-binding: t; -*-
+;;; tabulated-list-tests.el --- Tests for emacs-lisp/tabulated-list.el  -*- 
lexical-binding: t; -*-
 
 ;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
 
@@ -56,10 +56,10 @@
   (tabulated-list--test-with-buffer
    ;; Basic printing.
    (should (string= (buffer-substring-no-properties (point-min) (point-max))
-                    "       zzzz-game  zzzz-game  2113      installed   play 
zzzz in Emacs
-       4clojure   4clojure   1507      obsolete    Open and evaluate 
4clojure.com questions
-       abc-mode   abc-mode   944       available   Major mode for editing abc 
music files
-       mode       mode       1128      installed   A simple mode for editing 
Actionscript 3 files\n"))
+                  "       zzzz-game          zzzz-game          2113         
installed           play zzzz in Emacs
+       4clojure          4clojure          1507         obsolete           
Open and evaluate 4clojure.com questions
+       abc-mode          abc-mode          944         available           
Major mode for editing abc music files
+       mode          mode          1128         installed           A simple 
mode for editing Actionscript 3 files\n"))
    ;; Preserve position.
    (forward-line 3)
    (let ((pos (thing-at-point 'line)))
@@ -67,16 +67,16 @@
      (tabulated-list-print t)
      (should (equal (thing-at-point 'line) pos))
      (should (string= (buffer-substring-no-properties (point-min) (point-max))
-                      "       4clojure   4clojure   1507      obsolete    Open 
and evaluate 4clojure.com questions
-       abc-mode   abc-mode   944       available   Major mode for editing abc 
music files
-       mode       mode       1128      installed   A simple mode for editing 
Actionscript 3 files\n"))
+                      "       4clojure          4clojure          1507         
obsolete           Open and evaluate 4clojure.com questions
+       abc-mode          abc-mode          944         available           
Major mode for editing abc music files
+       mode          mode          1128         installed           A simple 
mode for editing Actionscript 3 files\n"))
      ;; Check the UPDATE argument
      (pop tabulated-list-entries)
      (setf (cdr (car tabulated-list-entries)) (list ["x" "x" "944" "available" 
" XX"]))
      (tabulated-list-print t t)
      (should (string= (buffer-substring-no-properties (point-min) (point-max))
-                      "       x          x          944       available   XX
-       mode       mode       1128      installed   A simple mode for editing 
Actionscript 3 files\n"))
+                      "       x          x          944         available      
     XX
+       mode          mode          1128         installed           A simple 
mode for editing Actionscript 3 files\n"))
      (should (equal (thing-at-point 'line) pos)))))
 
 (ert-deftest tabulated-list-sort ()
@@ -86,10 +86,11 @@
    (skip-chars-forward "[:blank:]")
    (tabulated-list-sort)
    (let ((text (buffer-substring-no-properties (point-min) (point-max))))
-     (should (string= text "       4clojure   4clojure   1507      obsolete    
Open and evaluate 4clojure.com questions
-       abc-mode   abc-mode   944       available   Major mode for editing abc 
music files
-       mode       mode       1128      installed   A simple mode for editing 
Actionscript 3 files
-       zzzz-game  zzzz-game  2113      installed   play zzzz in Emacs\n"))
+     (should (string= text
+                      "       4clojure          4clojure          1507         
obsolete           Open and evaluate 4clojure.com questions
+       abc-mode          abc-mode          944         available           
Major mode for editing abc music files
+       mode          mode          1128         installed           A simple 
mode for editing Actionscript 3 files
+       zzzz-game          zzzz-game          2113         installed           
play zzzz in Emacs\n"))
 
      (skip-chars-forward "^[:blank:]")
      (skip-chars-forward "[:blank:]")
@@ -101,10 +102,10 @@
      ;; Invert.
      (tabulated-list-sort 1)
      (should (string= (buffer-substring-no-properties (point-min) (point-max))
-                      "       zzzz-game  zzzz-game  2113      installed   play 
zzzz in Emacs
-       mode       mode       1128      installed   A simple mode for editing 
Actionscript 3 files
-       abc-mode   abc-mode   944       available   Major mode for editing abc 
music files
-       4clojure   4clojure   1507      obsolete    Open and evaluate 
4clojure.com questions\n"))
+                      "       zzzz-game          zzzz-game          2113       
  installed           play zzzz in Emacs
+       mode          mode          1128         installed           A simple 
mode for editing Actionscript 3 files
+       abc-mode          abc-mode          944         available           
Major mode for editing abc music files
+       4clojure          4clojure          1507         obsolete           
Open and evaluate 4clojure.com questions\n"))
      ;; Again
      (tabulated-list-sort 1)
      (should (string= text (buffer-substring-no-properties (point-min) 
(point-max)))))
@@ -114,5 +115,4 @@
    (should-error (tabulated-list-sort) :type 'user-error)
    (should-error (tabulated-list-sort 4) :type 'user-error)))
 
-(provide 'tabulated-list-test)
-;;; tabulated-list-test.el ends here
+;;; tabulated-list-tests.el ends here
diff --git a/test/lisp/emacs-lisp/testcover-resources/testcases.el 
b/test/lisp/emacs-lisp/testcover-resources/testcases.el
index 7ced257c6f..29094526d7 100644
--- a/test/lisp/emacs-lisp/testcover-resources/testcases.el
+++ b/test/lisp/emacs-lisp/testcover-resources/testcases.el
@@ -77,12 +77,12 @@
 "Testcover doesn't prevent testing of defcustom values."
 ;; ====
 (defgroup testcover-testcase nil
-  "Test case for testcover"
+  "Test case for testcover."
   :group 'lisp
   :prefix "testcover-testcase-"
   :version "26.0")
 (defcustom testcover-testcase-flag t
-  "Test value used by testcover-tests.el"
+  "Test value used by testcover-tests.el."
   :type 'boolean
   :group 'testcover-testcase)
 (defun testcover-testcase-get-flag ()
@@ -111,7 +111,7 @@
 "Wrapping a form with noreturn prevents splotching."
 ;; ====
 (defun testcover-testcase-cancel (spacecraft)
-  (error "no destination for %s" spacecraft))
+  (error "No destination for %s" spacecraft))
 (defun testcover-testcase-launch (spacecraft planet)
   (if (null planet)
       (noreturn (testcover-testcase-cancel spacecraft%%%))
@@ -220,7 +220,7 @@
 (defun testcover-testcase-cc (arg)
   (condition-case nil
       (if (null arg%%%)%%%
-        (error "foo")
+        (error "Foo")
         "0")!!!
         (error nil)))
 (should-not (testcover-testcase-cc nil))
@@ -510,4 +510,4 @@ regarding the odd-looking coverage result for the quoted 
form."
 (testcover-testcase-cyc2 1 2)
 (testcover-testcase-cyc2 1 4)
 
-;; testcases.el ends here.
+;;; testcases.el ends here
diff --git a/test/lisp/emacs-lisp/testcover-tests.el 
b/test/lisp/emacs-lisp/testcover-tests.el
index 7854e33e77..a7e055a28b 100644
--- a/test/lisp/emacs-lisp/testcover-tests.el
+++ b/test/lisp/emacs-lisp/testcover-tests.el
@@ -45,34 +45,34 @@ testcases.el.  This can be used to create test cases if 
Testcover
 is working correctly on a code sample.  OPTARGS are optional
 arguments for `testcover-start'."
     (interactive "r")
-    (let ((tempfile (make-temp-file "testcover-tests-" nil ".el"))
-          (find-file-suppress-same-file-warnings t)
-          (code (buffer-substring beg end))
-          (marked-up-code))
-      (unwind-protect
-          (progn
-            (with-temp-file tempfile
-              (insert code))
-            (save-current-buffer
-              (let ((buf (find-file-noselect tempfile)))
-                (set-buffer buf)
-                (apply 'testcover-start (cons tempfile optargs))
-                (testcover-mark-all buf)
-                (dolist (overlay (overlays-in (point-min) (point-max)))
-                  (let ((ov-face (overlay-get overlay 'face)))
-                    (goto-char (overlay-end overlay))
-                    (cond
-                     ((eq ov-face 'testcover-nohits) (insert "!!!"))
-                     ((eq ov-face 'testcover-1value) (insert "%%%"))
-                     (t nil))))
-                (setq marked-up-code (buffer-string)))
-              (set-buffer-modified-p nil)))
-        (ignore-errors (kill-buffer (find-file-noselect tempfile)))
-        (ignore-errors (delete-file tempfile)))
-
-      ;; Now replace the original code with the marked up code.
-      (delete-region beg end)
-      (insert marked-up-code))))
+    (ert-with-temp-file tempfile
+      :suffix ".el"
+      (let ((find-file-suppress-same-file-warnings t)
+            (code (buffer-substring beg end))
+            (marked-up-code))
+        (unwind-protect
+            (progn
+              (with-temp-file tempfile
+                (insert code))
+              (save-current-buffer
+                (let ((buf (find-file-noselect tempfile)))
+                  (set-buffer buf)
+                  (apply 'testcover-start (cons tempfile optargs))
+                  (testcover-mark-all buf)
+                  (dolist (overlay (overlays-in (point-min) (point-max)))
+                    (let ((ov-face (overlay-get overlay 'face)))
+                      (goto-char (overlay-end overlay))
+                      (cond
+                       ((eq ov-face 'testcover-nohits) (insert "!!!"))
+                       ((eq ov-face 'testcover-1value) (insert "%%%"))
+                       (t nil))))
+                  (setq marked-up-code (buffer-string)))
+                (set-buffer-modified-p nil)))
+          (ignore-errors (kill-buffer (find-file-noselect tempfile))))
+
+        ;; Now replace the original code with the marked up code.
+        (delete-region beg end)
+        (insert marked-up-code)))))
 
 (eval-and-compile
   (defun testcover-tests-unmarkup-region (beg end)
@@ -99,32 +99,32 @@ arguments for `testcover-start'."
 (eval-and-compile
   (defun testcover-tests-run-test-case (marked-up-code)
     "Test the operation of Testcover on the string MARKED-UP-CODE."
-    (let ((tempfile (make-temp-file "testcover-tests-" nil ".el"))
-          (find-file-suppress-same-file-warnings t))
-      (unwind-protect
-          (progn
-            (with-temp-file tempfile
-              (insert marked-up-code))
-            ;; Remove the marks and mark the code up again. The original
-            ;; and recreated versions should match.
-            (save-current-buffer
-              (set-buffer (find-file-noselect tempfile))
-              ;; Fail the test if the debugger tries to become active,
-              ;; which can happen if Testcover fails to attach itself
-              ;; correctly. Note that this will prevent debugging
-              ;; these tests using Edebug.
-              (cl-letf (((symbol-function #'edebug-default-enter)
-                         (lambda (&rest _args)
-                           (ert-fail "Debugger invoked during test run"))))
-                (dolist (byte-compile '(t nil))
-                  (testcover-tests-unmarkup-region (point-min) (point-max))
-                  (unwind-protect
-                      (testcover-tests-markup-region (point-min) (point-max) 
byte-compile)
-                    (set-buffer-modified-p nil))
-                  (should (string= marked-up-code
-                                   (buffer-string)))))))
-        (ignore-errors (kill-buffer (find-file-noselect tempfile)))
-        (ignore-errors (delete-file tempfile))))))
+    (ert-with-temp-file tempfile
+      :suffix ".el"
+      (let ((find-file-suppress-same-file-warnings t))
+        (unwind-protect
+            (progn
+              (with-temp-file tempfile
+                (insert marked-up-code))
+              ;; Remove the marks and mark the code up again. The original
+              ;; and recreated versions should match.
+              (save-current-buffer
+                (set-buffer (find-file-noselect tempfile))
+                ;; Fail the test if the debugger tries to become active,
+                ;; which can happen if Testcover fails to attach itself
+                ;; correctly. Note that this will prevent debugging
+                ;; these tests using Edebug.
+                (cl-letf (((symbol-function #'edebug-default-enter)
+                           (lambda (&rest _args)
+                             (ert-fail "Debugger invoked during test run"))))
+                  (dolist (byte-compile '(t nil))
+                    (testcover-tests-unmarkup-region (point-min) (point-max))
+                    (unwind-protect
+                        (testcover-tests-markup-region (point-min) (point-max) 
byte-compile)
+                      (set-buffer-modified-p nil))
+                    (should (string= marked-up-code
+                                     (buffer-string)))))))
+          (ignore-errors (kill-buffer (find-file-noselect tempfile))))))))
 
 ;; Convert test case file to ert-defmethod.
 
diff --git a/test/lisp/emacs-lisp/unsafep-tests.el 
b/test/lisp/emacs-lisp/unsafep-tests.el
index b2a48d8067..f0d9b03243 100644
--- a/test/lisp/emacs-lisp/unsafep-tests.el
+++ b/test/lisp/emacs-lisp/unsafep-tests.el
@@ -105,7 +105,7 @@
       . (variable (x)))
     ( (let (1) 2)
       . (variable 1))
-    ( (error "asdf")
+    ( (error "Asdf")
       . #'error)
     ( (signal 'error "asdf")
       . #'signal)
diff --git a/test/lisp/emulation/viper-tests.el 
b/test/lisp/emulation/viper-tests.el
index 0d999763b6..b8efc87ab7 100644
--- a/test/lisp/emulation/viper-tests.el
+++ b/test/lisp/emulation/viper-tests.el
@@ -21,7 +21,8 @@
 
 ;;; Code:
 
-
+(require 'ert)
+(require 'ert-x)
 (require 'viper)
 
 (defun viper-test-undo-kmacro (kmacro)
@@ -30,47 +31,42 @@
 This function makes as many attempts as possible to clean up
 after itself, although it will leave a buffer called
 *viper-test-buffer* if it fails (this is deliberate!)."
-  (let (
-        ;; Viper just turns itself off during batch use.
-        (noninteractive nil)
-        ;; Switch off start up message or it will chew the key presses.
-        (viper-inhibit-startup-message 't)
-        ;; Select an expert-level for the same reason.
-        (viper-expert-level 5)
-        ;; viper loads this even with -q so make sure it's empty!
-        (viper-custom-file-name (make-temp-file "viper-tests" nil ".elc"))
-        (before-buffer (current-buffer)))
-    (unwind-protect
-        (progn
-          ;; viper-mode is essentially global, so set it here.
-          (viper-mode)
-          ;; We must switch to buffer because we are using a keyboard macro
-          ;; which appears to not go to the current-buffer but what ever is
-          ;; currently taking keyboard events. We use a named buffer because
-          ;; then we can see what it in it if it all goes wrong.
-          (switch-to-buffer
-           (get-buffer-create
-            "*viper-test-buffer*"))
-          (erase-buffer)
-          ;; The new buffer fails to enter vi state so set it.
-          (viper-change-state-to-vi)
-          ;; Run the macro.
-          (execute-kbd-macro kmacro)
-          (let ((rtn
-                 (buffer-substring-no-properties
-                  (point-min)
-                  (point-max))))
-            ;; Kill the buffer iff the macro succeeds.
-            (kill-buffer)
-            rtn))
-      ;; Switch everything off and restore the buffer.
-      (toggle-viper-mode)
-      (delete-file viper-custom-file-name)
-      (switch-to-buffer before-buffer))))
-
-(ert-deftest viper-test-go ()
-  "Test that this file is running."
-  (should t))
+  (ert-with-temp-file viper-custom-file-name
+    ;; viper loads this even with -q so make sure it's empty!
+    :prefix "emacs-viper-tests" :suffix ".elc"
+    (let (;; Viper just turns itself off during batch use.
+          (noninteractive nil)
+          ;; Switch off start up message or it will chew the key presses.
+          (viper-inhibit-startup-message 't)
+          ;; Select an expert-level for the same reason.
+          (viper-expert-level 5)
+          (before-buffer (current-buffer)))
+      (unwind-protect
+          (progn
+            ;; viper-mode is essentially global, so set it here.
+            (viper-mode)
+            ;; We must switch to buffer because we are using a keyboard macro
+            ;; which appears to not go to the current-buffer but what ever is
+            ;; currently taking keyboard events. We use a named buffer because
+            ;; then we can see what it in it if it all goes wrong.
+            (switch-to-buffer
+             (get-buffer-create
+              "*viper-test-buffer*"))
+            (erase-buffer)
+            ;; The new buffer fails to enter vi state so set it.
+            (viper-change-state-to-vi)
+            ;; Run the macro.
+            (execute-kbd-macro kmacro)
+            (let ((rtn
+                   (buffer-substring-no-properties
+                    (point-min)
+                    (point-max))))
+              ;; Kill the buffer iff the macro succeeds.
+              (kill-buffer)
+              rtn))
+        ;; Switch everything off and restore the buffer.
+        (toggle-viper-mode)
+        (switch-to-buffer before-buffer)))))
 
 (ert-deftest viper-test-fix ()
   "Test that the viper kmacro fixture is working."
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index 741574f0ad..1384221c49 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -58,48 +58,45 @@
 (cl-defmacro with-epg-tests ((&optional &key require-passphrase
                                        require-public-key
                                        require-secret-key)
-                           &rest body)
+                             &rest body)
   "Set up temporary locations and variables for testing."
   (declare (indent 1) (debug (sexp body)))
-  `(let* ((epg-tests-home-directory (make-temp-file "epg-tests-homedir" t))
-         (process-environment
-          (append
-           (list "GPG_AGENT_INFO"
-                 (format "GNUPGHOME=%s" epg-tests-home-directory))
-           process-environment)))
-     (unwind-protect
-         ;; GNUPGHOME is needed to find a usable gpg, so we can't
-         ;; check whether to skip any earlier (Bug#23561).
-         (let ((epg-config (or (epg-tests-find-usable-gpg-configuration
-                                ,require-passphrase ,require-public-key)
-                               (ert-skip "No usable gpg config")))
-               (context (epg-make-context 'OpenPGP)))
-           (setf (epg-context-program context)
-                 (alist-get 'program epg-config))
-          (setf (epg-context-home-directory context)
-                epg-tests-home-directory)
-          ,(if require-passphrase
-               '(with-temp-file (expand-file-name
-                                  "gpg-agent.conf" epg-tests-home-directory)
-                   (insert "pinentry-program "
-                           (ert-resource-file "dummy-pinentry")
-                           "\n")
-                   (epg-context-set-passphrase-callback
-                    context
-                    #'epg-tests-passphrase-callback)))
-          ,(if require-public-key
-               '(epg-import-keys-from-file
-                 context
-                  (ert-resource-file "pubkey.asc")))
-          ,(if require-secret-key
-               '(epg-import-keys-from-file
-                 context
-                  (ert-resource-file "seckey.asc")))
-          (with-temp-buffer
-             (setq-local epg-tests-context context)
-            ,@body))
-       (when (file-directory-p epg-tests-home-directory)
-        (delete-directory epg-tests-home-directory t)))))
+  `(ert-with-temp-directory epg-tests-home-directory
+     (let* ((process-environment
+             (append
+              (list "GPG_AGENT_INFO"
+                    (format "GNUPGHOME=%s" epg-tests-home-directory))
+              process-environment)))
+       ;; GNUPGHOME is needed to find a usable gpg, so we can't
+       ;; check whether to skip any earlier (Bug#23561).
+       (let ((epg-config (or (epg-tests-find-usable-gpg-configuration
+                           ,require-passphrase ,require-public-key)
+                          (ert-skip "No usable gpg config")))
+             (context (epg-make-context 'OpenPGP)))
+         (setf (epg-context-program context)
+               (alist-get 'program epg-config))
+         (setf (epg-context-home-directory context)
+               epg-tests-home-directory)
+         ,(if require-passphrase
+              '(with-temp-file (expand-file-name
+                                "gpg-agent.conf" epg-tests-home-directory)
+                 (insert "pinentry-program "
+                         (ert-resource-file "dummy-pinentry")
+                         "\n")
+                 (epg-context-set-passphrase-callback
+                  context
+                  #'epg-tests-passphrase-callback)))
+         ,(if require-public-key
+              '(epg-import-keys-from-file
+                context
+                (ert-resource-file "pubkey.asc")))
+         ,(if require-secret-key
+              '(epg-import-keys-from-file
+                context
+                (ert-resource-file "seckey.asc")))
+         (with-temp-buffer
+           (setq-local epg-tests-context context)
+           ,@body)))))
 
 (ert-deftest epg-decrypt-1 ()
   :expected-result (if (getenv "EMACS_HYDRA_CI") :failed :passed) ; fixme
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 22f62a35c7..b2dbc1012d 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -227,3 +227,76 @@
   (when noninteractive
     (kill-buffer "*erc-protocol*")
     (should-not erc-debug-irc-protocol)))
+
+
+;; The point of this test is to ensure output is handled identically
+;; regardless of whether a command handler is summoned.
+
+(ert-deftest erc-process-input-line ()
+  (let (erc-server-last-sent-time
+        erc-server-flood-queue
+        (orig-erc-cmd-MSG (symbol-function 'erc-cmd-MSG))
+        (erc-default-recipients '("#chan"))
+        calls)
+    (with-temp-buffer
+      (cl-letf (((symbol-function 'erc-cmd-MSG)
+                 (lambda (line)
+                   (push line calls)
+                   (funcall orig-erc-cmd-MSG line)))
+                ((symbol-function 'erc-server-buffer)
+                 (lambda () (current-buffer)))
+                ((symbol-function 'erc-server-process-alive)
+                 (lambda () t))
+                ((symbol-function 'erc-server-send-queue)
+                 #'ignore))
+
+        (ert-info ("Dispatch to user command handler")
+
+          (ert-info ("Baseline")
+            (erc-process-input-line "/msg #chan hi\n")
+            (should (equal (pop calls) " #chan hi"))
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :hi\r\n" . utf-8))))
+
+          (ert-info ("Quote preserves line intact")
+            (erc-process-input-line "/QUOTE FAKE foo bar\n")
+            (should (equal (pop erc-server-flood-queue)
+                           '("FAKE foo bar\r\n" . utf-8))))
+
+          (ert-info ("Unknown command respected")
+            (erc-process-input-line "/FAKE foo bar\n")
+            (should (equal (pop erc-server-flood-queue)
+                           '("FAKE foo bar\r\n" . utf-8))))
+
+          (ert-info ("Spaces preserved")
+            (erc-process-input-line "/msg #chan hi you\n")
+            (should (equal (pop calls) " #chan hi you"))
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :hi you\r\n" . utf-8))))
+
+          (ert-info ("Empty line honored")
+            (erc-process-input-line "/msg #chan\n")
+            (should (equal (pop calls) " #chan"))
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :\r\n" . utf-8)))))
+
+        (ert-info ("Implicit cmd via `erc-send-input-line-function'")
+
+          (ert-info ("Baseline")
+            (erc-process-input-line "hi")
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :hi\r\n" . utf-8))))
+
+          (ert-info ("Spaces preserved")
+            (erc-process-input-line "hi you")
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :hi you\r\n" . utf-8))))
+
+          (ert-info ("Empty line transmitted without injected-space kludge")
+            (erc-process-input-line "")
+            (should (equal (pop erc-server-flood-queue)
+                           '("PRIVMSG #chan :\r\n" . utf-8))))
+
+          (should-not calls))))))
+
+;;; erc-tests.el ends here
diff --git a/test/lisp/erc/erc-track-tests.el b/test/lisp/erc/erc-track-tests.el
index 0ce93bd45c..b2687a96ab 100644
--- a/test/lisp/erc/erc-track-tests.el
+++ b/test/lisp/erc/erc-track-tests.el
@@ -119,3 +119,5 @@
                        '(bold erc-current-nick-face) str1)
     (should (erc-faces-in str0))
     (should (erc-faces-in str1)) ))
+
+;;; erc-track-tests.el ends here
diff --git a/test/lisp/eshell/em-hist-tests.el 
b/test/lisp/eshell/em-hist-tests.el
index 31967a61c3..5bc5690675 100644
--- a/test/lisp/eshell/em-hist-tests.el
+++ b/test/lisp/eshell/em-hist-tests.el
@@ -20,19 +20,18 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'em-hist)
 
 (ert-deftest eshell-write-readonly-history ()
   "Test that having read-only strings in history is okay."
-  (let ((histfile (make-temp-file "eshell-history"))
-        (eshell-history-ring (make-ring 2)))
-    (ring-insert eshell-history-ring
-                 (propertize "echo foo" 'read-only t))
-    (ring-insert eshell-history-ring
-                 (propertize "echo bar" 'read-only t))
-    (unwind-protect
-        (eshell-write-history histfile)
-      (delete-file histfile))))
+  (ert-with-temp-file histfile
+    (let ((eshell-history-ring (make-ring 2)))
+      (ring-insert eshell-history-ring
+                   (propertize "echo foo" 'read-only t))
+      (ring-insert eshell-history-ring
+                   (propertize "echo bar" 'read-only t))
+      (eshell-write-history histfile))))
 
 (provide 'em-hist-test)
 
diff --git a/test/lisp/eshell/em-ls-tests.el b/test/lisp/eshell/em-ls-tests.el
index 5d1742b76f..3ea11ab2de 100644
--- a/test/lisp/eshell/em-ls-tests.el
+++ b/test/lisp/eshell/em-ls-tests.el
@@ -25,30 +25,30 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'em-ls)
 (require 'dired)
 
 (ert-deftest em-ls-test-bug27631 ()
   "Test for https://debbugs.gnu.org/27631 ."
-  (let* ((dir (make-temp-file "bug27631" 'dir))
-         (dir1 (expand-file-name "dir1" dir))
-         (dir2 (expand-file-name "dir2" dir))
-         (default-directory dir)
-         (orig eshell-ls-use-in-dired)
-         buf)
-    (unwind-protect
-        (progn
-          (customize-set-value 'eshell-ls-use-in-dired t)
-          (make-directory dir1)
-          (make-directory dir2)
-          (with-temp-file (expand-file-name "a.txt" dir1))
-          (with-temp-file (expand-file-name "b.txt" dir2))
-          (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
-          (dired-toggle-marks)
-          (should (cdr (dired-get-marked-files))))
-      (customize-set-variable 'eshell-ls-use-in-dired orig)
-      (delete-directory dir 'recursive)
-      (when (buffer-live-p buf) (kill-buffer buf)))))
+  (ert-with-temp-directory dir
+    (let* ((dir1 (expand-file-name "dir1" dir))
+           (dir2 (expand-file-name "dir2" dir))
+           (default-directory dir)
+           (orig eshell-ls-use-in-dired)
+           buf)
+      (unwind-protect
+          (progn
+            (customize-set-value 'eshell-ls-use-in-dired t)
+            (make-directory dir1)
+            (make-directory dir2)
+            (with-temp-file (expand-file-name "a.txt" dir1))
+            (with-temp-file (expand-file-name "b.txt" dir2))
+            (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
+            (dired-toggle-marks)
+            (should (cdr (dired-get-marked-files))))
+        (customize-set-variable 'eshell-ls-use-in-dired orig)
+        (when (buffer-live-p buf) (kill-buffer buf))))))
 
 (ert-deftest em-ls-test-bug27817 ()
   "Test for https://debbugs.gnu.org/27817 ."
diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el
index 4f0cc9b678..0974784ef4 100644
--- a/test/lisp/eshell/eshell-tests.el
+++ b/test/lisp/eshell/eshell-tests.el
@@ -26,23 +26,23 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'esh-mode)
 (require 'eshell)
 
 (defmacro with-temp-eshell (&rest body)
   "Evaluate BODY in a temporary Eshell buffer."
-  `(let* ((eshell-directory-name (make-temp-file "eshell" t))
-          ;; We want no history file, so prevent Eshell from falling
-          ;; back on $HISTFILE.
-          (process-environment (cons "HISTFILE" process-environment))
-          (eshell-history-file-name nil)
-          (eshell-buffer (eshell t)))
-     (unwind-protect
-         (with-current-buffer eshell-buffer
-           ,@body)
-       (let (kill-buffer-query-functions)
-         (kill-buffer eshell-buffer)
-         (delete-directory eshell-directory-name t)))))
+  `(ert-with-temp-directory eshell-directory-name
+     (let* (;; We want no history file, so prevent Eshell from falling
+            ;; back on $HISTFILE.
+            (process-environment (cons "HISTFILE" process-environment))
+            (eshell-history-file-name nil)
+            (eshell-buffer (eshell t)))
+       (unwind-protect
+           (with-current-buffer eshell-buffer
+             ,@body)
+         (let (kill-buffer-query-functions)
+           (kill-buffer eshell-buffer))))))
 
 (defun eshell-insert-command (text &optional func)
   "Insert a command at the end of the buffer."
@@ -65,11 +65,9 @@
 
 (defun eshell-test-command-result (command)
   "Like `eshell-command-result', but not using HOME."
-  (let ((eshell-directory-name (make-temp-file "eshell" t))
-        (eshell-history-file-name nil))
-    (unwind-protect
-        (eshell-command-result command)
-      (delete-directory eshell-directory-name t))))
+  (ert-with-temp-directory eshell-directory-name
+    (let ((eshell-history-file-name nil))
+      (eshell-command-result command))))
 
 ;;; Tests:
 
@@ -262,4 +260,4 @@ chars"
 
 (provide 'eshell-tests)
 
-;;; tests/eshell-tests.el ends here
+;;; eshell-tests.el ends here
diff --git a/test/lisp/faces-resources/faces-test-dark-theme.el 
b/test/lisp/faces-resources/faces-test-dark-theme.el
index f3ef6b67fa..7e8871ec10 100644
--- a/test/lisp/faces-resources/faces-test-dark-theme.el
+++ b/test/lisp/faces-resources/faces-test-dark-theme.el
@@ -22,7 +22,7 @@
 ;;; Code:
 
 (deftheme faces-test-dark
-  "")
+  "Dark test theme.")
 
 (custom-theme-set-faces
  'faces-test-dark
diff --git a/test/lisp/faces-resources/faces-test-light-theme.el 
b/test/lisp/faces-resources/faces-test-light-theme.el
index 390b846164..70a7501761 100644
--- a/test/lisp/faces-resources/faces-test-light-theme.el
+++ b/test/lisp/faces-resources/faces-test-light-theme.el
@@ -22,7 +22,7 @@
 ;;; Code:
 
 (deftheme faces-test-light
-  "")
+  "Light test theme.")
 
 (custom-theme-set-faces
  'faces-test-light
diff --git a/test/lisp/faces-tests.el b/test/lisp/faces-tests.el
index c0db9c9de1..fe5f3ec95f 100644
--- a/test/lisp/faces-tests.el
+++ b/test/lisp/faces-tests.el
@@ -25,7 +25,7 @@
 (require 'ert)
 (require 'ert-x)
 
-(defgroup faces--test nil ""
+(defgroup faces--test nil "Group to test faces."
   :group 'faces--test)
 
 (defface faces--test1
diff --git a/test/lisp/ffap-tests.el b/test/lisp/ffap-tests.el
index f8113bffc1..84b9cea6c1 100644
--- a/test/lisp/ffap-tests.el
+++ b/test/lisp/ffap-tests.el
@@ -25,30 +25,29 @@
 
 (require 'cl-lib)
 (require 'ert)
+(require 'ert-x)
 (require 'ffap)
 
 (ert-deftest ffap-tests-25243 ()
   "Test for https://debbugs.gnu.org/25243 ."
-  (let ((file (make-temp-file "test-Bug#25243")))
-    (unwind-protect
-        (with-temp-file file
-          (let ((str "diff --git b/lisp/ffap.el a/lisp/ffap.el
+  (ert-with-temp-file file
+    :suffix "-bug25243"
+    (let ((str "diff --git b/lisp/ffap.el a/lisp/ffap.el
 index 3d7cebadcf..ad4b70d737 100644
 --- b/lisp/ffap.el
 +++ a/lisp/ffap.el
 @@ -203,6 +203,9 @@ ffap-foo-at-bar-prefix
 "))
-            (transient-mark-mode 1)
-            (when (natnump ffap-max-region-length)
-              (insert
-               (concat
-                str
-                (make-string ffap-max-region-length #xa)
-                (format "%s ENDS HERE" file)))
-              (call-interactively 'mark-whole-buffer)
-              (should (equal "" (ffap-string-at-point)))
-              (should (equal '(1 1) ffap-string-at-point-region)))))
-      (and (file-exists-p file) (delete-file file)))))
+      (transient-mark-mode 1)
+      (when (natnump ffap-max-region-length)
+        (insert
+         (concat
+          str
+          (make-string ffap-max-region-length #xa)
+          (format "%s ENDS HERE" file)))
+        (call-interactively 'mark-whole-buffer)
+        (should (equal "" (ffap-string-at-point)))
+        (should (equal '(1 1) ffap-string-at-point-region))))))
 
 (ert-deftest ffap-gopher-at-point ()
   (with-temp-buffer
diff --git a/test/lisp/filenotify-tests.el b/test/lisp/filenotify-tests.el
index 6125069c6b..0fe72f278d 100644
--- a/test/lisp/filenotify-tests.el
+++ b/test/lisp/filenotify-tests.el
@@ -162,9 +162,7 @@ Return nil when any other file notification watch is still 
active."
 
 (defun file-notify--test-cleanup ()
   "Cleanup after a test."
-  (file-notify-rm-watch file-notify--test-desc)
-  (file-notify-rm-watch file-notify--test-desc1)
-  (file-notify-rm-watch file-notify--test-desc2)
+  (file-notify-rm-all-watches)
 
   (ignore-errors
     (delete-file (file-newest-backup file-notify--test-tmpfile)))
@@ -421,7 +419,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
 
 ;; This test is inspired by Bug#26126 and Bug#26127.
 (ert-deftest file-notify-test02-rm-watch ()
-  "Check `file-notify-rm-watch'."
+  "Check `file-notify-rm-watch' and `file-notify-rm-all-watches'."
   (skip-unless (file-notify--test-local-enabled))
 
   (unwind-protect
@@ -516,6 +514,31 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
             ;; The environment shall be cleaned up.
             (file-notify--test-cleanup-p))))
 
+    ;; Cleanup.
+    (file-notify--test-cleanup))
+
+  (unwind-protect
+      ;; Check `file-notify-rm-all-watches'.
+      (progn
+        (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
+              file-notify--test-tmpfile1 (file-notify--test-make-temp-name))
+        (write-region "any text" nil file-notify--test-tmpfile nil 'no-message)
+        (write-region "any text" nil file-notify--test-tmpfile1 nil 
'no-message)
+        (should
+         (setq file-notify--test-desc
+               (file-notify-add-watch
+                file-notify--test-tmpfile '(change) #'ignore)))
+        (should
+         (setq file-notify--test-desc1
+               (file-notify-add-watch
+                file-notify--test-tmpfile1 '(change) #'ignore)))
+        (file-notify-rm-all-watches)
+        (delete-file file-notify--test-tmpfile)
+        (delete-file file-notify--test-tmpfile1)
+
+        ;; The environment shall be cleaned up.
+        (file-notify--test-cleanup-p))
+
     ;; Cleanup.
     (file-notify--test-cleanup)))
 
@@ -743,7 +766,7 @@ delivered."
             ;; the directory.  Except for
             ;; GFam{File,Directory}Monitor, GPollFileMonitor and
             ;; kqueue.  And GFam{File,Directory}Monitor and
-            ;; GPollFileMonitordo not raise a `changed' event.
+            ;; GPollFileMonitor do not raise a `changed' event.
             ((memq (file-notify--test-monitor)
                     '(GFamFileMonitor GFamDirectoryMonitor GPollFileMonitor))
              '(created deleted stopped))
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index b283a512a4..1e20317739 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -176,15 +176,14 @@ form.")
   ;; If called interactively, environment variable
   ;; $EMACS_TEST_DIRECTORY does not exist.
   (skip-unless (file-exists-p files-test-bug-18141-file))
-  (let ((tempfile (make-temp-file "files-test-bug-18141" nil ".gz")))
-    (unwind-protect
-       (progn
-         (copy-file files-test-bug-18141-file tempfile t)
-         (with-current-buffer (find-file-noselect tempfile)
-           (set-buffer-modified-p t)
-           (save-buffer)
-           (should (eq buffer-file-coding-system 'iso-2022-7bit-unix))))
-      (delete-file tempfile))))
+  (ert-with-temp-file tempfile
+    :prefix "emacs-test-files-bug-18141"
+    :suffix ".gz"
+    (copy-file files-test-bug-18141-file tempfile t)
+    (with-current-buffer (find-file-noselect tempfile)
+      (set-buffer-modified-p t)
+      (save-buffer)
+      (should (eq buffer-file-coding-system 'iso-2022-7bit-unix)))))
 
 (ert-deftest files-tests-make-temp-file-empty-prefix ()
   "Test make-temp-file with an empty prefix."
@@ -283,22 +282,20 @@ If we are in a directory named `~', the default value 
should not
 be $HOME."
   (cl-letf (((symbol-function 'completing-read)
              (lambda (_prompt _coll &optional _pred _req init _hist def _)
-               (or def init)))
-            (dir (make-temp-file "read-file-name-test" t)))
-    (unwind-protect
-        (let ((subdir (expand-file-name "./~/" dir)))
-          (make-directory subdir t)
-          (with-temp-buffer
-            (setq default-directory subdir)
-            (should-not (equal
-                         (expand-file-name (read-file-name "File: "))
-                         (expand-file-name "~/")))
-            ;; Don't overquote either!
-            (setq default-directory (concat "/:" subdir))
-            (should-not (equal
-                         (expand-file-name (read-file-name "File: "))
-                         (concat "/:/:" subdir)))))
-      (delete-directory dir 'recursive))))
+               (or def init))))
+    (ert-with-temp-directory dir
+      (let ((subdir (expand-file-name "./~/" dir)))
+        (make-directory subdir t)
+        (with-temp-buffer
+          (setq default-directory subdir)
+          (should-not (equal
+                       (expand-file-name (read-file-name "File: "))
+                       (expand-file-name "~/")))
+          ;; Don't overquote either!
+          (setq default-directory (concat "/:" subdir))
+          (should-not (equal
+                       (expand-file-name (read-file-name "File: "))
+                       (concat "/:/:" subdir))))))))
 
 (ert-deftest files-tests-file-name-non-special-quote-unquote ()
   (let (;; Just in case it is quoted, who knows.
@@ -341,14 +338,6 @@ be $HOME."
            (progn ,@body)
          (advice-remove #',symbol ,function)))))
 
-(defmacro files-tests--with-temp-file (name &rest body)
-  (declare (indent 1) (debug (symbolp body)))
-  (cl-check-type name symbol)
-  `(let ((,name (make-temp-file "emacs")))
-     (unwind-protect
-         (progn ,@body)
-       (delete-file ,name))))
-
 (ert-deftest files-tests-file-name-non-special--buffers ()
   "Check that Bug#25951 is fixed.
 We call `verify-visited-file-modtime' on a buffer visiting a file
@@ -357,7 +346,7 @@ the buffer current and a nil argument, second passing the 
buffer
 object explicitly.  In both cases no error should be raised and
 the `file-name-non-special' handler for quoted file names should
 be invoked with the right arguments."
-  (files-tests--with-temp-file temp-file-name
+  (ert-with-temp-file temp-file-name
     (with-temp-buffer
      (let* ((buffer-visiting-file (current-buffer))
             (actual-args ())
@@ -1239,26 +1228,26 @@ works as expected if the default directory is quoted."
         (insert-directory-wildcard-in-dir-p (car path-res)))))))
 
 (ert-deftest files-tests-make-directory ()
-  (let* ((dir (make-temp-file "files-mkdir-test" t))
-        (dirname (file-name-as-directory dir))
-        (file (concat dirname "file"))
-        (subdir1 (concat dirname "subdir1"))
-        (subdir2 (concat dirname "subdir2"))
-        (a/b (concat dirname "a/b")))
-    (write-region "" nil file)
-    (should-error (make-directory "/"))
-    (should-not (make-directory "/" t))
-    (should-error (make-directory dir))
-    (should-not (make-directory dir t))
-    (should-error (make-directory dirname))
-    (should-not (make-directory dirname t))
-    (should-error (make-directory file))
-    (should-error (make-directory file t))
-    (should-not (make-directory subdir1))
-    (should-not (make-directory subdir2 t))
-    (should-error (make-directory a/b))
-    (should-not (make-directory a/b t))
-    (delete-directory dir 'recursive)))
+  (ert-with-temp-directory dir
+    (let* ((dirname (file-name-as-directory dir))
+           (file (concat dirname "file"))
+           (subdir1 (concat dirname "subdir1"))
+           (subdir2 (concat dirname "subdir2"))
+           (a/b (concat dirname "a/b")))
+      (write-region "" nil file)
+      (should-error (make-directory "/"))
+      (should-not (make-directory "/" t))
+      (should-error (make-directory dir))
+      (should-not (make-directory dir t))
+      (should-error (make-directory dirname))
+      (should-not (make-directory dirname t))
+      (should-error (make-directory file))
+      (should-error (make-directory file t))
+      (should-not (make-directory subdir1))
+      (should-not (make-directory subdir2 t))
+      (should-error (make-directory a/b))
+      (should-not (make-directory a/b t))
+      (delete-directory dir 'recursive))))
 
 (ert-deftest files-tests-file-modes-symbolic-to-number ()
   (let ((alist (list (cons "a=rwx" #o777)
@@ -1318,7 +1307,7 @@ name (Bug#28412)."
       (set-buffer-modified-p t)
       (should-error (save-buffer) :type 'error))
     ;; Then a buffer visiting a file: should save normally.
-    (files-tests--with-temp-file temp-file-name
+    (ert-with-temp-file temp-file-name
       (with-current-buffer (find-file-noselect temp-file-name)
         (setq write-contents-functions nil)
         (insert "p")
@@ -1326,21 +1315,54 @@ name (Bug#28412)."
         (should (eq (buffer-size) 1))))))
 
 (ert-deftest files-tests-copy-directory ()
-  (let* ((dir (make-temp-file "files-mkdir-test" t))
-        (dirname (file-name-as-directory dir))
-        (source (concat dirname "source"))
-        (dest (concat dirname "dest/new/directory/"))
-        (file (concat (file-name-as-directory source) "file"))
-        (source2 (concat dirname "source2"))
-        (dest2 (concat dirname "dest/new2")))
-    (make-directory source)
-    (write-region "" nil file)
-    (copy-directory source dest t t t)
-    (should (file-exists-p (concat dest "file")))
-    (make-directory (concat (file-name-as-directory source2) "a") t)
-    (copy-directory source2 dest2)
-    (should (file-directory-p (concat (file-name-as-directory dest2) "a")))
-    (delete-directory dir 'recursive)))
+  (ert-with-temp-directory dir
+    (let* ((dirname (file-name-as-directory dir))
+           (source (concat dirname "source"))
+           (dest (concat dirname "dest/new/directory/"))
+           (file (concat (file-name-as-directory source) "file"))
+           (source2 (concat dirname "source2"))
+           (dest2 (concat dirname "dest/new2")))
+      (make-directory source)
+      (write-region "" nil file)
+      (copy-directory source dest t t t)
+      (should (file-exists-p (concat dest "file")))
+      (make-directory (concat (file-name-as-directory source2) "a") t)
+      (copy-directory source2 dest2)
+      (should (file-directory-p (concat (file-name-as-directory dest2) "a")))
+      (delete-directory dir 'recursive))))
+
+(ert-deftest files-tests-abbreviate-file-name-homedir ()
+  ;; Check homedir abbreviation.
+  (let* ((homedir temporary-file-directory)
+         (process-environment (cons (format "HOME=%s" homedir)
+                                    process-environment))
+         (abbreviated-home-dir nil))
+    (should (equal "~/foo/bar"
+                   (abbreviate-file-name (concat homedir "foo/bar")))))
+  ;; Check that homedir abbreviation doesn't occur when homedir is just /.
+  (let* ((homedir "/")
+         (process-environment (cons (format "HOME=%s" homedir)
+                                    process-environment))
+         (abbreviated-home-dir nil))
+    (should (equal "/foo/bar"
+                   (abbreviate-file-name (concat homedir "foo/bar"))))))
+
+(ert-deftest files-tests-abbreviate-file-name-directory-abbrev-alist ()
+    ;; Check `directory-abbrev-alist' abbreviation.
+    (let ((directory-abbrev-alist '(("\\`/nowhere/special" . "/nw/sp"))))
+      (should (equal "/nw/sp/here"
+                     (abbreviate-file-name "/nowhere/special/here"))))
+    ;; Check homedir and `directory-abbrev-alist' abbreviation.
+    (let* ((homedir temporary-file-directory)
+           (process-environment (cons (format "HOME=%s" homedir)
+                                      process-environment))
+           (abbreviated-home-dir nil)
+           (directory-abbrev-alist
+            `((,(concat "\\`" (regexp-quote homedir) "nowhere/special")
+              . ,(concat homedir "nw/sp")))))
+      (should (equal "~/nw/sp/here"
+                     (abbreviate-file-name
+                      (concat homedir "nowhere/special/here"))))))
 
 (ert-deftest files-tests-abbreviated-home-dir ()
   "Test that changing HOME does not confuse `abbreviate-file-name'.
@@ -1359,43 +1381,40 @@ See <https://debbugs.gnu.org/19657#20>."
 (ert-deftest files-tests-executable-find ()
   "Test that `executable-find' works also with a relative or remote PATH.
 See <https://debbugs.gnu.org/35241>."
-  (let ((tmpfile (make-temp-file "files-test" nil (car exec-suffixes))))
-    (unwind-protect
-        (progn
-          (set-file-modes tmpfile #o777)
-          (let ((exec-path `(,temporary-file-directory)))
-            (should
-             (equal tmpfile
-                    (executable-find (file-name-nondirectory tmpfile)))))
-          ;; An empty element of `exec-path' means `default-directory'.
-          (let ((default-directory temporary-file-directory)
-                (exec-path nil))
-            (should
-             (equal tmpfile
-                    (executable-find (file-name-nondirectory tmpfile)))))
-          ;; The remote file name shall be quoted, and handled like a
-          ;; non-existing directory.
-          (let ((default-directory "/ssh::")
-                (exec-path (append exec-path `("." 
,temporary-file-directory))))
-            (should
-             (equal tmpfile
-                    (executable-find (file-name-nondirectory tmpfile))))))
-      (delete-file tmpfile))))
+  (ert-with-temp-file tmpfile
+    :suffix (car exec-suffixes)
+    (set-file-modes tmpfile #o755)
+    (let ((exec-path `(,temporary-file-directory)))
+      (should
+       (equal tmpfile
+              (executable-find (file-name-nondirectory tmpfile)))))
+    ;; An empty element of `exec-path' means `default-directory'.
+    (let ((default-directory temporary-file-directory)
+          (exec-path nil))
+      (should
+       (equal tmpfile
+              (executable-find (file-name-nondirectory tmpfile)))))
+    ;; The remote file name shall be quoted, and handled like a
+    ;; non-existing directory.
+    (let ((default-directory "/ssh::")
+          (exec-path (append exec-path `("." ,temporary-file-directory))))
+      (should
+       (equal tmpfile
+              (executable-find (file-name-nondirectory tmpfile)))))))
 
 (ert-deftest files-tests-dont-rewrite-precious-files ()
   "Test that `file-precious-flag' forces files to be saved by
 renaming only, rather than modified in-place."
-  (let* ((temp-file-name (make-temp-file "files-tests"))
-         (advice (lambda (_start _end filename &rest _r)
-                   (should-not (string= filename temp-file-name)))))
-    (unwind-protect
-        (with-current-buffer (find-file-noselect temp-file-name)
-          (advice-add #'write-region :before advice)
-          (setq-local file-precious-flag t)
-          (insert "foobar")
-          (should (null (save-buffer))))
-      (ignore-errors (advice-remove #'write-region advice))
-      (ignore-errors (delete-file temp-file-name)))))
+  (ert-with-temp-file temp-file-name
+    (let* ((advice (lambda (_start _end filename &rest _r)
+                     (should-not (string= filename temp-file-name)))))
+      (unwind-protect
+          (with-current-buffer (find-file-noselect temp-file-name)
+            (advice-add #'write-region :before advice)
+            (setq-local file-precious-flag t)
+            (insert "foobar")
+            (should (null (save-buffer))))
+        (ignore-errors (advice-remove #'write-region advice))))))
 
 (ert-deftest files-test-file-size-human-readable ()
   (should (equal (file-size-human-readable 13) "13"))
@@ -1509,7 +1528,7 @@ The door of all subtleties!
 
 (ert-deftest files-tests-revert-buffer ()
   "Test that revert-buffer is successful."
-  (files-tests--with-temp-file temp-file-name
+  (ert-with-temp-file temp-file-name
     (with-temp-buffer
       (insert files-tests-lao)
       (write-file temp-file-name)
@@ -1522,7 +1541,7 @@ The door of all subtleties!
 
 (ert-deftest files-tests-revert-buffer-with-fine-grain ()
   "Test that revert-buffer-with-fine-grain is successful."
-  (files-tests--with-temp-file temp-file-name
+  (ert-with-temp-file temp-file-name
     (with-temp-buffer
       (insert files-tests-lao)
       (write-file temp-file-name)
@@ -1551,6 +1570,14 @@ The door of all subtleties!
   (should-error (file-name-with-extension "Jack" "."))
   (should-error (file-name-with-extension "/is/a/directory/" "css")))
 
+(ert-deftest files-tests-file-name-base ()
+  (should (equal (file-name-base "") ""))
+  (should (equal (file-name-base "/foo/") ""))
+  (should (equal (file-name-base "/foo") "foo"))
+  (should (equal (file-name-base "/foo/bar") "bar"))
+  (should (equal (file-name-base "foo") "foo"))
+  (should (equal (file-name-base "foo/bar") "bar")))
+
 (ert-deftest files-test-dir-locals-auto-mode-alist ()
   "Test an `auto-mode-alist' entry in `.dir-locals.el'"
   (find-file (ert-resource-file "whatever.quux"))
@@ -1578,40 +1605,39 @@ on BUF-1 and BUF-2 after the `save-some-buffers' call.
 The test is repeated with `save-some-buffers-default-predicate'
 let-bound to PRED and passing nil as second arg of
 `save-some-buffers'."
-  (let* ((dir (make-temp-file "testdir" 'dir))
-         (file-1 (expand-file-name "subdir-1/file.foo" dir))
-         (file-2 (expand-file-name "subdir-2/file.bar" dir))
-         (inhibit-message t)
-         buf-1 buf-2)
-    (unwind-protect
-        (progn
-          (make-empty-file file-1 'parens)
-          (make-empty-file file-2 'parens)
-          (setq buf-1 (find-file file-1)
-                buf-2 (find-file file-2))
-          (dolist (buf (list buf-1 buf-2))
-            (with-current-buffer buf (insert "foobar\n")))
-          ;; Run the test.
-          (with-current-buffer buf-1
-            (let ((save-some-buffers-default-predicate def-pred-bind))
-              (save-some-buffers t pred))
-            (should (eq exp-1 (buffer-modified-p buf-1)))
-            (should (eq exp-2 (buffer-modified-p buf-2))))
-          ;; Set both buffers as modified to run another test.
-          (dolist (buf (list buf-1 buf-2))
-            (with-current-buffer buf (set-buffer-modified-p t)))
-          ;; The result of this test must be identical as the previous one.
-          (with-current-buffer buf-1
-            (let ((save-some-buffers-default-predicate (or pred 
def-pred-bind)))
-              (save-some-buffers t nil))
-            (should (eq exp-1 (buffer-modified-p buf-1)))
-            (should (eq exp-2 (buffer-modified-p buf-2)))))
-      ;; Clean up.
-      (dolist (buf (list buf-1 buf-2))
-        (with-current-buffer buf
-          (set-buffer-modified-p nil)
-          (kill-buffer buf)))
-      (delete-directory dir 'recursive))))
+  (ert-with-temp-directory dir
+    (let* ((file-1 (expand-file-name "subdir-1/file.foo" dir))
+           (file-2 (expand-file-name "subdir-2/file.bar" dir))
+           (inhibit-message t)
+           buf-1 buf-2)
+      (unwind-protect
+          (progn
+            (make-empty-file file-1 'parens)
+            (make-empty-file file-2 'parens)
+            (setq buf-1 (find-file file-1)
+                  buf-2 (find-file file-2))
+            (dolist (buf (list buf-1 buf-2))
+              (with-current-buffer buf (insert "foobar\n")))
+            ;; Run the test.
+            (with-current-buffer buf-1
+              (let ((save-some-buffers-default-predicate def-pred-bind))
+                (save-some-buffers t pred))
+              (should (eq exp-1 (buffer-modified-p buf-1)))
+              (should (eq exp-2 (buffer-modified-p buf-2))))
+            ;; Set both buffers as modified to run another test.
+            (dolist (buf (list buf-1 buf-2))
+              (with-current-buffer buf (set-buffer-modified-p t)))
+            ;; The result of this test must be identical as the previous one.
+            (with-current-buffer buf-1
+              (let ((save-some-buffers-default-predicate (or pred 
def-pred-bind)))
+                (save-some-buffers t nil))
+              (should (eq exp-1 (buffer-modified-p buf-1)))
+              (should (eq exp-2 (buffer-modified-p buf-2)))))
+        ;; Clean up.
+        (dolist (buf (list buf-1 buf-2))
+          (with-current-buffer buf
+            (set-buffer-modified-p nil)
+            (kill-buffer buf)))))))
 
 (ert-deftest files-tests-save-some-buffers ()
   "Test `save-some-buffers'.
@@ -1774,6 +1800,12 @@ Prompt users for any modified buffer with 
`buffer-offer-save' non-nil."
          ;; `save-some-buffers-default-predicate' (i.e. the 2nd element) is 
ignored.
          (nil save-some-buffers-root ,nb-might-save))))))
 
+(defun test-file-name-split ()
+  (should (equal (file-name-split "foo/bar") '("foo" "bar")))
+  (should (equal (file-name-split "/foo/bar") '("" "foo" "bar")))
+  (should (equal (file-name-split "/foo/bar/zot") '("" "foo" "bar" "zot")))
+  (should (equal (file-name-split "/foo/bar/") '("" "foo" "bar" "")))
+  (should (equal (file-name-split "foo/bar/") '("foo" "bar" ""))))
 
 (provide 'files-tests)
 ;;; files-tests.el ends here
diff --git a/test/lisp/gnus/gnus-group-tests.el 
b/test/lisp/gnus/gnus-group-tests.el
new file mode 100644
index 0000000000..ee1e01be4b
--- /dev/null
+++ b/test/lisp/gnus/gnus-group-tests.el
@@ -0,0 +1,52 @@
+;;; gnus-group-tests.el --- Tests for gnus-group.el  -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'gnus-group)
+(require 'ert)
+
+(ert-deftest gnus-short-group-name ()
+  (map-apply
+   (lambda (input expected)
+     (should (string-equal (gnus-short-group-name input) expected)))
+   '(("nnimap+email@example.com:archives/2020/03" . "email@example:a/2/03")
+     ("nndiary+diary:birthdays" . "diary:birthdays")
+     ("nnimap+email@example.com:test" . "email@example:test")
+     ("nnimap+email@example.com:234" . "email@example:234")
+
+     ;; This is a very aggressive shortening of the left hand side.
+     ("nnimap+email@banana.salesman.example.com:234" . "email@banana:234")
+     ("nntp+some.where.edu:soc.motss" . "some:s.motss")
+     ("nntp+news.gmane.org:gmane.emacs.gnus.general" . "news:g.e.g.general";)
+     ("nntp+news.gnus.org:gmane.text.docbook.apps" . "news:g.t.d.apps";)
+
+     ;; nnimap groups.
+     ("nnimap+email@example.com:[Invoices]/Bananas" . 
"email@example:I/Bananas")
+     ("nnimap+email@banana.salesman.example.com:[Invoices]/Bananas"
+      . "email@banana:I/Bananas")
+
+     ;; The "n" from "nnspool" is perhaps not optimal.
+     ("nnspool+alt.binaries.pictures.furniture" . "n.b.p.furniture"))))
+
+;;; gnus-group-tests.el ends here
diff --git a/test/lisp/gnus/gnus-icalendar-tests.el 
b/test/lisp/gnus/gnus-icalendar-tests.el
index 90c3a34a5c..1206a976f6 100644
--- a/test/lisp/gnus/gnus-icalendar-tests.el
+++ b/test/lisp/gnus/gnus-icalendar-tests.el
@@ -216,7 +216,7 @@ RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
 DTSTAMP:20200915T120627Z
 ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
 UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
-ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
+ATTENDEE;CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED;RSVP=TRUE
  
;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
 CREATED:20200325T095723Z
 DESCRIPTION:Coffee talk
diff --git a/test/lisp/gnus/gnus-search-tests.el 
b/test/lisp/gnus/gnus-search-tests.el
index 6148da6562..9f012d4e88 100644
--- a/test/lisp/gnus/gnus-search-tests.el
+++ b/test/lisp/gnus/gnus-search-tests.el
@@ -97,4 +97,4 @@
                      "more bits"))))
 
 (provide 'gnus-search-tests)
-;;; search-tests.el ends here
+;;; gnus-search-tests.el ends here
diff --git a/test/lisp/gnus/gnus-util-tests.el 
b/test/lisp/gnus/gnus-util-tests.el
index f8d30f6373..60a9cde0e7 100644
--- a/test/lisp/gnus/gnus-util-tests.el
+++ b/test/lisp/gnus/gnus-util-tests.el
@@ -132,4 +132,4 @@
   (should (equal '("1") (gnus-setdiff '(2 "1" 2) '(2))))
   (should (equal '("1" "1") (gnus-setdiff '(2 "1" 2 "1") '(2)))))
 
-;;; gnustest-gnus-util.el ends here
+;;; gnus-util-tests.el ends here
diff --git a/test/lisp/gnus/message-tests.el b/test/lisp/gnus/message-tests.el
index b4f2b7f675..0f42f62f38 100644
--- a/test/lisp/gnus/message-tests.el
+++ b/test/lisp/gnus/message-tests.el
@@ -185,4 +185,4 @@ Hello.
 
 (provide 'message-mode-tests)
 
-;;; message-mode-tests.el ends here
+;;; message-tests.el ends here
diff --git a/test/lisp/help-fns-tests.el b/test/lisp/help-fns-tests.el
index 513a0c2dae..24a42290a3 100644
--- a/test/lisp/help-fns-tests.el
+++ b/test/lisp/help-fns-tests.el
@@ -148,7 +148,7 @@ Return first line of the output of (describe-function-1 
FUNC)."
 (ert-deftest help-fns-test-describe-keymap/value ()
   (describe-keymap minibuffer-local-must-match-map)
   (with-current-buffer "*Help*"
-    (should (looking-at "^key"))))
+    (should (looking-at "\nKey"))))
 
 (ert-deftest help-fns-test-describe-keymap/not-keymap ()
   (should-error (describe-keymap nil))
@@ -158,7 +158,7 @@ Return first line of the output of (describe-function-1 
FUNC)."
   (let ((foobar minibuffer-local-must-match-map))
     (describe-keymap foobar)
     (with-current-buffer "*Help*"
-      (should (looking-at "^key")))))
+      (should (looking-at "\nKey")))))
 
 (ert-deftest help-fns-test-describe-keymap/dynamically-bound-no-file ()
   (setq help-fns-test--describe-keymap-foo minibuffer-local-must-match-map)
diff --git a/test/lisp/help-tests.el b/test/lisp/help-tests.el
index 871417da3d..a331ec440a 100644
--- a/test/lisp/help-tests.el
+++ b/test/lisp/help-tests.el
@@ -65,7 +65,7 @@
                                 result))))
               (test-re
                (lambda (orig regexp)
-                 (should (string-match (concat "^" regexp "$")
+                 (should (string-match (concat "\\`" regexp "\\'")
                                        (substitute-command-keys orig))))))
      ,@body))
 
@@ -90,18 +90,16 @@
 
 (ert-deftest help-tests-substitute-command-keys/keymaps ()
   (with-substitute-command-keys-test
-   (test "\\{minibuffer-local-must-match-map}"
-         "\
-key             binding
----             -------
-
+   (test-re "\\{minibuffer-local-must-match-map}"
+         "
+Key             Binding
+-+
 C-g            abort-minibuffers
 TAB            minibuffer-complete
 C-j            minibuffer-complete-and-exit
 RET            minibuffer-complete-and-exit
-ESC            Prefix Command
 SPC            minibuffer-complete-word
-?              minibuffer-completion-help
+\\?            minibuffer-completion-help
 C-<tab>                file-cache-minibuffer-complete
 <XF86Back>     previous-history-element
 <XF86Forward>  next-history-element
@@ -110,11 +108,8 @@ C-<tab>            file-cache-minibuffer-complete
 <prior>                switch-to-completions
 <up>           previous-line-or-history-element
 
-M-g            Prefix Command
 M-v            switch-to-completions
 
-M-g ESC                Prefix Command
-
 M-<            minibuffer-beginning-of-buffer
 M-n            next-history-element
 M-p            previous-history-element
@@ -122,7 +117,6 @@ M-r         previous-matching-history-element
 M-s            next-matching-history-element
 
 M-g M-c                switch-to-completions
-
 ")))
 
 (ert-deftest help-tests-substitute-command-keys/keymap-change ()
@@ -249,11 +243,10 @@ M-g M-c           switch-to-completions
   (with-substitute-command-keys-test
    (with-temp-buffer
      (help-tests-major-mode)
-     (test "\\{help-tests-major-mode-map}"
-           "\
-key             binding
----             -------
-
+     (test-re "\\{help-tests-major-mode-map}"
+           "
+Key             Binding
+-+
 ( .. )         short-range
 1 .. 4         foo-range
 a .. c         foo-other-range
@@ -261,7 +254,6 @@ a .. c              foo-other-range
 C-e            foo-something
 x              foo-original
 <F1>           foo-function-key1
-
 "))))
 
 (ert-deftest help-tests-substitute-command-keys/shadow ()
@@ -269,11 +261,10 @@ x         foo-original
    (with-temp-buffer
      (help-tests-major-mode)
      (help-tests-minor-mode)
-     (test "\\{help-tests-major-mode-map}"
-           "\
-key             binding
----             -------
-
+     (test-re "\\{help-tests-major-mode-map}"
+           "
+Key             Binding
+-+
 ( .. )         short-range
 1 .. 4         foo-range
 a .. c         foo-other-range
@@ -283,7 +274,6 @@ C-e         foo-something
 x              foo-original
   (this binding is currently shadowed)
 <F1>           foo-function-key1
-
 "))))
 
 (ert-deftest help-tests-substitute-command-keys/command-remap ()
@@ -292,15 +282,11 @@ x         foo-original
     (with-temp-buffer
       (help-tests-major-mode)
       (define-key help-tests-major-mode-map [remap foo] 'bar)
-      (test "\\{help-tests-major-mode-map}"
-            "\
-key             binding
----             -------
-
-<remap>                Prefix Command
-
+      (test-re "\\{help-tests-major-mode-map}"
+            "
+Key             Binding
+-+
 <remap> <foo>  bar
-
 ")))))
 
 (ert-deftest help-tests-describe-map-tree/no-menu-t ()
@@ -312,12 +298,11 @@ key             binding
                                           :enable mark-active
                                           :help "Help text"))))))
       (describe-map-tree map nil nil nil nil t nil nil nil)
-      (should (equal (buffer-string) "key             binding
----             -------
-
-C-a            foo
-
-")))))
+      (should (string-match "
+Key             Binding
+-+
+C-a            foo\n"
+                            (buffer-string))))))
 
 (ert-deftest help-tests-describe-map-tree/no-menu-nil ()
   (with-temp-buffer
@@ -328,15 +313,13 @@ C-a               foo
                                           :enable mark-active
                                           :help "Help text"))))))
       (describe-map-tree map nil nil nil nil nil nil nil nil)
-      (should (equal (buffer-string) "key             binding
----             -------
-
+      (should (string-match "
+Key             Binding
+-+
 C-a            foo
-<menu-bar>     Prefix Command
 
-<menu-bar> <foo>               foo
-
-")))))
+<menu-bar> <foo>       foo\n"
+                            (buffer-string))))))
 
 (ert-deftest help-tests-describe-map-tree/mention-shadow-t ()
   (with-temp-buffer
@@ -345,14 +328,13 @@ C-a               foo
                            (2 . bar))))
           (shadow-maps '((keymap . ((1 . baz))))))
       (describe-map-tree map t shadow-maps nil nil t nil nil t)
-      (should (equal (buffer-string) "key             binding
----             -------
-
+      (should (string-match "
+Key             Binding
+-+
 C-a            foo
   (this binding is currently shadowed)
-C-b            bar
-
-")))))
+C-b            bar\n"
+                            (buffer-string))))))
 
 (ert-deftest help-tests-describe-map-tree/mention-shadow-nil ()
   (with-temp-buffer
@@ -361,12 +343,11 @@ C-b               bar
                            (2 . bar))))
           (shadow-maps '((keymap . ((1 . baz))))))
       (describe-map-tree map t shadow-maps nil nil t nil nil nil)
-      (should (equal (buffer-string) "key             binding
----             -------
-
-C-b            bar
-
-")))))
+      (should (string-match "
+Key             Binding
+-+
+C-b            bar\n"
+                            (buffer-string))))))
 
 (ert-deftest help-tests-describe-map-tree/partial-t ()
   (with-temp-buffer
@@ -374,12 +355,11 @@ C-b               bar
           (map '(keymap . ((1 . foo)
                            (2 . undefined)))))
       (describe-map-tree map t nil nil nil nil nil nil nil)
-      (should (equal (buffer-string) "key             binding
----             -------
-
-C-a            foo
-
-")))))
+      (should (string-match "
+Key             Binding
+-+
+C-a            foo\n"
+                            (buffer-string))))))
 
 (ert-deftest help-tests-describe-map-tree/partial-nil ()
   (with-temp-buffer
@@ -387,13 +367,12 @@ C-a               foo
           (map '(keymap . ((1 . foo)
                            (2 . undefined)))))
       (describe-map-tree map nil nil nil nil nil nil nil nil)
-      (should (equal (buffer-string) "key             binding
----             -------
-
+      (should (string-match "
+Key             Binding
+-+
 C-a            foo
-C-b            undefined
-
-")))))
+C-b            undefined\n"
+                            (buffer-string))))))
 
 (defvar help-tests--was-in-buffer nil)
 
diff --git a/test/lisp/hi-lock-tests.el b/test/lisp/hi-lock-tests.el
index 199512fe7d..200caa7e1a 100644
--- a/test/lisp/hi-lock-tests.el
+++ b/test/lisp/hi-lock-tests.el
@@ -31,7 +31,8 @@
     (with-temp-buffer
       (insert "a A b B\n")
       (cl-letf (((symbol-function 'completing-read)
-                   (lambda (_prompt _coll _x _y _z _hist defaults)
+                   (lambda (_prompt _coll
+                                    &optional _x _y _z _hist defaults _inherit)
                      (car defaults))))
         (dotimes (_ 2)
           (let ((face (hi-lock-read-face-name)))
@@ -43,7 +44,8 @@
     (with-temp-buffer
       (insert "foo bar")
       (cl-letf (((symbol-function 'completing-read)
-                 (lambda (_prompt _coll _x _y _z _hist defaults)
+                 (lambda (_prompt _coll
+                                  &optional _x _y _z _hist defaults _inherit)
                    (car defaults))))
         (hi-lock-set-pattern "9999" (hi-lock-read-face-name)) ; No match
         (hi-lock-set-pattern "foo" (hi-lock-read-face-name)))
@@ -89,7 +91,8 @@
       (let ((search-spaces-regexp search-whitespace-regexp)) (highlight-regexp 
"a   a"))
       (should (= (length (overlays-in (point-min) (point-max))) 1))
       (cl-letf (((symbol-function 'completing-read)
-                 (lambda (_prompt _coll _x _y _z _hist defaults)
+                 (lambda (_prompt _coll
+                                  &optional _x _y _z _hist defaults _inherit)
                    (car defaults))))
         (call-interactively 'unhighlight-regexp))
       (should (= (length (overlays-in (point-min) (point-max))) 0))
@@ -142,7 +145,8 @@
       (font-lock-ensure)
       (should (memq 'hi-yellow (get-text-property 1 'face)))
       (cl-letf (((symbol-function 'completing-read)
-                 (lambda (_prompt _coll _x _y _z _hist defaults)
+                 (lambda (_prompt _coll
+                                  &optional _x _y _z _hist defaults _inherit)
                    (car defaults)))
                 (font-lock-fontified t))
         (call-interactively 'unhighlight-regexp))
@@ -155,7 +159,8 @@
       (insert "aAbB\n")
 
       (cl-letf (((symbol-function 'completing-read)
-                 (lambda (_prompt _coll _x _y _z _hist defaults)
+                 (lambda (_prompt _coll
+                                  &optional _x _y _z _hist defaults _inherit)
                    (car defaults))))
 
         (highlight-regexp "a")
diff --git a/test/lisp/htmlfontify-tests.el b/test/lisp/htmlfontify-tests.el
index 879131cae3..15798319a1 100644
--- a/test/lisp/htmlfontify-tests.el
+++ b/test/lisp/htmlfontify-tests.el
@@ -43,4 +43,4 @@ available (Bug#25468)."
                  0)))
 
 (provide 'htmlfontify-tests)
-;; htmlfontify-tests.el ends here
+;;; htmlfontify-tests.el ends here
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el
index a51079180a..9b0327b0ef 100644
--- a/test/lisp/ibuffer-tests.el
+++ b/test/lisp/ibuffer-tests.el
@@ -826,4 +826,4 @@
   (should (equal (ibuffer-unary-operand '(not . a)) 'a)))
 
 (provide 'ibuffer-tests)
-;; ibuffer-tests.el ends here
+;;; ibuffer-tests.el ends here
diff --git a/test/lisp/newcomment-tests.el b/test/lisp/image-dired-tests.el
similarity index 55%
copy from test/lisp/newcomment-tests.el
copy to test/lisp/image-dired-tests.el
index 5485673b72..3f0304ee40 100644
--- a/test/lisp/newcomment-tests.el
+++ b/test/lisp/image-dired-tests.el
@@ -1,4 +1,4 @@
-;;; newcomment-tests.el  -*- lexical-binding:t -*-
+;;; image-dired-tests.el --- Tests for image-dired.el  -*- lexical-binding: t 
-*-
 
 ;; Copyright (C) 2021 Free Software Foundation, Inc.
 
@@ -17,23 +17,21 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;;; Commentary:
-
 ;;; Code:
 
 (require 'ert)
+(require 'image-dired)
+
+(defun image-dired-test-image-file (name)
+  (expand-file-name
+   name (expand-file-name "data/image"
+                          (or (getenv "EMACS_TEST_DIRECTORY")
+                              "../"))))
+
+(ert-deftest image-dired-tests-get-exif-file-name ()
+  (skip-unless (image-type-available-p 'jpeg))
+  (let ((img (image-dired-test-image-file "black.jpg")))
+    (should (equal (image-dired-get-exif-file-name img)
+                   "2019_09_21_16_22_13_black.jpg"))))
 
-(ert-deftest test-uncomment-space-comment-continue ()
-  (let ((comment-style 'multi-line)
-        (comment-continue "   ")
-        (text "  a\n  b"))
-    (should
-     (equal text
-            (with-temp-buffer
-              (c-mode)
-              (insert text)
-              (comment-region (point-min) (point-max))
-              (uncomment-region (point-min) (point-max))
-              (buffer-string))))))
-
-;;; newcomment-testsuite.el ends here
+;;; image-dired-tests.el ends here
diff --git a/test/lisp/image-tests.el b/test/lisp/image-tests.el
index aa8600609c..79b0014f60 100644
--- a/test/lisp/image-tests.el
+++ b/test/lisp/image-tests.el
@@ -28,6 +28,27 @@
   (expand-file-name "images" data-directory)
   "Directory containing Emacs images.")
 
+(defconst image-tests--files
+  `((gif . ,(expand-file-name "test/data/image/black.gif"
+                               source-directory))
+    (jpeg . ,(expand-file-name "test/data/image/black.jpg"
+                               source-directory))
+    (pbm . ,(expand-file-name "splash.pbm"
+                              image-tests--emacs-images-directory))
+    (png . ,(expand-file-name "splash.png"
+                              image-tests--emacs-images-directory))
+    (svg . ,(expand-file-name "splash.svg"
+                              image-tests--emacs-images-directory))
+    (tiff . ,(expand-file-name
+              "nextstep/GNUstep/Emacs.base/Resources/emacs.tiff"
+              source-directory))
+    (webp . ,(expand-file-name "test/data/image/black.webp"
+                               source-directory))
+    (xbm . ,(expand-file-name "gnus/gnus.xbm"
+                              image-tests--emacs-images-directory))
+    (xpm . ,(expand-file-name "splash.xpm"
+                              image-tests--emacs-images-directory))))
+
 (ert-deftest image--set-property ()
   "Test `image--set-property' behavior."
   (let ((image (list 'image)))
@@ -49,12 +70,14 @@
     (should (equal image '(image)))))
 
 (ert-deftest image-find-image ()
-  (find-image '((:type xpm :file "undo.xpm")))
-  (find-image '((:type png :file "newsticker/rss-feed.png" :ascent center))))
+  (should (listp (find-image '((:type xpm :file "undo.xpm")))))
+  (should (listp (find-image '((:type png :file "newsticker/rss-feed.png" 
:ascent center)))))
+  (should-not (find-image '((:type png :file "does-not-exist-foo-bar.png")))))
 
 (ert-deftest image-type-from-file-name ()
   (should (eq (image-type-from-file-name "foo.jpg") 'jpeg))
-  (should (eq (image-type-from-file-name "foo.png") 'png)))
+  (should (eq (image-type-from-file-name "foo.png") 'png))
+  (should (eq (image-type-from-file-name "foo.webp") 'webp)))
 
 (ert-deftest image-type/from-filename ()
   ;; On emba, `image-types' and `image-load-path' do not exist.
@@ -62,12 +85,37 @@
                     (bound-and-true-p image-load-path)))
   (should (eq (image-type "foo.jpg") 'jpeg)))
 
-(ert-deftest image-type-from-file-header-test ()
+(defun image-tests--type-from-file-header (type)
   "Test image-type-from-file-header."
-  (should (eq (if (image-type-available-p 'svg) 'svg)
-             (image-type-from-file-header
-              (expand-file-name "splash.svg"
-                                image-tests--emacs-images-directory)))))
+  (should (eq (if (image-type-available-p type) type)
+              (image-type-from-file-header (cdr (assq type 
image-tests--files))))))
+
+(ert-deftest image-type-from-file-header-test/gif ()
+  (image-tests--type-from-file-header 'gif))
+
+(ert-deftest image-type-from-file-header-test/jpeg ()
+  (image-tests--type-from-file-header 'jpeg))
+
+(ert-deftest image-type-from-file-header-test/pbm ()
+  (image-tests--type-from-file-header 'pbm))
+
+(ert-deftest image-type-from-file-header-test/png ()
+  (image-tests--type-from-file-header 'png))
+
+(ert-deftest image-type-from-file-header-test/svg ()
+  (image-tests--type-from-file-header 'svg))
+
+(ert-deftest image-type-from-file-header-test/tiff ()
+  (image-tests--type-from-file-header 'tiff))
+
+(ert-deftest image-type-from-file-header-test/webp ()
+  (image-tests--type-from-file-header 'webp))
+
+(ert-deftest image-type-from-file-header-test/xbm ()
+  (image-tests--type-from-file-header 'xbm))
+
+(ert-deftest image-type-from-file-header-test/xpm ()
+  (image-tests--type-from-file-header 'xpm))
 
 (ert-deftest image-rotate ()
   "Test `image-rotate'."
diff --git a/test/lisp/image/exif-tests.el b/test/lisp/image/exif-tests.el
index ddbee75467..2357113f63 100644
--- a/test/lisp/image/exif-tests.el
+++ b/test/lisp/image/exif-tests.el
@@ -28,24 +28,19 @@
                           (or (getenv "EMACS_TEST_DIRECTORY")
                               "../../"))))
 
-(defun exif-elem (exif elem)
-  (plist-get (seq-find (lambda (e)
-                         (eq elem (plist-get e :tag-name)))
-                       exif)
-             :value))
-
 (ert-deftest test-exif-parse ()
   (let ((exif (exif-parse-file (test-image-file "black.jpg"))))
-    (should (equal (exif-elem exif 'make) "Panasonic"))
-    (should (equal (exif-elem exif 'orientation) 1))
-    (should (equal (exif-elem exif 'x-resolution) '(180 . 1)))))
+    (should (equal (exif-field 'make exif) "Panasonic"))
+    (should (equal (exif-field 'orientation exif) 1))
+    (should (equal (exif-field 'x-resolution exif) '(180 . 1)))
+    (should (equal (exif-field 'date-time exif) "2019:09:21 16:22:13"))))
 
 (ert-deftest test-exif-parse-short ()
   (let ((exif (exif-parse-file (test-image-file "black-short.jpg"))))
-    (should (equal (exif-elem exif 'make) "thr"))
-    (should (equal (exif-elem exif 'model) "four"))
-    (should (equal (exif-elem exif 'software) "em"))
-    (should (equal (exif-elem exif 'artist) "z"))))
+    (should (equal (exif-field 'make exif) "thr"))
+    (should (equal (exif-field 'model exif) "four"))
+    (should (equal (exif-field 'software exif) "em"))
+    (should (equal (exif-field 'artist exif) "z"))))
 
 (ert-deftest test-exit-direct-ascii-value ()
   (should (equal (exif--direct-ascii-value 28005 2 t) (string ?e ?m 0)))
diff --git a/test/lisp/info-xref-tests.el b/test/lisp/info-xref-tests.el
index ecba86146f..9379a53fe1 100644
--- a/test/lisp/info-xref-tests.el
+++ b/test/lisp/info-xref-tests.el
@@ -22,6 +22,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'info-xref)
 
 (defun info-xref-test-internal (body result)
@@ -96,15 +97,17 @@ text.
 (ert-deftest info-xref-test-makeinfo ()
   "Test that info-xref can parse basic makeinfo output."
   (skip-unless (executable-find "makeinfo"))
-  (let ((tempfile (make-temp-file "info-xref-test" nil ".texi"))
-        (tempfile2 (make-temp-file "info-xref-test2" nil ".texi"))
-        (errflag t))
-    (unwind-protect
-        (progn
-          ;; tempfile contains xrefs to various things, including tempfile2.
-          (info-xref-test-write-file
-           tempfile
-           (concat "\
+  (ert-with-temp-file tempfile
+    :suffix ".texi"
+    (ert-with-temp-file tempfile2
+      :suffix ".texi"
+      (let ((errflag t))
+        (unwind-protect
+            (progn
+              ;; tempfile contains xrefs to various things, including 
tempfile2.
+              (info-xref-test-write-file
+               tempfile
+               (concat "\
 @xref{nodename,,,missing,Missing Manual}.
 
 @xref{nodename,crossref,title,missing,Missing Manual}.
@@ -114,35 +117,36 @@ text.
 @xref{Chapter One,Something}.
 
 "
-                   (format "@xref{Chapter One,,,%s,Present Manual}.\n"
-                           (file-name-sans-extension (file-name-nondirectory
-                                                      tempfile2)))))
-          ;; Something for tempfile to xref to.
-          (info-xref-test-write-file tempfile2 "")
-          (require 'info)
-          (save-window-excursion
-            (let ((Info-directory-list
-                   (list
-                    (or (file-name-directory tempfile) ".")))
-                  Info-additional-directory-list)
-              (info-xref-check (format "%s.info" (file-name-sans-extension
-                                                  tempfile))))
-            (should (equal (list info-xref-bad info-xref-good
-                                 info-xref-unavail)
-                           '(0 1 2)))
-            (setq errflag nil)
-            ;; If there was an error, we can leave this around.
-            (kill-buffer info-xref-output-buffer)))
-      ;; Useful diagnostic in case of problems.
-      (if errflag
-          (with-temp-buffer
-            (call-process "makeinfo" nil t nil "--version")
-            (message "%s" (buffer-string))))
-      (mapc 'delete-file (list tempfile tempfile2
-                               (format "%s.info" (file-name-sans-extension
-                                                  tempfile))
-                               (format "%s.info" (file-name-sans-extension
-                                                  tempfile2)))))))
+                       (format "@xref{Chapter One,,,%s,Present Manual}.\n"
+                               (file-name-sans-extension 
(file-name-nondirectory
+                                                          tempfile2)))))
+              ;; Something for tempfile to xref to.
+              (info-xref-test-write-file tempfile2 "")
+              (require 'info)
+              (save-window-excursion
+                (let ((Info-directory-list
+                       (list
+                        (or (file-name-directory tempfile) ".")))
+                      Info-additional-directory-list)
+                  (info-xref-check (format "%s.info" (file-name-sans-extension
+                                             tempfile))))
+                (should (equal (list info-xref-bad info-xref-good
+                                     info-xref-unavail)
+                               '(0 1 2)))
+                (setq errflag nil)
+                ;; If there was an error, we can leave this around.
+                (kill-buffer info-xref-output-buffer)))
+          ;; Useful diagnostic in case of problems.
+          (if errflag
+              (with-temp-buffer
+                (call-process "makeinfo" nil t nil "--version")
+                (message "%s" (buffer-string))))
+          (ignore-errors
+            (delete-file (format "%s.info" (file-name-sans-extension
+                                            tempfile))))
+          (ignore-errors
+            (delete-file (format "%s.info" (file-name-sans-extension
+                                            tempfile2)))))))))
 
 (ert-deftest info-xref-test-emacs-manuals ()
   "Test that all internal links in the Emacs manuals work."
@@ -161,4 +165,4 @@ text.
                                                (line-end-position)))))))
 
 
-;;; info-xref.el ends here
+;;; info-xref-tests.el ends here
diff --git a/test/lisp/international/ccl-tests.el 
b/test/lisp/international/ccl-tests.el
index 0f765e4ff8..f3da2d8873 100644
--- a/test/lisp/international/ccl-tests.el
+++ b/test/lisp/international/ccl-tests.el
@@ -246,3 +246,5 @@ At EOF:
            (registers [17 0 0 0 0 0 0 0]))
       (ccl-execute compiled registers)
       (should (equal registers [2 16 0 0 0 0 0 1])))))
+
+;;; ccl-tests.el ends here
diff --git a/test/lisp/international/mule-tests.el 
b/test/lisp/international/mule-tests.el
index 7727c118b2..8ca1ade771 100644
--- a/test/lisp/international/mule-tests.el
+++ b/test/lisp/international/mule-tests.el
@@ -23,7 +23,7 @@
 
 ;;; Code:
 
-(require 'ert-x)                        ;For `ert-run-keys'.
+(require 'ert-x)                        ;For `ert-simulate-keys'.
 
 (ert-deftest find-auto-coding--bug27391 ()
   "Check that Bug#27391 is fixed."
diff --git a/test/lisp/international/ucs-normalize-tests.el 
b/test/lisp/international/ucs-normalize-tests.el
index 52c3d3704e..eb577b97dc 100644
--- a/test/lisp/international/ucs-normalize-tests.el
+++ b/test/lisp/international/ucs-normalize-tests.el
@@ -123,9 +123,9 @@ The following invariants must be true for all conformant 
implementations..."
 
 (defsubst ucs-normalize-tests--rule2-holds-p (X)
  "Check 2nd conformance rule.
-For every code point X assigned in this version of Unicode that is not 
specifically
-listed in Part 1, the following invariants must be true for all conformant
-implementations:
+For every code point X assigned in this version of Unicode that
+is not specifically listed in Part 1, the following invariants
+must be true for all conformant implementations:
 
   X == toNFC(X) == toNFD(X) == toNFKC(X) == toNFKD(X)"
  (and (ucs-normalize-tests--normalization-chareq-p NFC X X)
diff --git a/test/lisp/jit-lock-tests.el b/test/lisp/jit-lock-tests.el
index 121966b2b7..a54aad8165 100644
--- a/test/lisp/jit-lock-tests.el
+++ b/test/lisp/jit-lock-tests.el
@@ -58,3 +58,5 @@
     (with-silent-modifications
       (put-text-property (point-min) (point-max) 'fontified t))
     (jit-lock-fontify-now (point-min) (point-max))))
+
+;;; jit-lock-tests.el ends here
diff --git a/test/lisp/kmacro-tests.el b/test/lisp/kmacro-tests.el
index 8736f7fd2d..ecd3d5fc22 100644
--- a/test/lisp/kmacro-tests.el
+++ b/test/lisp/kmacro-tests.el
@@ -834,7 +834,7 @@ and `read-event' and `read-key-sequence' set up to return 
items from
 EVENTS and SEQUENCES respectively.  SEQUENCES may be nil, but
 EVENTS should not be.  EVENTS should be a list of symbols bound
 in `kmacro-step-edit-map' or `query-replace' map, and this function
-will do the keymap lookup for you. SEQUENCES should contain
+will do the keymap lookup for you.  SEQUENCES should contain
 return values for `read-key-sequence'.
 
 Before running the macro, the current buffer will be erased.
diff --git a/test/lisp/ls-lisp-tests.el b/test/lisp/ls-lisp-tests.el
index e386398eea..e3a75bed41 100644
--- a/test/lisp/ls-lisp-tests.el
+++ b/test/lisp/ls-lisp-tests.el
@@ -25,6 +25,7 @@
 
 ;;; Code:
 (require 'ert)
+(require 'ert-x)
 (require 'ls-lisp)
 (require 'dired)
 
@@ -59,22 +60,22 @@
 
 (ert-deftest ls-lisp-test-bug27631 ()
   "Test for https://debbugs.gnu.org/27631 ."
-  (let* ((dir (make-temp-file "bug27631" 'dir))
-         (dir1 (expand-file-name "dir1" dir))
-         (dir2 (expand-file-name "dir2" dir))
-         (default-directory dir)
-         ls-lisp-use-insert-directory-program buf)
-    (unwind-protect
-        (progn
-          (make-directory dir1)
-          (make-directory dir2)
-          (with-temp-file (expand-file-name "a.txt" dir1))
-          (with-temp-file (expand-file-name "b.txt" dir2))
-          (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
-          (dired-toggle-marks)
-          (should (cdr (dired-get-marked-files))))
-      (delete-directory dir 'recursive)
-      (when (buffer-live-p buf) (kill-buffer buf)))))
+  (ert-with-temp-directory dir
+    :suffix "bug27631"
+    (let* ((dir1 (expand-file-name "dir1" dir))
+           (dir2 (expand-file-name "dir2" dir))
+           (default-directory dir)
+           ls-lisp-use-insert-directory-program buf)
+      (unwind-protect
+          (progn
+            (make-directory dir1)
+            (make-directory dir2)
+            (with-temp-file (expand-file-name "a.txt" dir1))
+            (with-temp-file (expand-file-name "b.txt" dir2))
+            (setq buf (dired (expand-file-name "dir*/*.txt" dir)))
+            (dired-toggle-marks)
+            (should (cdr (dired-get-marked-files))))
+        (when (buffer-live-p buf) (kill-buffer buf))))))
 
 (ert-deftest ls-lisp-test-bug27693 ()
   "Test for https://debbugs.gnu.org/27693 ."
diff --git a/test/lisp/mail/rmail-tests.el b/test/lisp/mail/rmail-tests.el
index f533401496..826a90455f 100644
--- a/test/lisp/mail/rmail-tests.el
+++ b/test/lisp/mail/rmail-tests.el
@@ -32,4 +32,4 @@
      'rmail-edit-current-message))))
 
 (provide 'rmail-tests)
-;; rmail-tests.el ends here
+;;; rmail-tests.el ends here
diff --git a/test/lisp/mail/rmailmm-tests.el b/test/lisp/mail/rmailmm-tests.el
index a022008b53..d7b3775d6d 100644
--- a/test/lisp/mail/rmailmm-tests.el
+++ b/test/lisp/mail/rmailmm-tests.el
@@ -114,4 +114,4 @@ This is the epilogue.  It is also to be ignored."))
 
 (provide 'rmailmm-tests)
 
-;; rmailmm-tests.el ends here
+;;; rmailmm-tests.el ends here
diff --git a/test/lisp/mail/uudecode-tests.el b/test/lisp/mail/uudecode-tests.el
index 6ff767562e..1899ff50f6 100644
--- a/test/lisp/mail/uudecode-tests.el
+++ b/test/lisp/mail/uudecode-tests.el
@@ -35,11 +35,11 @@
 
 (defvar uudecode-tests-encoded-str
   (uudecode-tests-read-file (ert-resource-file "uuencoded.txt"))
-  "Uuencoded data for bookmark-tests.el
+  "Uuencoded data for bookmark-tests.el.
 Same as `uudecode-tests-decoded-str' but uuencoded.")
 (defvar uudecode-tests-decoded-str
   (uudecode-tests-read-file (ert-resource-file "uudecoded.txt"))
-  "Plain text data for bookmark-tests.el
+  "Plain text data for bookmark-tests.el.
 Same as `uudecode-tests-encoded-str' but plain text.")
 
 (ert-deftest uudecode-tests-decode-region-internal ()
@@ -50,14 +50,11 @@ Same as `uudecode-tests-encoded-str' but plain text.")
     (should (equal (buffer-string) uudecode-tests-decoded-str)))
   ;; Write to file
   (with-temp-buffer
-    (let ((tmpfile (make-temp-file "uudecode-tests-")))
-      (unwind-protect
-          (progn
-            (insert uudecode-tests-encoded-str)
-            (uudecode-decode-region-internal (point-min) (point-max) tmpfile)
-            (should (equal (uudecode-tests-read-file tmpfile)
-                           uudecode-tests-decoded-str)))
-        (delete-file tmpfile)))))
+    (ert-with-temp-file tmpfile
+      (insert uudecode-tests-encoded-str)
+      (uudecode-decode-region-internal (point-min) (point-max) tmpfile)
+      (should (equal (uudecode-tests-read-file tmpfile)
+                     uudecode-tests-decoded-str)))))
 
 (ert-deftest uudecode-tests-decode-region-external ()
   ;; Write to buffer
@@ -68,14 +65,11 @@ Same as `uudecode-tests-encoded-str' but plain text.")
       (should (equal (buffer-string) uudecode-tests-decoded-str)))
     ;; Write to file
     (with-temp-buffer
-      (let ((tmpfile (make-temp-file "uudecode-tests-")))
-        (unwind-protect
-            (progn
-              (insert uudecode-tests-encoded-str)
-              (uudecode-decode-region-external (point-min) (point-max) tmpfile)
-              (should (equal (uudecode-tests-read-file tmpfile)
-                             uudecode-tests-decoded-str)))
-          (delete-file tmpfile))))))
+      (ert-with-temp-file tmpfile
+        (insert uudecode-tests-encoded-str)
+        (uudecode-decode-region-external (point-min) (point-max) tmpfile)
+        (should (equal (uudecode-tests-read-file tmpfile)
+                       uudecode-tests-decoded-str))))))
 
 (provide 'uudecode-tests)
 ;;; uudecode-tests.el ends here
diff --git a/test/lisp/mh-e/mh-utils-tests.el b/test/lisp/mh-e/mh-utils-tests.el
index 68152ce3b6..ed979232a4 100644
--- a/test/lisp/mh-e/mh-utils-tests.el
+++ b/test/lisp/mh-e/mh-utils-tests.el
@@ -17,6 +17,34 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Commentary:
+
+;; This test suite runs tests that use and depend on MH programs
+;; installed on the system.
+
+;; When running such tests, MH-E can use a particular MH variant
+;; installed on the system, or it can use the mocks provided here.
+;; (Setup is done by the `with-mh-test-env' macro.)
+
+;; By setting environment variable TEST_MH_PATH, you can select which of
+;; the installed MH variants to use, or ignore them all and use mocks.
+;; See also the script test-all-mh-variants.sh in this directory.
+
+;; 1.  To run these tests against the default MH variant installed on
+;;     this system:
+;; cd ../.. && make lisp/mh-e/mh-utils-tests
+
+;; 2.  To run these tests against an MH variant installed in a
+;;     specific directory, set TEST_MH_PATH, as in this example:
+;; cd ../.. && make lisp/mh-e/mh-utils-tests TEST_MH_PATH=/usr/local/nmh/bin
+
+;; 3.  To search for and run these tests against all MH variants
+;;     installed on this system:
+;; ./test-all-mh-variants.sh
+
+;; Setting the environment variable TEST_MH_DEBUG or the Lisp variable
+;; mh-test-utils-debug-mocks logs access to the file system during the test.
+
 ;;; Code:
 
 (require 'ert)
@@ -56,35 +84,33 @@
 ;; Folder names that are used by the following tests.
 (defvar mh-test-rel-folder "rela-folder")
 (defvar mh-test-abs-folder "/abso-folder")
-(defvar mh-test-no-such-folder "/testdir/none"
-  "Name of a folder that the user does not have.")
+(defvar mh-test-no-such-folder "/testdir/none" "A folder that does not exist.")
+
+(defvar mh-test-utils-variants nil
+  "The value of `mh-variants' used for these tests.
+This variable allows setting `mh-variants' to a limited set for targeted
+testing.  Its value can be different from the normal value when
+environment variable TEST_MH_PATH is set.  By remembering the value, we
+can log the choice only once, which makes the batch log easier to read.")
 
 (defvar mh-test-variant-logged-already nil
   "Whether `with-mh-test-env' has written the MH variant to the log.")
-(setq mh-test-variant-logged-already nil) ;reset if buffer is re-evaluated
 
-(defvar mh-test-utils-debug-mocks nil
+(defvar mh-test-utils-debug-mocks (> (length (getenv "TEST_MH_DEBUG")) 0)
   "Whether to log detailed behavior of mock functions.")
 
 (defvar mh-test-call-process-real (symbol-function 'call-process))
 (defvar mh-test-file-directory-p-real (symbol-function 'file-directory-p))
 
-
-;;; This macro wraps tests that touch the file system and/or run programs.
-;;; When running such tests, MH-E can use a particular MH variant
-;;; installed on the system, or it can use the mocks provided below.
-
-;;; By setting PATH and mh-sys-path, you can select which of the
-;;; installed MH variants to use or ignore them all and use mocks.
+;;; The macro with-mh-test-env wraps tests that touch the file system
+;;; and/or run programs.
 
 (defmacro with-mh-test-env (&rest body)
   "Evaluate BODY with a test mail environment.
 Functions that touch the file system or run MH programs are either
-mocked out or pointed at a test tree.  When called from Emacs's batch
-testing infrastructure, this will use mocks and thus run on systems
-that do not have any MH variant installed.  MH-E developers can
-install an MH variant and test it interactively."
-  (declare (indent defun))
+mocked out or pointed at a test tree.  Uses `mh-test-utils-setup' to
+select which."
+  (declare (indent 0) (debug t))
   `(cl-letf ((temp-home-dir nil)
              ;; make local bindings for things we will modify for test env
              (mh-user-path)
@@ -93,20 +119,61 @@ install an MH variant and test it interactively."
              ((symbol-function 'file-directory-p))
              ;; the test always gets its own sub-folders cache
              (mh-sub-folders-cache (make-hash-table :test #'equal))
+             ;; Allow envvar TEST_MH_PATH to control mh-variants.
+             (mh-variants mh-test-utils-variants)
              ;; remember the original value
+             (original-mh-test-variant-logged mh-test-variant-logged-already)
+             (original-mh-path mh-path)
+             (original-mh-sys-path mh-sys-path)
+             (original-exec-path exec-path)
+             (original-mh-variant-in-use mh-variant-in-use)
+             (original-mh-progs mh-progs)
+             (original-mh-lib mh-lib)
+             (original-mh-lib-progs mh-lib-progs)
              (original-mh-envvar (getenv "MH")))
-     (unless mh-test-variant-logged-already
-       (mh-variant-set mh-variant)
-       (setq mh-test-variant-logged-already t))
      (unwind-protect
          (progn
-           (if mh-variant-in-use
-               (setq temp-home-dir (mh-test-utils-setup-with-variant))
-             (mh-test-utils-setup-with-mocks))
+           (setq temp-home-dir (mh-test-utils-setup))
            ,@body)
+       (unless noninteractive
+         ;; If interactive, forget that we logged the variant and
+         ;; restore any changes TEST_MH_PATH made.
+         (setq mh-test-variant-logged-already original-mh-test-variant-logged
+               mh-path original-mh-path
+               mh-sys-path original-mh-sys-path
+               exec-path original-exec-path
+               mh-variant-in-use original-mh-variant-in-use
+               mh-progs original-mh-progs
+               mh-lib original-mh-lib
+               mh-lib-progs original-mh-lib-progs))
        (if temp-home-dir (delete-directory temp-home-dir t))
        (setenv "MH" original-mh-envvar))))
 
+(defun mh-test-utils-setup ()
+  "Set dynamically bound variables needed by mock and/or variants.
+Call `mh-variant-set' to look through the directories named by
+envionment variable `TEST_MH_PATH' (default: `mh-path' and `mh-sys-path')
+to find the MH variant to use, if any.
+Return the name of the root of the created directory tree, if any."
+  (when (getenv "TEST_MH_PATH")
+    ;; force mh-variants to use only TEST_MH_PATH
+    (setq mh-path (split-string (getenv "TEST_MH_PATH") path-separator t)
+          mh-sys-path nil
+          exec-path '("/bin" "/usr/bin")))
+  (unless mh-test-variant-logged-already
+    (mh-variant-set mh-variant)
+    (setq mh-test-utils-variants mh-variants)
+    (setq mh-test-variant-logged-already t))
+  (when (native-comp-available-p)
+    ;; As `call-process'' and `file-directory-p' will be redefined, the
+    ;; native compiler will invoke `call-process' to compile the
+    ;; respective trampolines.  To avoid interference with the
+    ;; `call-process' mocking, we build these ahead of time.
+    (mapc #'comp-subr-trampoline-install '(call-process file-directory-p)))
+  (if mh-variant-in-use
+      (mh-test-utils-setup-with-variant)
+    (mh-test-utils-setup-with-mocks)))
+
 (defun mh-test-utils-setup-with-mocks ()
   "Set dynamically bound variables so that MH programs are mocked out.
 The tests use this method if no configured MH variant is found."
@@ -117,7 +184,9 @@ The tests use this method if no configured MH variant is 
found."
   (mh-populate-sub-folders-cache "+rela-folder/foo")
   (mh-populate-sub-folders-cache "+rela-folder/food")
   (fset 'call-process #'mh-test-utils-mock-call-process)
-  (fset 'file-directory-p #'mh-test-utils-mock-file-directory-p))
+  (fset 'file-directory-p #'mh-test-utils-mock-file-directory-p)
+  ;; no temp directory created
+  nil)
 
 (defun mh-test-utils-mock-call-process (program
                                         &optional _infile _destination _display
@@ -186,7 +255,7 @@ Return the name of the root of the created directory tree.
 Set dynamically bound variables so that MH programs may log.
 The tests use this method if a configured MH variant is found."
   (let* ((temp-home-dir
-          (make-temp-file "emacs-mh-e-unit-test" t))
+          (make-temp-file "emacs-mh-e-unit-test-" t))
          (profile (expand-file-name
                    ".mh_profile" temp-home-dir))
          (mail-dir (expand-file-name "Mail" temp-home-dir))
@@ -305,6 +374,7 @@ values for the FLAG argument of 
`mh-folder-completion-function'.
 NIL-EXPECTED is the expected value with FLAG nil.
 T-EXPECTED is the expected value with FLAG t.
 LAMBDA-EXPECTED is the expected value with FLAG lambda."
+  (declare (debug t))
   `(with-mh-test-env
      (mh-test-folder-completion-2 ,nil-expected ;case "a"
                                   (mh-folder-completion-function ,name nil 
nil))
@@ -319,6 +389,7 @@ LAMBDA-EXPECTED is the expected value with FLAG lambda."
 ACTUAL should evaluate to either EXPECTED or to a list containing EXPECTED.
 ACTUAL may be evaluated twice, but this gives a clearer error on failure,
 and the `should' macro requires idempotent evaluation anyway."
+  (declare (debug t))
   `(if (and (not (consp ,expected)) (consp ,actual))
        (should (member ,expected ,actual))
      (should (equal ,expected ,actual))))
diff --git a/test/lisp/mh-e/test-all-mh-variants.sh 
b/test/lisp/mh-e/test-all-mh-variants.sh
new file mode 100755
index 0000000000..e917d8155b
--- /dev/null
+++ b/test/lisp/mh-e/test-all-mh-variants.sh
@@ -0,0 +1,104 @@
+#! /bin/bash
+# Run the mh-utils-tests against all MH variants found on this system.
+
+# Copyright (C) 2021 Free Software Foundation, Inc.
+
+# This file is part of GNU Emacs.
+
+# GNU Emacs is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# GNU Emacs is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+# Commentary:
+
+# By default runs all tests; test names or Emacs-style regexps may be
+# given on the command line to run just those tests.
+#
+# Option -d turns on Emacs variable mh-test-utils-debug-mocks, which
+# causes the tests to output all interactions with the file system.
+
+# If you want to run the tests for only one MH variant, you don't need
+# to use this script, because "make" can do it.  See the commentary at
+# the top of ./mh-utils-tests.el for the recipe.
+
+debug=
+if [[ "$1" = -* ]]; then
+    if [[ "$1" != -d ]]; then
+        echo "Usage: $(basename "$0") [-d] [test ...]" >&2
+        exit 2
+    fi
+    debug=t
+    shift
+fi
+
+shopt -s extglob
+ert_test_list=()
+for tst; do
+    # Guess the type the test spec
+    case $tst in
+        *[\[\].*+\\]*)  # Regexp: put in string quotes
+            ert_test_list+=("\"$tst\"")
+            ;;
+        *)  # Lisp expression, keyword, or symbol: use as is
+            ert_test_list+=("$tst")
+            ;;
+    esac
+done
+if [[ ${#ert_test_list[@]} -eq 0 ]]; then
+    # t means true for all tests, runs everything
+    ert_test_list=(t)
+fi
+
+# This script is 3 directories down in the Emacs source tree.
+cd "$(dirname "$0")"
+cd ../../..
+emacs=(src/emacs --batch -Q)
+
+# MH-E has a good list of directories where an MH variant might be installed,
+# so we look in each of those.
+read -r -a mh_sys_path \
+    < <("${emacs[@]}" -l mh-e --eval "(princ mh-sys-path)" | sed 's/[()]//g')
+
+have_done_mocked_variant=false
+declare -i tests_total=0 tests_passed=0
+
+for path in "${mh_sys_path[@]}"; do
+    if [[ ! -x "$path/mhparam" ]]; then
+        if [[ "$have_done_mocked_variant" = false ]]; then
+            have_done_mocked_variant=true
+        else
+            continue
+        fi
+    fi
+    echo "Testing with PATH $path"
+    ((++tests_total))
+    # The LD_LIBRARY_PATH setting is needed
+    # to run locally installed Mailutils.
+    TEST_MH_PATH=$path TEST_MH_DEBUG=$debug \
+    LD_LIBRARY_PATH=/usr/local/lib HOME=/nonexistent \
+    "${emacs[@]}" -l ert \
+        --eval "(setq load-prefer-newer t)" \
+        --eval "(load \"$PWD/test/lisp/mh-e/mh-utils-tests\" nil t)" \
+        --eval "(ert-run-tests-batch-and-exit '(or ${ert_test_list[*]}))" \
+        && ((++tests_passed))
+done
+
+if (( tests_total == 0 )); then
+    echo "NO tests run"
+    exit 1
+elif (( tests_total == tests_passed )); then
+    echo "All tested variants pass: $tests_passed/$tests_total"
+else
+    echo "Tested variants passing: $tests_passed/$tests_total," \
+         "FAILING: $((tests_total - tests_passed))/$tests_total"
+    exit 1
+fi
diff --git a/test/lisp/net/browse-url-tests.el 
b/test/lisp/net/browse-url-tests.el
index 4264e03d91..68c7c34901 100644
--- a/test/lisp/net/browse-url-tests.el
+++ b/test/lisp/net/browse-url-tests.el
@@ -28,6 +28,7 @@
 
 (require 'browse-url)
 (require 'ert)
+(require 'ert-x)
 
 (ert-deftest browse-url-tests-browser-kind ()
   (should (eq (browse-url--browser-kind #'browse-url-w3 "gnu.org")
@@ -87,11 +88,10 @@
                  "ftp://foo/";)))
 
 (ert-deftest browse-url-tests-delete-temp-file ()
-  (let ((browse-url-temp-file-name
-         (make-temp-file "browse-url-tests-")))
+  (ert-with-temp-file browse-url-temp-file-name
     (browse-url-delete-temp-file)
     (should-not (file-exists-p browse-url-temp-file-name)))
-  (let ((file (make-temp-file "browse-url-tests-")))
+  (ert-with-temp-file file
     (browse-url-delete-temp-file file)
     (should-not (file-exists-p file))))
 
diff --git a/test/lisp/net/dbus-tests.el b/test/lisp/net/dbus-tests.el
index 53c786ada4..cfc380d302 100644
--- a/test/lisp/net/dbus-tests.el
+++ b/test/lisp/net/dbus-tests.el
@@ -630,16 +630,19 @@ This includes initialization and closing the bus."
             :session dbus--test-service dbus--test-path
             dbus--test-interface method1 "foo" "bar"))
           `(dbus-error ,dbus-error-invalid-args "Wrong arguments (foo bar)")))
-        ;; Three arguments, D-Bus error activated by `dbus-error' signal.
+        ;; Three arguments, D-Bus error activated by `dbus-error'
+        ;; signal.  On CentOS, it is not guaranteed which format the
+        ;; error message arises.  (Bug#51369)
         (should
-         (equal
+         (member
           (should-error
            (dbus-call-method
             :session dbus--test-service dbus--test-path
             dbus--test-interface method1 "foo" "bar" "baz"))
-          `(dbus-error
-            ,dbus-error-failed
-            "D-Bus error: \"D-Bus signal\", \"foo\", \"bar\", \"baz\"")))
+          `((dbus-error "D-Bus signal" "foo" "bar" "baz")
+            (dbus-error
+             ,dbus-error-failed
+             "D-Bus error: \"D-Bus signal\", \"foo\", \"bar\", \"baz\""))))
 
         ;; Unregister method.
         (should (dbus-unregister-object registered))
diff --git a/test/lisp/net/shr-tests.el b/test/lisp/net/shr-tests.el
index ed532af657..bfb83f2518 100644
--- a/test/lisp/net/shr-tests.el
+++ b/test/lisp/net/shr-tests.el
@@ -67,4 +67,4 @@
 
 (require 'shr)
 
-;;; shr-stream-tests.el ends here
+;;; shr-tests.el ends here
diff --git a/test/lisp/net/socks-tests.el b/test/lisp/net/socks-tests.el
index c0f90bc2d4..7fb885235c 100644
--- a/test/lisp/net/socks-tests.el
+++ b/test/lisp/net/socks-tests.el
@@ -128,7 +128,7 @@
 
 (defvar socks-tests-canned-server-patterns nil
   "Alist containing request/response cons pairs to be tried in order.
-Vectors must match verbatim. Strings are considered regex patterns.")
+Vectors must match verbatim.  Strings are considered regex patterns.")
 
 (defun socks-tests-canned-server-create ()
   "Create and return a fake SOCKS server."
@@ -203,7 +203,7 @@ Vectors must match verbatim. Strings are considered regex 
patterns.")
                    (should (equal host "example.com"))
                    (list 93 184 216 34)))
                 ((symbol-function 'user-full-name)
-                 (lambda () "foo")))
+                 (lambda (&optional _) "foo")))
         (socks-tests-perform-hello-world-http-request)))))
 
 ;; Replace first pattern below with ([5 3 0 1 2] . [5 2]) to validate
diff --git a/test/lisp/net/tramp-archive-tests.el 
b/test/lisp/net/tramp-archive-tests.el
index aac1b13bd0..98012f4e90 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -923,9 +923,10 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
         "(progn \
            (message \"tramp-archive loaded: %%s\" \
               (featurep 'tramp-archive)) \
-           (file-attributes %S \"/\") \
+           (let ((inhibit-message t)) \
+              (file-attributes %S \"/\")) \
            (message \"tramp-archive loaded: %%s\" \
-              (featurep 'tramp-archive)))"))
+              (featurep 'tramp-archive))))"))
     (dolist (default-directory
               `(,temporary-file-directory
                ;;  Starting Emacs in a directory which has
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 9f0264abc1..3d6ce963ee 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -52,6 +52,7 @@
 (require 'vc-git)
 (require 'vc-hg)
 
+(declare-function tramp-check-remote-uname "tramp-sh")
 (declare-function tramp-find-executable "tramp-sh")
 (declare-function tramp-get-remote-chmod-h "tramp-sh")
 (declare-function tramp-get-remote-gid "tramp-sh")
@@ -61,6 +62,7 @@
 (declare-function tramp-list-tramp-buffers "tramp-cmds")
 (declare-function tramp-method-out-of-band-p "tramp-sh")
 (declare-function tramp-smb-get-localname "tramp-smb")
+(declare-function dired-compress "dired-aux")
 (defvar ange-ftp-make-backup-files)
 (defvar auto-save-file-name-transforms)
 (defvar lock-file-name-transforms)
@@ -68,6 +70,7 @@
 (defvar tramp-connection-properties)
 (defvar tramp-copy-size-limit)
 (defvar tramp-display-escape-sequence-regexp)
+(defvar tramp-fuse-unmount-on-cleanup)
 (defvar tramp-inline-compress-start-size)
 (defvar tramp-persistency-file-name)
 (defvar tramp-remote-path)
@@ -2784,7 +2787,7 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
             :type 'file-already-exists)
            (should (file-directory-p tmp-name1))
            (should (file-accessible-directory-p tmp-name1))
-           (when (tramp--test-supports-file-modes-p)
+           (when (tramp--test-supports-set-file-modes-p)
              (should (equal (format "%#o" unusual-file-mode-1)
                             (format "%#o" (file-modes tmp-name1)))))
            (should-error
@@ -2794,7 +2797,7 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
              (make-directory tmp-name2 'parents))
            (should (file-directory-p tmp-name2))
            (should (file-accessible-directory-p tmp-name2))
-           (when (tramp--test-supports-file-modes-p)
+           (when (tramp--test-supports-set-file-modes-p)
              (should (equal (format "%#o" unusual-file-mode-2)
                             (format "%#o" (file-modes tmp-name2)))))
            ;; If PARENTS is non-nil, `make-directory' shall not
@@ -3157,7 +3160,20 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
                  (regexp-opt (directory-files tmp-name1))
                  (length (directory-files tmp-name1)))))))
 
-           ;; Check error case.
+           ;; Check error cases.
+           (when (and (tramp--test-supports-set-file-modes-p)
+                      ;; With "sshfs", directories with zero file
+                      ;; modes are still "accessible".
+                      (not (tramp--test-sshfs-p))
+                      ;; A directory is always accessible for user "root".
+                      (not (zerop (tramp-compat-file-attribute-user-id
+                                   (file-attributes tmp-name1)))))
+             (set-file-modes tmp-name1 0)
+             (with-temp-buffer
+               (should-error
+                (insert-directory tmp-name1 nil)
+                :type 'file-error))
+             (set-file-modes tmp-name1 #o777))
            (delete-directory tmp-name1 'recursive)
            (with-temp-buffer
              (should-error
@@ -3370,9 +3386,21 @@ This tests also `access-file', `file-readable-p',
                       (tramp-get-remote-gid tramp-test-vec 'integer)))
              (delete-file tmp-name1))
 
+           (when (tramp--test-supports-set-file-modes-p)
+             (write-region "foo" nil tmp-name1)
+             ;; A file is always accessible for user "root".
+             (when (not (zerop (tramp-compat-file-attribute-user-id
+                                (file-attributes tmp-name1))))
+               (set-file-modes tmp-name1 0)
+               (should-error
+                (access-file tmp-name1 "error")
+                :type 'file-error)
+               (set-file-modes tmp-name1 #o777))
+             (delete-file tmp-name1))
            (should-error
             (access-file tmp-name1 "error")
             :type tramp-file-missing)
+
            ;; `file-ownership-preserved-p' should return t for
            ;; non-existing files.
            (when test-file-ownership-preserved-p
@@ -3600,7 +3628,8 @@ They might differ only in time attributes or directory 
size."
   "Check `file-modes'.
 This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
   (skip-unless (tramp--test-enabled))
-  (skip-unless (tramp--test-supports-file-modes-p))
+  (skip-unless (tramp--test-supports-set-file-modes-p))
+
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
     (let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
          (tmp-name2 (tramp--test-make-temp-name nil quoted)))
@@ -3935,7 +3964,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
             (make-symbolic-link tmp-name2 tmp-name1)
             (should (file-symlink-p tmp-name1))
             (if (tramp--test-smb-p)
-                ;; The symlink command of `smbclient' detects the
+                ;; The symlink command of "smbclient" detects the
                 ;; cycle already.
                 (should-error
                  (make-symbolic-link tmp-name1 tmp-name2)
@@ -4046,6 +4075,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
 (ert-deftest tramp-test24-file-acl ()
   "Check that `file-acl' and `set-file-acl' work proper."
   (skip-unless (tramp--test-enabled))
+  ;; The following test checks also whether `set-file-modes' will work.
   (skip-unless (file-acl tramp-test-temporary-file-directory))
   (skip-unless (not (tramp--test-crypt-p)))
 
@@ -4413,8 +4443,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
   "Check `process-file'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (tramp--test-supports-processes-p))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
     (let* ((tmp-name (tramp--test-make-temp-name nil quoted))
@@ -4456,7 +4485,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
              (write-region "foo" nil tmp-name)
              (should (file-exists-p tmp-name))
              (should (zerop (process-file "ls" nil t nil fnnd)))
-             ;; `ls' could produce colorized output.
+             ;; "ls" could produce colorized output.
              (goto-char (point-min))
              (while
                  (re-search-forward tramp-display-escape-sequence-regexp nil t)
@@ -4467,7 +4496,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
              ;; Second run.  The output must be appended.
              (goto-char (point-max))
              (should (zerop (process-file "ls" nil t t fnnd)))
-             ;; `ls' could produce colorized output.
+             ;; "ls" could produce colorized output.
              (goto-char (point-min))
              (while
                  (re-search-forward tramp-display-escape-sequence-regexp nil t)
@@ -4480,7 +4509,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
        ;; Cleanup.
        (ignore-errors (delete-file tmp-name))))))
 
-;; Must be a command, because used as `sigusr' handler.
+;; Must be a command, because used as `sigusr1' handler.
 (defun tramp--test-timeout-handler (&rest _ignore)
   "Timeout handler, reporting a failed test."
   (interactive)
@@ -4494,8 +4523,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
   "Check `start-file-process'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (tramp--test-supports-processes-p))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
     (let ((default-directory tramp-test-temporary-file-directory)
@@ -4560,6 +4588,26 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
 
+      ;; "telnet" and "sshfs" do not cooperate with disabled filter.
+      (unless (or (tramp--test-telnet-p) (tramp--test-sshfs-p))
+       (unwind-protect
+           (with-temp-buffer
+             (setq proc (start-file-process "test3" (current-buffer) "cat"))
+             (should (processp proc))
+             (should (equal (process-status proc) 'run))
+             (set-process-filter proc t)
+             (process-send-string proc "foo\n")
+             (process-send-eof proc)
+             ;; Read output.
+             (with-timeout (10 (tramp--test-timeout-handler))
+               (while (process-live-p proc)
+                 (while (accept-process-output proc 0 nil t))))
+             ;; No output due to process filter.
+             (should (= (point-min) (point-max))))
+
+         ;; Cleanup.
+         (ignore-errors (delete-process proc))))
+
       ;; Process connection type.
       (when (and (tramp--test-sh-p)
                 (not (tramp-direct-async-process-p))
@@ -4587,8 +4635,10 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
                    (while (accept-process-output proc 0 nil t))))
                (should
                 (string-match-p
-                 (if (memq process-connection-type '(nil pipe))
-                     ;; `telnet' converts \r to <CR><NUL> if `crlf'
+                 (if (and (memq process-connection-type '(nil pipe))
+                           (not (tramp--test-macos-p)))
+                      ;; On macOS, there is always newline conversion.
+                     ;; "telnet" converts \r to <CR><NUL> if `crlf'
                      ;; flag is FALSE.  See telnet(1) man page.
                      "66\n6F\n6F\n0D\\(\n00\\)?\n0A\n"
                    "66\n6F\n6F\n0A\\(\n00\\)?\n0A\n")
@@ -4652,8 +4702,7 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
   "Check `make-process'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (tramp--test-supports-processes-p))
   ;; `make-process' supports file name handlers since Emacs 27.
   (skip-unless (tramp--test-emacs27-p))
 
@@ -4731,6 +4780,30 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
 
+      ;; "telnet" and "sshfs" do not cooperate with disabled filter.
+      (unless (or (tramp--test-telnet-p) (tramp--test-sshfs-p))
+       (unwind-protect
+           (with-temp-buffer
+             (setq proc
+                   (with-no-warnings
+                     (make-process
+                      :name "test3" :buffer (current-buffer) :command '("cat")
+                      :filter t
+                      :file-handler t)))
+             (should (processp proc))
+             (should (equal (process-status proc) 'run))
+             (process-send-string proc "foo\n")
+             (process-send-eof proc)
+             ;; Read output.
+             (with-timeout (10 (tramp--test-timeout-handler))
+               (while (process-live-p proc)
+                 (while (accept-process-output proc 0 nil t))))
+             ;; No output due to process filter.
+             (should (= (point-min) (point-max))))
+
+         ;; Cleanup.
+         (ignore-errors (delete-process proc))))
+
       ;; Process sentinel.
       (unwind-protect
          (with-temp-buffer
@@ -4756,7 +4829,7 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
 
-      ;; Process with stderr buffer.  `telnet' does not cooperate with
+      ;; Process with stderr buffer.  "telnet" does not cooperate with
       ;; three processes.
       (unless (or (tramp--test-telnet-p) (tramp-direct-async-process-p))
        (let ((stderr (generate-new-buffer "*stderr*")))
@@ -4852,9 +4925,11 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
                      (while (accept-process-output proc 0 nil t))))
                  (should
                   (string-match-p
-                   (if (memq (or connection-type process-connection-type)
-                             '(nil pipe))
-                       ;; `telnet' converts \r to <CR><NUL> if `crlf'
+                   (if (and (memq (or connection-type process-connection-type)
+                                  '(nil pipe))
+                             (not (tramp--test-macos-p)))
+                        ;; On macOS, there is always newline conversion.
+                       ;; "telnet" converts \r to <CR><NUL> if `crlf'
                        ;; flag is FALSE.  See telnet(1) man page.
                        "66\n6F\n6F\n0D\\(\n00\\)?\n0A\n"
                      "66\n6F\n6F\n0A\\(\n00\\)?\n0A\n")
@@ -4930,11 +5005,11 @@ INPUT, if non-nil, is a string sent to the process."
   "Check `shell-command'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
+  (skip-unless (tramp--test-supports-processes-p))
   ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
   ;; remote processes in Emacs.  That doesn't work for tramp-adb.el.
-  (skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
-                  (tramp--test-sh-p) (tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (when (tramp--test-adb-p)
+    (skip-unless (tramp--test-emacs27-p)))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
     (let ((tmp-name (tramp--test-make-temp-name nil quoted))
@@ -4958,7 +5033,7 @@ INPUT, if non-nil, is a string sent to the process."
               this-shell-command
               (format "ls %s" (file-name-nondirectory tmp-name))
               (current-buffer))
-             ;; `ls' could produce colorized output.
+             ;; "ls" could produce colorized output.
              (goto-char (point-min))
              (while
                  (re-search-forward tramp-display-escape-sequence-regexp nil t)
@@ -5032,8 +5107,7 @@ INPUT, if non-nil, is a string sent to the process."
   :tags '(:expensive-test :unstable)
   (skip-unless (tramp--test-enabled))
   (skip-unless nil)
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (tramp--test-supports-processes-p))
   ;; Prior Emacs 27, `shell-command-dont-erase-buffer' wasn't working properly.
   (skip-unless (tramp--test-emacs27-p))
 
@@ -5354,11 +5428,11 @@ Use direct async.")
   "Check that connection-local `explicit-shell-file-name' is set."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
+  (skip-unless (tramp--test-supports-processes-p))
   ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
   ;; remote processes in Emacs.  That doesn't work for tramp-adb.el.
-  (skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
-                  (tramp--test-sh-p) (tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (when (tramp--test-adb-p)
+    (skip-unless (tramp--test-emacs27-p)))
   ;; Since Emacs 26.1.
   (skip-unless (and (fboundp 'connection-local-set-profile-variables)
                    (fboundp 'connection-local-set-profiles)))
@@ -5413,8 +5487,8 @@ Use direct async.")
 (ert-deftest tramp-test35-exec-path ()
   "Check `exec-path' and `executable-find'."
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (skip-unless (tramp--test-supports-processes-p))
+  (skip-unless (tramp--test-supports-set-file-modes-p))
   ;; Since Emacs 27.1.
   (skip-unless (fboundp 'exec-path))
 
@@ -5435,6 +5509,7 @@ Use direct async.")
          ;; found.
          (write-region "foo" nil tmp-name)
          (should (file-exists-p tmp-name))
+
          (set-file-modes tmp-name #o777)
          (should (file-executable-p tmp-name))
          (should
@@ -5879,10 +5954,7 @@ Use direct async.")
          tramp-allow-unsafe-temporary-files
           (inhibit-message t)
          ;; tramp-rclone.el and tramp-sshfs.el cache the mounted files.
-         (tramp-cleanup-connection-hook
-          (append
-           (and (tramp--test-fuse-p) '(tramp-fuse-unmount))
-           tramp-cleanup-connection-hook))
+         (tramp-fuse-unmount-on-cleanup t)
           auto-save-default
          noninteractive)
 
@@ -6062,7 +6134,7 @@ This requires restrictions of file name syntax."
    'tramp-ftp-file-name-handler))
 
 (defun tramp--test-crypt-p ()
-  "Check, whether the remote directory is crypted"
+  "Check, whether the remote directory is crypted."
   (tramp-crypt-file-name-p tramp-test-temporary-file-directory))
 
 (defun tramp--test-docker-p ()
@@ -6099,8 +6171,7 @@ If optional METHOD is given, it is checked first."
 Several special characters do not work properly there."
   ;; We must refill the cache.  `file-truename' does it.
   (file-truename tramp-test-temporary-file-directory)
-  (string-match-p
-   "^HP-UX" (tramp-get-connection-property tramp-test-vec "uname" "")))
+  (tramp-check-remote-uname tramp-test-vec "^HP-UX"))
 
 (defun tramp--test-ksh-p ()
   "Check, whether the remote shell is ksh.
@@ -6111,12 +6182,22 @@ a $'' syntax."
   (string-match-p
    "ksh$" (tramp-get-connection-property tramp-test-vec "remote-shell" "")))
 
+(defun tramp--test-macos-p ()
+  "Check, whether the remote host runs macOS."
+  ;; We must refill the cache.  `file-truename' does it.
+  (file-truename tramp-test-temporary-file-directory)
+  (tramp-check-remote-uname tramp-test-vec "Darwin"))
+
 (defun tramp--test-mock-p ()
   "Check, whether the mock method is used.
 This does not support external Emacs calls."
   (string-equal
    "mock" (file-remote-p tramp-test-temporary-file-directory 'method)))
 
+(defun tramp--test-out-of-band-p ()
+  "Check, whether an out-of-band method is used."
+  (tramp-method-out-of-band-p tramp-test-vec 1))
+
 (defun tramp--test-rclone-p ()
   "Check, whether the remote host is offered by rclone.
 This requires restrictions of file name syntax."
@@ -6172,13 +6253,13 @@ This does not support special file names."
 (defun tramp--test-windows-nt-and-out-of-band-p ()
   "Check, whether the locale host runs MS Windows and an out-of-band method.
 This does not support utf8 based file transfer."
-  (and (eq system-type 'windows-nt)
-       (tramp-method-out-of-band-p tramp-test-vec 1)))
+  (and (tramp--test-windows-nt-p)
+       (tramp--test-out-of-band-p)))
 
 (defun tramp--test-windows-nt-or-smb-p ()
   "Check, whether the locale or remote host runs MS Windows.
 This requires restrictions of file name syntax."
-  (or (eq system-type 'windows-nt)
+  (or (tramp--test-windows-nt-p)
       (tramp--test-smb-p)))
 
 (defun tramp--test-smb-p ()
@@ -6186,8 +6267,13 @@ This requires restrictions of file name syntax."
 This requires restrictions of file name syntax."
   (tramp-smb-file-name-p tramp-test-temporary-file-directory))
 
-(defun tramp--test-supports-file-modes-p ()
-  "Return whether the method under test supports file modes."
+(defun tramp--test-supports-processes-p ()
+  "Return whether the method under test supports external processes."
+  (and (or (tramp--test-adb-p) (tramp--test-sh-p) (tramp--test-sshfs-p))
+       (not (tramp--test-crypt-p))))
+
+(defun tramp--test-supports-set-file-modes-p ()
+  "Return whether the method under test supports setting file modes."
   ;; "smb" does not unless the SMB server supports "posix" extensions.
   ;; "adb" does not unless the Android device is rooted.
   (or (tramp--test-sh-p) (tramp--test-sshfs-p) (tramp--test-sudoedit-p)
@@ -6290,9 +6376,9 @@ This requires restrictions of file name syntax."
            (kill-buffer buffer)
 
            ;; `substitute-in-file-name' could return different
-           ;; values.  For `adb', there could be strange file
+           ;; values.  For "adb", there could be strange file
            ;; permissions preventing overwriting a file.  We don't
-           ;; care in this testcase.
+           ;; care in this test case.
            (dolist (elt files)
              (let ((file1
                     (substitute-in-file-name (expand-file-name elt tmp-name1)))
@@ -6458,7 +6544,7 @@ This requires restrictions of file name syntax."
 
 (ert-deftest tramp-test41-special-characters-with-stat ()
   "Check special characters in file names.
-Use the `stat' command."
+Use the \"stat\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 287s
   (skip-unless (tramp--test-enabled))
@@ -6477,7 +6563,7 @@ Use the `stat' command."
 
 (ert-deftest tramp-test41-special-characters-with-perl ()
   "Check special characters in file names.
-Use the `perl' command."
+Use the \"perl\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 266s
   (skip-unless (tramp--test-enabled))
@@ -6499,7 +6585,7 @@ Use the `perl' command."
 
 (ert-deftest tramp-test41-special-characters-with-ls ()
   "Check special characters in file names.
-Use the `ls' command."
+Use the \"ls\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 287s
   (skip-unless (tramp--test-enabled))
@@ -6581,14 +6667,14 @@ Use the `ls' command."
 
 (ert-deftest tramp-test42-utf8-with-stat ()
   "Check UTF8 encoding in file names and file contents.
-Use the `stat' command."
+Use the \"stat\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 595s
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-docker-p)))
   (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
+  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
@@ -6604,14 +6690,14 @@ Use the `stat' command."
 
 (ert-deftest tramp-test42-utf8-with-perl ()
   "Check UTF8 encoding in file names and file contents.
-Use the `perl' command."
+Use the \"perl\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 620s
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-docker-p)))
   (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
+  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
@@ -6630,14 +6716,14 @@ Use the `perl' command."
 
 (ert-deftest tramp-test42-utf8-with-ls ()
   "Check UTF8 encoding in file names and file contents.
-Use the `ls' command."
+Use the \"ls\" command."
   :tags '(:expensive-test)
   (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 690s
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-docker-p)))
   (skip-unless (not (tramp--test-rsync-p)))
-  (skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
+  (skip-unless (not (tramp--test-out-of-band-p))) ; SLOW
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
 
@@ -6717,13 +6803,14 @@ process sentinels.  They shall not disturb each other."
   :tags (if (getenv "EMACS_EMBA_CI")
            '(:expensive-test :unstable) '(:expensive-test))
   (skip-unless (tramp--test-enabled))
+  (skip-unless (tramp--test-supports-processes-p))
   ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
   ;; remote processes in Emacs.  That doesn't work for tramp-adb.el.
-  (skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
-                  (tramp--test-sh-p)))
-  (skip-unless (not (tramp--test-crypt-p)))
+  (when (tramp--test-adb-p)
+    (skip-unless (tramp--test-emacs27-p)))
   (skip-unless (not (tramp--test-docker-p)))
   (skip-unless (not (tramp--test-telnet-p)))
+  (skip-unless (not (tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-windows-nt-p)))
 
   (with-timeout
@@ -6788,6 +6875,8 @@ process sentinels.  They shall not disturb each other."
                           (default-directory tmp-name)
                           (file
                            (buffer-name
+                            ;; Use `seq-random-elt' once <26.1 support
+                            ;; is dropped.
                             (nth (random (length buffers)) buffers)))
                          ;; A remote operation in a timer could
                          ;; confuse Tramp heavily.  So we ignore this
@@ -6853,6 +6942,7 @@ process sentinels.  They shall not disturb each other."
             ;; the buffers.  Mix with regular operation.
             (let ((buffers (copy-sequence buffers)))
               (while buffers
+                ;; Use `seq-random-elt' once <26.1 support is dropped.
                 (let* ((buf (nth (random (length buffers)) buffers))
                        (proc (get-buffer-process buf))
                        (file (process-get proc 'foo))
@@ -6909,8 +6999,40 @@ process sentinels.  They shall not disturb each other."
 ;; (tramp--test--deftest-direct-async-process 
tramp-test44-asynchronous-requests
 ;;   "Check parallel direct asynchronous requests." 'unstable)
 
+(ert-deftest tramp-test45-dired-compress-file ()
+  "Check that Tramp (un)compresses normal files."
+  (skip-unless (tramp--test-enabled))
+  (skip-unless (tramp--test-sh-p))
+  (let ((default-directory tramp-test-temporary-file-directory)
+        (tmp-name (tramp--test-make-temp-name)))
+    (write-region "foo" nil tmp-name)
+    (dired default-directory)
+    (dired-revert)
+    (dired-goto-file tmp-name)
+    (should-not (dired-compress))
+    (should (string= (concat tmp-name ".gz") (dired-get-filename)))
+    (should-not (dired-compress))
+    (should (string= tmp-name (dired-get-filename)))
+    (delete-file tmp-name)))
+
+(ert-deftest tramp-test45-dired-compress-dir ()
+  "Check that Tramp (un)compresses directories."
+  (skip-unless (tramp--test-enabled))
+  (skip-unless (tramp--test-sh-p))
+  (let ((default-directory tramp-test-temporary-file-directory)
+        (tmp-name (tramp--test-make-temp-name)))
+    (make-directory tmp-name)
+    (dired default-directory)
+    (dired-revert)
+    (dired-goto-file tmp-name)
+    (should-not (dired-compress))
+    (should (string= (concat tmp-name ".tar.gz") (dired-get-filename)))
+    (should-not (dired-compress))
+    (should (string= tmp-name (dired-get-filename)))
+    (delete-directory tmp-name)))
+
 ;; This test is inspired by Bug#29163.
-(ert-deftest tramp-test45-auto-load ()
+(ert-deftest tramp-test46-auto-load ()
   "Check that Tramp autoloads properly."
   ;; If we use another syntax but `default', Tramp is already loaded
   ;; due to the `tramp-change-syntax' call.
@@ -6935,7 +7057,7 @@ process sentinels.  They shall not disturb each other."
        (mapconcat #'shell-quote-argument load-path " -L ")
        (shell-quote-argument code)))))))
 
-(ert-deftest tramp-test45-delay-load ()
+(ert-deftest tramp-test46-delay-load ()
   "Check that Tramp is loaded lazily, only when needed."
   ;; The autoloaded Tramp objects are different since Emacs 26.1.  We
   ;; cannot test older Emacsen, therefore.
@@ -6968,7 +7090,7 @@ process sentinels.  They shall not disturb each other."
          (mapconcat #'shell-quote-argument load-path " -L ")
          (shell-quote-argument (format code tm)))))))))
 
-(ert-deftest tramp-test45-recursive-load ()
+(ert-deftest tramp-test46-recursive-load ()
   "Check that Tramp does not fail due to recursive load."
   (skip-unless (tramp--test-enabled))
 
@@ -6992,7 +7114,7 @@ process sentinels.  They shall not disturb each other."
          (mapconcat #'shell-quote-argument load-path " -L ")
          (shell-quote-argument code))))))))
 
-(ert-deftest tramp-test45-remote-load-path ()
+(ert-deftest tramp-test46-remote-load-path ()
   "Check that Tramp autoloads its packages with remote `load-path'."
   ;; The autoloaded Tramp objects are different since Emacs 26.1.  We
   ;; cannot test older Emacsen, therefore.
@@ -7021,7 +7143,7 @@ process sentinels.  They shall not disturb each other."
        (mapconcat #'shell-quote-argument load-path " -L ")
        (shell-quote-argument code)))))))
 
-(ert-deftest tramp-test46-unload ()
+(ert-deftest tramp-test47-unload ()
   "Check that Tramp and its subpackages unload completely.
 Since it unloads Tramp, it shall be the last test to run."
   :tags '(:expensive-test)
@@ -7100,8 +7222,8 @@ If INTERACTIVE is non-nil, the tests are run 
interactively."
 
 ;; * Work on skipped tests.  Make a comment, when it is impossible.
 ;; * Revisit expensive tests, once problems in `tramp-error' are solved.
-;; * Fix `tramp-test06-directory-file-name' for `ftp'.
-;; * Implement `tramp-test31-interrupt-process' for `adb', `sshfs' and
+;; * Fix `tramp-test06-directory-file-name' for "ftp".
+;; * Implement `tramp-test31-interrupt-process' for "adb", "sshfs" and
 ;;   for direct async processes.
 ;; * Check, why direct async processes do not work for
 ;;   `tramp-test44-asynchronous-requests'.
diff --git a/test/lisp/newcomment-tests.el b/test/lisp/newcomment-tests.el
index 5485673b72..65690e593d 100644
--- a/test/lisp/newcomment-tests.el
+++ b/test/lisp/newcomment-tests.el
@@ -1,4 +1,4 @@
-;;; newcomment-tests.el  -*- lexical-binding:t -*-
+;;; newcomment-tests.el --- Tests for newcomment.el  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2021 Free Software Foundation, Inc.
 
@@ -36,4 +36,4 @@
               (uncomment-region (point-min) (point-max))
               (buffer-string))))))
 
-;;; newcomment-testsuite.el ends here
+;;; newcomment-tests.el ends here
diff --git a/test/lisp/org/org-tests.el b/test/lisp/org/org-tests.el
index c1985a46a4..e53b038408 100644
--- a/test/lisp/org/org-tests.el
+++ b/test/lisp/org/org-tests.el
@@ -29,3 +29,5 @@ Ref <https://debbugs.gnu.org/30310>."
   (should (require 'org-version nil t))
   (should (equal (version-to-list (org-release))
                  (cdr (assq 'org package--builtin-versions)))))
+
+;;; org-tests.el ends here
diff --git a/test/lisp/paren-tests.el b/test/lisp/paren-tests.el
index c4bec5d86d..11249ee9bc 100644
--- a/test/lisp/paren-tests.el
+++ b/test/lisp/paren-tests.el
@@ -117,5 +117,36 @@
                          (- (point-max) 1) (point-max)
                          nil)))))
 
+(ert-deftest paren-tests-open-paren-line ()
+  (cl-flet ((open-paren-line ()
+                             (let* ((data (show-paren--default))
+                                    (here-beg (nth 0 data))
+                                    (there-beg (nth 2 data)))
+                               (blink-paren-open-paren-line-string
+                                (min here-beg there-beg)))))
+    ;; Lisp-like
+    (with-temp-buffer
+      (insert "(defun foo ()
+                  (dummy))")
+      (goto-char (point-max))
+      (should (string= "(defun foo ()" (open-paren-line))))
+
+    ;; C-like
+    (with-temp-buffer
+      (insert "int foo() {
+                 int blah;
+             }")
+      (goto-char (point-max))
+      (should (string= "int foo() {" (open-paren-line))))
+
+    ;; C-like with hanging {
+    (with-temp-buffer
+      (insert "int foo()
+               {
+                 int blah;
+               }")
+      (goto-char (point-max))
+      (should (string= "int foo()...{" (open-paren-line))))))
+
 (provide 'paren-tests)
 ;;; paren-tests.el ends here
diff --git a/test/lisp/play/cookie1-tests.el b/test/lisp/play/cookie1-tests.el
index 75dea4e5ef..2dd73d1802 100644
--- a/test/lisp/play/cookie1-tests.el
+++ b/test/lisp/play/cookie1-tests.el
@@ -37,4 +37,4 @@
     (should (= (length (cookie-apropos "false" fortune-file)) 1))))
 
 (provide 'fortune-tests)
-;;; fortune-tests.el ends here
+;;; cookie1-tests.el ends here
diff --git a/test/lisp/progmodes/bug-reference-tests.el 
b/test/lisp/progmodes/bug-reference-tests.el
new file mode 100644
index 0000000000..7a3ab5fbda
--- /dev/null
+++ b/test/lisp/progmodes/bug-reference-tests.el
@@ -0,0 +1,128 @@
+;;; bug-reference-tests.el --- Tests for bug-reference.el  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'bug-reference)
+(require 'ert)
+
+(defun test--get-github-entry (url)
+  (and (string-match
+       (car (bug-reference--build-forge-setup-entry
+              "github.com" 'github "https"))
+        url)
+       (match-string 1 url)))
+
+(defun test--get-gitlab-entry (url)
+  (and (string-match
+       (car (bug-reference--build-forge-setup-entry
+              "gitlab.com" 'gitlab "https"))
+        url)
+       (match-string 1 url)))
+
+(defun test--get-gitea-entry (url)
+  (and (string-match
+       (car (bug-reference--build-forge-setup-entry
+              "gitea.com" 'gitea "https"))
+        url)
+       (match-string 1 url)))
+
+(ert-deftest test-github-entry ()
+  (should
+   (equal
+    (test--get-github-entry "git@github.com:larsmagne/csid.git")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-github-entry "git@github.com:larsmagne/csid")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-github-entry "https://github.com/magit/magit.git";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-github-entry "https://github.com/magit/magit.git/";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-github-entry "https://github.com/magit/magit";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-github-entry "https://github.com/magit/magit/";)
+    "magit/magit")))
+
+(ert-deftest test-gitlab-entry ()
+  (should
+   (equal
+    (test--get-gitlab-entry "git@gitlab.com:larsmagne/csid.git")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-gitlab-entry "git@gitlab.com:larsmagne/csid")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-gitlab-entry "https://gitlab.com/magit/magit.git";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitlab-entry "https://gitlab.com/magit/magit.git/";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitlab-entry "https://gitlab.com/magit/magit";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitlab-entry "https://gitlab.com/magit/magit/";)
+    "magit/magit")))
+
+(ert-deftest test-gitea-entry ()
+  (should
+   (equal
+    (test--get-gitea-entry "git@gitea.com:larsmagne/csid.git")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-gitea-entry "git@gitea.com:larsmagne/csid")
+    "larsmagne/csid"))
+  (should
+   (equal
+    (test--get-gitea-entry "https://gitea.com/magit/magit.git";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitea-entry "https://gitea.com/magit/magit.git/";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitea-entry "https://gitea.com/magit/magit";)
+    "magit/magit"))
+  (should
+   (equal
+    (test--get-gitea-entry "https://gitea.com/magit/magit/";)
+    "magit/magit")))
+
+;;; bug-reference-tests.el ends here
diff --git a/test/lisp/progmodes/elisp-mode-resources/elisp-indents.erts 
b/test/lisp/progmodes/elisp-mode-resources/elisp-indents.erts
new file mode 100644
index 0000000000..2c0d51edae
--- /dev/null
+++ b/test/lisp/progmodes/elisp-mode-resources/elisp-indents.erts
@@ -0,0 +1,88 @@
+Code:
+  (lambda ()
+    (emacs-lisp-mode)
+    (indent-region (point-min) (point-max)))
+
+Name: defun
+
+=-=
+(defun foo ()
+"doc"
+(+ 1 2))
+=-=
+(defun foo ()
+  "doc"
+  (+ 1 2))
+=-=-=
+
+Name: function call
+
+=-=
+(foo zot
+bar
+(zot bar))
+=-=
+(foo zot
+     bar
+     (zot bar))
+=-=-=
+
+Name: lisp data
+
+=-=
+( foo zot
+bar
+(zot bar))
+=-=
+( foo zot
+  bar
+  (zot bar))
+=-=-=
+
+Name: defun-space
+
+=-=
+(defun x ()
+  (print (quote ( thingy great
+                 stuff)))
+  (print (quote (thingy great
+                       stuff))))
+=-=-=
+
+Name: defvar-keymap
+
+=-=
+(defvar-keymap eww-link-keymap
+  :copy shr-map
+  :foo bar
+  "\r" #'eww-follow-link)
+=-=-=
+
+Name: def-indent1
+
+=-=
+(defzot-does-not-exist 1
+                       2 3)
+=-=-=
+
+Name: def-indent2
+
+=-=
+(define-keymap 1
+  2 3)
+=-=-=
+
+Name: elisp-indents1
+
+=-=
+(defvar foo
+  ()
+  "bar")
+=-=-=
+
+Name: elisp-indents2
+
+=-=
+(defvar foo ()
+  "bar")
+=-=-=
diff --git a/test/lisp/progmodes/elisp-mode-resources/flet.erts 
b/test/lisp/progmodes/elisp-mode-resources/flet.erts
new file mode 100644
index 0000000000..da3dcb6ec3
--- /dev/null
+++ b/test/lisp/progmodes/elisp-mode-resources/flet.erts
@@ -0,0 +1,353 @@
+Name: flet1
+
+=-=
+(cl-flet ()
+  (a (dangerous-position
+      b)))
+=-=-=
+
+Name: flet2
+
+=-=
+(cl-flet wrong-syntax-but-should-not-obstruct-indentation
+  (a (dangerous-position
+      b)))
+=-=-=
+
+Name: flet3
+
+=-=
+(cl-flet ((a (arg-of-flet-a)
+            b
+            c)))
+=-=-=
+
+Name: flet4
+
+=-=
+(cl-flet ((a (arg-of-flet-a)
+            b
+            c
+            (if d
+                e
+              f))
+          (irregular-local-def (form
+                                returning
+                                lambda))
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet5
+
+=-=
+(cl-flet ((a (arg-of-flet-a)
+            b
+            c
+            (if d
+                e
+              f))
+          (irregular-local-def (form
+                                returning
+                                lambda))
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet6
+
+=-=
+(cl-flet ((a (arg-of-flet-a)
+            b
+            c
+            (if d
+                e
+              f))
+          (irregular-local-def (form
+                                returning
+                                lambda))
+          (irregular-local-def (form returning
+                                     lambda))
+          wrong-syntax-but-should-not-osbtruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet7
+
+=-=
+(cl-flet ((a (arg-of-flet-a)
+            b
+            c
+            (if d
+                e
+              f))
+          (irregular-local-def (form
+                                returning
+                                lambda))
+          wrong-syntax-but-should-not-osbtruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet8
+
+=-=
+(cl-flet (wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+;; (setf _) not yet supported but looks like it will be
+Name: flet9
+
+=-=
+(cl-flet (((setf a) (new value)
+            stuff)
+          wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet10
+
+=-=
+(cl-flet (   (a (arg-of-flet-a)
+               b
+               c
+               (if d
+                   e
+                 f))
+             (irregular-local-def (form
+                                   returning
+                                   lambda))
+             (g (arg-of--flet-g)
+               h
+               i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet11
+
+=-=
+(cl-flet (   wrong-syntax-but-should-not-obstruct-indentation
+             (g (arg-of--flet-g)
+               h
+               i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet12
+
+=-=
+(cl-flet (   wrong-syntax-but-should-not-obstruct-indentation
+             (g (arg-of--flet-g)
+               h
+               i))
+  (let ((j k))
+    (if dangerous-position
+        l
+      m)))
+=-=-=
+
+Name: flet13
+
+=-=
+(cl-flet (wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i)
+          wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i)))
+=-=-=
+
+Name: flet14
+
+=-=
+(cl-flet (wrong-syntax-but-should-not-obstruct-indentation
+          wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i)
+          wrong-syntax-but-should-not-obstruct-indentation))
+=-=-=
+
+Name: flet15
+
+=-=
+(cl-flet (wrong-syntax-but-should-not-obstruct-indentation
+          wrong-syntax-but-should-not-obstruct-indentation
+          wrong-syntax-but-should-not-obstruct-indentation
+          (g (arg-of--flet-g)
+            h
+            i)))
+=-=-=
+
+Name: flet16
+
+=-=
+(cl-flet ((f (x)
+            (g x)))
+  (pcase e
+    ((dangerous-expression)
+     (form))))
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-no-side-effects-1
+Code: (lambda () (emacs-lisp-mode) (setq indent-tabs-mode nil) (newline nil t))
+Point-Char: |
+
+=-=
+(let ((x (and y|
+=-=
+(let ((x (and y
+              |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-no-side-effects-2
+
+=-=
+(let ((x|
+=-=
+(let ((x
+       |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-whitespace-1
+Point-Char: |
+
+=-=
+(cl-flet((f (x)|
+=-=
+(cl-flet((f (x)
+           |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-whitespace-2
+Point-Char: |
+
+=-=
+(cl-flet((f(x)|
+=-=
+(cl-flet((f(x)
+           |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-whitespace-3
+
+=-=
+(cl-flet ((f(x)|
+=-=
+(cl-flet ((f(x)
+            |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-whitespace-4
+
+=-=
+(cl-flet( (f (x)|
+=-=
+(cl-flet( (f (x)
+            |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-whitespace-5
+
+=-=
+(cl-flet( (f(x)|
+=-=
+(cl-flet( (f(x)
+            |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-1
+
+=-=
+(cl-flet((f  (x)|
+=-=
+(cl-flet((f  (x)
+           |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-2
+
+=-=
+(cl-flet  ((f(x)|
+=-=
+(cl-flet  ((f(x)
+             |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-3
+
+=-=
+(cl-flet( (f  (x)|
+=-=
+(cl-flet( (f  (x)
+            |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-4
+
+=-=
+(cl-flet(  (f (x)|
+=-=
+(cl-flet(  (f (x)
+             |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-5
+
+=-=
+(cl-flet(  (f  (x)|
+=-=
+(cl-flet(  (f  (x)
+             |
+=-=-=
+
+Name: flet-indentation-incomplete-sexp-missing-and-excessive-whitespace-6
+
+=-=
+(cl-flet(  (f(x)|
+=-=
+(cl-flet(  (f(x)
+             |
+=-=-=
diff --git a/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el 
b/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el
new file mode 100644
index 0000000000..9b41fb5426
--- /dev/null
+++ b/test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el
@@ -0,0 +1,40 @@
+;;; simple-shorthand-test.el ---   -*- lexical-binding: t; -*-
+
+(defun f-test ()
+  (let ((read-symbol-shorthands '(("foo-" . "bar-"))))
+    (with-temp-buffer
+      (insert "(foo-bar)")
+      (goto-char (point-min))
+      (read (current-buffer)))))
+
+(defun f-test2 ()
+  (let ((read-symbol-shorthands '(("foo-" . "bar-"))))
+    (read-from-string "(foo-bar)")))
+
+
+(defun f-test3 ()
+  (let ((read-symbol-shorthands '(("foo-" . "bar-"))))
+    (intern "foo-bar")))
+
+(defvar f-test-complete-me 42)
+
+(elisp--foo-test3)
+
+(defun #_f-test4--- () 84)
+
+(defmacro f-define-test-5 ())
+
+;; should be font locked with both shorthand
+;; highlighting _and_ macro highlighting.
+(f-define-test-5)
+
+(when nil
+  (f-test3)
+  (f-test2)
+  (f-test)
+  (#_f-test4---))
+
+
+;; Local Variables:
+;; read-symbol-shorthands: (("f-" . "elisp--foo-"))
+;; End:
diff --git a/test/lisp/progmodes/elisp-mode-tests.el 
b/test/lisp/progmodes/elisp-mode-tests.el
index 60946c2f44..7f1cd6795e 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -23,8 +23,10 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'xref)
 (eval-when-compile (require 'cl-lib))
+(require 'ert-x)
 
 ;;; Completion
 
@@ -300,12 +302,9 @@
 
 ;; tmp may be on a different filesystem to the tests, but, ehh.
 (defvar xref--case-insensitive
-  (let ((dir (make-temp-file "xref-test" t)))
-    (unwind-protect
-        (progn
-          (with-temp-file (expand-file-name "hElLo" dir) "hello")
-          (file-exists-p (expand-file-name "HELLO" dir)))
-      (delete-directory dir t)))
+  (ert-with-temp-directory dir
+    (with-temp-file (expand-file-name "hElLo" dir) "hello")
+    (file-exists-p (expand-file-name "HELLO" dir)))
   "Non-nil if file system seems to be case-insensitive.")
 
 (defun xref-elisp-test-run (xrefs expected-xrefs)
@@ -315,27 +314,27 @@
            (expected (pop expected-xrefs))
            (expected-xref (or (when (consp expected) (car expected)) expected))
            (expected-source (when (consp expected) (cdr expected)))
-           (xref-file (xref-elisp-location-file (oref xref location)))
+           (xref-file (xref-elisp-location-file (xref-item-location xref)))
            (expected-file (xref-elisp-location-file
-                           (oref expected-xref location))))
+                           (xref-item-location expected-xref))))
 
       ;; Make sure file names compare as strings.
       (when (file-name-absolute-p xref-file)
-        (setf (xref-elisp-location-file (oref xref location))
-              (file-truename (xref-elisp-location-file (oref xref location)))))
+        (setf (xref-elisp-location-file (xref-item-location xref))
+              (file-truename (xref-elisp-location-file (xref-item-location 
xref)))))
       (when (file-name-absolute-p expected-file)
-        (setf (xref-elisp-location-file (oref expected-xref location))
+        (setf (xref-elisp-location-file (xref-item-location expected-xref))
               (file-truename (xref-elisp-location-file
-                              (oref expected-xref location)))))
+                              (xref-item-location expected-xref)))))
 
       ;; Downcase the filenames for case-insensitive file systems.
       (when xref--case-insensitive
-        (setf (xref-elisp-location-file (oref xref location))
-              (downcase (xref-elisp-location-file (oref xref location))))
+        (setf (xref-elisp-location-file (xref-item-location xref))
+              (downcase (xref-elisp-location-file (xref-item-location xref))))
 
-        (setf (xref-elisp-location-file (oref expected-xref location))
+        (setf (xref-elisp-location-file (xref-item-location expected-xref))
               (downcase (xref-elisp-location-file
-                         (oref expected-xref location)))))
+                         (xref-item-location expected-xref)))))
 
       (should (equal xref expected-xref))
 
@@ -416,8 +415,6 @@ to (xref-elisp-test-descr-to-target xref)."
 
 ;; FIXME: defconst
 
-;; FIXME: eieio defclass
-
 ;; Possible ways of defining the default method implementation for a
 ;; generic function. We declare these here, so we know we cover all
 ;; cases, and we don't rely on other code not changing.
@@ -429,7 +426,7 @@ to (xref-elisp-test-descr-to-target xref)."
   slot-1)
 
 (cl-defgeneric xref-elisp-generic-no-methods (arg1 arg2)
-  "doc string generic no-methods"
+  "Doc string generic no-methods."
   ;; No default implementation, no methods, but fboundp is true for
   ;; this symbol; it calls cl-no-applicable-method
   )
@@ -440,44 +437,44 @@ to (xref-elisp-test-descr-to-target xref)."
 ;; ‘this’. It passes in interactive tests, so I haven't been able to
 ;; track down the problem.
 (cl-defmethod xref-elisp-generic-no-default ((this xref-elisp-root-type) arg2)
-  "doc string generic no-default xref-elisp-root-type"
+  "Doc string generic no-default xref-elisp-root-type."
   "non-default for no-default")
 
 ;; defgeneric after defmethod in file to ensure the fallback search
 ;; method of just looking for the function name will fail.
 (cl-defgeneric xref-elisp-generic-no-default (arg1 arg2)
-  "doc string generic no-default generic"
+  "Doc string generic no-default generic."
   ;; No default implementation; this function calls the cl-generic
   ;; dispatching code.
   )
 
 (cl-defgeneric xref-elisp-generic-co-located-default (arg1 arg2)
-  "doc string generic co-located-default"
+  "Doc string generic co-located-default."
   "co-located default")
 
 (cl-defmethod xref-elisp-generic-co-located-default ((this 
xref-elisp-root-type) arg2)
-  "doc string generic co-located-default xref-elisp-root-type"
+  "Doc string generic co-located-default xref-elisp-root-type."
   "non-default for co-located-default")
 
 (cl-defgeneric xref-elisp-generic-separate-default (arg1 arg2)
-  "doc string generic separate-default"
+  "Doc string generic separate-default."
   ;; default implementation provided separately
   )
 
 (cl-defmethod xref-elisp-generic-separate-default (arg1 arg2)
-  "doc string generic separate-default default"
+  "Doc string generic separate-default default."
   "separate default")
 
 (cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type) 
arg2)
-  "doc string generic separate-default xref-elisp-root-type"
+  "Doc string generic separate-default xref-elisp-root-type."
   "non-default for separate-default")
 
 (cl-defmethod xref-elisp-generic-implicit-generic (arg1 arg2)
-  "doc string generic implicit-generic default"
+  "Doc string generic implicit-generic default."
   "default for implicit generic")
 
 (cl-defmethod xref-elisp-generic-implicit-generic ((this xref-elisp-root-type) 
arg2)
-  "doc string generic implicit-generic xref-elisp-root-type"
+  "Doc string generic implicit-generic xref-elisp-root-type."
   "non-default for implicit generic")
 
 
@@ -623,35 +620,35 @@ to (xref-elisp-test-descr-to-target xref)."
 (declare-function xref-elisp-overloadable-no-default-default 
"elisp-mode-tests")
 
 (define-overloadable-function xref-elisp-overloadable-no-methods ()
-  "doc string overloadable no-methods")
+  "Doc string overloadable no-methods.")
 
 (define-overloadable-function xref-elisp-overloadable-no-default ()
-  "doc string overloadable no-default")
+  "Doc string overloadable no-default.")
 
 (define-mode-local-override xref-elisp-overloadable-no-default c-mode
   (_start _end &optional _nonterminal _depth _returnonerror)
-  "doc string overloadable no-default c-mode."
+  "Doc string overloadable no-default c-mode."
   "result overloadable no-default c-mode.")
 
 (define-overloadable-function xref-elisp-overloadable-co-located-default ()
-  "doc string overloadable co-located-default"
+  "Doc string overloadable co-located-default."
   "result overloadable co-located-default.")
 
 (define-mode-local-override xref-elisp-overloadable-co-located-default c-mode
   (_start _end &optional _nonterminal _depth _returnonerror)
-  "doc string overloadable co-located-default c-mode."
+  "Doc string overloadable co-located-default c-mode."
   "result overloadable co-located-default c-mode.")
 
 (define-overloadable-function xref-elisp-overloadable-separate-default ()
-  "doc string overloadable separate-default.")
+  "Doc string overloadable separate-default.")
 
 (defun xref-elisp-overloadable-separate-default-default ()
-  "doc string overloadable separate-default default"
+  "Doc string overloadable separate-default default."
   "result overloadable separate-default.")
 
 (define-mode-local-override xref-elisp-overloadable-separate-default c-mode
   (_start _end &optional _nonterminal _depth _returnonerror)
-  "doc string overloadable separate-default c-mode."
+  "Doc string overloadable separate-default c-mode."
   "result overloadable separate-default c-mode.")
 
 (xref-elisp-deftest find-defs-define-overload-no-methods
@@ -782,11 +779,11 @@ to (xref-elisp-test-descr-to-target xref)."
    ))
 
 (xref-elisp-deftest find-defs-defvar-el
-  (elisp--xref-find-definitions 'xref--marker-ring)
+  (elisp--xref-find-definitions 'xref--history)
   (list
-   (xref-make "(defvar xref--marker-ring)"
+   (xref-make "(defvar xref--history)"
              (xref-make-elisp-location
-              'xref--marker-ring 'defvar
+              'xref--history 'defvar
               (expand-file-name "../../../lisp/progmodes/xref.el" 
emacs-test-dir)))
     ))
 
@@ -842,18 +839,6 @@ to (xref-elisp-test-descr-to-target xref)."
     (insert "?\\N{HEAVY CHECK MARK}")
     (should (equal (elisp--preceding-sexp) ?\N{HEAVY CHECK MARK}))))
 
-(ert-deftest elisp-indent-basic ()
-  (with-temp-buffer
-    (emacs-lisp-mode)
-    (let ((orig "(defun x ()
-  (print (quote ( thingy great
-                 stuff)))
-  (print (quote (thingy great
-                       stuff))))"))
-      (insert orig)
-      (indent-region (point-min) (point-max))
-      (should (equal (buffer-string) orig)))))
-
 (defun test--font (form search)
   (with-temp-buffer
     (emacs-lisp-mode)
@@ -977,6 +962,17 @@ evaluation of BODY."
     (should (equal (elisp--xref-infer-namespace p6) 'maybe-variable))
     (should (equal (elisp--xref-infer-namespace p7) 'variable)))
 
+  (elisp-mode-test--with-buffer
+      (concat "(let (({p1}alpha {p2}beta)\n"
+              "      ({p3}gamma ({p4}delta {p5}epsilon)))\n"
+              "  ({p6}zeta))\n")
+    (should (equal (elisp--xref-infer-namespace p1) 'variable))
+    (should (equal (elisp--xref-infer-namespace p2) 'variable))
+    (should (equal (elisp--xref-infer-namespace p3) 'variable))
+    (should (equal (elisp--xref-infer-namespace p4) 'function))
+    (should (equal (elisp--xref-infer-namespace p5) 'maybe-variable))
+    (should (equal (elisp--xref-infer-namespace p6) 'function)))
+
   (elisp-mode-test--with-buffer
       (concat "(defun {p1}alpha () {p2}beta)\n"
               "(defface {p3}gamma ...)\n"
@@ -1021,5 +1017,96 @@ evaluation of BODY."
     (should (equal (elisp--xref-infer-namespace p3) 'any))
     (should (equal (elisp--xref-infer-namespace p4) 'any))))
 
+
+(ert-deftest elisp-shorthand-read-buffer ()
+  (let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
+         (shorthand-sname (format "s-%s" gsym))
+         (expected (intern (format "shorthand-longhand-%s" gsym))))
+    (cl-assert (not (intern-soft shorthand-sname)))
+    (should (equal (let ((read-symbol-shorthands
+                          '(("s-" . "shorthand-longhand-"))))
+                     (with-temp-buffer
+                       (insert shorthand-sname)
+                       (goto-char (point-min))
+                       (read (current-buffer))))
+                   expected))
+    (should (not (intern-soft shorthand-sname)))))
+
+(ert-deftest elisp-shorthand-read-from-string ()
+  (let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
+         (shorthand-sname (format "s-%s" gsym))
+         (expected (intern (format "shorthand-longhand-%s" gsym))))
+    (cl-assert (not (intern-soft shorthand-sname)))
+    (should (equal (let ((read-symbol-shorthands
+                          '(("s-" . "shorthand-longhand-"))))
+                     (car (read-from-string shorthand-sname)))
+                   expected))
+    (should (not (intern-soft shorthand-sname)))))
+
+(ert-deftest elisp-shorthand-load-a-file ()
+  (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+    (mapatoms (lambda (s)
+                (when (string-match "^elisp--foo-" (symbol-name s))
+                  (unintern s obarray))))
+    (load test-file)
+    (should (intern-soft "elisp--foo-test"))
+    (should-not (intern-soft "f-test"))))
+
+(ert-deftest elisp-shorthand-byte-compile-a-file ()
+
+  (let ((test-file (ert-resource-file "simple-shorthand-test.el"))
+        (byte-compiled (ert-resource-file "simple-shorthand-test.elc")))
+    (mapatoms (lambda (s)
+                (when (string-match "^elisp--foo-" (symbol-name s))
+                  (unintern s obarray))))
+    (byte-compile-file test-file)
+    (should-not (intern-soft "f-test"))
+    (should (intern-soft "elisp--foo-test"))
+    (should-not (fboundp (intern-soft "elisp--foo-test")))
+    (load byte-compiled)
+    (should (intern-soft "elisp--foo-test"))
+    (should-not (intern-soft "f-test"))))
+
+(ert-deftest elisp-shorthand-completion-at-point ()
+  (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+    (load test-file)
+    (with-current-buffer (find-file-noselect test-file)
+      (revert-buffer t t)
+      (goto-char (point-min))
+      (insert "f-test-compl")
+      (completion-at-point)
+      (goto-char (point-min))
+      (should (search-forward "f-test-complete-me" (line-end-position) t))
+      (goto-char (point-min))
+      (should (string= (symbol-name (read (current-buffer)))
+                       "elisp--foo-test-complete-me"))
+      (revert-buffer t t))))
+
+(ert-deftest elisp-shorthand-escape ()
+  (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+    (load test-file)
+    (should (intern-soft "f-test4---"))
+    (should-not (intern-soft "elisp--foo-test4---"))
+    (should (= 84 (funcall (intern-soft "f-test4---"))))
+    (should (unintern "f-test4---"))))
+
+(ert-deftest elisp-dont-shadow-punctuation-only-symbols ()
+  (let* ((shorthanded-form '(/= 42 (-foo 42)))
+         (expected-longhand-form '(/= 42 (fooey-foo 42)))
+         (observed (let ((read-symbol-shorthands
+                          '(("-" . "fooey-"))))
+                     (car (read-from-string
+                           (with-temp-buffer
+                             (print shorthanded-form (current-buffer))
+                             (buffer-string)))))))
+    (should (equal observed expected-longhand-form))))
+
+(ert-deftest test-indentation ()
+  (ert-test-erts-file (ert-resource-file "elisp-indents.erts"))
+  (ert-test-erts-file (ert-resource-file "flet.erts")
+                      (lambda ()
+                        (emacs-lisp-mode)
+                        (indent-region (point-min) (point-max)))))
+
 (provide 'elisp-mode-tests)
 ;;; elisp-mode-tests.el ends here
diff --git a/test/lisp/progmodes/etags-tests.el 
b/test/lisp/progmodes/etags-tests.el
index 35a2592e76..32b73f101e 100644
--- a/test/lisp/progmodes/etags-tests.el
+++ b/test/lisp/progmodes/etags-tests.el
@@ -22,6 +22,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'etags)
 (eval-when-compile (require 'cl-lib))
 
@@ -95,19 +96,19 @@
 
 (ert-deftest etags-buffer-local-tags-table-list ()
   "Test that a buffer-local value of `tags-table-list' is used."
-  (let ((file (make-temp-file "etag-test-tmpfile")))
-    (unwind-protect
-        (progn
-          (set-buffer (find-file-noselect file))
-          (fundamental-mode)
-          (setq-local tags-table-list
-                      (list (expand-file-name "manual/etags/ETAGS.good_3"
-                                              etags-tests--test-dir)))
-          (cl-letf ((tag-tables tags-table-list)
-                    (tags-file-name nil)
-                    ((symbol-function 'read-file-name)
-                     (lambda (&rest _)
-                       (error "We should not prompt the user"))))
-            (should (visit-tags-table-buffer))
-            (should (equal tags-file-name (car tag-tables)))))
-      (delete-file file))))
+  (ert-with-temp-file file
+    :suffix "etag-test-tmpfile"
+    (set-buffer (find-file-noselect file))
+    (fundamental-mode)
+    (setq-local tags-table-list
+                (list (expand-file-name "manual/etags/ETAGS.good_3"
+                                        etags-tests--test-dir)))
+    (cl-letf ((tag-tables tags-table-list)
+              (tags-file-name nil)
+              ((symbol-function 'read-file-name)
+               (lambda (&rest _)
+                 (error "We should not prompt the user"))))
+      (should (visit-tags-table-buffer))
+      (should (equal tags-file-name (car tag-tables))))))
+
+;;; etags-tests.el ends here
diff --git a/test/lisp/progmodes/flymake-tests.el 
b/test/lisp/progmodes/flymake-tests.el
index 10111ca06c..4840018236 100644
--- a/test/lisp/progmodes/flymake-tests.el
+++ b/test/lisp/progmodes/flymake-tests.el
@@ -23,6 +23,7 @@
 
 ;;; Code:
 (require 'ert)
+(require 'ert-x)
 (require 'flymake)
 (eval-when-compile (require 'subr-x)) ; string-trim
 
@@ -123,22 +124,21 @@ SEVERITY-PREDICATE is used to setup
   "Test the ruby backend."
   (skip-unless (executable-find "ruby"))
   ;; Some versions of ruby fail if HOME doesn't exist (bug#29187).
-  (let* ((tempdir (make-temp-file "flymake-tests-ruby" t))
-         (process-environment (cons (format "HOME=%s" tempdir)
-                                    process-environment))
-         ;; And see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19657#20
-         ;; for this particular yuckiness
-         (abbreviated-home-dir nil))
-    (unwind-protect
-        (let ((ruby-mode-hook
-               (lambda ()
-                 (setq flymake-diagnostic-functions '(ruby-flymake-simple)))))
-          (flymake-tests--with-flymake ("test.rb")
-            (flymake-goto-next-error)
-            (should (eq 'flymake-warning (face-at-point)))
-            (flymake-goto-next-error)
-            (should (eq 'flymake-error (face-at-point)))))
-      (delete-directory tempdir t))))
+  (ert-with-temp-directory  tempdir
+    :suffix "flymake-tests-ruby"
+    (let* ((process-environment (cons (format "HOME=%s" tempdir)
+                                      process-environment))
+           ;; And see https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19657#20
+           ;; for this particular yuckiness
+           (abbreviated-home-dir nil)
+           (ruby-mode-hook
+            (lambda ()
+              (setq flymake-diagnostic-functions '(ruby-flymake-simple)))))
+      (flymake-tests--with-flymake ("test.rb")
+        (flymake-goto-next-error)
+        (should (eq 'flymake-warning (face-at-point)))
+        (flymake-goto-next-error)
+        (should (eq 'flymake-error (face-at-point)))))))
 
 (ert-deftest different-diagnostic-types ()
   "Test GCC warning via function predicate."
@@ -193,7 +193,7 @@ SEVERITY-PREDICATE is used to setup
 
 (defun flymake-tests--diagnose-words
     (report-fn type words)
-  "Helper. Call REPORT-FN with diagnostics for WORDS in buffer."
+  "Helper.  Call REPORT-FN with diagnostics for WORDS in buffer."
   (funcall report-fn
            (cl-loop
             for word in words
diff --git a/test/lisp/progmodes/gdb-mi-tests.el 
b/test/lisp/progmodes/gdb-mi-tests.el
index ab482214af..d66df961b6 100644
--- a/test/lisp/progmodes/gdb-mi-tests.el
+++ b/test/lisp/progmodes/gdb-mi-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'gdb-mi)
 
@@ -44,3 +46,5 @@
   )
 
 (provide 'gdb-mi-tests)
+
+;;; gdb-mi-tests.el ends here
diff --git a/test/lisp/progmodes/opascal-tests.el 
b/test/lisp/progmodes/opascal-tests.el
index 682f2c6cb6..ea91479362 100644
--- a/test/lisp/progmodes/opascal-tests.el
+++ b/test/lisp/progmodes/opascal-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'opascal)
 
diff --git a/test/lisp/progmodes/pascal-tests.el 
b/test/lisp/progmodes/pascal-tests.el
index e9c705806b..f5202143e2 100644
--- a/test/lisp/progmodes/pascal-tests.el
+++ b/test/lisp/progmodes/pascal-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 (require 'pascal)
 
@@ -61,3 +63,5 @@
     (should (equal (point) 15))))
 
 (provide 'pascal-tests)
+
+;;; pascal-tests.el ends here
diff --git a/test/lisp/progmodes/project-tests.el 
b/test/lisp/progmodes/project-tests.el
index 1e3f258ac2..a469414a74 100644
--- a/test/lisp/progmodes/project-tests.el
+++ b/test/lisp/progmodes/project-tests.el
@@ -29,29 +29,17 @@
 
 (require 'cl-lib)
 (require 'ert)
+(require 'ert-x) ; ert-with-temp-directory
 (require 'grep)
 (require 'xref)
 
-(defmacro project-tests--with-temporary-directory (var &rest body)
-  "Create a new temporary directory.
-Bind VAR to the name of the directory, and evaluate BODY.  Delete
-the directory after BODY exits."
-  (declare (debug (symbolp body)) (indent 1))
-  (cl-check-type var symbol)
-  (let ((directory (make-symbol "directory")))
-    `(let ((,directory (make-temp-file "project-tests-" :directory)))
-       (unwind-protect
-           (let ((,var ,directory))
-             ,@body)
-         (delete-directory ,directory :recursive)))))
-
 (ert-deftest project/quoted-directory ()
   "Check that `project-files' and `project-find-regexp' deal with
 quoted directory names (Bug#47799)."
   (skip-unless (executable-find find-program))
   (skip-unless (executable-find "xargs"))
   (skip-unless (executable-find "grep"))
-  (project-tests--with-temporary-directory directory
+  (ert-with-temp-directory directory
     (let ((default-directory directory)
           (project-current-inhibit-prompt t)
           (project-find-functions nil)
@@ -95,7 +83,7 @@ quoted directory names (Bug#47799)."
 returned by `project-ignores' if the root directory is a
 directory name (Bug#48471)."
   (skip-unless (executable-find find-program))
-  (project-tests--with-temporary-directory dir
+  (ert-with-temp-directory dir
     (make-empty-file (expand-file-name "some-file" dir))
     (make-empty-file (expand-file-name "ignored-file" dir))
     (let* ((project (make-project-tests--trivial
@@ -111,7 +99,7 @@ directory name (Bug#48471)."
   "Check that `project-files' does not ignore all files.
 When `project-ignores' includes a name matching project dir."
   (skip-unless (executable-find find-program))
-  (project-tests--with-temporary-directory dir
+  (ert-with-temp-directory dir
     (make-empty-file (expand-file-name "some-file" dir))
     (let* ((project (make-project-tests--trivial
                      :root (file-name-as-directory dir)
diff --git a/test/lisp/progmodes/python-tests.el 
b/test/lisp/progmodes/python-tests.el
index 6ab9c62746..15bda5c197 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -22,6 +22,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'python)
 
 ;; Dependencies for testing:
@@ -48,17 +49,17 @@ BODY is code to be executed within the temp buffer.  Point 
is
 always located at the beginning of buffer."
   (declare (indent 1) (debug t))
   ;; temp-file never actually used for anything?
-  `(let* ((temp-file (make-temp-file "python-tests" nil ".py"))
-          (buffer (find-file-noselect temp-file))
-          (python-indent-guess-indent-offset nil))
-     (unwind-protect
-         (with-current-buffer buffer
-           (python-mode)
-           (insert ,contents)
-           (goto-char (point-min))
-           ,@body)
-       (and buffer (kill-buffer buffer))
-       (delete-file temp-file))))
+  `(ert-with-temp-file temp-file
+     :suffix "-python.py"
+     (let ((buffer (find-file-noselect temp-file))
+           (python-indent-guess-indent-offset nil))
+       (unwind-protect
+           (with-current-buffer buffer
+             (python-mode)
+             (insert ,contents)
+             (goto-char (point-min))
+             ,@body)
+         (and buffer (kill-buffer buffer))))))
 
 (defun python-tests-look-at (string &optional num restore-point)
   "Move point at beginning of STRING in the current buffer.
diff --git a/test/lisp/progmodes/sql-tests.el b/test/lisp/progmodes/sql-tests.el
index 21dd064952..1bbe3a95e9 100644
--- a/test/lisp/progmodes/sql-tests.el
+++ b/test/lisp/progmodes/sql-tests.el
@@ -28,6 +28,7 @@
 
 (require 'cl-lib)
 (require 'ert)
+(require 'ert-x)
 (require 'sql)
 
 (ert-deftest sql-tests-postgres-list-databases ()
@@ -50,7 +51,7 @@
         (lambda (_command) t))
        ((symbol-function 'process-lines)
         (lambda (_program &rest _args)
-          (error "some error"))))
+          (error "Some error"))))
     (should-not (sql-postgres-list-databases))))
 
 ;;; Check Connection Password Handling/Wallet
@@ -63,52 +64,49 @@ Identify tests by ID.  Set :sql-login dialect attribute to
 LOGIN-PARAMS.  Provide the CONNECTION parameters and the EXPECTED
 string of values passed to the comint function for validation."
   (declare (indent 2))
-  `(cl-letf
-       ((sql-test-login-params ' ,login-params)
-        ((symbol-function 'sql-comint-test)
-         (lambda (product options &optional buf-name)
-           (with-current-buffer (get-buffer-create buf-name)
-             (insert (pp-to-string (list product options sql-user sql-password 
sql-server sql-database))))))
-        ((symbol-function 'sql-run-test)
-         (lambda (&optional buffer)
-           (interactive "P")
-           (sql-product-interactive 'sqltest buffer)))
-        (sql-user nil)
-        (sql-server nil)
-        (sql-database nil)
-        (sql-product-alist
-         '((ansi)
-           (sqltest
-            :name "SqlTest"
-            :sqli-login sql-test-login-params
-            :sqli-comint-func sql-comint-test)))
-        (sql-connection-alist
-         '((,(format "test-%s" id)
-            ,@connection)))
-        (sql-password-wallet
-         (list
-          (make-temp-file
-           "sql-test-netrc" nil nil
-           (mapconcat #'identity
-                      '("machine aMachine user aUserName password \"netrc-A 
aPassword\""
-                        "machine aServer user aUserName password \"netrc-B 
aPassword\""
-                        "machine aMachine server aServer user aUserName 
password \"netrc-C aPassword\""
-                        "machine aMachine database aDatabase user aUserName 
password \"netrc-D aPassword\""
-                        "machine aDatabase user aUserName password \"netrc-E 
aPassword\""
-                        "machine aMachine server aServer database aDatabase 
user aUserName password \"netrc-F aPassword\""
-                        "machine \"aServer/aDatabase\" user aUserName password 
\"netrc-G aPassword\""
-                        ) "\n")))))
-
-     (let* ((connection ,(format "test-%s" id))
-            (buffername (format "*SQL: ERT TEST <%s>*" connection)))
-       (when (get-buffer buffername)
-         (kill-buffer buffername))
-       (sql-connect connection buffername)
-       (should (get-buffer buffername))
-       (should (string-equal (with-current-buffer buffername (buffer-string)) 
,expected))
-       (when (get-buffer buffername)
-         (kill-buffer buffername))
-       (delete-file (car sql-password-wallet)))))
+  `(ert-with-temp-file tempfile
+     :suffix "sql-test-netrc"
+     :text (concat
+            "machine aMachine user aUserName password \"netrc-A aPassword\""
+            "machine aServer user aUserName password \"netrc-B aPassword\""
+            "machine aMachine server aServer user aUserName password \"netrc-C 
aPassword\""
+            "machine aMachine database aDatabase user aUserName password 
\"netrc-D aPassword\""
+            "machine aDatabase user aUserName password \"netrc-E aPassword\""
+            "machine aMachine server aServer database aDatabase user aUserName 
password \"netrc-F aPassword\""
+            "machine \"aServer/aDatabase\" user aUserName password \"netrc-G 
aPassword\""
+            "\n")
+     (cl-letf
+         ((sql-test-login-params ' ,login-params)
+          ((symbol-function 'sql-comint-test)
+           (lambda (product options &optional buf-name)
+             (with-current-buffer (get-buffer-create buf-name)
+               (insert (pp-to-string (list product options sql-user 
sql-password sql-server sql-database))))))
+          ((symbol-function 'sql-run-test)
+           (lambda (&optional buffer)
+             (interactive "P")
+             (sql-product-interactive 'sqltest buffer)))
+          (sql-user nil)
+          (sql-server nil)
+          (sql-database nil)
+          (sql-product-alist
+           '((ansi)
+             (sqltest
+              :name "SqlTest"
+              :sqli-login sql-test-login-params
+              :sqli-comint-func sql-comint-test)))
+          (sql-connection-alist
+           '((,(format "test-%s" id)
+              ,@connection)))
+          (sql-password-wallet (list tempfile)))
+       (let* ((connection ,(format "test-%s" id))
+              (buffername (format "*SQL: ERT TEST <%s>*" connection)))
+         (when (get-buffer buffername)
+           (kill-buffer buffername))
+         (sql-connect connection buffername)
+         (should (get-buffer buffername))
+         (should (string-equal (with-current-buffer buffername 
(buffer-string)) ,expected))
+         (when (get-buffer buffername)
+           (kill-buffer buffername))))))
 
 (ert-deftest sql-test-connect ()
   "Test of basic `sql-connect'."
@@ -416,6 +414,16 @@ The ACTION will be tested after set-up of PRODUCT."
 
     (kill-buffer "*SQL: exist*")))
 
+(ert-deftest sql-tests-comint-automatic-password ()
+  (let ((sql-password nil))
+    (should-not (sql-comint-automatic-password "Password: ")))
+  (let ((sql-password ""))
+    (should-not (sql-comint-automatic-password "Password: ")))
+  (let ((sql-password "password"))
+    (should (equal "password" (sql-comint-automatic-password "Password: "))))
+  ;; Also, we shouldn't care what the password is - we rely on comint for that.
+  (let ((sql-password "password"))
+    (should (equal "password" (sql-comint-automatic-password "")))))
 
 (provide 'sql-tests)
 ;;; sql-tests.el ends here
diff --git a/test/lisp/ps-print-tests.el b/test/lisp/ps-print-tests.el
index b25e88622d..d468911dd3 100644
--- a/test/lisp/ps-print-tests.el
+++ b/test/lisp/ps-print-tests.el
@@ -34,3 +34,5 @@
    (autoloadp
     (symbol-function
      'ps-mule-initialize))))
+
+;;; ps-print-tests.el ends here
diff --git a/test/lisp/repeat-tests.el b/test/lisp/repeat-tests.el
new file mode 100644
index 0000000000..a1f9bbb173
--- /dev/null
+++ b/test/lisp/repeat-tests.el
@@ -0,0 +1,111 @@
+;;; repeat-tests.el --- Tests for repeat.el          -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Juri Linkov <juri@linkov.net>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'repeat)
+
+(defvar repeat-tests-calls nil)
+
+(defun repeat-tests-call-a (&optional arg)
+  (interactive "p")
+  (push `(,arg a) repeat-tests-calls))
+
+(defun repeat-tests-call-b (&optional arg)
+  (interactive "p")
+  (push `(,arg b) repeat-tests-calls))
+
+(defvar repeat-tests-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-x w a") 'repeat-tests-call-a)
+    map)
+  "Keymap for keys that initiate repeating sequences.")
+
+(defvar repeat-tests-repeat-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "a" 'repeat-tests-call-a)
+    (define-key map "b" 'repeat-tests-call-b)
+    map)
+  "Keymap for repeating sequences.")
+(put 'repeat-tests-call-a 'repeat-map 'repeat-tests-repeat-map)
+(put 'repeat-tests-call-b 'repeat-map 'repeat-tests-repeat-map)
+
+(defmacro with-repeat-mode (&rest body)
+  "Create environment for testing `repeat-mode'."
+  `(unwind-protect
+      (progn
+        (repeat-mode +1)
+        (with-temp-buffer
+          (save-window-excursion
+            ;; `execute-kbd-macro' applied to window only
+            (set-window-buffer nil (current-buffer))
+            (use-local-map repeat-tests-map)
+            ,@body)))
+    (repeat-mode -1)))
+
+(defun repeat-tests--check (keys calls inserted)
+  (setq repeat-tests-calls nil)
+  (delete-region (point-min) (point-max))
+  (execute-kbd-macro (kbd keys))
+  (should (equal (nreverse repeat-tests-calls) calls))
+  ;; Check for self-inserting keys
+  (should (equal (buffer-string) inserted)))
+
+(ert-deftest repeat-tests-exit-key ()
+  (with-repeat-mode
+   (let ((repeat-echo-function 'ignore))
+     (let ((repeat-exit-key nil))
+       (repeat-tests--check
+        "C-x w a b a b RET c"
+        '((1 a) (1 b) (1 a) (1 b)) "\nc"))
+     (let ((repeat-exit-key [return]))
+       (repeat-tests--check
+        "C-x w a b a b <return> c"
+        '((1 a) (1 b) (1 a) (1 b)) "c")))))
+
+(ert-deftest repeat-tests-keep-prefix ()
+  (with-repeat-mode
+   (let ((repeat-echo-function 'ignore))
+     (repeat-tests--check
+      "C-x w a b a b c"
+      '((1 a) (1 b) (1 a) (1 b)) "c")
+     (let ((repeat-keep-prefix nil))
+       (repeat-tests--check
+        "C-2 C-x w a b a b c"
+        '((2 a) (1 b) (1 a) (1 b)) "c")
+       (repeat-tests--check
+        "C-2 C-x w a C-3 c"
+        '((2 a)) "ccc"))
+     ;; TODO: fix and uncomment
+     ;; (let ((repeat-keep-prefix t))
+     ;;   (repeat-tests--check
+     ;;    "C-2 C-x w a b a b c"
+     ;;    '((2 a) (2 b) (2 a) (2 b)) "c")
+     ;;   (repeat-tests--check
+     ;;    "C-2 C-x w a C-1 C-2 b a C-3 C-4 b c"
+     ;;    '((2 a) (12 b) (12 a) (34 b)) "c"))
+     )))
+
+;; TODO: :tags '(:expensive-test)  for repeat-exit-timeout
+
+(provide 'repeat-tests)
+;;; repeat-tests.el ends here
diff --git a/test/lisp/saveplace-tests.el b/test/lisp/saveplace-tests.el
index 17199ed443..190ffb7828 100644
--- a/test/lisp/saveplace-tests.el
+++ b/test/lisp/saveplace-tests.el
@@ -21,6 +21,8 @@
 
 ;;; Commentary:
 
+;;; Code:
+
 (require 'ert)
 (require 'ert-x)
 (require 'saveplace)
@@ -39,49 +41,42 @@
 
 (ert-deftest saveplace-test-save-place-to-alist/file ()
   (save-place-mode)
-  (let* ((tmpfile (make-temp-file "emacs-test-saveplace-"))
-         (tmpfile (file-truename tmpfile))
-         (save-place-alist nil)
-         (save-place-loaded t)
-         (loc tmpfile)
-         (pos 4))
-    (unwind-protect
-        (save-window-excursion
-          (find-file loc)
-          (insert "abc") ; must insert something
-          (save-place-to-alist)
-          (should (equal save-place-alist (list (cons tmpfile pos)))))
-      (delete-file tmpfile))))
+  (ert-with-temp-file tmpfile
+    (let* ((tmpfile (file-truename tmpfile))
+           (save-place-alist nil)
+           (save-place-loaded t)
+           (loc tmpfile)
+           (pos 4))
+      (save-window-excursion
+        (find-file loc)
+        (insert "abc")                  ; must insert something
+        (save-place-to-alist)
+        (should (equal save-place-alist (list (cons tmpfile pos))))))))
 
 (ert-deftest saveplace-test-forget-unreadable-files ()
   (save-place-mode)
-  (let* ((save-place-loaded t)
-         (tmpfile (make-temp-file "emacs-test-saveplace-"))
-         (alist-orig (list (cons "/this/file/does/not/exist" 10)
-                           (cons tmpfile 1917)))
-         (save-place-alist alist-orig))
-    (unwind-protect
-        (progn
-          (save-place-forget-unreadable-files)
-          (should (equal save-place-alist (cdr alist-orig))))
-      (delete-file tmpfile))))
+  (ert-with-temp-file tmpfile
+    :suffix "-saveplace"
+    (let* ((save-place-loaded t)
+           (alist-orig (list (cons "/this/file/does/not/exist" 10)
+                             (cons tmpfile 1917)))
+           (save-place-alist alist-orig))
+      (save-place-forget-unreadable-files)
+      (should (equal save-place-alist (cdr alist-orig))))))
 
 (ert-deftest saveplace-test-place-alist-to-file ()
   (save-place-mode)
-  (let* ((tmpfile (make-temp-file "emacs-test-saveplace-"))
-         (tmpfile2 (make-temp-file "emacs-test-saveplace-"))
-         (save-place-file tmpfile)
-         (save-place-alist (list (cons tmpfile2 99))))
-    (unwind-protect
-        (progn (save-place-alist-to-file)
-               (setq save-place-alist nil)
-               (save-window-excursion
-                 (find-file save-place-file)
-                 (unwind-protect
-                     (should (string-match tmpfile2 (buffer-string)))
-                   (kill-buffer))))
-      (delete-file tmpfile)
-      (delete-file tmpfile2))))
+  (ert-with-temp-file tmpfile
+    (ert-with-temp-file tmpfile2
+      (let* ((save-place-file tmpfile)
+             (save-place-alist (list (cons tmpfile2 99))))
+        (save-place-alist-to-file)
+        (setq save-place-alist nil)
+        (save-window-excursion
+          (find-file save-place-file)
+          (unwind-protect
+              (should (string-match tmpfile2 (buffer-string)))
+            (kill-buffer)))))))
 
 (ert-deftest saveplace-test-load-alist-from-file ()
   (save-place-mode)
diff --git a/test/lisp/ses-tests.el b/test/lisp/ses-tests.el
index 04f255dcd4..9a7fb502d7 100644
--- a/test/lisp/ses-tests.el
+++ b/test/lisp/ses-tests.el
@@ -175,3 +175,5 @@ to `ses--bar' and inserting a row, makes A2 value empty, 
and `ses--bar' equal to
 
 
 (provide 'ses-tests)
+
+;;; ses-tests.el ends here
diff --git a/test/lisp/shell-tests.el b/test/lisp/shell-tests.el
index 223a18590b..342b421911 100644
--- a/test/lisp/shell-tests.el
+++ b/test/lisp/shell-tests.el
@@ -1,4 +1,4 @@
-;;; shell-tests.el  -*- lexical-binding:t -*-
+;;; shell-tests.el --- Tests for shell.el  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
 
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index 3ece61290b..742da0bde5 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -972,4 +972,4 @@ See Bug#21722."
     (should (= (length (delq nil (undo-make-selective-list 6 9))) 0))))
 
 (provide 'simple-test)
-;;; simple-test.el ends here
+;;; simple-tests.el ends here
diff --git a/test/lisp/so-long-tests/so-long-tests-helpers.el 
b/test/lisp/so-long-tests/so-long-tests-helpers.el
index dd2331e6e4..f542806ac1 100644
--- a/test/lisp/so-long-tests/so-long-tests-helpers.el
+++ b/test/lisp/so-long-tests/so-long-tests-helpers.el
@@ -106,8 +106,8 @@
 (defun so-long-tests-remember ()
   "Remember the original states of modes and variables.
 
-Call this after setting up a buffer in the normal (not so-long)
-state for its major mode, so that after triggering a so-long
+Call this after setting up a buffer in the normal (not `so-long')
+state for its major mode, so that after triggering a `so-long'
 action we can call `so-long-revert' and compare the reverted
 state against this remembered state."
   (setq so-long-tests-memory nil)
diff --git a/test/lisp/so-long-tests/spelling-tests.el 
b/test/lisp/so-long-tests/spelling-tests.el
index f778b64663..b598366ba7 100644
--- a/test/lisp/so-long-tests/spelling-tests.el
+++ b/test/lisp/so-long-tests/spelling-tests.el
@@ -23,6 +23,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'ispell)
 (require 'cl-lib)
 
@@ -50,20 +51,19 @@
     ;; The Emacs test Makefile's use of HOME=/nonexistent triggers an error
     ;; when starting the inferior ispell process, so we set HOME to a valid
     ;; (but empty) temporary directory for this test.
-    (let* ((tmpdir (make-temp-file "so-long." :dir ".ispell"))
-           (process-environment (cons (format "HOME=%s" tmpdir)
-                                      process-environment))
-           (find-spelling-mistake
-            (unwind-protect
-                (cl-letf (((symbol-function 'ispell-command-loop)
-                           (lambda (_miss _guess word _start _end)
-                             (message "Unrecognised word: %s." word)
-                             (throw 'mistake t))))
-                  (catch 'mistake
-                    (find-library "so-long")
-                    (ispell-buffer)
-                    nil))
-              (delete-directory tmpdir))))
-      (should (not find-spelling-mistake)))))
+    (ert-with-temp-file tmpdir
+      :suffix "so-long.ispell"
+      (let* ((process-environment (cons (format "HOME=%s" tmpdir)
+                                        process-environment))
+             (find-spelling-mistake
+              (cl-letf (((symbol-function 'ispell-command-loop)
+                         (lambda (_miss _guess word _start _end)
+                           (message "Unrecognised word: %s." word)
+                           (throw 'mistake t))))
+                (catch 'mistake
+                  (find-library "so-long")
+                  (ispell-buffer)
+                  nil))))
+        (should (not find-spelling-mistake))))))
 
 ;;; spelling-tests.el ends here
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index 695da10408..238c9be1ab 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -84,16 +84,237 @@
 ;;;; Keymap support.
 
 (ert-deftest subr-test-kbd ()
+  (should (equal (kbd "") ""))
   (should (equal (kbd "f") "f"))
+  (should (equal (kbd "X") "X"))
+  (should (equal (kbd "foobar") "foobar")) ; 6 characters
+  (should (equal (kbd "return") "return")) ; 6 characters
+
+  (should (equal (kbd "<F2>") [F2]))
+  (should (equal (kbd "<f1> <f2> TAB") [f1 f2 ?\t]))
+  (should (equal (kbd "<f1> RET") [f1 ?\r]))
+  (should (equal (kbd "<f1> SPC") [f1 ? ]))
   (should (equal (kbd "<f1>") [f1]))
-  (should (equal (kbd "RET") "\C-m"))
+  (should (equal (kbd "<f1>") [f1]))
+  (should (equal (kbd "[f1]") "[f1]"))
+  (should (equal (kbd "<return>") [return]))
+  (should (equal (kbd "< right >") "<right>")) ; 7 characters
+
+  ;; Modifiers:
+  (should (equal (kbd "C-x") "\C-x"))
   (should (equal (kbd "C-x a") "\C-xa"))
-  ;; Check that kbd handles both new and old style key descriptions
-  ;; (bug#45536).
+  (should (equal (kbd "C-;") [?\C-\;]))
+  (should (equal (kbd "C-a") "\C-a"))
+  (should (equal (kbd "C-c SPC") "\C-c "))
+  (should (equal (kbd "C-c TAB") "\C-c\t"))
+  (should (equal (kbd "C-c c") "\C-cc"))
+  (should (equal (kbd "C-x 4 C-f") "\C-x4\C-f"))
+  (should (equal (kbd "C-x C-f") "\C-x\C-f"))
+  (should (equal (kbd "C-M-<down>") [C-M-down]))
+  (should (equal (kbd "<C-M-down>") [C-M-down]))
+  (should (equal (kbd "C-RET") [?\C-\C-m]))
+  (should (equal (kbd "C-SPC") [?\C- ]))
+  (should (equal (kbd "C-TAB") [?\C-\t]))
+  (should (equal (kbd "C-<down>") [C-down]))
+  (should (equal (kbd "C-c C-c C-c") "\C-c\C-c\C-c"))
+
+  (should (equal (kbd "M-a") [?\M-a]))
+  (should (equal (kbd "M-<DEL>") [?\M-\d]))
+  (should (equal (kbd "M-C-a") [?\M-\C-a]))
+  (should (equal (kbd "M-ESC") [?\M-\e]))
+  (should (equal (kbd "M-RET") [?\M-\r]))
+  (should (equal (kbd "M-SPC") [?\M- ]))
+  (should (equal (kbd "M-TAB") [?\M-\t]))
+  (should (equal (kbd "M-x a") [?\M-x ?a]))
+  (should (equal (kbd "M-<up>") [M-up]))
+  (should (equal (kbd "M-c M-c M-c") [?\M-c ?\M-c ?\M-c]))
+
+  (should (equal (kbd "s-SPC") [?\s- ]))
+  (should (equal (kbd "s-a") [?\s-a]))
+  (should (equal (kbd "s-x a") [?\s-x ?a]))
+  (should (equal (kbd "s-c s-c s-c") [?\s-c ?\s-c ?\s-c]))
+
+  (should (equal (kbd "S-H-a") [?\S-\H-a]))
+  (should (equal (kbd "S-a") [?\S-a]))
+  (should (equal (kbd "S-x a") [?\S-x ?a]))
+  (should (equal (kbd "S-c S-c S-c") [?\S-c ?\S-c ?\S-c]))
+
+  (should (equal (kbd "H-<RET>") [?\H-\r]))
+  (should (equal (kbd "H-DEL") [?\H-\d]))
+  (should (equal (kbd "H-a") [?\H-a]))
+  (should (equal (kbd "H-x a") [?\H-x ?a]))
+  (should (equal (kbd "H-c H-c H-c") [?\H-c ?\H-c ?\H-c]))
+
+  (should (equal (kbd "A-H-a") [?\A-\H-a]))
+  (should (equal (kbd "A-SPC") [?\A- ]))
+  (should (equal (kbd "A-TAB") [?\A-\t]))
+  (should (equal (kbd "A-a") [?\A-a]))
+  (should (equal (kbd "A-c A-c A-c") [?\A-c ?\A-c ?\A-c]))
+
+  (should (equal (kbd "C-M-a") [?\C-\M-a]))
+  (should (equal (kbd "C-M-<up>") [C-M-up]))
+
+  ;; Special characters.
+  (should (equal (kbd "DEL") "\d"))
+  (should (equal (kbd "ESC C-a") "\e\C-a"))
+  (should (equal (kbd "ESC") "\e"))
+  (should (equal (kbd "LFD") "\n"))
+  (should (equal (kbd "NUL") "\0"))
+  (should (equal (kbd "RET") "\C-m"))
+  (should (equal (kbd "SPC") "\s"))
+  (should (equal (kbd "TAB") "\t"))
+  (should (equal (kbd "\^i") ""))
+  (should (equal (kbd "^M") "\^M"))
+
+  ;; With numbers.
+  (should (equal (kbd "\177") "\^?"))
+  (should (equal (kbd "\000") "\0"))
+  (should (equal (kbd "\\177") "\^?"))
+  (should (equal (kbd "\\000") "\0"))
+  (should (equal (kbd "C-x \\150") "\C-xh"))
+
+  ;; Multibyte
+  (should (equal (kbd "ñ") [?ñ]))
+  (should (equal (kbd "ü") [?ü]))
+  (should (equal (kbd "ö") [?ö]))
+  (should (equal (kbd "ğ") [?ğ]))
+  (should (equal (kbd "ա") [?ա]))
+  (should (equal (kbd "üüöö") [?ü ?ü ?ö ?ö]))
+  (should (equal (kbd "C-ü") [?\C-ü]))
+  (should (equal (kbd "M-ü") [?\M-ü]))
+  (should (equal (kbd "H-ü") [?\H-ü]))
+
+  ;; Handle both new and old style key descriptions (bug#45536).
   (should (equal (kbd "s-<return>") [s-return]))
   (should (equal (kbd "<s-return>") [s-return]))
   (should (equal (kbd "C-M-<return>") [C-M-return]))
-  (should (equal (kbd "<C-M-return>") [C-M-return])))
+  (should (equal (kbd "<C-M-return>") [C-M-return]))
+
+  ;; Error.
+  (should-error (kbd "C-xx"))
+  (should-error (kbd "M-xx"))
+  (should-error (kbd "M-x<TAB>"))
+
+  ;; These should be equivalent:
+  (should (equal (kbd "\C-xf") (kbd "C-x f"))))
+
+(ert-deftest subr-test-kbd-valid-p ()
+  (should (not (kbd-valid-p "")))
+  (should (kbd-valid-p "f"))
+  (should (kbd-valid-p "X"))
+  (should (not (kbd-valid-p " X")))
+  (should (kbd-valid-p "X f"))
+  (should (not (kbd-valid-p "a  b")))
+  (should (not (kbd-valid-p "foobar")))
+  (should (not (kbd-valid-p "return")))
+
+  (should (kbd-valid-p "<F2>"))
+  (should (kbd-valid-p "<f1> <f2> TAB"))
+  (should (kbd-valid-p "<f1> RET"))
+  (should (kbd-valid-p "<f1> SPC"))
+  (should (kbd-valid-p "<f1>"))
+  (should (not (kbd-valid-p "[f1]")))
+  (should (kbd-valid-p "<return>"))
+  (should (not (kbd-valid-p "< right >")))
+
+  ;; Modifiers:
+  (should (kbd-valid-p "C-x"))
+  (should (kbd-valid-p "C-x a"))
+  (should (kbd-valid-p "C-;"))
+  (should (kbd-valid-p "C-a"))
+  (should (kbd-valid-p "C-c SPC"))
+  (should (kbd-valid-p "C-c TAB"))
+  (should (kbd-valid-p "C-c c"))
+  (should (kbd-valid-p "C-x 4 C-f"))
+  (should (kbd-valid-p "C-x C-f"))
+  (should (kbd-valid-p "C-M-<down>"))
+  (should (not (kbd-valid-p "<C-M-down>")))
+  (should (kbd-valid-p "C-RET"))
+  (should (kbd-valid-p "C-SPC"))
+  (should (kbd-valid-p "C-TAB"))
+  (should (kbd-valid-p "C-<down>"))
+  (should (kbd-valid-p "C-c C-c C-c"))
+
+  (should (kbd-valid-p "M-a"))
+  (should (kbd-valid-p "M-<DEL>"))
+  (should (not (kbd-valid-p "M-C-a")))
+  (should (kbd-valid-p "C-M-a"))
+  (should (kbd-valid-p "M-ESC"))
+  (should (kbd-valid-p "M-RET"))
+  (should (kbd-valid-p "M-SPC"))
+  (should (kbd-valid-p "M-TAB"))
+  (should (kbd-valid-p "M-x a"))
+  (should (kbd-valid-p "M-<up>"))
+  (should (kbd-valid-p "M-c M-c M-c"))
+
+  (should (kbd-valid-p "s-SPC"))
+  (should (kbd-valid-p "s-a"))
+  (should (kbd-valid-p "s-x a"))
+  (should (kbd-valid-p "s-c s-c s-c"))
+
+  (should (not (kbd-valid-p "S-H-a")))
+  (should (kbd-valid-p "S-a"))
+  (should (kbd-valid-p "S-x a"))
+  (should (kbd-valid-p "S-c S-c S-c"))
+
+  (should (kbd-valid-p "H-<RET>"))
+  (should (kbd-valid-p "H-DEL"))
+  (should (kbd-valid-p "H-a"))
+  (should (kbd-valid-p "H-x a"))
+  (should (kbd-valid-p "H-c H-c H-c"))
+
+  (should (kbd-valid-p "A-H-a"))
+  (should (kbd-valid-p "A-SPC"))
+  (should (kbd-valid-p "A-TAB"))
+  (should (kbd-valid-p "A-a"))
+  (should (kbd-valid-p "A-c A-c A-c"))
+
+  (should (kbd-valid-p "C-M-a"))
+  (should (kbd-valid-p "C-M-<up>"))
+
+  ;; Special characters.
+  (should (kbd-valid-p "DEL"))
+  (should (kbd-valid-p "ESC C-a"))
+  (should (kbd-valid-p "ESC"))
+  (should (kbd-valid-p "LFD"))
+  (should (kbd-valid-p "NUL"))
+  (should (kbd-valid-p "RET"))
+  (should (kbd-valid-p "SPC"))
+  (should (kbd-valid-p "TAB"))
+  (should (not (kbd-valid-p "\^i")))
+  (should (not (kbd-valid-p "^M")))
+
+  ;; With numbers.
+  (should (not (kbd-valid-p "\177")))
+  (should (not (kbd-valid-p "\000")))
+  (should (not (kbd-valid-p "\\177")))
+  (should (not (kbd-valid-p "\\000")))
+  (should (not (kbd-valid-p "C-x \\150")))
+
+  ;; Multibyte
+  (should (kbd-valid-p "ñ"))
+  (should (kbd-valid-p "ü"))
+  (should (kbd-valid-p "ö"))
+  (should (kbd-valid-p "ğ"))
+  (should (kbd-valid-p "ա"))
+  (should (not (kbd-valid-p "üüöö")))
+  (should (kbd-valid-p "C-ü"))
+  (should (kbd-valid-p "M-ü"))
+  (should (kbd-valid-p "H-ü"))
+
+  ;; Handle both new and old style key descriptions (bug#45536).
+  (should (kbd-valid-p "s-<return>"))
+  (should (not (kbd-valid-p "<s-return>")))
+  (should (kbd-valid-p "C-M-<return>"))
+  (should (not (kbd-valid-p "<C-M-return>")))
+
+  (should (kbd-valid-p "<mouse-1>"))
+  (should (kbd-valid-p "<Scroll_Lock>"))
+
+  (should (not (kbd-valid-p "c-x")))
+  (should (not (kbd-valid-p "C-xx")))
+  (should (not (kbd-valid-p "M-xx")))
+  (should (not (kbd-valid-p "M-x<TAB>"))))
 
 (ert-deftest subr-test-define-prefix-command ()
   (define-prefix-command 'foo-prefix-map)
@@ -767,6 +988,18 @@ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19350.";
       (should-not (equal dir default-directory))
       (should (file-exists-p default-directory)))))
 
+(ert-deftest subr-test-internal--format-docstring-line ()
+  (should
+   (string= (let ((fill-column 70))
+              (internal--format-docstring-line
+               "In addition to any hooks its parent mode might have run, this \
+mode runs the hook ‘foo-bar-baz-very-long-name-indeed-mode-hook’, as the final 
\
+or penultimate step during initialization."))
+            "In addition to any hooks its parent mode might have run, this mode
+runs the hook ‘foo-bar-baz-very-long-name-indeed-mode-hook’, as the
+final or penultimate step during initialization."))
+  (should-error (internal--format-docstring-line "foo\nbar")))
+
 (ert-deftest test-ensure-list ()
   (should (equal (ensure-list nil) nil))
   (should (equal (ensure-list :foo) '(:foo)))
diff --git a/test/lisp/tar-mode-tests.el b/test/lisp/tar-mode-tests.el
index 48a127157d..6964d42318 100644
--- a/test/lisp/tar-mode-tests.el
+++ b/test/lisp/tar-mode-tests.el
@@ -47,4 +47,4 @@
 
 (provide 'tar-mode-tests)
 
-;; tar-mode-tests.el ends here
+;;; tar-mode-tests.el ends here
diff --git a/test/lisp/term-tests.el b/test/lisp/term-tests.el
index 50ac370b5b..73d39cf3b6 100644
--- a/test/lisp/term-tests.el
+++ b/test/lisp/term-tests.el
@@ -28,6 +28,65 @@
 (defvar term-height)                    ; Number of lines in window.
 (defvar term-width)                     ; Number of columns in window.
 
+(defvar yellow-fg-props
+  `( :foreground ,(face-foreground 'term-color-yellow nil 'default)
+     :background "unspecified-bg" :inverse-video nil))
+(defvar yellow-bg-props
+  `( :foreground "unspecified-fg"
+     :background ,(face-background 'term-color-yellow nil 'default)
+     :inverse-video nil))
+(defvar bright-yellow-fg-props
+  `( :foreground ,(face-foreground 'term-color-bright-yellow nil 'default)
+     :background "unspecified-bg" :inverse-video nil))
+(defvar bright-yellow-bg-props
+  `( :foreground "unspecified-fg"
+     :background ,(face-background 'term-color-bright-yellow nil 'default)
+     :inverse-video nil))
+(defvar custom-color-fg-props
+  `( :foreground "#87FFFF"
+     :background "unspecified-bg" :inverse-video nil))
+
+(defvar ansi-test-strings
+  `(("\e[33mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face `(,yellow-fg-props)))
+    ("\e[43mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face `(,yellow-bg-props)))
+    ("\e[93mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face `(,bright-yellow-fg-props)))
+    ("\e[103mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face `(,bright-yellow-bg-props)))
+    ("\e[1;33mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,yellow-fg-props term-bold))
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,bright-yellow-fg-props term-bold)))
+    ("\e[33;1mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,yellow-fg-props term-bold))
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,bright-yellow-fg-props term-bold)))
+    ("\e[1m\e[33mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,yellow-fg-props term-bold))
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,bright-yellow-fg-props term-bold)))
+    ("\e[33m\e[1mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,yellow-fg-props term-bold))
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,bright-yellow-fg-props term-bold)))
+    ("\e[38;5;3;1mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,yellow-fg-props term-bold))
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,bright-yellow-fg-props term-bold)))
+    ("\e[38;5;123;1mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,custom-color-fg-props term-bold)))
+    ("\e[38;2;135;255;255;1mHello World\e[0m"
+     ,(propertize "Hello World" 'font-lock-face
+                  `(,custom-color-fg-props term-bold)))))
+
 (defun term-test-screen-from-input (width height input &optional return-var)
   (with-temp-buffer
     (term-mode)
@@ -48,7 +107,7 @@
                 (mapc (lambda (input) (term-emulate-terminal proc input)) 
input)
               (term-emulate-terminal proc input))
       (if return-var (buffer-local-value return-var (current-buffer))
-        (buffer-substring-no-properties (point-min) (point-max))))))
+        (buffer-substring (point-min) (point-max))))))
 
 (ert-deftest term-simple-lines ()
   (skip-unless (not (memq system-type '(windows-nt ms-dos))))
@@ -77,6 +136,24 @@ first line\r_next line\r\n"))
            (term-test-screen-from-input 40 12 (let ((str (make-string 30 ?a)))
                                                 (list str str))))))
 
+(ert-deftest term-colors ()
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (pcase-dolist (`(,str ,expected) ansi-test-strings)
+    (let ((result (term-test-screen-from-input 40 12 str)))
+      (should (equal result expected))
+      (should (equal (text-properties-at 0 result)
+                     (text-properties-at 0 expected))))))
+
+(ert-deftest term-colors-bold-is-bright ()
+  (skip-unless (not (memq system-type '(windows-nt ms-dos))))
+  (let ((ansi-color-bold-is-bright t))
+    (pcase-dolist (`(,str ,expected ,bright-expected) ansi-test-strings)
+      (let ((expected (or bright-expected expected))
+            (result (term-test-screen-from-input 40 12 str)))
+        (should (equal result expected))
+        (should (equal (text-properties-at 0 result)
+                       (text-properties-at 0 expected)))))))
+
 (ert-deftest term-cursor-movement ()
   (skip-unless (not (memq system-type '(windows-nt ms-dos))))
   ;; Absolute positioning.
diff --git a/test/lisp/term/tty-colors-tests.el 
b/test/lisp/term/tty-colors-tests.el
index ba29a9c376..d0e739b5ec 100644
--- a/test/lisp/term/tty-colors-tests.el
+++ b/test/lisp/term/tty-colors-tests.el
@@ -35,4 +35,4 @@
 
 (provide 'term-tests)
 
-;;; term-tests.el ends here
+;;; tty-colors-tests.el ends here
diff --git a/test/lisp/textmodes/dns-mode-tests.el 
b/test/lisp/textmodes/dns-mode-tests.el
index 8bc48732c6..1be5291509 100644
--- a/test/lisp/textmodes/dns-mode-tests.el
+++ b/test/lisp/textmodes/dns-mode-tests.el
@@ -77,3 +77,5 @@
       (insert " ")
       (dns-mode-ipv6-to-nibbles nil)
       (should (equal (buffer-string) "8.b.d.0.1.0.0.2.ip6.arpa.  ")))))
+
+;;; dns-mode-tests.el ends here
diff --git a/test/lisp/textmodes/fill-tests.el 
b/test/lisp/textmodes/fill-tests.el
index fcc2c75709..2a1195b87e 100644
--- a/test/lisp/textmodes/fill-tests.el
+++ b/test/lisp/textmodes/fill-tests.el
@@ -76,6 +76,28 @@
                (buffer-string)
                "aaa =   baaaaaaaa aaaaaaaaaa\n         aaaaaaaaaa\n")))))
 
+(ert-deftest test-fill-end-period ()
+  (should
+   (equal
+    (with-temp-buffer
+      (text-mode)
+      (auto-fill-mode)
+      (insert "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed 
do eius.")
+      (self-insert-command 1 ?\s)
+      (buffer-string))
+    "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eius. "))
+  (should
+   (equal
+    (with-temp-buffer
+      (text-mode)
+      (auto-fill-mode)
+      (insert "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed 
do eius.Foo")
+      (forward-char -3)
+      (self-insert-command 1 ?\s)
+      (buffer-string))
+    "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
+eius. Foo")))
+
 (provide 'fill-tests)
 
 ;;; fill-tests.el ends here
diff --git a/test/lisp/textmodes/reftex-tests.el 
b/test/lisp/textmodes/reftex-tests.el
index b824e05f6d..cc5b23e1c9 100644
--- a/test/lisp/textmodes/reftex-tests.el
+++ b/test/lisp/textmodes/reftex-tests.el
@@ -24,6 +24,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 
 ;;; reftex
 (require 'reftex)
@@ -33,32 +34,31 @@
 
 (ert-deftest reftex-locate-bibliography-files ()
   "Test `reftex-locate-bibliography-files'."
-  (let ((temp-dir (make-temp-file "reftex-bib" 'dir))
-        (files '("ref1.bib" "ref2.bib"))
-        (test '(("\\addbibresource{ref1.bib}\n" . ("ref1.bib"))
-                ("\\\\addbibresource[label=x]{ref2.bib}\\n" . ("ref2.bib"))
-                ("\\begin{document}\n\\bibliographystyle{plain}\n
+  (ert-with-temp-directory temp-dir
+    (let ((files '("ref1.bib" "ref2.bib"))
+          (test '(("\\addbibresource{ref1.bib}\n" . ("ref1.bib"))
+                  ("\\\\addbibresource[label=x]{ref2.bib}\\n" . ("ref2.bib"))
+                  ("\\begin{document}\n\\bibliographystyle{plain}\n
 \\bibliography{ref1,ref2}\n\\end{document}" . ("ref1.bib" "ref2.bib"))))
-        (reftex-bibliography-commands
-         ;; Default value: See reftex-vars.el `reftex-bibliography-commands'
-         '("bibliography" "nobibliography" "setupbibtex\\[.*?database="
-           "addbibresource")))
-    (with-temp-buffer
-      (insert "test\n")
+          (reftex-bibliography-commands
+           ;; Default value: See reftex-vars.el `reftex-bibliography-commands'
+           '("bibliography" "nobibliography" "setupbibtex\\[.*?database="
+             "addbibresource")))
+      (with-temp-buffer
+        (insert "test\n")
+        (mapc
+         (lambda (file)
+           (write-region (point-min) (point-max) (expand-file-name file
+                                                                   temp-dir)))
+         files))
       (mapc
-       (lambda (file)
-        (write-region (point-min) (point-max) (expand-file-name file
-                                                                temp-dir)))
-       files))
-    (mapc
-     (lambda (data)
-       (with-temp-buffer
-         (insert (car data))
-         (let ((res (mapcar #'file-name-nondirectory
-                            (reftex-locate-bibliography-files temp-dir))))
-           (should (equal res (cdr data))))))
-     test)
-    (delete-directory temp-dir 'recursive)))
+       (lambda (data)
+         (with-temp-buffer
+           (insert (car data))
+           (let ((res (mapcar #'file-name-nondirectory
+                              (reftex-locate-bibliography-files temp-dir))))
+             (should (equal res (cdr data))))))
+       test))))
 
 (ert-deftest reftex-what-environment-test ()
   "Test `reftex-what-environment'."
@@ -102,12 +102,12 @@
   ;; reason.  (An alternative solution would be to use file-equal-p,
   ;; but I'm too lazy to do that, as one of the tests compares a
   ;; list.)
-  (let* ((temp-dir (file-truename (make-temp-file "reftex-parse" 'dir)))
-         (tex-file (expand-file-name "test.tex" temp-dir))
-         (bib-file (expand-file-name "ref.bib" temp-dir)))
-    (with-temp-buffer
-      (insert
-"\\begin{document}
+  (ert-with-temp-directory temp-dir
+    (let* ((tex-file (expand-file-name "test.tex" temp-dir))
+           (bib-file (expand-file-name "ref.bib" temp-dir)))
+      (with-temp-buffer
+        (insert
+         "\\begin{document}
 \\section{test}\\label{sec:test}
 \\subsection{subtest}
 
@@ -118,27 +118,26 @@
 \\bibliographystyle{plain}
 \\bibliography{ref}
 \\end{document}")
-      (write-region (point-min) (point-max) tex-file))
-    (with-temp-buffer
-      (insert "test\n")
-      (write-region (point-min) (point-max) bib-file))
-    (reftex-ensure-compiled-variables)
-    (let ((parsed (reftex-parse-from-file tex-file nil temp-dir)))
-      (should (equal (car parsed) `(eof ,tex-file)))
-      (pop parsed)
-      (while parsed
-        (let ((entry (pop parsed)))
-         (cond
-          ((eq (car entry) 'bib)
-           (should (string= (cadr entry) bib-file)))
-          ((eq (car entry) 'toc)) ;; ...
-          ((string= (car entry) "eq:foo"))
-          ((string= (car entry) "sec:test"))
-          ((eq (car entry) 'bof)
-           (should (string= (cadr entry) tex-file))
-           (should (null parsed)))
-          (t (should-not t)))))
-      (delete-directory temp-dir 'recursive))))
+        (write-region (point-min) (point-max) tex-file))
+      (with-temp-buffer
+        (insert "test\n")
+        (write-region (point-min) (point-max) bib-file))
+      (reftex-ensure-compiled-variables)
+      (let ((parsed (reftex-parse-from-file tex-file nil temp-dir)))
+        (should (equal (car parsed) `(eof ,tex-file)))
+        (pop parsed)
+        (while parsed
+          (let ((entry (pop parsed)))
+            (cond
+             ((eq (car entry) 'bib)
+              (should (string= (cadr entry) bib-file)))
+             ((eq (car entry) 'toc)) ;; ...
+             ((string= (car entry) "eq:foo"))
+             ((string= (car entry) "sec:test"))
+             ((eq (car entry) 'bof)
+              (should (string= (cadr entry) tex-file))
+              (should (null parsed)))
+             (t (should-not t)))))))))
 
 ;;; reftex-cite
 (require 'reftex-cite)
diff --git a/test/lisp/textmodes/texinfo-resources/fill.erts 
b/test/lisp/textmodes/texinfo-resources/fill.erts
new file mode 100644
index 0000000000..95f3b09eba
--- /dev/null
+++ b/test/lisp/textmodes/texinfo-resources/fill.erts
@@ -0,0 +1,70 @@
+Code:
+  (lambda ()
+    (texinfo-mode)
+    (fill-paragraph))
+
+Name: fill1
+Point-Char: |
+
+=-=
+@noindent Everyone is permitted to copy and distribute verbatim copies of this 
license document, but changing it is not allowed.
+=-=
+@noindent Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+=-=-=
+
+Name: fill2
+Point-Char: |
+
+=-=
+@cindex relative| remapping, faces
+@cindex base remapping, faces
+  The following functions implement a higher-level interface to 
@code{face-remapping-alist}.
+=-=-=
+
+
+Name: fill3
+Point-Char: |
+
+=-=
+@cindex relative remapping, faces
+@cindex base remapping, faces|
+  The following functions implement a higher-level interface to 
@code{face-remapping-alist}.
+=-=-=
+
+Name: fill4
+Point-Char: |
+
+=-=
+@cindex relative remapping, faces
+@cindex base remapping, faces
+  The following functions| implement a higher-level interface to 
@code{face-remapping-alist}.
+=-=
+@cindex relative remapping, faces
+@cindex base remapping, faces
+  The following functions| implement a higher-level interface to
+@code{face-remapping-alist}.
+=-=-=
+
+Name: fill5
+Point-Char: |
+
+=-=
+@defun face-remap-add-relative face &rest specs
+|This function adds the face spec in @var{specs} as relative
+remappings for face @var{face} in the current buffer.  The remaining
+arguments, @var{specs}, should form either a list of face names, or a
+property list of attribute/value pairs.
+=-=
+@defun face-remap-add-relative face &rest specs
+This function adds the face spec in @var{specs} as relative remappings
+for face @var{face} in the current buffer.  The remaining arguments,
+@var{specs}, should form either a list of face names, or a property
+list of attribute/value pairs.
+=-=-=
+
+Name: fill6
+
+=-=
+@subsection This is a very very very very very very very very very very long 
subsection name
+=-=-=
diff --git a/test/src/charset-tests.el b/test/lisp/textmodes/texinfo-tests.el
similarity index 69%
copy from test/src/charset-tests.el
copy to test/lisp/textmodes/texinfo-tests.el
index 5c46627c16..fa0c4de005 100644
--- a/test/src/charset-tests.el
+++ b/test/lisp/textmodes/texinfo-tests.el
@@ -1,6 +1,6 @@
-;;; charset-tests.el --- Tests for charset.c -*- lexical-binding: t -*-
+;;; texinfo-tests.el --- Tests for texinfo.el  -*- lexical-binding: t; -*-
 
-;; Copyright 2017-2021 Free Software Foundation, Inc.
+;; Copyright (C) 2021 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -17,12 +17,17 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Commentary:
+
+;;
+
 ;;; Code:
 
+(require 'texinfo)
 (require 'ert)
+(require 'ert-x)
 
-(ert-deftest charset-decode-char ()
-  "Test decode-char."
-  (should-error (decode-char 'ascii 0.5)))
+(ert-deftest test-filling ()
+  (ert-test-erts-file (ert-resource-file "fill.erts")))
 
-(provide 'charset-tests)
+;;; texinfo-tests.el ends here
diff --git a/test/lisp/thingatpt-tests.el b/test/lisp/thingatpt-tests.el
index 1849480347..2a32dc57b1 100644
--- a/test/lisp/thingatpt-tests.el
+++ b/test/lisp/thingatpt-tests.el
@@ -70,7 +70,7 @@
     ;; UUID, only hex is allowed
     ("01234567-89ab-cdef-ABCD-EF0123456789" 1 uuid 
"01234567-89ab-cdef-ABCD-EF0123456789")
     ("01234567-89ab-cdef-ABCD-EF012345678G" 1 uuid nil))
-  "List of thing-at-point tests.
+  "List of `thing-at-point' tests.
 Each list element should have the form
 
   (STRING POS THING RESULT)
@@ -231,4 +231,4 @@ position to retrieve THING.")
     (goto-char 5)
     (should (eq (symbol-at-point) 'bar))))
 
-;;; thingatpt.el ends here
+;;; thingatpt-tests.el ends here
diff --git a/test/lisp/thumbs-tests.el b/test/lisp/thumbs-tests.el
index ee09613845..a9b41d7c00 100644
--- a/test/lisp/thumbs-tests.el
+++ b/test/lisp/thumbs-tests.el
@@ -20,15 +20,13 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'thumbs)
 
 (ert-deftest thumbs-tests-thumbsdir/create-if-missing ()
-  (let ((thumbs-thumbsdir (make-temp-file "thumbs-test" t)))
-    (unwind-protect
-        (progn
-          (delete-directory thumbs-thumbsdir)
-          (should (file-directory-p (thumbs-thumbsdir))))
-      (delete-directory thumbs-thumbsdir))))
+  (ert-with-temp-directory thumbs-thumbsdir
+    (delete-directory thumbs-thumbsdir)
+    (should (file-directory-p (thumbs-thumbsdir)))))
 
 (provide 'thumbs-tests)
 ;;; thumbs-tests.el ends here
diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el
index 4e6fbbba92..fa9edcbd40 100644
--- a/test/lisp/time-stamp-tests.el
+++ b/test/lisp/time-stamp-tests.el
@@ -26,7 +26,7 @@
 
 (defmacro with-time-stamp-test-env (&rest body)
   "Evaluate BODY with some standard time-stamp test variables bound."
-  (declare (indent defun))
+  (declare (indent 0) (debug t))
   `(let ((user-login-name "test-logname")
          (user-full-name "100%d Tester") ;verify "%" passed unchanged
          (buffer-file-name "/emacs/test/time-stamped-file")
@@ -46,7 +46,7 @@
 
 (defmacro with-time-stamp-test-time (reference-time &rest body)
   "Force any contained time-stamp call to use time REFERENCE-TIME."
-  (declare (indent defun))
+  (declare (indent 1) (debug t))
   `(cl-letf*
          ((orig-time-stamp-string-fn (symbol-function 'time-stamp-string))
          ((symbol-function 'time-stamp-string)
@@ -56,13 +56,14 @@
 
 (defmacro with-time-stamp-system-name (name &rest body)
   "Force (system-name) to return NAME while evaluating BODY."
-  (declare (indent defun))
+  (declare (indent 1) (debug t))
   `(cl-letf (((symbol-function 'system-name)
               (lambda () ,name)))
      ,@body))
 
 (defmacro time-stamp-should-warn (form)
   "Similar to `should' but verifies that a format warning is generated."
+  (declare (debug t))
   `(let ((warning-count 0))
      (cl-letf (((symbol-function 'time-stamp-conv-warn)
                 (lambda (_old _new)
@@ -86,7 +87,7 @@
       (should (equal (time-stamp-string "%H %Z" ref-time1) "15 GMT")))))
 
 (iter-defun time-stamp-test-pattern-sequential ()
-  "Iterate through each possibility for a part of time-stamp-pattern."
+  "Iterate through each possibility for a part of `time-stamp-pattern'."
   (let ((pattern-value-parts
          '(("4/" "10/" "-4/" "0/" "")                     ;0: line limit
            ("stamp<" "")                                  ;1: start
@@ -115,7 +116,7 @@
                                     (extract-part 5))))))))))
 
 (iter-defun time-stamp-test-pattern-multiply ()
-  "Iterate through every combination of parts of time-stamp-pattern."
+  "Iterate through every combination of parts of `time-stamp-pattern'."
   (let ((line-limit-values '("" "4/"))
         (start-values '("" "stamp<"))
         (format-values '("%%" "%m"))
@@ -141,9 +142,9 @@
                            ts-format _format-lines _end-lines)
               ;; Verify that time-stamp parsed time-stamp-pattern and
               ;; called us with the correct pieces.
-              (let ((limit-number (string-to-number line-limit1)))
-                (if (equal line-limit1 "")
-                    (setq limit-number time-stamp-line-limit))
+              (let ((limit-number (if (equal line-limit1 "")
+                                      time-stamp-line-limit
+                                    (string-to-number line-limit1))))
                 (goto-char (point-min))
                 (if (> limit-number 0)
                     (should (= search-limit (line-beginning-position
@@ -761,6 +762,7 @@ and is used for testing."
   "Formats ZONE and compares it to EXPECT.
 Uses the free variables `form-string' and `pattern-mod'.
 The functions in `pattern-mod' are composed left to right."
+  (declare (debug t))
   `(let ((result ,expect))
      (dolist (fn pattern-mod)
        (setq result (funcall fn result)))
@@ -871,7 +873,7 @@ The functions in `pattern-mod' are composed left to right."
 
 (defmacro formatz-generate-tests
     (form-strings hour-mod mins-mod secs-mod big-mod secbig-mod)
-  "Defines ert-deftest tests for time formats FORM-STRINGS.
+  "Defines tests for time formats FORM-STRINGS.
 FORM-STRINGS is a list of formats, each \"%z\" or some variation thereof.
 
 Each of the remaining arguments is an unquoted list of the form
@@ -895,10 +897,11 @@ BIG-MOD is the result for offset +100 hours and modifiers 
for the other
 expected results for hours greater than 99 with a whole number of minutes.
 SECBIG-MOD is the result for offset +100 hours 30 seconds and modifiers for
 the other expected results for hours greater than 99 with non-zero seconds."
-  (declare (indent 1))
+  (declare (indent 1) (debug (&rest sexp)))
   ;; Generate a form to create a list of tests to define.  When this
   ;; macro is called, the form is evaluated, thus defining the tests.
-  (let ((ert-test-list '(list)))
+  ;; We will modify this list, so start with a list consed at runtime.
+  (let ((ert-test-list (list 'list)))
     (dolist (form-string form-strings ert-test-list)
       (nconc
        ert-test-list
diff --git a/test/lisp/time-tests.el b/test/lisp/time-tests.el
index 88b7638d91..89e6985b84 100644
--- a/test/lisp/time-tests.el
+++ b/test/lisp/time-tests.el
@@ -21,6 +21,8 @@
 
 ;;; Commentary:
 
+;;; Code:
+
 (require 'ert)
 (require 'ert-x)
 (require 'time)
diff --git a/test/lisp/timezone-tests.el b/test/lisp/timezone-tests.el
index 9f6961409e..9bbe36cfe8 100644
--- a/test/lisp/timezone-tests.el
+++ b/test/lisp/timezone-tests.el
@@ -21,6 +21,8 @@
 
 ;;; Commentary:
 
+;;; Code:
+
 (require 'ert)
 (require 'timezone)
 
diff --git a/test/lisp/url/url-handlers-test.el 
b/test/lisp/url/url-handlers-tests.el
similarity index 94%
rename from test/lisp/url/url-handlers-test.el
rename to test/lisp/url/url-handlers-tests.el
index 7e5a60363d..71e054b128 100644
--- a/test/lisp/url/url-handlers-test.el
+++ b/test/lisp/url/url-handlers-tests.el
@@ -1,4 +1,4 @@
-;;; url-handlers-test.el --- Test suite for url-handlers.el  -*- 
lexical-binding: t; -*-
+;;; url-handlers-tests.el --- Test suite for url-handlers.el  -*- 
lexical-binding: t; -*-
 
 ;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
 
@@ -73,5 +73,4 @@
     (should (equal (file-name-directory "https://foo.org/";)
                    "https://foo.org/";))))
 
-(provide 'url-handlers-test)
-;;; url-handlers-test.el ends here
+;;; url-handlers-tests.el ends here
diff --git a/test/lisp/url/url-parse-tests.el b/test/lisp/url/url-parse-tests.el
index 2418af40ac..a7f81eba8f 100644
--- a/test/lisp/url/url-parse-tests.el
+++ b/test/lisp/url/url-parse-tests.el
@@ -23,7 +23,7 @@
 ;;; Commentary:
 
 ;; Test cases covering generic URI syntax as described in RFC3986,
-;; section 3. Syntax Components and 4. Usage. See also appendix
+;; section 3. Syntax Components and 4. Usage.  See also appendix
 ;; A. Collected ABNF for URI, as the example given here are all
 ;; productions of this grammar.
 
diff --git a/test/lisp/vc/add-log-tests.el b/test/lisp/vc/add-log-tests.el
index dc2b9961c6..70e49fe57f 100644
--- a/test/lisp/vc/add-log-tests.el
+++ b/test/lisp/vc/add-log-tests.el
@@ -29,8 +29,8 @@
                                              content marker expected-defun)
   "Generate an ert test for mode-own `add-log-current-defun-function'.
 Run `add-log-current-defun' at the point where MARKER specifies
-in a buffer which content is CONTENT under major mode MODE. Then
-it compares the result with EXPECTED-DEFUN."
+in a buffer which content is CONTENT under major mode MODE.
+Then it compares the result with EXPECTED-DEFUN."
   (let ((xname (intern (concat "add-log-current-defun-test-"
                               (symbol-name name)
                               ))))
diff --git a/test/lisp/vc/diff-mode-tests.el b/test/lisp/vc/diff-mode-tests.el
index fefe50d517..909d5620de 100644
--- a/test/lisp/vc/diff-mode-tests.el
+++ b/test/lisp/vc/diff-mode-tests.el
@@ -173,35 +173,33 @@ wristwatches
 wrongheadedly
 wrongheadedness
 youthfulness
-")
-        (temp-dir (make-temp-file "diff-mode-test" 'dir)))
-
-    (let ((buf  (find-file-noselect (format "%s/%s" temp-dir "fil" )))
-          (buf2 (find-file-noselect (format "%s/%s" temp-dir "fil2"))))
-      (unwind-protect
-          (progn
-            (with-current-buffer buf  (insert fil_before)  (save-buffer))
-            (with-current-buffer buf2 (insert fil2_before) (save-buffer))
-
-            (with-temp-buffer
-              (cd temp-dir)
-              (insert patch)
-              (goto-char (point-min))
-              (diff-apply-hunk)
-              (diff-apply-hunk)
-              (diff-apply-hunk))
-
-            (should (equal (with-current-buffer buf (buffer-string))
-                           fil_after))
-            (should (equal (with-current-buffer buf2 (buffer-string))
-                           fil2_after)))
-
-        (ignore-errors
-          (with-current-buffer buf (set-buffer-modified-p nil))
-          (kill-buffer buf)
-          (with-current-buffer buf2 (set-buffer-modified-p nil))
-          (kill-buffer buf2)
-          (delete-directory temp-dir 'recursive))))))
+"))
+    (ert-with-temp-directory temp-dir
+     (let ((buf  (find-file-noselect (format "%s/%s" temp-dir "fil" )))
+           (buf2 (find-file-noselect (format "%s/%s" temp-dir "fil2"))))
+       (unwind-protect
+           (progn
+             (with-current-buffer buf  (insert fil_before)  (save-buffer))
+             (with-current-buffer buf2 (insert fil2_before) (save-buffer))
+
+             (with-temp-buffer
+               (cd temp-dir)
+               (insert patch)
+               (goto-char (point-min))
+               (diff-apply-hunk)
+               (diff-apply-hunk)
+               (diff-apply-hunk))
+
+             (should (equal (with-current-buffer buf (buffer-string))
+                            fil_after))
+             (should (equal (with-current-buffer buf2 (buffer-string))
+                            fil2_after)))
+
+         (ignore-errors
+           (with-current-buffer buf (set-buffer-modified-p nil))
+           (kill-buffer buf)
+           (with-current-buffer buf2 (set-buffer-modified-p nil))
+           (kill-buffer buf2)))))))
 
 (ert-deftest diff-mode-test-hunk-text-no-newline ()
   "Check output of `diff-hunk-text' with no newline at end of file."
@@ -481,3 +479,4 @@ baz"))))
                    '("/tmp/ange-ftp1351895K.el" "/tmp/ange-ftp13518wvE.el")))))
 
 (provide 'diff-mode-tests)
+;;; diff-mode-tests.el ends here
diff --git a/test/lisp/vc/ediff-ptch-tests.el b/test/lisp/vc/ediff-ptch-tests.el
index a464db2349..0f09616a81 100644
--- a/test/lisp/vc/ediff-ptch-tests.el
+++ b/test/lisp/vc/ediff-ptch-tests.el
@@ -22,6 +22,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'ediff-ptch)
 
 (ert-deftest ediff-ptch-test-bug25010 ()
@@ -45,34 +46,33 @@ index 6a07f80..6e8e947 100644
   "Test for https://debbugs.gnu.org/26084 ."
   (skip-unless (executable-find "git"))
   (skip-unless (executable-find ediff-patch-program))
-  (let* ((tmpdir (make-temp-file "ediff-ptch-test" t))
-         (default-directory (file-name-as-directory tmpdir))
-         (patch (make-temp-file "ediff-ptch-test"))
-         (qux (expand-file-name "qux.txt" tmpdir))
-         (bar (expand-file-name "bar.txt" tmpdir))
-         (git-program (executable-find "git")))
-    ;; Create repository.
-    (with-temp-buffer
-      (insert "qux here\n")
-      (write-region nil nil qux nil 'silent)
-      (erase-buffer)
-      (insert "bar here\n")
-      (write-region nil nil bar nil 'silent))
-    (call-process git-program nil nil nil "init")
-    (call-process git-program nil nil nil "add" ".")
-    (call-process git-program nil nil nil "commit" "-m" "Test repository.")
-    ;; Update repo., save the diff and reset to initial state.
-    (with-temp-buffer
-      (insert "foo here\n")
-      (write-region nil nil qux nil 'silent)
-      (write-region nil nil bar nil 'silent))
-    (call-process git-program nil `(:file ,patch) nil "diff")
-    (call-process git-program nil nil nil "reset" "--hard" "HEAD")
-    ;; Visit the diff file i.e., patch; extract from it the parts
-    ;; affecting just each of the files: store in patch-bar the part
-    ;; affecting 'bar', and in patch-qux the part affecting 'qux'.
-    (find-file patch)
-    (unwind-protect
+  (ert-with-temp-directory tmpdir
+    (ert-with-temp-file patch
+      (let* ((default-directory (file-name-as-directory tmpdir))
+             (qux (expand-file-name "qux.txt" tmpdir))
+             (bar (expand-file-name "bar.txt" tmpdir))
+             (git-program (executable-find "git")))
+        ;; Create repository.
+        (with-temp-buffer
+          (insert "qux here\n")
+          (write-region nil nil qux nil 'silent)
+          (erase-buffer)
+          (insert "bar here\n")
+          (write-region nil nil bar nil 'silent))
+        (call-process git-program nil nil nil "init")
+        (call-process git-program nil nil nil "add" ".")
+        (call-process git-program nil nil nil "commit" "-m" "Test repository.")
+        ;; Update repo., save the diff and reset to initial state.
+        (with-temp-buffer
+          (insert "foo here\n")
+          (write-region nil nil qux nil 'silent)
+          (write-region nil nil bar nil 'silent))
+        (call-process git-program nil `(:file ,patch) nil "diff")
+        (call-process git-program nil nil nil "reset" "--hard" "HEAD")
+        ;; Visit the diff file i.e., patch; extract from it the parts
+        ;; affecting just each of the files: store in patch-bar the part
+        ;; affecting 'bar', and in patch-qux the part affecting 'qux'.
+        (find-file patch)
         (let* ((info
                 (progn (ediff-map-patch-buffer (current-buffer)) 
ediff-patch-map))
                (patch-bar
@@ -116,9 +116,7 @@ index 6a07f80..6e8e947 100644
                             (buffer-string))
                           (with-temp-buffer
                             (insert-file-contents backup)
-                            (buffer-string)))))))
-          (delete-directory tmpdir 'recursive)
-          (delete-file patch)))))
+                            (buffer-string))))))))))))
 
 
 (provide 'ediff-ptch-tests)
diff --git a/test/lisp/vc/smerge-mode-tests.el 
b/test/lisp/vc/smerge-mode-tests.el
index 2c8f48618e..d7827c7a8c 100644
--- a/test/lisp/vc/smerge-mode-tests.el
+++ b/test/lisp/vc/smerge-mode-tests.el
@@ -34,3 +34,5 @@
     (should (equal (buffer-substring (point-min) (point-max)) ""))))
 
 (provide 'smerge-mode-tests)
+
+;;; smerge-mode-tests.el ends here
diff --git a/test/lisp/vc/vc-bzr-tests.el b/test/lisp/vc/vc-bzr-tests.el
index b02dce8f70..afced819fb 100644
--- a/test/lisp/vc/vc-bzr-tests.el
+++ b/test/lisp/vc/vc-bzr-tests.el
@@ -25,6 +25,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'vc-bzr)
 (require 'vc-dir)
 
@@ -51,106 +52,97 @@
   ;; temporary directory.
   ;; TODO does this means tests should be setting XDG_ variables (not
   ;; just HOME) to temporary values too?
-  (let* ((homedir (make-temp-file "vc-bzr-test" t))
-         (bzrdir (expand-file-name "bzr" homedir))
-         (ignored-dir (progn
-                        (make-directory bzrdir)
-                        (expand-file-name "ignored-dir" bzrdir)))
-         (default-directory (file-name-as-directory bzrdir))
-         (process-environment (cons (format "HOME=%s" homedir)
-                                    process-environment)))
-    (unwind-protect
-        (progn
-          (make-directory ignored-dir)
-          (with-temp-buffer
-            (insert (file-name-nondirectory ignored-dir))
-            (write-region nil nil (expand-file-name ".bzrignore" bzrdir)
-                          nil 'silent))
-          (skip-unless (eq 0            ; some internal bzr error
-                           (call-process vc-bzr-program nil nil nil "init")))
-          (call-process vc-bzr-program nil nil nil "add")
-          (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
-          (with-temp-buffer
-            (insert "unregistered file")
-            (write-region nil nil (expand-file-name "testfile2" ignored-dir)
-                          nil 'silent))
-          (vc-dir ignored-dir)
-          (while (vc-dir-busy)
-            (sit-for 0.1))
-          ;; FIXME better to explicitly test for error from process sentinel.
-          (with-current-buffer "*vc-dir*"
-            (goto-char (point-min))
-            (should (search-forward "unregistered" nil t))))
-      (delete-directory homedir t))))
+  (ert-with-temp-directory homedir
+    (let* ((bzrdir (expand-file-name "bzr" homedir))
+           (ignored-dir (progn
+                          (make-directory bzrdir)
+                          (expand-file-name "ignored-dir" bzrdir)))
+           (default-directory (file-name-as-directory bzrdir))
+           (process-environment (cons (format "HOME=%s" homedir)
+                                      process-environment)))
+      (make-directory ignored-dir)
+      (with-temp-buffer
+        (insert (file-name-nondirectory ignored-dir))
+        (write-region nil nil (expand-file-name ".bzrignore" bzrdir)
+                      nil 'silent))
+      (skip-unless (eq 0           ; some internal bzr error
+                       (call-process vc-bzr-program nil nil nil "init")))
+      (call-process vc-bzr-program nil nil nil "add")
+      (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
+      (with-temp-buffer
+        (insert "unregistered file")
+        (write-region nil nil (expand-file-name "testfile2" ignored-dir)
+                      nil 'silent))
+      (vc-dir ignored-dir)
+      (while (vc-dir-busy)
+        (sit-for 0.1))
+      ;; FIXME better to explicitly test for error from process sentinel.
+      (with-current-buffer "*vc-dir*"
+        (goto-char (point-min))
+        (should (search-forward "unregistered" nil t))))))
 
 ;; Not specific to bzr.
 (ert-deftest vc-bzr-test-bug9781 ()
   "Test for https://debbugs.gnu.org/9781 ."
   (skip-unless (executable-find vc-bzr-program))
-  (let* ((homedir (make-temp-file "vc-bzr-test" t))
-         (bzrdir (expand-file-name "bzr" homedir))
-         (subdir (progn
-                   (make-directory bzrdir)
-                   (expand-file-name "subdir" bzrdir)))
-         (file (expand-file-name "file" bzrdir))
-         (default-directory (file-name-as-directory bzrdir))
-         (process-environment (cons (format "HOME=%s" homedir)
-                                    process-environment)))
-    (unwind-protect
-        (progn
-          (skip-unless (eq 0            ; some internal bzr error
-                           (call-process vc-bzr-program nil nil nil "init")))
-          (make-directory subdir)
-          (with-temp-buffer
-            (insert "text")
-            (write-region nil nil file nil 'silent)
-            (write-region nil nil (expand-file-name "subfile" subdir)
-                          nil 'silent))
-          (call-process vc-bzr-program nil nil nil "add")
-          (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
-          (call-process vc-bzr-program nil nil nil "remove" subdir)
-          (with-temp-buffer
-            (insert "different text")
-            (write-region nil nil file nil 'silent))
-          (vc-dir bzrdir)
-          (while (vc-dir-busy)
-            (sit-for 0.1))
-          (vc-dir-mark-all-files t)
-          (cl-letf (((symbol-function 'y-or-n-p) (lambda (_) t)))
-            (vc-next-action nil))
-          (should (get-buffer "*vc-log*")))
-      (delete-directory homedir t))))
+  (ert-with-temp-directory homedir
+    (let* ((bzrdir (expand-file-name "bzr" homedir))
+           (subdir (progn
+                     (make-directory bzrdir)
+                     (expand-file-name "subdir" bzrdir)))
+           (file (expand-file-name "file" bzrdir))
+           (default-directory (file-name-as-directory bzrdir))
+           (process-environment (cons (format "HOME=%s" homedir)
+                                      process-environment)))
+      (skip-unless (eq 0           ; some internal bzr error
+                       (call-process vc-bzr-program nil nil nil "init")))
+      (make-directory subdir)
+      (with-temp-buffer
+        (insert "text")
+        (write-region nil nil file nil 'silent)
+        (write-region nil nil (expand-file-name "subfile" subdir)
+                      nil 'silent))
+      (call-process vc-bzr-program nil nil nil "add")
+      (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
+      (call-process vc-bzr-program nil nil nil "remove" subdir)
+      (with-temp-buffer
+        (insert "different text")
+        (write-region nil nil file nil 'silent))
+      (vc-dir bzrdir)
+      (while (vc-dir-busy)
+        (sit-for 0.1))
+      (vc-dir-mark-all-files t)
+      (cl-letf (((symbol-function 'y-or-n-p) (lambda (_) t)))
+        (vc-next-action nil))
+      (should (get-buffer "*vc-log*")))))
 
 ;; https://lists.gnu.org/r/help-gnu-emacs/2012-04/msg00145.html
 (ert-deftest vc-bzr-test-faulty-bzr-autoloads ()
   "Test we can generate autoloads in a bzr directory when bzr is faulty."
   (skip-unless (executable-find vc-bzr-program))
-  (let* ((homedir (make-temp-file "vc-bzr-test" t))
-         (bzrdir (expand-file-name "bzr" homedir))
-         (file (progn
-                 (make-directory bzrdir)
-                 (expand-file-name "foo.el" bzrdir)))
-         (default-directory (file-name-as-directory bzrdir))
-         (process-environment (cons (format "HOME=%s" homedir)
-                                    process-environment)))
-    (unwind-protect
-        (progn
-          (call-process vc-bzr-program nil nil nil "init")
-          (with-temp-buffer
-            (insert ";;;###autoload
+  (ert-with-temp-directory homedir
+    (let* ((bzrdir (expand-file-name "bzr" homedir))
+           (file (progn
+                   (make-directory bzrdir)
+                   (expand-file-name "foo.el" bzrdir)))
+           (default-directory (file-name-as-directory bzrdir))
+           (process-environment (cons (format "HOME=%s" homedir)
+                                      process-environment)))
+      (call-process vc-bzr-program nil nil nil "init")
+      (with-temp-buffer
+        (insert ";;;###autoload
 \(defun foo () \"foo\" (interactive) (message \"foo!\"))")
-            (write-region nil nil file nil 'silent))
-          (call-process vc-bzr-program nil nil nil "add")
-          (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
-          ;; Deleting dirstate ensures both that vc-bzr's status heuristic
-          ;; fails, so it has to call the external bzr status, and
-          ;; causes bzr status to fail.  This simulates a broken bzr
-          ;; installation.
-          (delete-file ".bzr/checkout/dirstate")
-          (should (progn (make-directory-autoloads
-                          default-directory
-                          (expand-file-name "loaddefs.el" bzrdir))
-                         t)))
-      (delete-directory homedir t))))
+        (write-region nil nil file nil 'silent))
+      (call-process vc-bzr-program nil nil nil "add")
+      (call-process vc-bzr-program nil nil nil "commit" "-m" "Commit 1")
+      ;; Deleting dirstate ensures both that vc-bzr's status heuristic
+      ;; fails, so it has to call the external bzr status, and
+      ;; causes bzr status to fail.  This simulates a broken bzr
+      ;; installation.
+      (delete-file ".bzr/checkout/dirstate")
+      (should (progn (make-directory-autoloads
+                      default-directory
+                      (expand-file-name "loaddefs.el" bzrdir))
+                     t)))))
 
-;;; vc-bzr.el ends here
+;;; vc-bzr-tests.el ends here
diff --git a/test/lisp/vc/vc-tests.el b/test/lisp/vc/vc-tests.el
index aa401a2391..578d7ebb41 100644
--- a/test/lisp/vc/vc-tests.el
+++ b/test/lisp/vc/vc-tests.el
@@ -109,6 +109,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'vc)
 (require 'log-edit)
 
@@ -178,41 +179,38 @@ For backends which dont support it, it is emulated."
 
 (defun vc-test--create-repo (backend)
   "Create a test repository in `default-directory', a temporary directory."
-
-  (let ((vc-handled-backends `(,backend))
-       (default-directory
-         (file-name-as-directory
-          (expand-file-name
-           (make-temp-name "vc-test") temporary-file-directory)))
-       (process-environment process-environment)
-       tempdir
-       vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--create-repo" t)
-           process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                     process-environment)))
-
-    (unwind-protect
-       (progn
-         ;; Cleanup.
-         (add-hook
-          'vc-test--cleanup-hook
-          `(lambda () (delete-directory ,default-directory 'recursive)))
-
-         ;; Check the revision granularity.
-         (should (memq (vc-test--revision-granularity-function backend)
-                       '(file repository)))
-
-         ;; Create empty repository.
-         (make-directory default-directory)
-         (should (file-directory-p default-directory))
-         (vc-test--create-repo-function backend)
-         (should (eq (vc-responsible-backend default-directory) backend)))
-
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Check the revision granularity.
+            (should (memq (vc-test--revision-granularity-function backend)
+                          '(file repository)))
+
+            ;; Create empty repository.
+            (make-directory default-directory)
+            (should (file-directory-p default-directory))
+            (vc-test--create-repo-function backend)
+            (should (eq (vc-responsible-backend default-directory) backend)))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 ;; FIXME: Why isn't there `vc-unregister'?
 (defun vc-test--unregister-function (backend file)
@@ -235,447 +233,429 @@ Catch the `vc-not-supported' error."
 (defun vc-test--register (backend)
   "Register and unregister a file.
 This checks also `vc-backend' and `vc-responsible-backend'."
-
-  (let ((vc-handled-backends `(,backend))
-       (default-directory
-         (file-name-as-directory
-          (expand-file-name
-           (make-temp-name "vc-test") temporary-file-directory)))
-       (process-environment process-environment)
-       tempdir
-       vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--register" t)
-           process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                     process-environment)))
-    (unwind-protect
-       (progn
-         ;; Cleanup.
-         (add-hook
-          'vc-test--cleanup-hook
-          `(lambda () (delete-directory ,default-directory 'recursive)))
-
-         ;; Create empty repository.
-         (make-directory default-directory)
-         (vc-test--create-repo-function backend)
-          ;; For file oriented backends CVS, RCS and SVN the backend is
-          ;; returned, and the directory is registered already.
-          (should (if (vc-backend default-directory)
-                      (vc-registered default-directory)
-                    (not (vc-registered default-directory))))
-          (should (eq (vc-responsible-backend default-directory) backend))
-
-         (let ((tmp-name1 (expand-file-name "foo" default-directory))
-               (tmp-name2 "bla"))
-           ;; Register files.  Check for it.
-           (write-region "foo" nil tmp-name1 nil 'nomessage)
-           (should (file-exists-p tmp-name1))
-            (should-not (vc-backend tmp-name1))
-            (should (eq (vc-responsible-backend tmp-name1) backend))
-           (should-not (vc-registered tmp-name1))
-
-           (write-region "bla" nil tmp-name2 nil 'nomessage)
-           (should (file-exists-p tmp-name2))
-            (should-not (vc-backend tmp-name2))
-            (should (eq (vc-responsible-backend tmp-name2) backend))
-           (should-not (vc-registered tmp-name2))
-
-           (vc-register (list backend (list tmp-name1 tmp-name2)))
-           (should (file-exists-p tmp-name1))
-            (should (eq (vc-backend tmp-name1) backend))
-            (should (eq (vc-responsible-backend tmp-name1) backend))
-           (should (vc-registered tmp-name1))
-
-           (should (file-exists-p tmp-name2))
-            (should (eq (vc-backend tmp-name2) backend))
-            (should (eq (vc-responsible-backend tmp-name2) backend))
-           (should (vc-registered tmp-name2))
-
-            ;; `vc-backend' accepts also a list of files,
-            ;; `vc-responsible-backend' doesn't.
-            (should (vc-backend (list tmp-name1 tmp-name2)))
-
-           ;; Unregister the files.
-            (unless (eq (vc-test--run-maybe-unsupported-function
-                        'vc-test--unregister-function backend tmp-name1)
-                       'vc-not-supported)
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+            ;; For file oriented backends CVS, RCS and SVN the backend is
+            ;; returned, and the directory is registered already.
+            (should (if (vc-backend default-directory)
+                        (vc-registered default-directory)
+                      (not (vc-registered default-directory))))
+            (should (eq (vc-responsible-backend default-directory) backend))
+
+            (let ((tmp-name1 (expand-file-name "foo" default-directory))
+                  (tmp-name2 "bla"))
+              ;; Register files.  Check for it.
+              (write-region "foo" nil tmp-name1 nil 'nomessage)
+              (should (file-exists-p tmp-name1))
               (should-not (vc-backend tmp-name1))
-              (should-not (vc-registered tmp-name1)))
-            (unless (eq (vc-test--run-maybe-unsupported-function
-                        'vc-test--unregister-function backend tmp-name2)
-                       'vc-not-supported)
-              (should-not (vc-backend tmp-name2))
-              (should-not (vc-registered tmp-name2)))
+              (should (eq (vc-responsible-backend tmp-name1) backend))
+              (should-not (vc-registered tmp-name1))
 
-            ;; The files should still exist.
-           (should (file-exists-p tmp-name1))
-           (should (file-exists-p tmp-name2))))
-
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+              (write-region "bla" nil tmp-name2 nil 'nomessage)
+              (should (file-exists-p tmp-name2))
+              (should-not (vc-backend tmp-name2))
+              (should (eq (vc-responsible-backend tmp-name2) backend))
+              (should-not (vc-registered tmp-name2))
+
+              (vc-register (list backend (list tmp-name1 tmp-name2)))
+              (should (file-exists-p tmp-name1))
+              (should (eq (vc-backend tmp-name1) backend))
+              (should (eq (vc-responsible-backend tmp-name1) backend))
+              (should (vc-registered tmp-name1))
+
+              (should (file-exists-p tmp-name2))
+              (should (eq (vc-backend tmp-name2) backend))
+              (should (eq (vc-responsible-backend tmp-name2) backend))
+              (should (vc-registered tmp-name2))
+
+              ;; `vc-backend' accepts also a list of files,
+              ;; `vc-responsible-backend' doesn't.
+              (should (vc-backend (list tmp-name1 tmp-name2)))
+
+              ;; Unregister the files.
+              (unless (eq (vc-test--run-maybe-unsupported-function
+                           'vc-test--unregister-function backend tmp-name1)
+                          'vc-not-supported)
+                (should-not (vc-backend tmp-name1))
+                (should-not (vc-registered tmp-name1)))
+              (unless (eq (vc-test--run-maybe-unsupported-function
+                           'vc-test--unregister-function backend tmp-name2)
+                          'vc-not-supported)
+                (should-not (vc-backend tmp-name2))
+                (should-not (vc-registered tmp-name2)))
+
+              ;; The files should still exist.
+              (should (file-exists-p tmp-name1))
+              (should (file-exists-p tmp-name2))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 (defun vc-test--state (backend)
   "Check the different states of a file."
-
-  (let ((vc-handled-backends `(,backend))
-       (default-directory
-         (file-name-as-directory
-          (expand-file-name
-           (make-temp-name "vc-test") temporary-file-directory)))
-       (process-environment process-environment)
-       tempdir
-       vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--state" t)
-           process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                     process-environment)))
-    (unwind-protect
-       (progn
-         ;; Cleanup.
-         (add-hook
-          'vc-test--cleanup-hook
-          `(lambda () (delete-directory ,default-directory 'recursive)))
-
-         ;; Create empty repository.
-         (make-directory default-directory)
-         (vc-test--create-repo-function backend)
-
-         (let ((tmp-name (expand-file-name "foo" default-directory)))
-           ;; Check state of a nonexistent file.
-
-            (message "vc-state2 %s" (vc-state tmp-name))
-           (should (null (vc-state tmp-name)))
-
-           ;; Write a new file.  Check state.
-           (write-region "foo" nil tmp-name nil 'nomessage)
-
-            ;; nil: Mtn
-            ;; unregistered: Bzr CVS Git Hg SVN RCS
-            (message "vc-state3 %s %s" backend (vc-state tmp-name backend))
-           (should (memq (vc-state tmp-name backend) '(nil unregistered)))
-
-           ;; Register a file.  Check state.
-           (vc-register
-            (list backend (list (file-name-nondirectory tmp-name))))
-
-            ;; FIXME: nil is definitely wrong.
-           ;; nil: SRC
-            ;; added: Bzr CVS Git Hg Mtn SVN
-           ;; up-to-date: RCS SCCS
-            (message "vc-state4 %s" (vc-state tmp-name))
-           (should (memq (vc-state tmp-name) '(nil added up-to-date)))
-
-           ;; Unregister the file.  Check state.
-            (if (eq (vc-test--run-maybe-unsupported-function
-                     'vc-test--unregister-function backend tmp-name)
-                    'vc-not-supported)
-                (message "vc-state5 unsupported")
-              ;; unregistered: Bzr Git RCS Hg
-              ;; unsupported: CVS Mtn SCCS SRC SVN
-              (message "vc-state5 %s %s" backend (vc-state tmp-name backend))
-              (should (memq (vc-state tmp-name backend)
-                            '(nil unregistered))))))
-
-      ;; Save exit.
-      (ignore-errors
-       (if tempdir (delete-directory tempdir t))
-       (run-hooks 'vc-test--cleanup-hook)))))
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+
+            (let ((tmp-name (expand-file-name "foo" default-directory)))
+              ;; Check state of a nonexistent file.
+
+              (message "vc-state2 %s" (vc-state tmp-name))
+              (should (null (vc-state tmp-name)))
+
+              ;; Write a new file.  Check state.
+              (write-region "foo" nil tmp-name nil 'nomessage)
+
+              ;; nil: Mtn
+              ;; unregistered: Bzr CVS Git Hg SVN RCS
+              (message "vc-state3 %s %s" backend (vc-state tmp-name backend))
+              (should (memq (vc-state tmp-name backend) '(nil unregistered)))
+
+              ;; Register a file.  Check state.
+              (vc-register
+               (list backend (list (file-name-nondirectory tmp-name))))
+
+              ;; FIXME: nil is definitely wrong.
+              ;; nil: SRC
+              ;; added: Bzr CVS Git Hg Mtn SVN
+              ;; up-to-date: RCS SCCS
+              (message "vc-state4 %s" (vc-state tmp-name))
+              (should (memq (vc-state tmp-name) '(nil added up-to-date)))
+
+              ;; Unregister the file.  Check state.
+              (if (eq (vc-test--run-maybe-unsupported-function
+                       'vc-test--unregister-function backend tmp-name)
+                      'vc-not-supported)
+                  (message "vc-state5 unsupported")
+                ;; unregistered: Bzr Git RCS Hg
+                ;; unsupported: CVS Mtn SCCS SRC SVN
+                (message "vc-state5 %s %s" backend (vc-state tmp-name backend))
+                (should (memq (vc-state tmp-name backend)
+                              '(nil unregistered))))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 (defun vc-test--working-revision (backend)
   "Check the working revision of a repository."
-
-  (let ((vc-handled-backends `(,backend))
-       (default-directory
-         (file-name-as-directory
-          (expand-file-name
-           (make-temp-name "vc-test") temporary-file-directory)))
-       (process-environment process-environment)
-       tempdir
-       vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--working-revision" t)
-           process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                     process-environment)))
-
-    (unwind-protect
-       (progn
-         ;; Cleanup.
-         (add-hook
-          'vc-test--cleanup-hook
-          `(lambda () (delete-directory ,default-directory 'recursive)))
-
-         ;; Create empty repository.  Check working revision of
-         ;; repository, should be nil.
-         (make-directory default-directory)
-         (vc-test--create-repo-function backend)
-
-          ;; FIXME: Is the value for SVN correct?
-         ;; nil: Bzr CVS Git Hg Mtn RCS SCCS SRC
-         ;; "0": SVN
-          (message
-           "vc-working-revision1 %s" (vc-working-revision default-directory))
-          (should (member (vc-working-revision default-directory) '(nil "0")))
-
-         (let ((tmp-name (expand-file-name "foo" default-directory)))
-           ;; Check initial working revision, should be nil until
-            ;; it's registered.
-
-            (message "vc-working-revision2 %s" (vc-working-revision tmp-name))
-            (should-not (vc-working-revision tmp-name))
-
-           ;; Write a new file.  Check working revision.
-           (write-region "foo" nil tmp-name nil 'nomessage)
-
-            (message "vc-working-revision3 %s" (vc-working-revision tmp-name))
-            (should-not (vc-working-revision tmp-name))
-
-           ;; Register a file.  Check working revision.
-           (vc-register
-            (list backend (list (file-name-nondirectory tmp-name))))
-
-            ;; XXX: nil is fine, at least in Git's case, because
-           ;; `vc-register' only makes the file `added' in this case.
-           ;; nil: Git Mtn
-           ;; "0": Bzr CVS Hg SRC SVN
-           ;; "1.1": RCS SCCS
-            ;; "-1": Hg versions before 5 (probably)
-            (message "vc-working-revision4 %s" (vc-working-revision tmp-name))
-            (should (member (vc-working-revision tmp-name) '(nil "0" "1.1" 
"-1")))
-
-            ;; TODO: Call `vc-checkin', and check the resulting
-            ;; working revision.  None of the return values should be
-            ;; nil then.
-
-           ;; Unregister the file.  Check working revision.
-            (if (eq (vc-test--run-maybe-unsupported-function
-                     'vc-test--unregister-function backend tmp-name)
-                    'vc-not-supported)
-                (message "vc-working-revision5 unsupported")
-              ;; nil: Bzr Git Hg RCS
-              ;; unsupported: CVS Mtn SCCS SRC SVN
-              (message "vc-working-revision5 %s" (vc-working-revision 
tmp-name))
-              (should-not (vc-working-revision tmp-name)))))
-
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.  Check working revision of
+            ;; repository, should be nil.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+
+            ;; FIXME: Is the value for SVN correct?
+            ;; nil: Bzr CVS Git Hg Mtn RCS SCCS SRC
+            ;; "0": SVN
+            (message
+             "vc-working-revision1 %s" (vc-working-revision default-directory))
+            (should (member (vc-working-revision default-directory) '(nil 
"0")))
+
+            (let ((tmp-name (expand-file-name "foo" default-directory)))
+              ;; Check initial working revision, should be nil until
+              ;; it's registered.
+
+              (message "vc-working-revision2 %s" (vc-working-revision 
tmp-name))
+              (should-not (vc-working-revision tmp-name))
+
+              ;; Write a new file.  Check working revision.
+              (write-region "foo" nil tmp-name nil 'nomessage)
+
+              (message "vc-working-revision3 %s" (vc-working-revision 
tmp-name))
+              (should-not (vc-working-revision tmp-name))
+
+              ;; Register a file.  Check working revision.
+              (vc-register
+               (list backend (list (file-name-nondirectory tmp-name))))
+
+              ;; XXX: nil is fine, at least in Git's case, because
+              ;; `vc-register' only makes the file `added' in this case.
+              ;; nil: Git Mtn
+              ;; "0": Bzr CVS Hg SRC SVN
+              ;; "1.1": RCS SCCS
+              ;; "-1": Hg versions before 5 (probably)
+              (message "vc-working-revision4 %s" (vc-working-revision 
tmp-name))
+              (should (member (vc-working-revision tmp-name) '(nil "0" "1.1" 
"-1")))
+
+              ;; TODO: Call `vc-checkin', and check the resulting
+              ;; working revision.  None of the return values should be
+              ;; nil then.
+
+              ;; Unregister the file.  Check working revision.
+              (if (eq (vc-test--run-maybe-unsupported-function
+                       'vc-test--unregister-function backend tmp-name)
+                      'vc-not-supported)
+                  (message "vc-working-revision5 unsupported")
+                ;; nil: Bzr Git Hg RCS
+                ;; unsupported: CVS Mtn SCCS SRC SVN
+                (message "vc-working-revision5 %s" (vc-working-revision 
tmp-name))
+                (should-not (vc-working-revision tmp-name)))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 (defun vc-test--checkout-model (backend)
   "Check the checkout model of a repository."
-
-  (let ((vc-handled-backends `(,backend))
-       (default-directory
-         (file-name-as-directory
-          (expand-file-name
-           (make-temp-name "vc-test") temporary-file-directory)))
-       (process-environment process-environment)
-       tempdir
-       vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--checkout-model" t)
-           process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                     process-environment)))
-
-    (unwind-protect
-       (progn
-         ;; Cleanup.
-         (add-hook
-          'vc-test--cleanup-hook
-          `(lambda () (delete-directory ,default-directory 'recursive)))
-
-         ;; Create empty repository.  Check repository checkout model.
-         (make-directory default-directory)
-         (vc-test--create-repo-function backend)
-
-         ;; Surprisingly, none of the backends returns 'announce.
-          ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
-          ;; locking: RCS SCCS
-          (message
-           "vc-checkout-model1 %s"
-           (vc-checkout-model backend default-directory))
-          (should (memq (vc-checkout-model backend default-directory)
-                       '(announce implicit locking)))
-
-         (let ((tmp-name (expand-file-name "foo" default-directory)))
-           ;; Check checkout model of a nonexistent file.
-
-           ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
-           ;; locking: RCS SCCS
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.  Check repository checkout model.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+
+            ;; Surprisingly, none of the backends returns 'announce.
+            ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
+            ;; locking: RCS SCCS
             (message
-             "vc-checkout-model2 %s" (vc-checkout-model backend tmp-name))
-           (should (memq (vc-checkout-model backend tmp-name)
-                         '(announce implicit locking)))
+             "vc-checkout-model1 %s"
+             (vc-checkout-model backend default-directory))
+            (should (memq (vc-checkout-model backend default-directory)
+                          '(announce implicit locking)))
 
-           ;; Write a new file.  Check checkout model.
-           (write-region "foo" nil tmp-name nil 'nomessage)
+            (let ((tmp-name (expand-file-name "foo" default-directory)))
+              ;; Check checkout model of a nonexistent file.
 
-           ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
-           ;; locking: RCS SCCS
-            (message
-             "vc-checkout-model3 %s" (vc-checkout-model backend tmp-name))
-           (should (memq (vc-checkout-model backend tmp-name)
-                         '(announce implicit locking)))
+              ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
+              ;; locking: RCS SCCS
+              (message
+               "vc-checkout-model2 %s" (vc-checkout-model backend tmp-name))
+              (should (memq (vc-checkout-model backend tmp-name)
+                            '(announce implicit locking)))
 
-           ;; Register a file.  Check checkout model.
-           (vc-register
-            (list backend (list (file-name-nondirectory tmp-name))))
+              ;; Write a new file.  Check checkout model.
+              (write-region "foo" nil tmp-name nil 'nomessage)
 
-           ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
-           ;; locking: RCS SCCS
-            (message
-             "vc-checkout-model4 %s" (vc-checkout-model backend tmp-name))
-           (should (memq (vc-checkout-model backend tmp-name)
-                         '(announce implicit locking)))
-
-           ;; Unregister the file.  Check checkout model.
-            (if (eq (vc-test--run-maybe-unsupported-function
-                     'vc-test--unregister-function backend tmp-name)
-                    'vc-not-supported)
-                (message "vc-checkout-model5 unsupported")
-              ;; implicit: Bzr Git Hg
-              ;; locking: RCS
-              ;; unsupported: CVS Mtn SCCS SRC SVN
+              ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
+              ;; locking: RCS SCCS
               (message
-               "vc-checkout-model5 %s" (vc-checkout-model backend tmp-name))
+               "vc-checkout-model3 %s" (vc-checkout-model backend tmp-name))
               (should (memq (vc-checkout-model backend tmp-name)
-                            '(announce implicit locking))))))
+                            '(announce implicit locking)))
 
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+              ;; Register a file.  Check checkout model.
+              (vc-register
+               (list backend (list (file-name-nondirectory tmp-name))))
+
+              ;; implicit: Bzr CVS Git Hg Mtn SRC SVN
+              ;; locking: RCS SCCS
+              (message
+               "vc-checkout-model4 %s" (vc-checkout-model backend tmp-name))
+              (should (memq (vc-checkout-model backend tmp-name)
+                            '(announce implicit locking)))
+
+              ;; Unregister the file.  Check checkout model.
+              (if (eq (vc-test--run-maybe-unsupported-function
+                       'vc-test--unregister-function backend tmp-name)
+                      'vc-not-supported)
+                  (message "vc-checkout-model5 unsupported")
+                ;; implicit: Bzr Git Hg
+                ;; locking: RCS
+                ;; unsupported: CVS Mtn SCCS SRC SVN
+                (message
+                 "vc-checkout-model5 %s" (vc-checkout-model backend tmp-name))
+                (should (memq (vc-checkout-model backend tmp-name)
+                              '(announce implicit locking))))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 (defun vc-test--rename-file (backend)
   "Check the rename-file action."
-
-  (let ((vc-handled-backends `(,backend))
-        (default-directory
-          (file-name-as-directory
-           (expand-file-name
-            (make-temp-name "vc-test") temporary-file-directory)))
-        (process-environment process-environment)
-        tempdir
-        vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--rename-file" t)
-            process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                      process-environment)))
-
-    (unwind-protect
-        (progn
-          ;; Cleanup.
-          (add-hook
-           'vc-test--cleanup-hook
-           `(lambda () (delete-directory ,default-directory 'recursive)))
-
-          ;; Create empty repository.
-          (make-directory default-directory)
-          (vc-test--create-repo-function backend)
-
-          (let ((tmp-name (expand-file-name "foo" default-directory))
-                (new-name (expand-file-name "bar" default-directory)))
-            ;; Write a new file.
-            (write-region "foo" nil tmp-name nil 'nomessage)
-
-            ;; Register it.  Renaming can fail otherwise.
-            (vc-register
-             (list backend (list (file-name-nondirectory tmp-name))))
-
-            (vc-rename-file tmp-name new-name)
-
-            (should (not (file-exists-p tmp-name)))
-            (should (file-exists-p new-name))
-
-            (should (equal (vc-state new-name)
-                           (if (memq backend '(RCS SCCS))
-                               'up-to-date
-                             'added)))))
-
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+
+            (let ((tmp-name (expand-file-name "foo" default-directory))
+                  (new-name (expand-file-name "bar" default-directory)))
+              ;; Write a new file.
+              (write-region "foo" nil tmp-name nil 'nomessage)
+
+              ;; Register it.  Renaming can fail otherwise.
+              (vc-register
+               (list backend (list (file-name-nondirectory tmp-name))))
+
+              (vc-rename-file tmp-name new-name)
+
+              (should (not (file-exists-p tmp-name)))
+              (should (file-exists-p new-name))
+
+              (should (equal (vc-state new-name)
+                             (if (memq backend '(RCS SCCS))
+                                 'up-to-date
+                               'added)))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 (declare-function log-edit-done "vc/log-edit")
 
 (defun vc-test--version-diff (backend)
   "Check the diff version of a repository."
-
-  (let ((vc-handled-backends `(,backend))
-        (default-directory
-          (file-name-as-directory
-           (expand-file-name
-            (make-temp-name "vc-test") temporary-file-directory)))
-        (process-environment process-environment)
-        tempdir
-        vc-test--cleanup-hook)
-    (when (eq backend 'Bzr)
-      (setq tempdir (make-temp-file "vc-test--version-diff" t)
-            process-environment (cons (format "BZR_HOME=%s" tempdir)
-                                      process-environment)))
-    ;; git tries various approaches to guess a user name and email,
-    ;; which can fail depending on how the system is configured.
-    ;; Eg if the user account has no GECOS, git commit can fail with
-    ;; status 128 "fatal: empty ident name".
-    (when (memq backend '(Bzr Git))
-      (setq process-environment (cons "EMAIL=john@doe.ee"
-                                      process-environment)))
-    (if (eq backend 'Git)
-        (setq process-environment (append '("GIT_AUTHOR_NAME=A"
-                                            "GIT_COMMITTER_NAME=C")
-                                          process-environment)))
-    (unwind-protect
-        (progn
-          ;; Cleanup.
-          (add-hook
-           'vc-test--cleanup-hook
-           `(lambda () (delete-directory ,default-directory 'recursive)))
-
-          ;; Create empty repository.  Check repository checkout model.
-          (make-directory default-directory)
-          (vc-test--create-repo-function backend)
-
-          (let* ((tmp-name (expand-file-name "foo" default-directory))
-                 (files (list (file-name-nondirectory tmp-name))))
-            ;; Write and register a new file.
-            (write-region "originaltext" nil tmp-name nil 'nomessage)
-            (vc-register (list backend files))
-
-            (let ((buff (find-file tmp-name)))
-              (with-current-buffer buff
+  (ert-with-temp-directory tempdir
+    (let ((vc-handled-backends `(,backend))
+          (default-directory
+           (file-name-as-directory
+            (expand-file-name
+             (make-temp-name "vc-test") temporary-file-directory)))
+          (process-environment process-environment)
+          vc-test--cleanup-hook)
+      (when (eq backend 'Bzr)
+        (setq process-environment (cons (format "BZR_HOME=%s" tempdir)
+                                        process-environment)))
+      ;; git tries various approaches to guess a user name and email,
+      ;; which can fail depending on how the system is configured.
+      ;; Eg if the user account has no GECOS, git commit can fail with
+      ;; status 128 "fatal: empty ident name".
+      (when (memq backend '(Bzr Git))
+        (setq process-environment (cons "EMAIL=john@doe.ee"
+                                        process-environment)))
+      (if (eq backend 'Git)
+          (setq process-environment (append '("GIT_AUTHOR_NAME=A"
+                                              "GIT_COMMITTER_NAME=C")
+                                            process-environment)))
+      (unwind-protect
+          (progn
+            ;; Cleanup.
+            (add-hook
+             'vc-test--cleanup-hook
+             `(lambda () (delete-directory ,default-directory 'recursive)))
+
+            ;; Create empty repository.  Check repository checkout model.
+            (make-directory default-directory)
+            (vc-test--create-repo-function backend)
+
+            (let* ((tmp-name (expand-file-name "foo" default-directory))
+                   (files (list (file-name-nondirectory tmp-name))))
+              ;; Write and register a new file.
+              (write-region "originaltext" nil tmp-name nil 'nomessage)
+              (vc-register (list backend files))
+
+              (let ((buff (find-file tmp-name)))
+                (with-current-buffer buff
+                  (progn
+                    ;; Optionally checkout file.
+                    (when (memq backend '(RCS CVS SCCS))
+                      (vc-checkout tmp-name))
+
+                    ;; Checkin file.
+                    (vc-checkin files backend)
+                    (insert "Testing vc-version-diff")
+                    (log-edit-done))))
+
+              ;; Modify file content.
+              (when (memq backend '(RCS CVS SCCS))
+                (vc-checkout tmp-name))
+              (write-region "updatedtext" nil tmp-name nil 'nomessage)
+
+              ;; Check version diff.
+              (vc-version-diff files nil nil)
+              (should (bufferp (get-buffer "*vc-diff*")))
+
+              (with-current-buffer "*vc-diff*"
                 (progn
-                  ;; Optionally checkout file.
-                  (when (memq backend '(RCS CVS SCCS))
-                    (vc-checkout tmp-name))
-
-                  ;; Checkin file.
-                  (vc-checkin files backend)
-                  (insert "Testing vc-version-diff")
-                  (log-edit-done))))
-
-            ;; Modify file content.
-            (when (memq backend '(RCS CVS SCCS))
-              (vc-checkout tmp-name))
-            (write-region "updatedtext" nil tmp-name nil 'nomessage)
-
-            ;; Check version diff.
-            (vc-version-diff files nil nil)
-            (should (bufferp (get-buffer "*vc-diff*")))
-
-            (with-current-buffer "*vc-diff*"
-              (progn
-                (let ((rawtext (buffer-substring-no-properties (point-min)
-                                                               (point-max))))
-                  (should (string-search "-originaltext" rawtext))
-                  (should (string-search "+updatedtext" rawtext)))))))
-
-      ;; Save exit.
-      (ignore-errors
-        (if tempdir (delete-directory tempdir t))
-        (run-hooks 'vc-test--cleanup-hook)))))
+                  (let ((rawtext (buffer-substring-no-properties (point-min)
+                                                                 (point-max))))
+                    (should (string-search "-originaltext" rawtext))
+                    (should (string-search "+updatedtext" rawtext)))))))
+
+        ;; Save exit.
+        (ignore-errors
+          (run-hooks 'vc-test--cleanup-hook))))))
 
 ;; Create the test cases.
 
diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el
index 96a01fc2c7..e768a16552 100644
--- a/test/lisp/wdired-tests.el
+++ b/test/lisp/wdired-tests.el
@@ -20,6 +20,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'dired)
 (require 'wdired)
 
@@ -28,104 +29,100 @@
 (ert-deftest wdired-test-bug32173-01 ()
   "Test using non-nil wdired-use-interactive-rename.
 Partially modifying a file name should succeed."
-  (let* ((test-dir (make-temp-file "test-dir-" t))
-        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
-        (replace "bar")
-        (new-file (string-replace "foo" replace test-file))
-        (wdired-use-interactive-rename t))
-    (write-region "" nil test-file nil 'silent)
-    (advice-add 'dired-query ; Don't ask confirmation to overwrite a file.
-                :override
-                (lambda (_sym _prompt &rest _args) (setq dired-query t))
-                '((name . "advice-dired-query")))
-    (let ((buf (find-file-noselect test-dir)))
-      (unwind-protect
-         (with-current-buffer buf
-           (should (equal (dired-file-name-at-point) test-file))
-           (dired-toggle-read-only)
-           (kill-region (point) (progn (search-forward ".")
-                                       (forward-char -1) (point)))
-           (insert replace)
-           (wdired-finish-edit)
-           (should (equal (dired-file-name-at-point) new-file)))
-       (if buf (kill-buffer buf))
-       (delete-directory test-dir t)))))
+  (ert-with-temp-directory test-dir
+    (let* ((test-file (concat (file-name-as-directory test-dir) "foo.c"))
+           (replace "bar")
+           (new-file (string-replace "foo" replace test-file))
+           (wdired-use-interactive-rename t))
+      (write-region "" nil test-file nil 'silent)
+      (advice-add 'dired-query ; Don't ask confirmation to overwrite a file.
+                  :override
+                  (lambda (_sym _prompt &rest _args) (setq dired-query t))
+                  '((name . "advice-dired-query")))
+      (let ((buf (find-file-noselect test-dir)))
+        (unwind-protect
+            (with-current-buffer buf
+              (should (equal (dired-file-name-at-point) test-file))
+              (dired-toggle-read-only)
+              (kill-region (point) (progn (search-forward ".")
+                                          (forward-char -1) (point)))
+              (insert replace)
+              (wdired-finish-edit)
+              (should (equal (dired-file-name-at-point) new-file)))
+          (if buf (kill-buffer buf)))))))
 
 (ert-deftest wdired-test-bug32173-02 ()
   "Test using non-nil wdired-use-interactive-rename.
 Aborting an edit should leaving original file name unchanged."
-  (let* ((test-dir (make-temp-file "test-dir-" t))
-        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
-        (wdired-use-interactive-rename t))
-    (write-region "" nil test-file nil 'silent)
-    ;; Make dired-do-create-files-regexp a noop to mimic typing C-g
-    ;; at its prompt before wdired-finish-edit returns.
-    (advice-add 'dired-do-create-files-regexp
-                :override
-                (lambda (&rest _) (ignore))
-                '((name . "advice-dired-do-create-files-regexp")))
-    (let ((buf (find-file-noselect test-dir)))
-      (unwind-protect
-         (with-current-buffer buf
-           (should (equal (dired-file-name-at-point) test-file))
-           (dired-toggle-read-only)
-           (kill-region (point) (progn (search-forward ".")
-                                       (forward-char -1) (point)))
-           (insert "bar")
-           (wdired-finish-edit)
-           (should (equal (dired-get-filename) test-file)))
-       (if buf (kill-buffer buf))
-       (delete-directory test-dir t)))))
+  (ert-with-temp-directory test-dir
+    (let* ((test-file (concat (file-name-as-directory test-dir) "foo.c"))
+           (wdired-use-interactive-rename t))
+      (write-region "" nil test-file nil 'silent)
+      ;; Make dired-do-create-files-regexp a noop to mimic typing C-g
+      ;; at its prompt before wdired-finish-edit returns.
+      (advice-add 'dired-do-create-files-regexp
+                  :override
+                  (lambda (&rest _) (ignore))
+                  '((name . "advice-dired-do-create-files-regexp")))
+      (let ((buf (find-file-noselect test-dir)))
+        (unwind-protect
+            (with-current-buffer buf
+              (should (equal (dired-file-name-at-point) test-file))
+              (dired-toggle-read-only)
+              (kill-region (point) (progn (search-forward ".")
+                                          (forward-char -1) (point)))
+              (insert "bar")
+              (wdired-finish-edit)
+              (should (equal (dired-get-filename) test-file)))
+          (if buf (kill-buffer buf)))))))
 
 (ert-deftest wdired-test-symlink-name ()
   "Test the file name of a symbolic link.
 The Dired and WDired functions returning the name should include
 only the name before the link arrow."
-  (let* ((test-dir (make-temp-file "test-dir-" t))
-         (link-name "foo"))
-    (let ((buf (find-file-noselect test-dir)))
-      (unwind-protect
-         (with-current-buffer buf
-            (skip-unless
-             ;; This check is for wdired, not symbolic links, so skip
-             ;; it when make-symbolic-link fails for any reason (like
-             ;; insufficient privileges).
-             (ignore-errors (make-symbolic-link "./bar/baz" link-name) t))
-            (revert-buffer)
-            (let* ((file-name (dired-get-filename))
-                   (dir-part (file-name-directory file-name))
-                   (lf-name (concat dir-part link-name)))
-             (should (equal file-name lf-name))
-             (dired-toggle-read-only)
-             (should (equal (wdired-get-filename) lf-name))
-             (dired-toggle-read-only)))
-       (if buf (kill-buffer buf))
-       (delete-directory test-dir t)))))
+  (ert-with-temp-directory test-dir
+    (let* ((link-name "foo"))
+      (let ((buf (find-file-noselect test-dir)))
+        (unwind-protect
+            (with-current-buffer buf
+              (skip-unless
+               ;; This check is for wdired, not symbolic links, so skip
+               ;; it when make-symbolic-link fails for any reason (like
+               ;; insufficient privileges).
+               (ignore-errors (make-symbolic-link "./bar/baz" link-name) t))
+              (revert-buffer)
+              (let* ((file-name (dired-get-filename))
+                     (dir-part (file-name-directory file-name))
+                     (lf-name (concat dir-part link-name)))
+                (should (equal file-name lf-name))
+                (dired-toggle-read-only)
+                (should (equal (wdired-get-filename) lf-name))
+                (dired-toggle-read-only)))
+          (if buf (kill-buffer buf)))))))
 
 (ert-deftest wdired-test-unfinished-edit-01 ()
   "Test editing a file name without saving the change.
 Finding the new name should be possible while still in
 wdired-mode."
-  (let* ((test-dir (make-temp-file "test-dir-" t))
-        (test-file (concat (file-name-as-directory test-dir) "foo.c"))
-        (replace "bar")
-        (new-file (string-replace "foo" replace test-file)))
-    (write-region "" nil test-file nil 'silent)
-    (let ((buf (find-file-noselect test-dir)))
-      (unwind-protect
-         (with-current-buffer buf
-           (should (equal (dired-file-name-at-point) test-file))
-           (dired-toggle-read-only)
-           (kill-region (point) (progn (search-forward ".")
-                                       (forward-char -1) (point)))
-           (insert replace)
-           (should (equal (dired-get-filename) new-file)))
-       (when buf
-         (with-current-buffer buf
-            ;; Prevent kill-buffer-query-functions from chiming in.
-           (set-buffer-modified-p nil)
-           (kill-buffer buf)))
-       (delete-directory test-dir t)))))
+  (ert-with-temp-directory test-dir
+    (let* ((test-file (concat (file-name-as-directory test-dir) "foo.c"))
+           (replace "bar")
+           (new-file (string-replace "foo" replace test-file)))
+      (write-region "" nil test-file nil 'silent)
+      (let ((buf (find-file-noselect test-dir)))
+        (unwind-protect
+            (with-current-buffer buf
+              (should (equal (dired-file-name-at-point) test-file))
+              (dired-toggle-read-only)
+              (kill-region (point) (progn (search-forward ".")
+                                          (forward-char -1) (point)))
+              (insert replace)
+              (should (equal (dired-get-filename) new-file)))
+          (when buf
+            (with-current-buffer buf
+              ;; Prevent kill-buffer-query-functions from chiming in.
+              (set-buffer-modified-p nil)
+              (kill-buffer buf))))))))
 
 (defvar server-socket-dir)
 (declare-function dired-smart-shell-command "dired-x"
@@ -139,61 +136,59 @@ dired-move-to-end-of-filename handles indicator 
characters, it
 suffices to compare the return values of dired-get-filename and
 wdired-get-filename before and after editing."
   ;; FIXME: Add a test for a door (indicator ">") only under Solaris?
-  (let* ((test-dir (make-temp-file "test-dir-" t))
-         (server-socket-dir test-dir)
-         (dired-listing-switches "-Fl")
-         (dired-ls-F-marks-symlinks (eq system-type 'darwin))
-         (buf (find-file-noselect test-dir)))
-    (unwind-protect
-        (progn
-         (with-current-buffer buf
-            (dired-create-empty-file "foo")
-            (set-file-modes "foo" (file-modes-symbolic-to-number "+x"))
-            (make-symbolic-link "foo" "bar")
-            (make-directory "foodir")
-            (require 'dired-x)
-            (dired-smart-shell-command "mkfifo foopipe")
-            (server-force-delete)
-            ;; FIXME?  This seems a heavy-handed way of making a socket.
-            (server-start)              ; Add a socket file.
-            (kill-buffer buf))
-          (dired test-dir)
-          (dired-toggle-read-only)
-          (let (names)
-            ;; Test that the file names are the same in Dired and WDired.
-            (while (not (eobp))
-              (should (equal (dired-get-filename 'no-dir t)
-                             (wdired-get-filename t)))
-              (insert "w")
-              (push (wdired-get-filename t) names)
-              (dired-next-line 1))
-            (wdired-finish-edit)
-            ;; Test that editing the file names ignores the indicator
-            ;; character.
-            (let (dir)
-              (while (and (dired-previous-line 1)
-                          (setq dir (dired-get-filename 'no-dir t)))
-                (should (equal dir (pop names)))))))
-      (kill-buffer (get-buffer test-dir))
-      (server-force-delete)
-      (delete-directory test-dir t))))
+  (ert-with-temp-directory test-dir
+    (let* ((server-socket-dir test-dir)
+           (dired-listing-switches "-Fl")
+           (dired-ls-F-marks-symlinks (eq system-type 'darwin))
+           (buf (find-file-noselect test-dir)))
+      (unwind-protect
+          (progn
+            (with-current-buffer buf
+              (dired-create-empty-file "foo")
+              (set-file-modes "foo" (file-modes-symbolic-to-number "+x"))
+              (make-symbolic-link "foo" "bar")
+              (make-directory "foodir")
+              (require 'dired-x)
+              (dired-smart-shell-command "mkfifo foopipe")
+              (server-force-delete)
+              ;; FIXME?  This seems a heavy-handed way of making a socket.
+              (server-start)             ; Add a socket file.
+              (kill-buffer buf))
+            (dired test-dir)
+            (dired-toggle-read-only)
+            (let (names)
+              ;; Test that the file names are the same in Dired and WDired.
+              (while (not (eobp))
+                (should (equal (dired-get-filename 'no-dir t)
+                               (wdired-get-filename t)))
+                (insert "w")
+                (push (wdired-get-filename t) names)
+                (dired-next-line 1))
+              (wdired-finish-edit)
+              ;; Test that editing the file names ignores the indicator
+              ;; character.
+              (let (dir)
+                (while (and (dired-previous-line 1)
+                            (setq dir (dired-get-filename 'no-dir t)))
+                  (should (equal dir (pop names)))))))
+        (kill-buffer (get-buffer test-dir))
+        (server-force-delete)))))
 
 (ert-deftest wdired-test-bug39280 ()
   "Test for https://debbugs.gnu.org/39280.";
-  (let* ((test-dir (make-temp-file "test-dir" 'dir))
-         (fname "foo")
-         (full-fname (expand-file-name fname test-dir)))
-    (make-empty-file full-fname)
-    (let ((buf (find-file-noselect test-dir)))
-      (unwind-protect
-         (with-current-buffer buf
-           (dired-toggle-read-only)
-            (dolist (old '(t nil))
-              (should (equal fname (wdired-get-filename 'nodir old)))
-              (should (equal full-fname (wdired-get-filename nil old))))
-           (wdired-finish-edit))
-       (if buf (kill-buffer buf))
-       (delete-directory test-dir t)))))
+  (ert-with-temp-directory test-dir
+    (let* ((fname "foo")
+           (full-fname (expand-file-name fname test-dir)))
+      (make-empty-file full-fname)
+      (let ((buf (find-file-noselect test-dir)))
+        (unwind-protect
+            (with-current-buffer buf
+              (dired-toggle-read-only)
+              (dolist (old '(t nil))
+                (should (equal fname (wdired-get-filename 'nodir old)))
+                (should (equal full-fname (wdired-get-filename nil old))))
+              (wdired-finish-edit))
+          (if buf (kill-buffer buf)))))))
 
 (provide 'wdired-tests)
 ;;; wdired-tests.el ends here
diff --git a/test/lisp/whitespace-tests.el b/test/lisp/whitespace-tests.el
index 9f54a4fd34..1001476a28 100644
--- a/test/lisp/whitespace-tests.el
+++ b/test/lisp/whitespace-tests.el
@@ -51,7 +51,7 @@
 ;; We cannot call whitespace-mode because it will do nothing in batch
 ;; mode.  So we call its innards instead.
 (defun whitespace-tests-whitespace-mode-on ()
-  "Turn whitespace-mode on even in batch mode."
+  "Turn `whitespace-mode' on even in batch mode."
   (whitespace-turn-on)
   (whitespace-action-when-on)
   (setq whitespace-mode t))
diff --git a/test/lisp/xml-tests.el b/test/lisp/xml-tests.el
index b00b58acfc..7c64ef39f8 100644
--- a/test/lisp/xml-tests.el
+++ b/test/lisp/xml-tests.el
@@ -78,7 +78,7 @@
     ;; Bug#16344
     "<!----><x>< /x>"
     "<a>< b/></a>")
-  "List of XML strings that should signal an error in the parser")
+  "List of XML strings that should signal an error in the parser.")
 
 (defvar xml-parse-tests--qnames
   '( ;; Test data for name expansion
@@ -199,4 +199,4 @@ Parser is called with and without 'symbol-qnames argument.")
 ;; no-byte-compile: t
 ;; End:
 
-;;; xml-parse-tests.el ends here.
+;;; xml-tests.el ends here
diff --git a/test/manual/biditest.el b/test/manual/biditest.el
index a77fc15880..c84e7ed731 100644
--- a/test/manual/biditest.el
+++ b/test/manual/biditest.el
@@ -121,3 +121,5 @@ BidiCharacterTest.txt file."
   (message "%s" (bidi-resolved-levels)))
 
 (define-key global-map [f8] #'bidi-levels)
+
+;;; biditest.el ends here
diff --git a/test/manual/cedet/ede-tests.el b/test/manual/cedet/ede-tests.el
index 2af50860c6..17618381ef 100644
--- a/test/manual/cedet/ede-tests.el
+++ b/test/manual/cedet/ede-tests.el
@@ -80,4 +80,4 @@ The search is done with the current EDE root."
     (ede-locate-file-in-project loc file)
     (data-debug-insert-object-slots loc "]")))
 
-;;; ede-test.el ends here
+;;; ede-tests.el ends here
diff --git a/test/manual/cedet/semantic-tests.el 
b/test/manual/cedet/semantic-tests.el
index 044db29cda..3e416cc6b2 100644
--- a/test/manual/cedet/semantic-tests.el
+++ b/test/manual/cedet/semantic-tests.el
@@ -271,3 +271,5 @@ tag that contains point, and return that."
                 Lcount (semantic-tag-name target)
                 (semantic-elapsed-time start nil)))
       Lcount)))
+
+;;; semantic-tests.el ends here
diff --git a/test/manual/cedet/tests/test.el b/test/manual/cedet/tests/test.el
index d1d0d1602f..34c03619f8 100644
--- a/test/manual/cedet/tests/test.el
+++ b/test/manual/cedet/tests/test.el
@@ -19,31 +19,29 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;;; Require
-;;
+;;; Code:
+
 (require 'semantic)
 (require 'eieio "../eieio")
 
 ;; tags encapsulated in eval-when-compile and eval-and-compile
 ;; should be expanded out into the outer environment.
 (eval-when-compile
-  (require 'semantic-imenu)
-  )
+  (require 'semantic-imenu))
 
 (eval-and-compile
   (defconst const-1 nil)
   (defun function-1 (arg)
-    nil)
-  )
+    nil))
 
 ;;; Functions
 ;;
 (defun a-defun (arg1 arg2 &optional arg3)
-  "doc a"
+  "Doc a."
   nil)
 
 (defun a-defun-interactive (arg1 arg2 &optional arg3)
-  "doc a that is a command"
+  "Doc a that is a command."
   (interactive "R")
   nil)
 
@@ -52,15 +50,15 @@
   nil)
 
 (defsubst a-defsubst (arg1 arg2 &optional arg3)
-  "doc a-subst"
+  "Doc a-subst."
   nil)
 
 (defmacro a-defmacro (arg1 arg2 &optional arg3)
-  "doc a-macro"
+  "Doc a-macro."
   nil)
 
 (define-overload a-overload (arg)
-  "doc a-overload"
+  "Doc a-overload."
   nil)
 
 ;;; Methods
@@ -81,16 +79,16 @@
 ;;; Variables
 ;;
 (defvar a-defvar (cons 1 2)
-  "Variable a")
+  "Variable a.")
 
 ;; FIXME: This practice is not recommended in recent Emacs.  Remove?
 (defvar a-defvar-star (cons 1 2)
-  "*User visible var a")
+  "*User visible var a.")
 
-(defconst a-defconst 'a "var doc const")
+(defconst a-defconst 'a "Var doc const.")
 
 (defcustom a-defcustom nil
-  "doc custom"
+  "Doc custom."
   :group 'a-defgroup
   :type 'boolean)
 
@@ -111,7 +109,7 @@
 
 
 (defgroup a-defgroup nil
-  "Group for `emacs-lisp' regression-test")
+  "Group for `emacs-lisp' regression-test.")
 
 ;;; Classes
 ;;
@@ -154,3 +152,5 @@
   "some value")
 
 (provide 'test)
+
+;;; test.el ends here
diff --git a/test/manual/etags/el-src/emacs/lisp/progmodes/etags.el 
b/test/manual/etags/el-src/emacs/lisp/progmodes/etags.el
index 36f6624472..86cc882546 100644
--- a/test/manual/etags/el-src/emacs/lisp/progmodes/etags.el
+++ b/test/manual/etags/el-src/emacs/lisp/progmodes/etags.el
@@ -732,7 +732,7 @@ Returns t if it visits a tags table, or nil if there are no 
more in the list."
   "Return the file name of the file whose tags point is within.
 Assumes the tags table is the current buffer.
 If RELATIVE is non-nil, file name returned is relative to tags
-table file's directory. If RELATIVE is nil, file name returned
+table file's directory.  If RELATIVE is nil, file name returned
 is complete."
   (funcall file-of-tag-function relative))
 
diff --git a/test/manual/image-size-tests.el b/test/manual/image-size-tests.el
index 44846a7a67..067a0bfc8e 100644
--- a/test/manual/image-size-tests.el
+++ b/test/manual/image-size-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Commentary:
+
 ;; To test: Load the file and eval (image-size-tests).
 ;; A non-erroring result is a success.
 
diff --git a/test/manual/image-transforms-tests.el 
b/test/manual/image-transforms-tests.el
index debb74f2ed..acbaed5c0b 100644
--- a/test/manual/image-transforms-tests.el
+++ b/test/manual/image-transforms-tests.el
@@ -174,3 +174,5 @@
     (test-scaling)
     (test-scaling-rotation)
     (goto-char (point-min))))
+
+;;; image-transforms-tests.el ends here
diff --git a/test/manual/redisplay-testsuite.el 
b/test/manual/redisplay-testsuite.el
index 8e90f2d7a5..8a4828417c 100644
--- a/test/manual/redisplay-testsuite.el
+++ b/test/manual/redisplay-testsuite.el
@@ -350,3 +350,5 @@ static unsigned char x_bits[] = {0xff, 0x81, 0xbd, 0xa5, 
0xa5, 0xbd, 0x81, 0xff
     (test-redisplay-4)
     (test-redisplay-5)
     (goto-char (point-min))))
+
+;;; redisplay-testsuite.el ends here
diff --git a/test/misc/test-custom-libs.el b/test/misc/test-custom-libs.el
index cc2be99dea..d826dfbcab 100644
--- a/test/misc/test-custom-libs.el
+++ b/test/misc/test-custom-libs.el
@@ -19,7 +19,7 @@
 
 ;;; Commentary:
 
-;; This file runs for all libraries with autoloads separate emacs
+;; This file runs for all libraries with autoloads separate Emacs
 ;; processes of the form "emacs -batch -l LIB".
 
 ;;; Code:
@@ -45,4 +45,4 @@
   (cus-test-libs t)
   (should-not cus-test-libs-errors))
 
-;;; test-custom-deps.el ends here
+;;; test-custom-libs.el ends here
diff --git a/test/src/alloc-tests.el b/test/src/alloc-tests.el
index 1324c2d3b4..5383c43603 100644
--- a/test/src/alloc-tests.el
+++ b/test/src/alloc-tests.el
@@ -58,3 +58,5 @@
     (dolist (c (list 10003 ?b 128 ?c ?d (max-char) ?e))
       (aset s 0 c)
       (should (equal s (make-string 1 c))))))
+
+;;; alloc-tests.el ends here
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index 059926ff46..7943ac2ec2 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -19,6 +19,8 @@
 
 ;;; Code:
 
+(require 'ert)
+(require 'ert-x)
 (require 'cl-lib)
 
 (ert-deftest overlay-modification-hooks-message-other-buf ()
@@ -1421,66 +1423,63 @@ with parameters from the *Messages* buffer 
modification."
     (should (= (length (overlays-in (point-min) (point-max))) 0))))
 
 (ert-deftest test-kill-buffer-auto-save-default ()
-  (let ((file (make-temp-file "ert"))
-        auto-save)
-    (should (file-exists-p file))
-    ;; Always answer yes.
-    (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_) t)))
-      (unwind-protect
-          (progn
-            (find-file file)
-            (auto-save-mode t)
-            (insert "foo\n")
-            (should buffer-auto-save-file-name)
-            (setq auto-save buffer-auto-save-file-name)
-            (do-auto-save)
-            (should (file-exists-p auto-save))
-            (kill-buffer (current-buffer))
-            (should (file-exists-p auto-save)))
-        (ignore-errors (delete-file file))
-        (when auto-save
-          (ignore-errors (delete-file auto-save)))))))
+  (ert-with-temp-file file
+    (let (auto-save)
+      ;; Always answer yes.
+      (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_) t)))
+        (unwind-protect
+            (progn
+              (find-file file)
+              (auto-save-mode t)
+              (insert "foo\n")
+              (should buffer-auto-save-file-name)
+              (setq auto-save buffer-auto-save-file-name)
+              (do-auto-save)
+              (should (file-exists-p auto-save))
+              (kill-buffer (current-buffer))
+              (should (file-exists-p auto-save)))
+          (when auto-save
+            (ignore-errors (delete-file auto-save))))))))
 
 (ert-deftest test-kill-buffer-auto-save-delete ()
-  (let ((file (make-temp-file "ert"))
-        auto-save)
-    (should (file-exists-p file))
-    (setq kill-buffer-delete-auto-save-files t)
-    ;; Always answer yes.
-    (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_) t)))
-      (unwind-protect
-          (progn
-            (find-file file)
-            (auto-save-mode t)
-            (insert "foo\n")
-            (should buffer-auto-save-file-name)
-            (setq auto-save buffer-auto-save-file-name)
-            (do-auto-save)
-            (should (file-exists-p auto-save))
-            ;; This should delete the auto-save file.
-            (kill-buffer (current-buffer))
-            (should-not (file-exists-p auto-save)))
-        (ignore-errors (delete-file file))
-        (when auto-save
-          (ignore-errors (delete-file auto-save)))))
-    ;; Answer no to deletion.
-    (cl-letf (((symbol-function #'yes-or-no-p)
-               (lambda (prompt)
-                 (not (string-search "Delete auto-save file" prompt)))))
-      (unwind-protect
-          (progn
-            (find-file file)
-            (auto-save-mode t)
-            (insert "foo\n")
-            (should buffer-auto-save-file-name)
-            (setq auto-save buffer-auto-save-file-name)
-            (do-auto-save)
-            (should (file-exists-p auto-save))
-            ;; This should not delete the auto-save file.
-            (kill-buffer (current-buffer))
-            (should (file-exists-p auto-save)))
-        (ignore-errors (delete-file file))
-        (when auto-save
-          (ignore-errors (delete-file auto-save)))))))
+  (ert-with-temp-file file
+    (let (auto-save)
+      (should (file-exists-p file))
+      (setq kill-buffer-delete-auto-save-files t)
+      ;; Always answer yes.
+      (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_) t)))
+        (unwind-protect
+            (progn
+              (find-file file)
+              (auto-save-mode t)
+              (insert "foo\n")
+              (should buffer-auto-save-file-name)
+              (setq auto-save buffer-auto-save-file-name)
+              (do-auto-save)
+              (should (file-exists-p auto-save))
+              ;; This should delete the auto-save file.
+              (kill-buffer (current-buffer))
+              (should-not (file-exists-p auto-save)))
+          (ignore-errors (delete-file file))
+          (when auto-save
+            (ignore-errors (delete-file auto-save)))))
+      ;; Answer no to deletion.
+      (cl-letf (((symbol-function #'yes-or-no-p)
+                 (lambda (prompt)
+                   (not (string-search "Delete auto-save file" prompt)))))
+        (unwind-protect
+            (progn
+              (find-file file)
+              (auto-save-mode t)
+              (insert "foo\n")
+              (should buffer-auto-save-file-name)
+              (setq auto-save buffer-auto-save-file-name)
+              (do-auto-save)
+              (should (file-exists-p auto-save))
+              ;; This should not delete the auto-save file.
+              (kill-buffer (current-buffer))
+              (should (file-exists-p auto-save)))
+          (when auto-save
+            (ignore-errors (delete-file auto-save))))))))
 
 ;;; buffer-tests.el ends here
diff --git a/test/src/casefiddle-tests.el b/test/src/casefiddle-tests.el
index 9fa54dcaf4..dbbe9f3092 100644
--- a/test/src/casefiddle-tests.el
+++ b/test/src/casefiddle-tests.el
@@ -278,4 +278,20 @@
     (with-temp-buffer
       (should-error (upcase-region nil nil t)))))
 
+(ert-deftest casefiddle-turkish ()
+  (skip-unless (member "tr_TR.utf8" (get-locale-names)))
+  ;; See bug#50752.  The point is that unibyte and multibyte strings
+  ;; are upcased differently in the "dotless i" case in Turkish,
+  ;; turning ASCII into non-ASCII, which is very unusual.
+  (with-locale-environment "tr_TR.utf8"
+    (should (string-equal (downcase "I ı") "ı ı"))
+    (should (string-equal (downcase "İ i") "i̇ i"))
+    (should (string-equal (downcase "I") "i"))
+    (should (string-equal (capitalize "bIte") "Bite"))
+    (should (string-equal (capitalize "bIté") "Bıté"))
+    (should (string-equal (capitalize "indIa") "India"))
+    ;; This does not work -- it produces "Indıa".
+    ;;(should (string-equal (capitalize "indIá") "İndıa"))
+    ))
+
 ;;; casefiddle-tests.el ends here
diff --git a/test/src/character-tests.el b/test/src/character-tests.el
index f630b32a5e..ba24d49039 100644
--- a/test/src/character-tests.el
+++ b/test/src/character-tests.el
@@ -43,3 +43,5 @@
   (should (= (string-width "áëòç" nil 4) 2))
   (should (= (string-width "הַרְבֵּה אַהֲבָה") 9))
   (should (= (string-width "הַרְבֵּה אַהֲבָה" nil 8) 4)))
+
+;;; character-tests.el ends here
diff --git a/test/src/charset-tests.el b/test/src/charset-tests.el
index 5c46627c16..23e201ad45 100644
--- a/test/src/charset-tests.el
+++ b/test/src/charset-tests.el
@@ -22,7 +22,9 @@
 (require 'ert)
 
 (ert-deftest charset-decode-char ()
-  "Test decode-char."
+  "Test `decode-char'."
   (should-error (decode-char 'ascii 0.5)))
 
 (provide 'charset-tests)
+
+;;; charset-tests.el ends here
diff --git a/test/src/coding-tests.el b/test/src/coding-tests.el
index 134f567670..1c585ea537 100644
--- a/test/src/coding-tests.el
+++ b/test/src/coding-tests.el
@@ -434,4 +434,4 @@
 ;; End:
 
 (provide 'coding-tests)
-;; coding-tests.el ends here
+;;; coding-tests.el ends here
diff --git a/test/src/comp-resources/comp-test-funcs.el 
b/test/src/comp-resources/comp-test-funcs.el
index f2a246320a..6352a7c7e9 100644
--- a/test/src/comp-resources/comp-test-funcs.el
+++ b/test/src/comp-resources/comp-test-funcs.el
@@ -202,7 +202,7 @@
 (defun comp-tests-err-arith-f ()
   (/ 1 0))
 (defun comp-tests-err-foo-f ()
-  (error "foo"))
+  (error "Foo"))
 
 (defun comp-tests-condition-case-0-f ()
   ;; Bpushhandler Bpophandler
@@ -264,7 +264,7 @@
     (% a b)))
 
 (defun comp-tests-doc-f ()
-  "A nice docstring"
+  "A nice docstring."
   t)
 
 (defun comp-test-interactive-form0-f (dir)
@@ -478,6 +478,7 @@
              (eq family 'unspecified))
       family)))
 
+;; This function doesn't have a doc string on purpose.
 (defun comp-test-46670-1-f (_)
   "foo")
 
@@ -647,7 +648,7 @@
       (?> 2))))
 
 (defun comp-test-big-interactive (filename &optional force arg load)
-  ;; Check non trivial interactive form using `byte-recompile-file'.
+  "Check non trivial interactive form using `byte-recompile-file'."
   (interactive
    (let ((file buffer-file-name)
         (file-name nil)
@@ -683,17 +684,17 @@
 
 (defun comp-test-no-return-1 (x)
   (while x
-   (error "foo")))
+   (error "Foo")))
 
 (defun comp-test-no-return-2 (x)
   (cond
    ((eql x '2) t)
-   ((error "bar") nil)))
+   ((error "Bar") nil)))
 
 (defun comp-test-no-return-3 ())
 (defun comp-test-no-return-4 (x)
   (when x
-    (error "foo")
+    (error "Foo")
     (while (comp-test-no-return-3)
       (comp-test-no-return-3))))
 
diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el
index fb9441eb66..025bc2058e 100644
--- a/test/src/comp-tests.el
+++ b/test/src/comp-tests.el
@@ -53,30 +53,32 @@
   "Compile the compiler and load it to compile it-self.
 Check that the resulting binaries do not differ."
   :tags '(:expensive-test :nativecomp)
-  (let* ((byte+native-compile t) ; FIXME HACK
-         (comp-src (expand-file-name "../../../lisp/emacs-lisp/comp.el"
+  (ert-with-temp-file comp1-src
+    :suffix "-comp-stage1.el"
+    (ert-with-temp-file comp2-src
+      :suffix "-comp-stage2.el"
+      (let* ((byte+native-compile t)     ; FIXME HACK
+             (comp-src (expand-file-name "../../../lisp/emacs-lisp/comp.el"
                                      (ert-resource-directory)))
-         (comp1-src (make-temp-file "stage1-" nil ".el"))
-         (comp2-src (make-temp-file "stage2-" nil ".el"))
-         ;; Can't use debug symbols.
-         (native-comp-debug 0))
-    (copy-file comp-src comp1-src t)
-    (copy-file comp-src comp2-src t)
-    (let ((load-no-native t))
-      (load (concat comp-src "c") nil nil t t))
-    (should-not (subr-native-elisp-p (symbol-function #'native-compile)))
-    (message "Compiling stage1...")
-    (let* ((t0 (current-time))
-           (comp1-eln (native-compile comp1-src)))
-      (message "Done in %d secs" (float-time (time-since t0)))
-      (load comp1-eln nil nil t t)
-      (should (subr-native-elisp-p (symbol-function 'native-compile)))
-      (message "Compiling stage2...")
-      (let ((t0 (current-time))
-            (comp2-eln (native-compile comp2-src)))
-        (message "Done in %d secs" (float-time (time-since t0)))
-        (message "Comparing %s %s" comp1-eln comp2-eln)
-        (should (= (call-process "cmp" nil nil nil comp1-eln comp2-eln) 0))))))
+             ;; Can't use debug symbols.
+             (native-comp-debug 0))
+        (copy-file comp-src comp1-src t)
+        (copy-file comp-src comp2-src t)
+        (let ((load-no-native t))
+          (load (concat comp-src "c") nil nil t t))
+        (should-not (subr-native-elisp-p (symbol-function #'native-compile)))
+        (message "Compiling stage1...")
+        (let* ((t0 (current-time))
+               (comp1-eln (native-compile comp1-src)))
+          (message "Done in %d secs" (float-time (time-since t0)))
+          (load comp1-eln nil nil t t)
+          (should (subr-native-elisp-p (symbol-function 'native-compile)))
+          (message "Compiling stage2...")
+          (let ((t0 (current-time))
+                (comp2-eln (native-compile comp2-src)))
+            (message "Done in %d secs" (float-time (time-since t0)))
+            (message "Comparing %s %s" comp1-eln comp2-eln)
+            (should (= (call-process "cmp" nil nil nil comp1-eln comp2-eln) 
0))))))))
 
 (comp-deftest provide ()
   "Testing top level provide."
@@ -285,7 +287,7 @@ Check that the resulting binaries do not differ."
   (should (string= (comp-tests-condition-case-0-f)
                    "arith-error Arithmetic error catched"))
   (should (string= (comp-tests-condition-case-1-f)
-                   "error foo catched"))
+                   "error Foo catched"))
   (should (= (comp-tests-catch-f
               (lambda () (throw 'foo 3)))
              3))
@@ -333,7 +335,7 @@ Check that the resulting binaries do not differ."
 
 (comp-deftest doc ()
   (should (string= (documentation #'comp-tests-doc-f)
-                   "A nice docstring"))
+                   "A nice docstring."))
   ;; Check a preloaded function, we can't use `comp-tests-doc-f' now
   ;; as this is loaded manually with no .elc.
   (should (string-match "\\.*.elc\\'" (symbol-file #'error))))
@@ -1167,7 +1169,7 @@ Return a list of results."
 
       ;; 49
       ((defun comp-tests-ret-type-spec-f ()
-         (error "foo"))
+         (error "Foo"))
        nil)
 
       ;; 50
@@ -1373,7 +1375,7 @@ Return a list of results."
 
 (defun comp-tests-pure-checker-1 (_)
   "Check that inside `comp-tests-pure-caller-f' `comp-tests-pure-callee-f' is
- folded."
+folded."
   (should
    (cl-notany
     #'identity
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index b1e5fa0767..756c41b6ff 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -26,10 +26,10 @@
 (defconst data-tests--float-greater-than-fixnums (+ 1.0 most-positive-fixnum)
   "A floating-point value that is greater than all fixnums.
 It is also as small as conveniently possible, to make the tests sharper.
-Adding 1.0 to most-positive-fixnum should suffice on all
+Adding 1.0 to `most-positive-fixnum' should suffice on all
 practical Emacs platforms, since the result is a power of 2 and
 this is exactly representable and is greater than
-most-positive-fixnum, which is just less than a power of 2.")
+`most-positive-fixnum', which is just less than a power of 2.")
 
 (ert-deftest data-tests-= ()
   (should-error (=))
@@ -204,11 +204,11 @@ most-positive-fixnum, which is just less than a power of 
2.")
                "")))
 
 (defun test-bool-vector-count-consecutive-tc (desc)
-  "Run a test case for bool-vector-count-consecutive.
+  "Run a test case for `bool-vector-count-consecutive'.
 DESC is a string describing the test.  It is a sequence of
 hexadecimal digits describing the bool vector.  We exhaustively
 test all counts at all possible positions in the vector by
-comparing the subr with a much slower lisp implementation."
+comparing the subr with a much slower Lisp implementation."
   (let ((bv (test-bool-vector-bv-from-hex-string desc)))
     (cl-loop
      for lf in '(nil t)
@@ -338,7 +338,7 @@ comparing the subr with a much slower lisp implementation."
     (should (eq binding-test-some-local 'local))))
 
 (ert-deftest binding-test-setq-default ()
-  "Test that a setq-default has no effect when there is a local binding."
+  "Test that a `setq-default' has no effect when there is a local binding."
   (with-current-buffer binding-test-buffer-B
     ;; This variable is not local in this buffer.
     (let ((binding-test-some-local 'something-else))
@@ -399,28 +399,28 @@ comparing the subr with a much slower lisp 
implementation."
                   (eq binding-test-some-local 'outer))))))
 
 (ert-deftest binding-test-defvar-bool ()
-  "Test DEFVAR_BOOL"
+  "Test DEFVAR_BOOL."
   (let ((display-hourglass 5))
     (should (eq display-hourglass t))))
 
 (ert-deftest binding-test-defvar-int ()
-  "Test DEFVAR_INT"
+  "Test DEFVAR_INT."
   (should-error (setq gc-cons-threshold 5.0) :type 'wrong-type-argument))
 
 (ert-deftest binding-test-set-constant-t ()
-  "Test setting the constant t"
+  "Test setting the constant t."
   (with-no-warnings (should-error (setq t 'bob) :type 'setting-constant)))
 
 (ert-deftest binding-test-set-constant-nil ()
-  "Test setting the constant nil"
+  "Test setting the constant nil."
   (with-no-warnings (should-error (setq nil 'bob) :type 'setting-constant)))
 
 (ert-deftest binding-test-set-constant-keyword ()
-  "Test setting a keyword constant"
+  "Test setting a keyword constant."
   (with-no-warnings (should-error (setq :keyword 'bob) :type 
'setting-constant)))
 
 (ert-deftest binding-test-set-constant-nil ()
-  "Test setting a keyword to itself"
+  "Test setting a keyword to itself."
   (with-no-warnings (should (setq :keyword :keyword))))
 
 (ert-deftest data-tests--set-default-per-buffer ()
@@ -757,7 +757,7 @@ comparing the subr with a much slower lisp implementation."
   ;;   forwarding, but this needs to happen before the var is accessed
   ;;   from the Lisp side and before we switch to another buffer.
   ;; The trigger in bug#34318 doesn't exist any more because the C code has
-  ;; changes.  Instead I found the trigger below.
+  ;; changed.  Instead I found the trigger below.
   (with-temp-buffer
     (setq last-coding-system-used 'bug34318)
     (make-local-variable 'last-coding-system-used)
diff --git a/test/src/decompress-tests.el b/test/src/decompress-tests.el
index 520445cca5..1d25cf2f66 100644
--- a/test/src/decompress-tests.el
+++ b/test/src/decompress-tests.el
@@ -42,4 +42,4 @@
 
 (provide 'decompress-tests)
 
-;;; decompress-tests.el ends here.
+;;; decompress-tests.el ends here
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index a731a95ccf..e83dd7c857 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -23,16 +23,16 @@
 
 (ert-deftest format-properties ()
   ;; Bug #23730
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (propertize "%d" 'face '(:background "red")) 1)
            #("1" 0 1 (face (:background "red")))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (propertize "%2d" 'face '(:background "red")) 1)
            #(" 1" 0 2 (face (:background "red")))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (propertize "%02d" 'face '(:background "red")) 1)
            #("01" 0 2 (face (:background "red")))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (concat (propertize "%2d" 'x 'X)
                            (propertize "a" 'a 'A)
                            (propertize "b" 'b 'B))
@@ -40,27 +40,27 @@
            #(" 1ab" 0 2 (x X) 2 3 (a A) 3 4 (b B))))
 
   ;; Bug #5306
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%.10s"
                    (concat "1234567890aaaa"
                            (propertize "12345678901234567890" 'xxx 25)))
            "1234567890"))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%.10s"
                    (concat "123456789"
                            (propertize "12345678901234567890" 'xxx 25)))
            #("1234567891" 9 10 (xxx 25))))
 
   ;; Bug #23859
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%4s" (propertize "hi" 'face 'bold))
            #("  hi" 2 4 (face bold))))
 
   ;; Bug #23897
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%s" (concat (propertize "01234" 'face 'bold) "56789"))
            #("0123456789" 0 5 (face bold))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%s" (concat (propertize "01" 'face 'bold)
                                 (propertize "23" 'face 'underline)
                                 "45"))
@@ -68,63 +68,63 @@
   ;; The last property range is extended to include padding on the
   ;; right, but the first range is not extended to the left to include
   ;; padding on the left!
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%12s" (concat (propertize "01234" 'face 'bold) "56789"))
            #("  0123456789" 2 7 (face bold))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%-12s" (concat (propertize "01234" 'face 'bold) "56789"))
            #("0123456789  " 0 5 (face bold))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%10s" (concat (propertize "01" 'face 'bold)
                                   (propertize "23" 'face 'underline)
                                   "45"))
            #("    012345" 4 6 (face bold) 6 8 (face underline))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%-10s" (concat (propertize "01" 'face 'bold)
                                    (propertize "23" 'face 'underline)
                                    "45"))
            #("012345    " 0 2 (face bold) 2 4 (face underline))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format "%-10s" (concat (propertize "01" 'face 'bold)
                                    (propertize "23" 'face 'underline)
                                    (propertize "45" 'face 'italic)))
            #("012345    "
              0 2 (face bold) 2 4 (face underline) 4 10 (face italic))))
   ;; Bug #38191
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (propertize "‘foo’ %s bar" 'face 'bold) "xxx")
            #("‘foo’ xxx bar" 0 13 (face bold))))
   ;; Bug #32404
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (concat (propertize "%s" 'face 'bold)
                            ""
                            (propertize "%s" 'face 'error))
                    "foo" "bar")
            #("foobar" 0 3 (face bold) 3 6 (face error))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (concat "%s" (propertize "%s" 'face 'error)) "foo" "bar")
            #("foobar" 3 6 (face error))))
-  (should (ert-equal-including-properties
+  (should (equal-including-properties
            (format (concat "%s " (propertize "%s" 'face 'error)) "foo" "bar")
            #("foo bar" 4 7 (face error))))
   ;; Bug #46317
   (let ((s (propertize "X" 'prop "val")))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%3s/" s) 12)
              #(" 12/X" 4 5 (prop "val"))))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%3S/" s) 12)
              #(" 12/X" 4 5 (prop "val"))))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%3d/" s) 12)
              #(" 12/X" 4 5 (prop "val"))))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%-3s/" s) 12)
              #("12 /X" 4 5 (prop "val"))))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%-3S/" s) 12)
              #("12 /X" 4 5 (prop "val"))))
-    (should (ert-equal-including-properties
+    (should (equal-including-properties
              (format (concat "%-3d/" s) 12)
              #("12 /X" 4 5 (prop "val"))))))
 
diff --git a/test/src/emacs-module-resources/mod-test.c 
b/test/src/emacs-module-resources/mod-test.c
index 5720af8c60..4c0b168e34 100644
--- a/test/src/emacs-module-resources/mod-test.c
+++ b/test/src/emacs-module-resources/mod-test.c
@@ -298,7 +298,10 @@ Fmod_test_userptr_make (emacs_env *env, ptrdiff_t nargs, 
emacs_value args[],
 {
   struct super_struct *p = calloc (1, sizeof *p);
   if (!p)
-    signal_errno (env, "calloc");
+    {
+      signal_errno (env, "calloc");
+      return NULL;
+    }
   p->amazing_int = env->extract_integer (env, args[0]);
   return env->make_user_ptr (env, free, p);
 }
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el
index 646c7bb270..442bca5fac 100644
--- a/test/src/emacs-module-tests.el
+++ b/test/src/emacs-module-tests.el
@@ -32,6 +32,11 @@
 (require 'help-fns)
 (require 'subr-x)
 
+;; Catch information for bug#50902.
+(when (getenv "EMACS_EMBA_CI")
+  (start-process-shell-command
+   "*timeout*" nil (format "sleep 60; kill -ABRT %d" (emacs-pid))))
+
 (defconst mod-test-emacs
   (expand-file-name invocation-name invocation-directory)
   "File name of the Emacs binary currently running.")
@@ -206,20 +211,6 @@ changes."
   (should (equal (help-function-arglist #'mod-test-sum)
                  '(arg1 arg2))))
 
-(defmacro module--with-temp-directory (name &rest body)
-  "Bind NAME to the name of a temporary directory and evaluate BODY.
-NAME must be a symbol.  Delete the temporary directory after BODY
-exits normally or non-locally.  NAME will be bound to the
-directory name (not the directory file name) of the temporary
-directory."
-  (declare (indent 1))
-  (cl-check-type name symbol)
-  `(let ((,name (file-name-as-directory
-                 (make-temp-file "emacs-module-test" :directory))))
-     (unwind-protect
-         (progn ,@body)
-       (delete-directory ,name :recursive))))
-
 (defmacro module--test-assertion (pattern &rest body)
   "Test that PATTERN matches the assertion triggered by BODY.
 Run Emacs as a subprocess, load the test module `mod-test-file',
@@ -228,7 +219,7 @@ assertion message that matches PATTERN.  PATTERN is 
evaluated and
 must evaluate to a regular expression string."
   (declare (indent 1))
   ;; To contain any core dumps.
-  `(module--with-temp-directory tempdir
+  `(ert-with-temp-directory tempdir
      (with-temp-buffer
        (let* ((default-directory tempdir)
               (status (call-process mod-test-emacs nil t nil
diff --git a/test/src/emacs-tests.el b/test/src/emacs-tests.el
index ac08e055b5..a1a412423c 100644
--- a/test/src/emacs-tests.el
+++ b/test/src/emacs-tests.el
@@ -25,6 +25,7 @@
 
 (require 'cl-lib)
 (require 'ert)
+(require 'ert-x) ; ert-with-temp-file
 (require 'rx)
 (require 'subr-x)
 
@@ -46,22 +47,6 @@
                         "--seccomp=/does-not-exist.bpf")
           0))))
 
-(cl-defmacro emacs-tests--with-temp-file
-    (var (prefix &optional suffix text) &rest body)
-  "Evaluate BODY while a new temporary file exists.
-Bind VAR to the name of the file.  Pass PREFIX, SUFFIX, and TEXT
-to `make-temp-file', which see."
-  (declare (indent 2) (debug (symbolp (form form form) body)))
-  (cl-check-type var symbol)
-  ;; Use an uninterned symbol so that the code still works if BODY
-  ;; changes VAR.
-  (let ((filename (make-symbol "filename")))
-    `(let ((,filename (make-temp-file ,prefix nil ,suffix ,text)))
-       (unwind-protect
-           (let ((,var ,filename))
-             ,@body)
-         (delete-file ,filename)))))
-
 (ert-deftest emacs-tests/seccomp/empty-file ()
   (skip-unless (string-match-p (rx bow "SECCOMP" eow)
                                system-configuration-features))
@@ -69,7 +54,8 @@ to `make-temp-file', which see."
          (expand-file-name invocation-name invocation-directory))
         (process-environment nil))
     (skip-unless (file-executable-p emacs))
-    (emacs-tests--with-temp-file filter ("seccomp-invalid-" ".bpf")
+    (ert-with-temp-file filter
+      :prefix "seccomp-invalid-" :suffix ".bpf"
       ;; The --seccomp option is processed early, without filename
       ;; handlers.  Therefore remote or quoted filenames wouldn't
       ;; work.
@@ -94,9 +80,9 @@ to `make-temp-file', which see."
         ;; Either 8 or 16, but 16 should be large enough in all cases.
         (filter-size 16))
     (skip-unless (file-executable-p emacs))
-    (emacs-tests--with-temp-file
-        filter ("seccomp-too-large-" ".bpf"
-                (make-string (* (1+ ushort-max) filter-size) ?a))
+    (ert-with-temp-file filter
+      :prefix "seccomp-too-large-" :suffix ".bpf"
+      :text (make-string (* (1+ ushort-max) filter-size) ?a)
       ;; The --seccomp option is processed early, without filename
       ;; handlers.  Therefore remote or quoted filenames wouldn't
       ;; work.
@@ -117,8 +103,8 @@ to `make-temp-file', which see."
          (expand-file-name invocation-name invocation-directory))
         (process-environment nil))
     (skip-unless (file-executable-p emacs))
-    (emacs-tests--with-temp-file filter ("seccomp-invalid-" ".bpf"
-                                         "123456")
+    (ert-with-temp-file filter
+      :prefix "seccomp-invalid-" :suffix ".bpf" :text "123456"
       ;; The --seccomp option is processed early, without filename
       ;; handlers.  Therefore remote or quoted filenames wouldn't
       ;; work.
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el
index b2b7dfefda..3c3e703341 100644
--- a/test/src/eval-tests.el
+++ b/test/src/eval-tests.el
@@ -39,31 +39,40 @@
 (ert-deftest eval-tests--bugs-24912-and-24913 ()
   "Check that Emacs doesn't accept weird argument lists.
 Bug#24912 and Bug#24913."
-  (dolist (args '((&rest &optional)
-                  (&rest a &optional) (&rest &optional a)
-                  (&optional &optional) (&optional &optional a)
-                  (&optional a &optional b)
-                  (&rest &rest) (&rest &rest a)
-                  (&rest a &rest b)))
-    (should-error (eval `(funcall (lambda ,args)) t) :type 'invalid-function)
-    (should-error (byte-compile-check-lambda-list args))
-    (let ((byte-compile-debug t))
-      (ert-info ((format "bytecomp: args = %S" args))
-       (should-error (eval `(byte-compile (lambda ,args)) t))))))
-
-(ert-deftest eval-tests-accept-empty-optional-rest ()
-  "Check that Emacs accepts empty &optional and &rest arglists.
+  (dolist (lb '(t false))
+    (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ")
+      (let ((lexical-binding lb))
+        (dolist (args '((&rest &optional)
+                        (&rest a &optional) (&rest &optional a)
+                        (&optional &optional) (&optional &optional a)
+                        (&optional a &optional b)
+                        (&rest &rest) (&rest &rest a)
+                        (&rest a &rest b)
+                        (&rest) (&optional &rest)
+                        ))
+          (ert-info ((prin1-to-string args) :prefix "args: ")
+            (should-error
+             (eval `(funcall (lambda ,args)) lb) :type 'invalid-function)
+            (should-error (byte-compile-check-lambda-list args))
+            (let ((byte-compile-debug t))
+              (should-error (eval `(byte-compile (lambda ,args)) lb)))))))))
+
+(ert-deftest eval-tests-accept-empty-optional ()
+  "Check that Emacs accepts empty &optional arglists.
 Bug#24912."
-  (dolist (args '((&optional) (&rest) (&optional &rest)
-                  (&optional &rest a) (&optional a &rest)))
-    (let ((fun `(lambda ,args 'ok)))
-      (ert-info ("eval")
-        (should (eq (funcall (eval fun t)) 'ok)))
-      (ert-info ("byte comp check")
-        (byte-compile-check-lambda-list args))
-      (ert-info ("bytecomp")
-        (let ((byte-compile-debug t))
-          (should (eq (funcall (byte-compile fun)) 'ok)))))))
+  (dolist (lb '(t false))
+    (ert-info ((prin1-to-string lb) :prefix "lexical-binding: ")
+      (let ((lexical-binding lb))
+        (dolist (args '((&optional) (&optional &rest a)))
+          (ert-info ((prin1-to-string args) :prefix "args: ")
+            (let ((fun `(lambda ,args 'ok)))
+              (ert-info ("eval")
+                (should (eq (funcall (eval fun lb)) 'ok)))
+              (ert-info ("byte comp check")
+                (byte-compile-check-lambda-list args))
+              (ert-info ("bytecomp")
+                (let ((byte-compile-debug t))
+                  (should (eq (funcall (byte-compile fun)) 'ok)))))))))))
 
 
 (dolist (form '(let let*))
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index 438ebebb76..4143503aa1 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 
 (defun try-link (target link)
@@ -97,7 +99,7 @@ Also check that an encoding error can appear in a symlink."
   (should (equal (file-name-as-directory "D:/abc//") "d:/abc//")))
 
 (ert-deftest fileio-tests--relative-HOME ()
-  "Test that expand-file-name works even when HOME is relative."
+  "Test that `expand-file-name' works even when HOME is relative."
   (let ((process-environment (copy-sequence process-environment)))
     (setenv "HOME" "a/b/c")
     (should (equal (expand-file-name "~/foo")
@@ -128,7 +130,7 @@ Also check that an encoding error can appear in a symlink."
       (if f (delete-file f)))))
 
 (ert-deftest fileio-tests--relative-default-directory ()
-  "Test expand-file-name when default-directory is relative."
+  "Test `expand-file-name' when `default-directory' is relative."
   (let ((default-directory "some/relative/name"))
     (should (file-name-absolute-p (expand-file-name "foo"))))
   (let* ((default-directory "~foo")
@@ -137,7 +139,7 @@ Also check that an encoding error can appear in a symlink."
                  (not (eq (aref name 0) ?~))))))
 
 (ert-deftest fileio-test--expand-file-name-null-bytes ()
-  "Test that expand-file-name checks for null bytes in filenames."
+  "Test that `expand-file-name' checks for null bytes in filenames."
   (should-error (expand-file-name (concat "file" (char-to-string ?\0) ".txt"))
                 :type 'wrong-type-argument)
   (should-error (expand-file-name "file.txt" (concat "dir" (char-to-string 
?\0)))
@@ -146,7 +148,7 @@ Also check that an encoding error can appear in a symlink."
     (should-error (expand-file-name "file.txt") :type 'wrong-type-argument)))
 
 (ert-deftest fileio-tests--file-name-absolute-p ()
-  "Test file-name-absolute-p."
+  "Test `file-name-absolute-p'."
   (dolist (suffix '("" "/" "//" "/foo" "/foo/" "/foo//" "/foo/bar"))
     (unless (string-equal suffix "")
       (should (file-name-absolute-p suffix)))
@@ -157,7 +159,7 @@ Also check that an encoding error can appear in a symlink."
       (should (not (file-name-absolute-p (concat "~nosuchuser" suffix)))))))
 
 (ert-deftest fileio-tests--circular-after-insert-file-functions ()
-  "Test after-insert-file-functions as a circular list."
+  "Test `after-insert-file-functions' as a circular list."
   (let ((f (make-temp-file "fileio"))
         (after-insert-file-functions (list 'identity)))
     (setcdr after-insert-file-functions after-insert-file-functions)
diff --git a/test/src/filelock-tests.el b/test/src/filelock-tests.el
index a96d6d6728..ba00167963 100644
--- a/test/src/filelock-tests.el
+++ b/test/src/filelock-tests.el
@@ -28,6 +28,7 @@
 
 (require 'cl-macs)
 (require 'ert)
+(require 'ert-x)
 (require 'seq)
 
 (defun filelock-tests--fixture (test-function)
@@ -36,22 +37,20 @@ Create a test directory and a buffer whose 
`buffer-file-name' and
 `buffer-file-truename' are a file within it, then call
 TEST-FUNCTION.  Finally, delete the buffer and the test
 directory."
-  (let* ((temp-dir (make-temp-file "filelock-tests" t))
-         (name (concat (file-name-as-directory temp-dir)
-                       "userfile"))
-         (create-lockfiles t))
-    (unwind-protect
-        (with-temp-buffer
-          (setq buffer-file-name name
-                buffer-file-truename name)
-          (unwind-protect
-              (save-current-buffer
-                (funcall test-function))
-            ;; Set `buffer-file-truename' nil to prevent unlocking,
-            ;; which might prompt the user and/or signal errors.
-            (setq buffer-file-name nil
-                  buffer-file-truename nil)))
-      (delete-directory temp-dir t nil))))
+  (ert-with-temp-directory temp-dir
+    (let ((name (concat (file-name-as-directory temp-dir)
+                        "userfile"))
+          (create-lockfiles t))
+      (with-temp-buffer
+        (setq buffer-file-name name
+              buffer-file-truename name)
+        (unwind-protect
+            (save-current-buffer
+              (funcall test-function))
+          ;; Set `buffer-file-truename' nil to prevent unlocking,
+          ;; which might prompt the user and/or signal errors.
+          (setq buffer-file-name nil
+                buffer-file-truename nil))))))
 
 (defun filelock-tests--make-lock-name (file-name)
   "Return the lock file name for FILE-NAME.
diff --git a/test/src/floatfns-tests.el b/test/src/floatfns-tests.el
index 4a3c03d833..a066d2e15e 100644
--- a/test/src/floatfns-tests.el
+++ b/test/src/floatfns-tests.el
@@ -17,8 +17,72 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 
+(ert-deftest floatfns-tests-cos ()
+  (should (= (cos 0) 1.0))
+  (should (= (cos float-pi) -1.0)))
+
+(ert-deftest floatfns-tests-sin ()
+  (should (= (sin 0) 0.0)))
+
+(ert-deftest floatfns-tests-tan ()
+  (should (= (tan 0) 0.0)))
+
+(ert-deftest floatfns-tests-isnan ()
+  (should (isnan 0.0e+NaN))
+  (should (isnan -0.0e+NaN))
+  (should-error (isnan "foo") :type 'wrong-type-argument))
+
+(ert-deftest floatfns-tests-exp ()
+  (should (= (exp 0) 1.0)))
+
+(ert-deftest floatfns-tests-expt ()
+  (should (= (expt 2 8) 256)))
+
+(ert-deftest floatfns-tests-log ()
+  (should (= (log 1000 10) 3.0)))
+
+(ert-deftest floatfns-tests-sqrt ()
+  (should (= (sqrt 25) 5)))
+
+(ert-deftest floatfns-tests-abs ()
+  (should (= (abs 10) 10))
+  (should (= (abs -10) 10)))
+
+(ert-deftest floatfns-tests-logb ()
+  (should (= (logb 10000) 13)))
+
+(ert-deftest floatfns-tests-ceiling ()
+  (should (= (ceiling 0.5) 1)))
+
+(ert-deftest floatfns-tests-floor ()
+  (should (= (floor 1.5) 1)))
+
+(ert-deftest floatfns-tests-round ()
+  (should (= (round 1.49999999999) 1))
+  (should (= (round 1.50000000000) 2))
+  (should (= (round 1.50000000001) 2)))
+
+(ert-deftest floatfns-tests-truncate ()
+  (should (= (truncate float-pi) 3)))
+
+(ert-deftest floatfns-tests-fceiling ()
+  (should (= (fceiling 0.5) 1.0)))
+
+(ert-deftest floatfns-tests-ffloor ()
+  (should (= (ffloor 1.5) 1.0)))
+
+(ert-deftest floatfns-tests-fround ()
+  (should (= (fround 1.49999999999) 1.0))
+  (should (= (fround 1.50000000000) 2.0))
+  (should (= (fround 1.50000000001) 2.0)))
+
+(ert-deftest floatfns-tests-ftruncate ()
+  (should (= (ftruncate float-pi) 3.0)))
+
 (ert-deftest divide-extreme-sign ()
   (should (= (ceiling most-negative-fixnum -1.0) (- most-negative-fixnum)))
   (should (= (floor most-negative-fixnum -1.0) (- most-negative-fixnum)))
@@ -125,3 +189,5 @@
              (ash (1- (ash 1 53)) 2045))))
 
 (provide 'floatfns-tests)
+
+;;; floatfns-tests.el ends here
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index bd5a4358e6..bec5c03f9e 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -23,6 +23,29 @@
 
 (require 'cl-lib)
 
+(ert-deftest fns-tests-identity ()
+  (let ((num 12345)) (should (eq (identity num) num)))
+  (let ((str "foo")) (should (eq (identity str) str)))
+  (let ((lst '(11))) (should (eq (identity lst) lst))))
+
+(ert-deftest fns-tests-random ()
+  (should (integerp (random)))
+  (should (>= (random 10) 0))
+  (should (< (random 10) 10)))
+
+(ert-deftest fns-tests-length ()
+  (should (= (length nil) 0))
+  (should (= (length '(1 2 3)) 3))
+  (should (= (length '[1 2 3]) 3))
+  (should (= (length "foo") 3))
+  (should-error (length t)))
+
+(ert-deftest fns-tests-safe-length ()
+  (should (= (safe-length '(1 2 3)) 3)))
+
+(ert-deftest fns-tests-string-bytes ()
+  (should (= (string-bytes "abc") 3)))
+
 ;; Test that equality predicates work correctly on NaNs when combined
 ;; with hash tables based on those predicates.  This was not the case
 ;; for eql in Emacs 26.
@@ -34,6 +57,33 @@
       (puthash nan t h)
       (should (eq (funcall test nan -nan) (gethash -nan h))))))
 
+(ert-deftest fns-tests-equal-including-properties ()
+  (should (equal-including-properties "" ""))
+  (should (equal-including-properties "foo" "foo"))
+  (should (equal-including-properties #("foo" 0 3 (a b))
+                                      (propertize "foo" 'a 'b)))
+  (should (equal-including-properties #("foo" 0 3 (a b c d))
+                                      (propertize "foo" 'a 'b 'c 'd)))
+  (should (equal-including-properties #("a" 0 1 (k v))
+                                      #("a" 0 1 (k v))))
+  (should-not (equal-including-properties #("a" 0 1 (k v))
+                                          #("a" 0 1 (k x))))
+  (should-not (equal-including-properties #("a" 0 1 (k v))
+                                          #("b" 0 1 (k v))))
+  (should-not (equal-including-properties #("foo" 0 3 (a b c e))
+                                          (propertize "foo" 'a 'b 'c 'd))))
+
+(ert-deftest fns-tests-equal-including-properties/string-prop-vals ()
+  "Handle string property values.  (Bug#6581)"
+  (should (equal-including-properties #("a" 0 1 (k "v"))
+                                      #("a" 0 1 (k "v"))))
+  (should (equal-including-properties #("foo" 0 3 (a (t)))
+                                      (propertize "foo" 'a (list t))))
+  (should-not (equal-including-properties #("a" 0 1 (k "v"))
+                                          #("a" 0 1 (k "x"))))
+  (should-not (equal-including-properties #("a" 0 1 (k "v"))
+                                          #("b" 0 1 (k "v")))))
+
 (ert-deftest fns-tests-reverse ()
   (should-error (reverse))
   (should-error (reverse 1))
@@ -430,6 +480,23 @@
                    (buffer-hash))
                  (sha1 "foo"))))
 
+(ert-deftest fns-tests-mapconcat ()
+  (should (string= (mapconcat #'identity '()) ""))
+  (should (string= (mapconcat #'identity '("a" "b")) "ab"))
+  (should (string= (mapconcat #'identity '() "_") ""))
+  (should (string= (mapconcat #'identity '("A") "_") "A"))
+  (should (string= (mapconcat #'identity '("A" "B") "_") "A_B"))
+  (should (string= (mapconcat #'identity '("A" "B" "C") "_") "A_B_C"))
+  ;; non-ASCII strings
+  (should (string= (mapconcat #'identity '("Ä" "ø" "☭" "தமிழ்") "_漢字_")
+                   "Ä_漢字_ø_漢字_☭_漢字_தமிழ்"))
+  ;; vector
+  (should (string= (mapconcat #'identity ["a" "b"] "") "ab"))
+  ;; bool-vector
+  (should (string= (mapconcat #'identity [nil nil] "") ""))
+  (should-error (mapconcat #'identity [nil nil t])
+                :type 'wrong-type-argument))
+
 (ert-deftest fns-tests-mapcan ()
   (should-error (mapcan))
   (should-error (mapcan #'identity))
@@ -1114,3 +1181,5 @@
     (should (= (line-number-at-pos nil) 11))
     (should-error (line-number-at-pos -1))
     (should-error (line-number-at-pos 100))))
+
+;;; fns-tests.el ends here
diff --git a/test/src/image-tests.el b/test/src/image-tests.el
new file mode 100644
index 0000000000..2b236086b6
--- /dev/null
+++ b/test/src/image-tests.el
@@ -0,0 +1,245 @@
+;;; image-tests.el --- Tests for image.c  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefan@marxist.se>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Most of these tests will only run in a GUI session, and not with
+;; "make check".  Run them manually in an interactive session with
+;; `M-x eval-buffer' followed by `M-x ert'.
+
+;;; Code:
+
+(require 'ert)
+
+(defmacro image-skip-unless (format)
+  `(skip-unless (and (display-images-p)
+                     (image-type-available-p ,format))))
+
+;;;; Images
+
+(defconst image-tests--images
+  `((gif . ,(expand-file-name "test/data/image/black.gif"
+                               source-directory))
+    (jpeg . ,(expand-file-name "test/data/image/black.jpg"
+                               source-directory))
+    (pbm . ,(find-image '((:file "splash.svg" :type svg))))
+    (png . ,(find-image '((:file "splash.png" :type png))))
+    (svg . ,(find-image '((:file "splash.pbm" :type pbm))))
+    (tiff . ,(expand-file-name
+              "nextstep/GNUstep/Emacs.base/Resources/emacs.tiff"
+              source-directory))
+    (webp . ,(expand-file-name "test/data/image/black.webp"
+                               source-directory))
+    (xbm . ,(find-image '((:file "gnus/gnus.xbm" :type xbm))))
+    (xpm . ,(find-image '((:file "splash.xpm" :type xpm))))))
+
+;;;; image-test-size
+
+(ert-deftest image-tests-image-size/gif ()
+  (image-skip-unless 'gif)
+  (pcase (image-size (create-image (cdr (assq 'gif image-tests--images))))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/jpeg ()
+  (image-skip-unless 'jpeg)
+  (pcase (image-size (create-image (cdr (assq 'jpeg image-tests--images))))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/pbm ()
+  (image-skip-unless 'pbm)
+  (pcase (image-size (cdr (assq 'pbm image-tests--images)))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/png ()
+  (image-skip-unless 'png)
+  (pcase (image-size (cdr (assq 'png image-tests--images)))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/svg ()
+  (image-skip-unless 'svg)
+  (pcase (image-size (cdr (assq 'svg image-tests--images)))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/tiff ()
+  (image-skip-unless 'tiff)
+  (pcase (image-size (create-image (cdr (assq 'tiff image-tests--images))))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/webp ()
+  (image-skip-unless 'webp)
+  (pcase (image-size (create-image (cdr (assq 'webp image-tests--images))))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/xbm ()
+  (image-skip-unless 'xbm)
+  (pcase (image-size (cdr (assq 'xbm image-tests--images)))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/xpm ()
+  (image-skip-unless 'xpm)
+  (pcase (image-size (cdr (assq 'xpm image-tests--images)))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
+(ert-deftest image-tests-image-size/error-on-invalid-spec ()
+  (skip-unless (display-images-p))
+  (should-error (image-size 'invalid-spec)))
+
+(ert-deftest image-tests-image-size/error-on-nongraphical-display ()
+  (skip-unless (not (display-images-p)))
+  (should-error (image-size 'invalid-spec)))
+
+;;;; image-mask-p
+
+(ert-deftest image-tests-image-mask-p/gif ()
+  (image-skip-unless 'gif)
+  (should-not (image-mask-p (create-image
+                             (cdr (assq 'gif image-tests--images))))))
+
+(ert-deftest image-tests-image-mask-p/jpeg ()
+  (image-skip-unless 'jpeg)
+  (should-not (image-mask-p (create-image
+                             (cdr (assq 'jpeg image-tests--images))))))
+
+(ert-deftest image-tests-image-mask-p/pbm ()
+  (image-skip-unless 'pbm)
+  (should-not (image-mask-p (cdr (assq 'pbm image-tests--images)))))
+
+(ert-deftest image-tests-image-mask-p/png ()
+  (image-skip-unless 'png)
+  (should-not (image-mask-p (cdr (assq 'png image-tests--images)))))
+
+(ert-deftest image-tests-image-mask-p/svg ()
+  (image-skip-unless 'svg)
+  (should-not (image-mask-p (cdr (assq 'svg image-tests--images)))))
+
+(ert-deftest image-tests-image-mask-p/tiff ()
+  (image-skip-unless 'tiff)
+  (should-not (image-mask-p (create-image
+                             (cdr (assq 'tiff image-tests--images))))))
+
+(ert-deftest image-tests-image-mask-p/webp ()
+  (image-skip-unless 'webp)
+  (should-not (image-mask-p (create-image
+                             (cdr (assq 'webp image-tests--images))))))
+
+(ert-deftest image-tests-image-mask-p/xbm ()
+  (image-skip-unless 'xbm)
+  (should-not (image-mask-p (cdr (assq 'xbm image-tests--images)))))
+
+(ert-deftest image-tests-image-mask-p/xpm ()
+  (image-skip-unless 'xpm)
+  (should-not (image-mask-p (cdr (assq 'xpm image-tests--images)))))
+
+(ert-deftest image-tests-image-mask-p/error-on-invalid-spec ()
+  (skip-unless (display-images-p))
+  (should-error (image-mask-p 'invalid-spec)))
+
+(ert-deftest image-tests-image-mask-p/error-on-nongraphical-display ()
+  (skip-unless (not (display-images-p)))
+  (should-error (image-mask-p (cdr (assq 'xpm image-tests--images)))))
+
+;;;; image-metadata
+
+;; TODO: These tests could be expanded with files that actually
+;;       contain metadata.
+
+(ert-deftest image-tests-image-metadata/gif ()
+  (image-skip-unless 'gif)
+  (should-not (image-metadata
+               (create-image (cdr (assq 'gif image-tests--images))))))
+
+(ert-deftest image-tests-image-metadata/jpeg ()
+  (image-skip-unless 'jpeg)
+  (should-not (image-metadata
+               (create-image (cdr (assq 'jpeg image-tests--images))))))
+
+(ert-deftest image-tests-image-metadata/pbm ()
+  (image-skip-unless 'pbm)
+  (should-not (image-metadata (cdr (assq 'pbm image-tests--images)))))
+
+(ert-deftest image-tests-image-metadata/png ()
+  (image-skip-unless 'png)
+  (should-not (image-metadata (cdr (assq 'png image-tests--images)))))
+
+(ert-deftest image-tests-image-metadata/svg ()
+  (image-skip-unless 'svg)
+  (should-not (image-metadata (cdr (assq 'svg image-tests--images)))))
+
+(ert-deftest image-tests-image-metadata/tiff ()
+  (image-skip-unless 'tiff)
+  (should-not (image-metadata
+               (create-image (cdr (assq 'tiff image-tests--images))))))
+
+(ert-deftest image-tests-image-metadata/webp ()
+  (image-skip-unless 'webp)
+  (should-not (image-metadata
+               (create-image (cdr (assq 'webp image-tests--images))))))
+
+(ert-deftest image-tests-image-metadata/xbm ()
+  (image-skip-unless 'xbm)
+  (should-not (image-metadata (cdr (assq 'xbm image-tests--images)))))
+
+(ert-deftest image-tests-image-metadata/xpm ()
+  (image-skip-unless 'xpm)
+  (should-not (image-metadata (cdr (assq 'xpm image-tests--images)))))
+
+(ert-deftest image-tests-image-metadata/nil-on-invalid-spec ()
+  (skip-unless (display-images-p))
+  (should-not (image-metadata 'invalid-spec)))
+
+(ert-deftest image-tests-image-metadata/error-on-nongraphical-display ()
+  (skip-unless (not (display-images-p)))
+  (should-error (image-metadata (cdr (assq 'xpm image-tests--images)))))
+
+;;;; ImageMagick
+
+(ert-deftest image-tests-imagemagick-types ()
+  (skip-unless (fboundp 'imagemagick-types))
+  (when (fboundp 'imagemagick-types)
+    (should (listp (imagemagick-types)))))
+
+;;;; Initialization
+
+(ert-deftest image-tests-init-image-library ()
+  (skip-unless (fboundp 'init-image-library))
+  (should (init-image-library 'pbm)) ; built-in
+  (should (init-image-library 'xpm)) ; built-in
+  (should-not (init-image-library 'invalid-image-type)))
+
+;;; image-tests.el ends here
diff --git a/test/src/indent-tests.el b/test/src/indent-tests.el
index 6a3f1a5c95..6cfe64c07e 100644
--- a/test/src/indent-tests.el
+++ b/test/src/indent-tests.el
@@ -57,3 +57,5 @@
       (move-to-column 12 t)
       (buffer-substring-no-properties 1 14))
     "\txxx    \tLine")))
+
+;;; indent-tests.el ends here
diff --git a/test/src/inotify-tests.el b/test/src/inotify-tests.el
index 5572c7d7a0..70330ac865 100644
--- a/test/src/inotify-tests.el
+++ b/test/src/inotify-tests.el
@@ -24,6 +24,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 
 (declare-function inotify-add-watch "inotify.c" (file-name aspect callback))
 (declare-function inotify-rm-watch "inotify.c" (watch-descriptor))
@@ -37,8 +38,7 @@
 
 ;; (ert-deftest filewatch-file-watch-aspects-check ()
 ;;   "Test whether `file-watch' properly checks the aspects."
-;;   (let ((temp-file (make-temp-file "filewatch-aspects")))
-;;     (should (stringp temp-file))
+;;   (ert-with-temp-file temp-file
 ;;     (should-error (file-watch temp-file 'wrong nil)
 ;;                   :type 'error)
 ;;     (should-error (file-watch temp-file '(modify t) nil)
@@ -50,24 +50,22 @@
 
 (ert-deftest inotify-file-watch-simple ()
   "Test if watching a normal file works."
-
   (skip-unless (featurep 'inotify))
-  (let ((temp-file (make-temp-file "inotify-simple"))
-       (events 0))
-    (let ((wd
-          (inotify-add-watch temp-file t (lambda (_ev)
-                                           (setq events (1+ events))))))
-      (unwind-protect
-         (progn
-           (with-temp-file temp-file
-             (insert "Foo\n"))
-           (read-event nil nil 5)
-           (should (> events 0)))
-       (should (inotify-valid-p wd))
-       (inotify-rm-watch wd)
-       (should-not (inotify-valid-p wd))
-       (delete-file temp-file)))))
+  (ert-with-temp-file temp-file
+    (let ((events 0))
+      (let ((wd
+             (inotify-add-watch temp-file t (lambda (_ev)
+                                       (setq events (1+ events))))))
+        (unwind-protect
+            (progn
+              (with-temp-file temp-file
+                (insert "Foo\n"))
+              (read-event nil nil 5)
+              (should (> events 0)))
+          (should (inotify-valid-p wd))
+          (inotify-rm-watch wd)
+          (should-not (inotify-valid-p wd)))))))
 
 (provide 'inotify-tests)
 
-;;; inotify-tests.el ends here.
+;;; inotify-tests.el ends here
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 68b42c346c..8e28faf2b2 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -124,6 +124,55 @@
 ;; (ert-deftest keymap-lookup-key/accept-default ()
 ;;   ...)
 
+(ert-deftest keymap-lookup-key/mixed-case ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo bar] 'foo)
+    (should (eq (lookup-key map [menu-bar foo bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Foo Bar]) 'foo)))
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar i-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar I-bar]) 'foo))))
+
+(ert-deftest keymap-lookup-key/mixed-case-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    ;; (downcase "Åäö") => "åäö"
+    (define-key map [menu-bar åäö bar] 'foo)
+    (should (eq (lookup-key map [menu-bar åäö bar]) 'foo))
+    (should (eq (lookup-key map [menu-bar Åäö Bar]) 'foo))
+    ;; (downcase "Γ") => "γ"
+    (define-key map [menu-bar γ bar] 'baz)
+    (should (eq (lookup-key map [menu-bar γ bar]) 'baz))
+    (should (eq (lookup-key map [menu-bar Γ Bar]) 'baz))))
+
+(ert-deftest keymap-lookup-key/menu-non-symbol ()
+  "Test for Bug#51527."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar buffer 1] 'foo)
+    (should (eq (lookup-key map [menu-bar buffer 1]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar foo-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Foo\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((map (make-keymap)))
+    (define-key map [menu-bar åäö-bar] 'foo)
+    (should (eq (lookup-key map [menu-bar Åäö\ Bar]) 'foo))))
+
+(ert-deftest keymap-lookup-keymap/with-spaces-multibyte-lang-env ()
+  "Backwards compatibility behaviour (Bug#50752)."
+  (let ((lang-env current-language-environment))
+    (set-language-environment "Turkish")
+    (let ((map (make-keymap)))
+      (define-key map [menu-bar i-bar] 'foo)
+      (should (eq (lookup-key map [menu-bar I-bar]) 'foo)))
+    (set-language-environment lang-env)))
+
 (ert-deftest describe-buffer-bindings/header-in-current-buffer ()
   "Header should be inserted into the current buffer.
 https://debbugs.gnu.org/39149#31";
@@ -274,12 +323,12 @@ commit 86c19714b097aa477d339ed99ffb5136c755a046."
     (with-temp-buffer
       (help--describe-vector (cadr orig-map) nil #'help--describe-command
                              t shadow-map orig-map t)
-      (should (equal (buffer-string)
-                     "
+      (should (equal (buffer-substring-no-properties (point-min) (point-max))
+                     (string-replace "\t" "" "
 e              foo
 f              foo  (currently shadowed by `bar')
 g .. h         foo
-")))))
+"))))))
 
 (ert-deftest help--describe-vector/bug-9293-same-command-does-not-shadow ()
   "Check that a command can't be shadowed by the same command."
@@ -300,10 +349,10 @@ g .. h            foo
    (with-temp-buffer
      (help--describe-vector (cadr range-map) nil #'help--describe-command
                             t shadow-map range-map t)
-     (should (equal (buffer-string)
-                    "
+     (should (equal (buffer-substring-no-properties (point-min) (point-max))
+                    (string-replace "\t" "" "
 0 .. 3         foo
-")))))
+"))))))
 
 (ert-deftest keymap--key-description ()
   (should (equal (key-description [right] [?\C-x])
@@ -317,6 +366,13 @@ g .. h             foo
   (should (equal (single-key-description 'C-s-home)
                  "C-s-<home>")))
 
+(ert-deftest keymap-test-lookups ()
+  (should (eq (lookup-key (current-global-map) "\C-x\C-f") 'find-file))
+  (should (eq (lookup-key (current-global-map) [(control x) (control f)])
+              'find-file))
+  (should (eq (lookup-key (current-global-map) ["C-x C-f"]) 'find-file))
+  (should (eq (lookup-key (current-global-map) [?\C-x ?\C-f]) 'find-file)))
+
 (provide 'keymap-tests)
 
 ;;; keymap-tests.el ends here
diff --git a/test/src/lcms-tests.el b/test/src/lcms-tests.el
index 40a48f1e9b..d2d137e9bd 100644
--- a/test/src/lcms-tests.el
+++ b/test/src/lcms-tests.el
@@ -95,7 +95,7 @@ B is considered the exact value."
     '(0.29902 0.31485 1.0))))
 
 (ert-deftest lcms-roundtrip ()
-  "Test accuracy of converting to and from different color spaces"
+  "Test accuracy of converting to and from different color spaces."
   (skip-unless (featurep 'lcms2))
   (should
    (let ((color '(.5 .3 .7)))
@@ -109,7 +109,7 @@ B is considered the exact value."
                            0.0001))))
 
 (ert-deftest lcms-ciecam02-gold ()
-  "Test CIE CAM02 JCh gold values"
+  "Test CIE CAM02 JCh gold values."
   (skip-unless (featurep 'lcms2))
   (should
    (lcms-triple-approx-p
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el
index dac8f95bc4..be685fe999 100644
--- a/test/src/lread-tests.el
+++ b/test/src/lread-tests.el
@@ -119,14 +119,6 @@
   (should (equal '(#s(foo) #s(foo))
                  (read "(#1=#s(foo) #1#)"))))
 
-(defmacro lread-tests--with-temp-file (file-name-var &rest body)
-  (declare (indent 1))
-  (cl-check-type file-name-var symbol)
-  `(let ((,file-name-var (make-temp-file "emacs")))
-     (unwind-protect
-         (progn ,@body)
-       (delete-file ,file-name-var))))
-
 (defun lread-tests--last-message ()
   (with-current-buffer "*Messages*"
     (save-excursion
@@ -137,7 +129,7 @@
 (ert-deftest lread-tests--unescaped-char-literals ()
   "Check that loading warns about unescaped character
 literals (Bug#20852)."
-  (lread-tests--with-temp-file file-name
+  (ert-with-temp-file file-name
     (write-region "?) ?( ?; ?\" ?[ ?]" nil file-name)
     (should (equal (load file-name nil :nomessage :nosuffix) t))
     (should (equal (lread-tests--last-message)
diff --git a/test/src/marker-tests.el b/test/src/marker-tests.el
index 234a0b35ea..cf8e82cd56 100644
--- a/test/src/marker-tests.el
+++ b/test/src/marker-tests.el
@@ -57,4 +57,4 @@
     (set-marker marker-2 marker-1)
     (should (goto-char marker-2))))
 
-;;; marker-tests.el ends here.
+;;; marker-tests.el ends here
diff --git a/test/src/minibuf-tests.el b/test/src/minibuf-tests.el
index feea1c112b..51d9c67453 100644
--- a/test/src/minibuf-tests.el
+++ b/test/src/minibuf-tests.el
@@ -414,8 +414,8 @@
   (let ((inhibit-interaction t))
     (should-error (read-from-minibuffer "foo: ") :type 'inhibited-interaction)
 
-    (should-error (y-or-n-p "foo: ") :type 'inhibited-interaction)
-    (should-error (yes-or-no-p "foo: ") :type 'inhibited-interaction)
+    (should-error (y-or-n-p "Foo?") :type 'inhibited-interaction)
+    (should-error (yes-or-no-p "Foo?") :type 'inhibited-interaction)
     (should-error (read-no-blanks-input "foo: ") :type 'inhibited-interaction)
 
     ;; See that we get the expected error.
diff --git a/test/src/process-tests.el b/test/src/process-tests.el
index 9bab523708..b831ca3bda 100644
--- a/test/src/process-tests.el
+++ b/test/src/process-tests.el
@@ -25,6 +25,7 @@
 
 (require 'cl-lib)
 (require 'ert)
+(require 'ert-x) ; ert-with-temp-directory
 (require 'puny)
 (require 'subr-x)
 (require 'dns)
@@ -64,24 +65,22 @@
 (when (eq system-type 'windows-nt)
   (ert-deftest process-test-quoted-batfile ()
     "Check that Emacs hides CreateProcess deficiency (bug#18745)."
-    (let (batfile)
-      (unwind-protect
-          (progn
-            ;; CreateProcess will fail when both the bat file and 1st
-            ;; argument are quoted, so include spaces in both of those
-            ;; to force quoting.
-            (setq batfile (make-temp-file "echo args" nil ".bat"))
-            (with-temp-file batfile
-              (insert "@echo arg1=%1, arg2=%2\n"))
-            (with-temp-buffer
-              (call-process batfile nil '(t t) t "x &y")
-              (should (string= (buffer-string) "arg1=\"x &y\", arg2=\n")))
-            (with-temp-buffer
-              (call-process-shell-command
-               (mapconcat #'shell-quote-argument (list batfile "x &y") " ")
-               nil '(t t) t)
-              (should (string= (buffer-string) "arg1=\"x &y\", arg2=\n"))))
-        (when batfile (delete-file batfile))))))
+    (ert-with-temp-file batfile
+      ;; CreateProcess will fail when both the bat file and 1st
+      ;; argument are quoted, so include spaces in both of those
+      ;; to force quoting.
+      :prefix "echo args"
+      :suffix ".bat"
+      (with-temp-file batfile
+        (insert "@echo arg1=%1, arg2=%2\n"))
+      (with-temp-buffer
+        (call-process batfile nil '(t t) t "x &y")
+        (should (string= (buffer-string) "arg1=\"x &y\", arg2=\n")))
+      (with-temp-buffer
+        (call-process-shell-command
+         (mapconcat #'shell-quote-argument (list batfile "x &y") " ")
+         nil '(t t) t)
+        (should (string= (buffer-string) "arg1=\"x &y\", arg2=\n"))))))
 
 (ert-deftest process-test-stderr-buffer ()
   (skip-unless (executable-find "bash"))
@@ -531,18 +530,6 @@ FD_SETSIZE."
            (delete-process (pop ,processes))
            ,@body)))))
 
-(defmacro process-tests--with-temp-directory (var &rest body)
-  "Bind VAR to the name of a new directory and evaluate BODY.
-Afterwards, delete the directory."
-  (declare (indent 1) (debug (symbolp body)))
-  (cl-check-type var symbol)
-  (let ((dir (make-symbol "dir")))
-    `(let ((,dir (make-temp-file "emacs-test-" :dir)))
-       (unwind-protect
-           (let ((,var ,dir))
-             ,@body)
-         (delete-directory ,dir :recursive)))))
-
 ;; Tests for FD_SETSIZE overflow (Bug#24325).  The following tests
 ;; generate lots of process objects of the various kinds.  Running the
 ;; tests with assertions enabled should not result in any crashes due
@@ -630,7 +617,7 @@ FD_SETSIZE file descriptors (Bug#24325)."
   ;; Avoid hang due to connect/accept handshake on Cygwin (bug#49496).
   (skip-unless (not (eq system-type 'cygwin)))
   (with-timeout (60 (ert-fail "Test timed out"))
-    (process-tests--with-temp-directory directory
+    (ert-with-temp-directory directory
       (process-tests--with-processes processes
         (let* ((num-clients 10)
                (socket-name (expand-file-name "socket" directory))
@@ -745,7 +732,7 @@ Return nil if that can't be determined."
   process-tests--EMFILE-message)
 
 (ert-deftest process-tests/sentinel-called ()
-  "Check that sentinels are called after processes finish"
+  "Check that sentinels are called after processes finish."
   (let ((command (process-tests--emacs-command)))
     (skip-unless command)
     (dolist (conn-type '(pipe pty))
@@ -946,5 +933,11 @@ Return nil if FILENAME doesn't exist."
       (when buf
         (kill-buffer buf)))))
 
+(ert-deftest process-num-processors ()
+  "Sanity checks for num-processors."
+  (should (equal (num-processors) (num-processors)))
+  (should (integerp (num-processors)))
+  (should (< 0 (num-processors))))
+
 (provide 'process-tests)
 ;;; process-tests.el ends here
diff --git a/test/src/regex-emacs-tests.el b/test/src/regex-emacs-tests.el
index 0607eacf39..71e3189443 100644
--- a/test/src/regex-emacs-tests.el
+++ b/test/src/regex-emacs-tests.el
@@ -279,11 +279,11 @@ on success"
 
 (defconst regex-tests-re-even-escapes
   "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*"
-  "Regex that matches an even number of \\ characters")
+  "Regex that matches an even number of \\ characters.")
 
 (defconst regex-tests-re-odd-escapes
   (concat regex-tests-re-even-escapes "\\\\")
-  "Regex that matches an odd number of \\ characters")
+  "Regex that matches an odd number of \\ characters.")
 
 
 (defun regex-tests-unextend (pattern)
@@ -396,9 +396,9 @@ pattern)"
    ;; emacs matches non-greedy regex ab.*? non-greedily
    639 677 712
    ]
-  "Line numbers in the boost test that should be skipped.  These
-are false-positive test failures that represent known/benign
-differences in behavior.")
+  "Line numbers in the boost test that should be skipped.
+These are false-positive test failures that represent
+known/benign differences in behavior.")
 
 ;; - Format
 ;;   - Comments are lines starting with ;
@@ -480,9 +480,9 @@ differences in behavior.")
    ;; ambiguous groupings are ambiguous
    610 611 1154 1157 1160 1168 1171 1176 1179 1182 1185 1188 1193 1196 1203
   ]
-  "Line numbers in the PCRE test that should be skipped.  These
-are false-positive test failures that represent known/benign
-differences in behavior.")
+  "Line numbers in the PCRE test that should be skipped.
+These are false-positive test failures that represent
+known/benign differences in behavior.")
 
 ;; - Format
 ;;
@@ -562,9 +562,9 @@ differences in behavior.")
    ;; fails to match
    168
   ]
-  "Line numbers in the PTESTS test that should be skipped.  These
-are false-positive test failures that represent known/benign
-differences in behavior.")
+  "Line numbers in the PTESTS test that should be skipped.
+These are false-positive test failures that represent
+known/benign differences in behavior.")
 
 ;; - Format
 ;;   - fields separated by ¦ (note: this is not a |)
@@ -621,9 +621,9 @@ differences in behavior.")
    ;; emacs is more stringent with regexes involving unbalanced )
    67
   ]
-  "Line numbers in the TESTS test that should be skipped.  These
-are false-positive test failures that represent known/benign
-differences in behavior.")
+  "Line numbers in the TESTS test that should be skipped.
+These are false-positive test failures that represent
+known/benign differences in behavior.")
 
 ;; - Format
 ;;   - fields separated by :. Watch for [\[:xxx:]]
diff --git a/test/src/textprop-tests.el b/test/src/textprop-tests.el
index b083588e64..c001579c47 100644
--- a/test/src/textprop-tests.el
+++ b/test/src/textprop-tests.el
@@ -69,4 +69,4 @@
                 (null stack)))))
 
 (provide 'textprop-tests)
-;; textprop-tests.el ends here.
+;;; textprop-tests.el ends here
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index fc7bc7441b..52eace7e9d 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -70,12 +70,12 @@
    (thread-live-p (make-thread #'ignore))))
 
 (ert-deftest threads-all-threads ()
-  "Simple test for all-threads."
+  "Simple test for `all-threads'."
   (skip-unless (featurep 'threads))
   (should (listp (all-threads))))
 
 (ert-deftest threads-main-thread ()
-  "Simple test for all-threads."
+  "Simple test for `all-threads'."
   (skip-unless (featurep 'threads))
   (should (eq main-thread (car (all-threads)))))
 
@@ -155,7 +155,7 @@
   (should (eq (type-of (make-mutex)) 'mutex)))
 
 (ert-deftest threads-mutex-lock-unlock ()
-  "Test mutex-lock and unlock."
+  "Test `mutex-lock' and unlock."
   (skip-unless (featurep 'threads))
   (should
    (let ((mx (make-mutex)))
@@ -392,4 +392,4 @@
   (let ((th (make-thread 'ignore)))
     (should-not (equal th main-thread))))
 
-;;; threads.el ends here
+;;; thread-tests.el ends here
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index 0a450a7573..bba9b3fcd8 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -241,3 +241,5 @@ a fixed place on the right and are padded on the left."
         (let ((xdiv (/ x divisor)))
           (should (= xdiv (float-time (time-convert xdiv t))))))
       (setq x (* x 2)))))
+
+;;; timefns-tests.el ends here
diff --git a/test/src/undo-tests.el b/test/src/undo-tests.el
index a658bccf6d..88fcfad14c 100644
--- a/test/src/undo-tests.el
+++ b/test/src/undo-tests.el
@@ -46,6 +46,7 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-x)
 (require 'facemenu)
 
 (ert-deftest undo-test0 ()
@@ -218,17 +219,14 @@
 
 (ert-deftest undo-test-file-modified ()
   "Test undoing marks buffer visiting file unmodified."
-  (let ((tempfile (make-temp-file "undo-test")))
-    (unwind-protect
-        (progn
-          (with-current-buffer (find-file-noselect tempfile)
-            (insert "1")
-            (undo-boundary)
-            (set-buffer-modified-p nil)
-            (insert "2")
-            (undo)
-            (should-not (buffer-modified-p))))
-      (delete-file tempfile))))
+  (ert-with-temp-file tempfile
+    (with-current-buffer (find-file-noselect tempfile)
+      (insert "1")
+      (undo-boundary)
+      (set-buffer-modified-p nil)
+      (insert "2")
+      (undo)
+      (should-not (buffer-modified-p)))))
 
 (ert-deftest undo-test-region-not-most-recent ()
   "Test undo in region of an edit not the most recent."
diff --git a/test/src/xdisp-tests.el b/test/src/xdisp-tests.el
index 4e7d2ad8ab..cc67aef8e1 100644
--- a/test/src/xdisp-tests.el
+++ b/test/src/xdisp-tests.el
@@ -99,4 +99,59 @@
            (width-in-chars (/ (car size) char-width)))
       (should (equal width-in-chars 3)))))
 
+(ert-deftest xdisp-tests--find-directional-overrides-case-1 ()
+  (with-temp-buffer
+    (insert "\
+int main() {
+  bool isAdmin = false;
+  /*‮ }⁦if (isAdmin)⁩ ⁦ begin admins only */
+  printf(\"You are an admin.\\n\");
+  /* end admins only ‮ { ⁦*/
+  return 0;
+}")
+    (goto-char (point-min))
+    (should (eq (bidi-find-overridden-directionality (point-min) (point-max)
+                                                     nil)
+                46))))
+
+(ert-deftest xdisp-tests--find-directional-overrides-case-2 ()
+  (with-temp-buffer
+    (insert "\
+#define is_restricted_user(user)                       \\
+  !strcmp (user, \"root\") ? 0 :                       \\
+  !strcmp (user, \"admin\") ? 0 :                      \\
+  !strcmp (user, \"superuser‮⁦? 0 : 1⁩ ⁦\")⁩‬
+
+int main () {
+  printf (\"root: %d\\n\", is_restricted_user (\"root\"));
+  printf (\"admin: %d\\n\", is_restricted_user (\"admin\"));
+  printf (\"superuser: %d\\n\", is_restricted_user (\"superuser\"));
+  printf (\"luser: %d\\n\", is_restricted_user (\"luser\"));
+  printf (\"nobody: %d\\n\", is_restricted_user (\"nobody\"));
+}")
+    (goto-char (point-min))
+    (should (eq (bidi-find-overridden-directionality (point-min) (point-max)
+                                                     nil)
+                138))))
+
+(ert-deftest xdisp-tests--find-directional-overrides-case-3 ()
+  (with-temp-buffer
+    (insert "\
+#define is_restricted_user(user)                       \\
+  !strcmp (user, \"root\") ? 0 :                       \\
+  !strcmp (user, \"admin\") ? 0 :                      \\
+  !strcmp (user, \"superuser‮⁦? '#' : '!'⁩ ⁦\")⁩‬
+
+int main () {
+  printf (\"root: %d\\n\", is_restricted_user (\"root\"));
+  printf (\"admin: %d\\n\", is_restricted_user (\"admin\"));
+  printf (\"superuser: %d\\n\", is_restricted_user (\"superuser\"));
+  printf (\"luser: %d\\n\", is_restricted_user (\"luser\"));
+  printf (\"nobody: %d\\n\", is_restricted_user (\"nobody\"));
+}")
+    (goto-char (point-min))
+    (should (eq (bidi-find-overridden-directionality (point-min) (point-max)
+                                                     nil)
+                138))))
+
 ;;; xdisp-tests.el ends here
diff --git a/test/src/xfaces-tests.el b/test/src/xfaces-tests.el
index 0a7ef55b2b..cba706f453 100644
--- a/test/src/xfaces-tests.el
+++ b/test/src/xfaces-tests.el
@@ -17,6 +17,8 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
+;;; Code:
+
 (require 'ert)
 
 (ert-deftest xfaces-color-distance ()
@@ -48,3 +50,5 @@
   (should (equal (color-values-from-color-spec "rgbi:0/0.5/10") nil)))
 
 (provide 'xfaces-tests)
+
+;;; xfaces-tests.el ends here
diff --git a/test/src/xml-tests.el b/test/src/xml-tests.el
index a35b4d2ccc..7c4ca396f7 100644
--- a/test/src/xml-tests.el
+++ b/test/src/xml-tests.el
@@ -52,4 +52,4 @@
       (should (equal (cdr test)
                      (libxml-parse-xml-region (point-min) (point-max)))))))
 
-;;; libxml-tests.el ends here
+;;; xml-tests.el ends here



reply via email to

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