diff --git a/README.md b/README.md
index f85540b2716c2e7de023dc0f9051bea6b920b99c..623d47d72fe080587ea3b9781be700a1dd0b1517 100644
--- a/README.md
+++ b/README.md
@@ -354,7 +354,7 @@ The following is adapted from Pd Vanilla's original source notes.  (Found
 in pd/src/CHANGELOG.txt for some reason...)
 
 Sections 2-3 below are quite old.  Someone needs to check whether they even
-hold true for Pd Vanilla any more.
+hold true for Pd Vanilla anymore.
 
 #### Structure definition roadmap.
 
@@ -364,19 +364,19 @@ and t_graph and t_canvas, should be unified...)
 
 BEFORE 0.35:
 
-    m_pd.h	    t_pd    	    	    anything with a class
-                    t_gobj	    	    "graphic object"
-                        t_text  	    text object
-    g_canvas.h  
-                        t_glist 	    list of graphic objects
-    g_canvas.c  	    	t_canvas    Pd "document"
+    m_pd.h      t_pd                        anything with a class
+                    t_gobj                  "graphic object"
+                        t_text              text object
+    g_canvas.h
+                        t_glist             list of graphic objects
+    g_canvas.c              t_canvas        Pd "document"
 
 AFTER 0.35:
 
-    m_pd.h	    t_pd    	    	    anything with a class
-                    t_gobj	    	    "graphic object"
-                        t_text  	    patchable object, AKA t_object
-    g_canvas.h     	    	t_glist     list of graphic objects, AKA t_canvas
+    m_pd.h      t_pd                        anything with a class
+                    t_gobj                  "graphic object"
+                        t_text              patchable object, AKA t_object
+    g_canvas.h              t_glist         list of graphic objects, AKA t_canvas
 
 Other structures:
 
@@ -390,7 +390,7 @@ Other structures:
 #### 1. Coding Style
 
 1.0  C coding style.  The source should pass most "warnings" of C compilers
-(-Wall on linux, for instance; see the makefile.)  Some informalities
+(-Wall on Linux, for instance-- see the makefile.)  Some informalities
 are intentional, for instance the loose use of function prototypes (see
 below) and uncast conversions from longer to shorter numerical formats.
 The code doesn't respect "const" yet.
@@ -483,7 +483,7 @@ which are all frequently called and which don't fit into simple categories.
 Important packages are:
 
     (pd-gui:)   pdgui -- everything
-    (pd:)	    pd -- functions common to all "pd" objects
+    (pd:)       pd -- functions common to all "pd" objects
                 obj -- fuctions common to all "patchable" objects ala Max
                 sys -- "system" level functions
                 binbuf -- functions manipulating binbufs
diff --git a/debuild/Makefile b/debuild/Makefile
index 6cc7d6954b74cf2dafa21c7ca0510a93579a2499..9367e67dfbf1ac15a7d1c654767250265de8e6d0 100644
--- a/debuild/Makefile
+++ b/debuild/Makefile
@@ -81,7 +81,8 @@ deb: $(debsrc) $(addprefix debian/nwjs/, $(nwjs))
 # This can be removed once Ubuntu 12.04 finally goes the way of the dodo.
 #	cd $(debdist) && patch -p1 < ../precise-configure.patch
 # Patch the user config dir name so that purr-data can coexist with pd-l2ork.
-	cd $(debdist) && patch -Np1 < ../userconfig.patch
+# Not needed with purr-data 2.4.5+ any more.
+#	cd $(debdist) && patch -Np1 < ../userconfig.patch
 # Make sure to copy the Debian files which may have uncommitted changes.
 # Then run debuild to create the package.
 	cd $(debdist) && cp -R ../debian . && debuild $(DEBUILD_FLAGS)
diff --git a/externals/ggee/gui/image.c b/externals/ggee/gui/image.c
index 070c542308cc71f48ef5006820ffd6c91b781894..67795a1338229bc096b6f492603535c0206148b6 100644
--- a/externals/ggee/gui/image.c
+++ b/externals/ggee/gui/image.c
@@ -465,7 +465,7 @@ static void image_setwidget(void)
 static void image_free(t_image *x)
 {
     //sys_vgui("image delete img%x\n", x);
-    gui_vmess("gui_drawimage_free", "x", x);
+    gui_vmess("gui_image_free", "x", x);
     if (x->x_receive)
     {
         pd_unbind(&x->x_obj.ob_pd,x->x_receive);
diff --git a/externals/tof/src/imagebang.c b/externals/tof/src/imagebang.c
index 31fb1fc34c7e990ad9f015ed41620680b0e56ddf..501991b398c37a75a7792d7fd80ef3ff63007752 100644
--- a/externals/tof/src/imagebang.c
+++ b/externals/tof/src/imagebang.c
@@ -305,8 +305,8 @@ static void imagebang_free(t_imagebang *x) {
     
     sprintf(key_a, "%lx_a", (long unsigned int)x);
     sprintf(key_b, "%lx_b", (long unsigned int)x);
-    gui_vmess("gui_drawimage_free", "s", key_a);
-    gui_vmess("gui_drawimage_free", "s", key_b);
+    gui_vmess("gui_image_free", "s", key_a);
+    gui_vmess("gui_image_free", "s", key_b);
     if (x->receive) {
         pd_unbind(&x->x_obj.ob_pd,x->receive);
     }
diff --git a/packages/linux_make/Makefile b/packages/linux_make/Makefile
index f47e205d30b1b3014e7b6e6dd2af85270596da0e..e19036680c8c3a3060326ae41d7b32be703571cc 100644
--- a/packages/linux_make/Makefile
+++ b/packages/linux_make/Makefile
@@ -12,18 +12,16 @@ BUILDLAYOUT_DIR = $(cvs_root_dir)/packages
 include $(BUILDLAYOUT_DIR)/Makefile.buildlayout
 
 # if machine has dpkg-deb, build a Debian package
-#ifeq ($(shell test -x /usr/bin/dpkg-deb && echo YES),YES)
-#  PACKAGE_TYPE = deb
-#else
-#  PACKAGE_TYPE = tarbz2
-#endif
+ifeq ($(shell test -x /usr/bin/dpkg-deb && echo YES),YES)
+  PACKAGE_TYPE = deb
+else
+  PACKAGE_TYPE = tarbz2
+endif
 
 # for command-line UNIX versions, you need to install Pd into the same
 # directory as $(prefix) otherwise Pd won't be able to find extra, doc, etc.
 ifeq ($(PACKAGE_TYPE),deb)
   prefix = /usr
-  # generates the dependencies for all externals and pd itself
-  PACKAGE_DEPENDS := $(shell find $(DESTDIR) \( -name "*.pd_linux" -or -name pd-gui -or -wholename \*bin/pd \) -print0 | xargs -0 dpkg-shlibdeps -O | sed 's|shlibs:Depends=|, |' )
 else
   prefix = /usr/local
 endif
@@ -160,6 +158,9 @@ deb: debstage
 	cp $(packages_src)/linux_make/debian/control $(DESTDIR)/DEBIAN
 	cp $(packages_src)/linux_make/debian/pd-l2ork.postrm $(DESTDIR)/DEBIAN
 	cp $(packages_src)/linux_make/debian/pd-l2ork.postinst $(DESTDIR)/DEBIAN
+# generate the dependencies for all externals and pd itself
+	$(eval PACKAGE_DEPENDS := $(shell find $(DESTDIR) \( -name "*.pd_linux" -or -name pd-gui -or -wholename \*bin/pd \) -print0 | xargs -0 dpkg-shlibdeps -O | sed 's|shlibs:Depends=|, |' ))
+
 # set build architecture and version for the package
 	sed -i 's|^Version:.*|Version: $(DEB_PD_VERSION)|' \
 		$(DESTDIR)/DEBIAN/control
@@ -279,7 +280,7 @@ test_locations:
 	@echo "EXAMPLESDIR  $(examplesdir)"
 	@echo --------------------------------------------------
 #	@echo "PACKAGE_DEPENDS 	$(PACKAGE_DEPENDS)"
-#	@echo --------------------------------------------------
+	@echo --------------------------------------------------
 	autoconf --version
 	@echo --------------------------------------------------
 	make --version
diff --git a/packages/linux_make/debian/control b/packages/linux_make/debian/control
index eb6ca665652a5e42f65aca033542f961171d1741..518fdbdaf5ad56f36484fe140f1a046c794c3250 100644
--- a/packages/linux_make/debian/control
+++ b/packages/linux_make/debian/control
@@ -6,7 +6,7 @@ Maintainer: Ivica Ico Bukvic <ico@vt.edu>
 Homepage: http://l2ork.music.vt.edu
 Package: pd-l2ork
 Architecture: i386
-Depends: libc6, xterm | x-terminal-emulator, libasound2, libjack-jackd2-0, libbluetooth3, libgl1-mesa-glx, libgl1-mesa-dri, libglu1-mesa, libftgl2, libgmerlin0, libgmerlin-avdec1, libavifile-0.7c2, libmpeg3-1 | libmpeg3-2, libquicktime2, libv4l-0, libraw1394-11, libdc1394-22, libfftw3-3, libvorbis0a, libmp3lame0, libspeex1, libgsl0ldbl | libgsl2, python, libsmpeg0, libjpeg62, libflite1, libgsm1, libxv1, fluid-soundfont-gm, byacc
+Depends: python, fluid-soundfont-gm
 Provides: pd-l2ork
 Installed-Size: 90624
 Recommends: xdg-utils, pulseaudio-utils, tap-plugins, ladspa-foo-plugins, invada-studio-plugins-ladspa, blepvco, swh-plugins, mcp-plugins, cmt, blop, slv2-jack, omins, ubuntustudio-audio-plugins, rev-plugins, dssi-utils, vco-plugins, wah-plugins, fil-plugins, mda-lv2
diff --git a/packages/linux_make/debian/control.desktop b/packages/linux_make/debian/control.desktop
index eb6ca665652a5e42f65aca033542f961171d1741..518fdbdaf5ad56f36484fe140f1a046c794c3250 100644
--- a/packages/linux_make/debian/control.desktop
+++ b/packages/linux_make/debian/control.desktop
@@ -6,7 +6,7 @@ Maintainer: Ivica Ico Bukvic <ico@vt.edu>
 Homepage: http://l2ork.music.vt.edu
 Package: pd-l2ork
 Architecture: i386
-Depends: libc6, xterm | x-terminal-emulator, libasound2, libjack-jackd2-0, libbluetooth3, libgl1-mesa-glx, libgl1-mesa-dri, libglu1-mesa, libftgl2, libgmerlin0, libgmerlin-avdec1, libavifile-0.7c2, libmpeg3-1 | libmpeg3-2, libquicktime2, libv4l-0, libraw1394-11, libdc1394-22, libfftw3-3, libvorbis0a, libmp3lame0, libspeex1, libgsl0ldbl | libgsl2, python, libsmpeg0, libjpeg62, libflite1, libgsm1, libxv1, fluid-soundfont-gm, byacc
+Depends: python, fluid-soundfont-gm
 Provides: pd-l2ork
 Installed-Size: 90624
 Recommends: xdg-utils, pulseaudio-utils, tap-plugins, ladspa-foo-plugins, invada-studio-plugins-ladspa, blepvco, swh-plugins, mcp-plugins, cmt, blop, slv2-jack, omins, ubuntustudio-audio-plugins, rev-plugins, dssi-utils, vco-plugins, wah-plugins, fil-plugins, mda-lv2
diff --git a/packages/linux_make/debian/control.raspbian b/packages/linux_make/debian/control.raspbian
index b758c52de69cc1750dec551450fc09dcc80c7894..518fdbdaf5ad56f36484fe140f1a046c794c3250 100644
--- a/packages/linux_make/debian/control.raspbian
+++ b/packages/linux_make/debian/control.raspbian
@@ -6,7 +6,7 @@ Maintainer: Ivica Ico Bukvic <ico@vt.edu>
 Homepage: http://l2ork.music.vt.edu
 Package: pd-l2ork
 Architecture: i386
-Depends: xterm | x-terminal-emulator, libasound2, libjack-jackd2-0, libbluetooth3, libgl1-mesa-glx, libglu1-mesa, libftgl2, libgmerlin0, libgmerlin-avdec1, libavifile-0.7c2, libmpeg3-1 | libmpeg3-2, libquicktime2, libv4l-0, libraw1394-11, libdc1394-22, libfftw3-3, libvorbis0a, libmp3lame0, libspeex1, libgsl0ldbl, python, libsmpeg0, libjpeg62, tkpng, libflite1, libgsm1, libxv1, fluid-soundfont-gm, byacc
+Depends: python, fluid-soundfont-gm
 Provides: pd-l2ork
 Installed-Size: 90624
 Recommends: xdg-utils, pulseaudio-utils, tap-plugins, ladspa-foo-plugins, invada-studio-plugins-ladspa, blepvco, swh-plugins, mcp-plugins, cmt, blop, slv2-jack, omins, ubuntustudio-audio-plugins, rev-plugins, dssi-utils, vco-plugins, wah-plugins, fil-plugins, mda-lv2
diff --git a/packages/linux_make/debian/control.ubuntu b/packages/linux_make/debian/control.ubuntu
index b203e170b31b2e312758f97e98d742b577902201..363fbf047959e9076be33991e6dee51fd64fffd4 100644
--- a/packages/linux_make/debian/control.ubuntu
+++ b/packages/linux_make/debian/control.ubuntu
@@ -6,7 +6,7 @@ Maintainer: Ivica Ico Bukvic <ico@vt.edu>
 Homepage: http://l2ork.music.vt.edu
 Package: pd-l2ork
 Architecture: i386
-Depends: xterm | x-terminal-emulator, libc6 (>= 2.1.5), libasound2, libjack-jackd2-0, libbluetooth3, libgl1-mesa-glx, libgl1-mesa-dri, libglu1-mesa, libglew1.5, libmagick++4, libftgl2, libgmerlin0, libgmerlin-avdec1, libavifile-0.7c2, libmpeg3-1, libquicktime2, libv4l-0, libraw1394-11, libdc1394-22, libfftw3-3, libvorbis0a, libmp3lame0, libspeex1, libgsl0ldbl, python, libsmpeg0, libjpeg62, libflite1, libgsm1
+Depends: python, fluid-soundfont-gm
 Provides: pd-l2ork
 Installed-Size: 90624
 Recommends: xdg-utils, pulseaudio-utils, tap-plugins, ladspa-foo-plugins, invada-studio-plugins-ladspa, blepvco, swh-plugins, mcp-plugins, cmt, blop, slv2-jack, omins, ubuntustudio-audio-plugins, rev-plugins, dssi-utils, vco-plugins, wah-plugins, fil-plugins, mda-lv2
diff --git a/pd/doc/4.data.structures/03.setting.data.pd b/pd/doc/4.data.structures/03.setting.data.pd
index ebe6f94547561fa305a1e4ce12812843174a6cbe..ffdb1d150f38a84a9f1154795873bff706311cf1 100644
--- a/pd/doc/4.data.structures/03.setting.data.pd
+++ b/pd/doc/4.data.structures/03.setting.data.pd
@@ -40,7 +40,7 @@
 and one unit thick \, through the points (0 \, 0) \, (w \, 0) \, (w
 \, h) \, and (0 \, h). Note that the three points containing variables
 become hot spots for mouse dragging.;
-#X text 26 204 Draw the value of q as an Araboc numeral \, at (0 \,
+#X text 26 204 Draw the value of q as an Arabic numeral \, at (0 \,
 0) \, in black.;
 #X obj 24 39 struct template3 float x float y float w float h float
 q;
diff --git a/pd/doc/5.reference/fudiformat-help.pd b/pd/doc/5.reference/fudiformat-help.pd
new file mode 100644
index 0000000000000000000000000000000000000000..a66f6ba7e31e1e2b31582c98e80089c0edaaadbd
--- /dev/null
+++ b/pd/doc/5.reference/fudiformat-help.pd
@@ -0,0 +1,38 @@
+#N canvas 51 189 685 507 10;
+#X text 36 21 fudiformat - convert lists to FUDI packets, f 61;
+#X msg 72 127 1 2 3;
+#X obj 180 312 fudiparse;
+#X obj 72 311 print packet;
+#X msg 342 389 disconnect;
+#X obj 334 416 netsend -u -b;
+#X msg 343 365 connect localhost 5000;
+#X obj 335 315 list prepend send;
+#X obj 335 340 list trim;
+#X obj 180 337 print reassembled;
+#X text 437 389 don't send;
+#X text 530 364 send as UDP;
+#X text 54 454 see also:;
+#X obj 127 455 fudiparse;
+#X obj 72 278 fudiformat;
+#X msg 80 154 foo 4 5 weasel 6 7 rat;
+#X text 125 128 FUDI messages with numbers and symbols.;
+#X text 29 55 fudiformat makes FUDI messages suitable for sending over
+the network via netsend (in UDP mode). Incoming messages are output
+as FUDI messages \, byte by byte., f 61;
+#X obj 439 250 fudiformat -u;
+#X obj 127 475 oscformat;
+#X text 281 193 The '-u' creation argument switches to "UDP" mode \,
+omitting the packet separator. This saves some two bytes \, but only
+works when sending single FUDI messages over UDP. It doesn't work with
+TCP/IP (however \, you can use the default format even with UDP transport).
+;
+#X connect 1 0 14 0;
+#X connect 2 0 9 0;
+#X connect 4 0 5 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 5 0;
+#X connect 14 0 3 0;
+#X connect 14 0 7 0;
+#X connect 14 0 2 0;
+#X connect 15 0 14 0;
diff --git a/pd/doc/5.reference/fudiparse-help.pd b/pd/doc/5.reference/fudiparse-help.pd
new file mode 100644
index 0000000000000000000000000000000000000000..8eb5a713baa2895df7a9c0a653b171bc3304b012
--- /dev/null
+++ b/pd/doc/5.reference/fudiparse-help.pd
@@ -0,0 +1,39 @@
+#N canvas 6 49 673 427 10;
+#X obj 171 286 fudiparse;
+#X text 52 373 see also:;
+#X obj 171 309 print parse-output;
+#X obj 419 231 netreceive -u -b;
+#X msg 419 176 listen 5000;
+#X msg 431 204 listen 0;
+#X text 520 203 stop listening;
+#X msg 57 181 1 2 3 foo 5;
+#X text 51 156 numbers and symbols;
+#X obj 57 286 print packet;
+#X text 416 152 packets from network;
+#X text 558 231 UDP packets \, binary output, f 13;
+#X text 80 11 fudiparse - parse FUDI packets into Pd messages, f 67
+;
+#X obj 57 206 fudiformat;
+#X obj 222 206 fudiformat -u;
+#X text 220 159 without packet separator;
+#X msg 222 181 flab -1 1.1;
+#X obj 140 373 fudiformat;
+#X obj 224 373 oscparse;
+#X obj 222 226 t a a;
+#X obj 57 226 t a a;
+#X text 45 40 fudiparse takes incoming lists of numbers \, interpreting
+them as the bytes in a FUDI message (as received when sending Pd-messages
+via [netreceive -b]).;
+#X text 521 176 listen on port 5000;
+#X connect 0 0 2 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 7 0 13 0;
+#X connect 13 0 20 0;
+#X connect 14 0 19 0;
+#X connect 16 0 14 0;
+#X connect 19 0 0 0;
+#X connect 19 1 9 0;
+#X connect 20 0 0 0;
+#X connect 20 1 9 0;
diff --git a/pd/doc/5.reference/help-intro.pd b/pd/doc/5.reference/help-intro.pd
index 58f412f7866fae9e9d655b21666a914e85315ba2..fd54495bc76bcb17e4e7eefb13bc88db352898bb 100644
--- a/pd/doc/5.reference/help-intro.pd
+++ b/pd/doc/5.reference/help-intro.pd
@@ -1,5 +1,5 @@
 #N struct ;
-#N canvas 355 65 579 812 12;
+#N canvas 394 53 579 639 12;
 #X declare;
 #X obj 24 150 bang;
 #X text 124 150 - output a bang message;
@@ -398,7 +398,6 @@ its "help window".;
 #X text 118 3676 - make copies of a subpatch;
 #X obj 26 3676 clone;
 #X obj 157 1167 midirealtimein;
-#X obj 301 1169 midiclkin;
 #X text 124 3530 - read with a time-varying delay time;
 #X obj 97 3532 vd~;
 #X obj 26 2081 rsqrt~;
diff --git a/pd/nw/locales/de/translation.json b/pd/nw/locales/de/translation.json
index d092082070d2cf252e463ca3df58f9f5c4607ee2..6b0ea4e01febdba7a7e0ea4addc83c8668359a81 100644
--- a/pd/nw/locales/de/translation.json
+++ b/pd/nw/locales/de/translation.json
@@ -306,6 +306,8 @@
         "viewbox_offsets": "Anzeigebox-Offsets",
         "arrays": "Feld-Optionen"
       },
+      "no_scroll": "Rollbalken verbergen (experimentell)",
+      "no_scroll_tt": "Rollbalken verbergen (experimentell)",
       "gop": "Anzeige im übergeordneten Patch",
       "gop_tt": "Zeige den Inhalt dieses Patches in einem Rechteck im übergeordneten Patch",
       "hide_name": "Namen und Argumente verbergen",
diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js
index 98036dd73ad802c154ee7c4ac7ca7791728e72bf..570b20e99bb0d78b99a15a6e7cf6d33a20381804 100644
--- a/pd/nw/pd_canvas.js
+++ b/pd/nw/pd_canvas.js
@@ -117,7 +117,7 @@ function nw_window_focus_callback(name) {
 
 function nw_window_blur_callback(name) {
     // Fake a mouseup event to keep from getting a dangling selection box
-    if (canvas_events.get_state === "normal") {
+    if (canvas_events.get_state() === "normal") {
         pdgui.pdsend(name, "mouseup_fake");
     }
 }
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 338f9eb960e8a84b21e544d62ba529ed16b6fd0f..be47469b56915d541ad1a3ac97fb6859cfb0bf7e 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -3575,7 +3575,7 @@ function gui_drawimage_new(obj_tag, file_path, canvasdir, flags) {
     pd_cache.set(obj_tag, drawimage_data); // add the data to container
 }
 
-function gui_drawimage_free(obj_tag) {
+function gui_image_free(obj_tag) {
     var c = pd_cache.get(obj_tag);
     if (c) {
         pd_cache.free(obj_tag); // empty the image(s)
diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
index 84748f1d840e1117d563ae93816de0f3d599488c..4c0c6591b97c9bd00a98c0bf7c064edbcebda05b 100644
--- a/pd/src/g_all_guis.c
+++ b/pd/src/g_all_guis.c
@@ -231,19 +231,15 @@ void iemgui_receive(t_iemgui *x, t_symbol *s)
 
 void iemgui_label(t_iemgui *x, t_symbol *s)
 {
+    t_symbol *old;
     if (s == &s_) s = s_empty; //tb: fix for empty label
+    old = x->x_lab;
     t_symbol *lab = iemgui_raute2dollar(s);
     x->x_lab_unexpanded = lab;
     x->x_lab = lab = canvas_realizedollar(x->x_glist, lab);
 
-    if(glist_isvisible(x->x_glist))
-    {
-        gui_vmess("gui_iemgui_label_set", "xxs",
-            glist_getcanvas(x->x_glist),
-            x,
-            s != s_empty ? x->x_lab->s_name : "");
+    if (glist_isvisible(x->x_glist) && lab != old)
         iemgui_shouldvis(x, IEM_GUI_DRAW_MODE_CONFIG);
-    }
 }
 
 void iemgui_label_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index 736a9dbd9e460f746515548b285c1fee1ea94dde..1e5d057b6c7839c3837e39de8e62cedd7be2e190 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -745,12 +745,12 @@ void canvas_scalar_event(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
 void canvas_show_scrollbars(t_canvas *x, t_floatarg f)
 {
     x->gl_noscroll = (int)f;
-    gui_vmess("gui_canvas_set_scrollbars", "xi", x, (int)f);
+    if (x->gl_mapped)
+        gui_vmess("gui_canvas_set_scrollbars", "xi", x, (int)f);
 }
 
 void canvas_show_menu(t_canvas *x, t_floatarg f)
 {
-post("setting nomenu to %d", f);
     x->gl_nomenu = (int)f;
 }
 
@@ -826,28 +826,29 @@ void canvas_map(t_canvas *x, t_floatarg f)
     t_gobj *y;
     if (flag)
     {
-        t_selection *sel;
-        if (!x->gl_havewindow)
-        {
-            bug("canvas_map");
-            canvas_vis(x, 1);
-        }
-
-        if (!x->gl_list) {
-            //if there are no objects on the canvas
-            canvas_create_editor(x);
-        }
-        else for (y = x->gl_list; y; y = y->g_next) {
-            gobj_vis(y, x, 1);
+        if (!glist_isvisible(x)) {
+            t_selection *sel;
+            if (!x->gl_havewindow)
+            {
+                bug("canvas_map");
+                canvas_vis(x, 1);
+            }
+            if (!x->gl_list) {
+                //if there are no objects on the canvas
+                canvas_create_editor(x);
+            }
+            else for (y = x->gl_list; y; y = y->g_next) {
+                gobj_vis(y, x, 1);
+            }
+            if (x->gl_editor && x->gl_editor->e_selection)
+                for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+                    gobj_select(sel->sel_what, x, 1);
+            x->gl_mapped = 1;
+            canvas_drawlines(x);
+            if (x->gl_isgraph && x->gl_goprect)
+                canvas_drawredrect(x, 1);
+            scrollbar_update(x);
         }
-        if (x->gl_editor && x->gl_editor->e_selection)
-            for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
-                gobj_select(sel->sel_what, x, 1);
-        x->gl_mapped = 1;
-        canvas_drawlines(x);
-        if (x->gl_isgraph && x->gl_goprect)
-            canvas_drawredrect(x, 1);
-        scrollbar_update(x);
     }
     else
     {
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index abea628172d14a05e7690a1065069106540dd0da..2817d1774700e3e04691c88ec96338c07d8cfe83 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -220,6 +220,13 @@ int gobj_shouldvis(t_gobj *x, struct _glist *glist)
     //fprintf(stderr,"shouldvis %d %d %d %d\n",
     //    glist->gl_havewindow, glist->gl_isgraph,
     //    glist->gl_goprect, glist->gl_owner != NULL);
+        /* if our parent is a graph, and if that graph itself isn't
+        visible, then we aren't either. */
+    if (!glist->gl_havewindow && glist->gl_isgraph && glist->gl_owner
+        && !gobj_shouldvis(&glist->gl_gobj, glist->gl_owner))
+            return (0);
+        /* if we're graphing-on-parent and the object falls outside the
+        graph rectangle, don't draw it. */
     if (!glist->gl_havewindow && glist->gl_isgraph && glist->gl_goprect &&
         glist->gl_owner && (pd_class(&x->g_pd) != scalar_class) &&
         (pd_class(&x->g_pd) != garray_class))
@@ -1329,6 +1336,14 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir,
                 do g = g->g_next in this case. */
             //int j = glist_getindex(gl, g);
             //fprintf(stderr, "rebuildlicious %d\n", j);
+
+            // Bugfix for cases where canvas_vis doesn't actually create a
+            // new editor. We need to fix canvas_vis so that the bug doesn't
+            // get triggered. But since we know this fixes a regression we'll
+            // keep this as a point in the history as we fix canvas_vis. Once
+            // that's done we can remove this call.
+            canvas_create_editor(gl);
+
             if (!gl->gl_havewindow)
             {
                 canvas_vis(glist_getcanvas(gl), 1);
@@ -1380,7 +1395,7 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir,
     them to reload an abstraction; also suppress window list update */
 int glist_amreloadingabstractions = 0;
 
-    /* call canvas_doreload on everyone */
+    /* call glist_doreload on everyone */
 void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except)
 {
     t_canvas *x;
@@ -2880,7 +2895,7 @@ static void canvas_donecanvasdialog(t_glist *x,
     {
         glist_noselect(x);
         gobj_vis(&x->gl_gobj, x->gl_owner, 0);
-        if (gobj_shouldvis(&x->gl_obj, x->gl_owner))
+        if (gobj_shouldvis(&x->gl_gobj, x->gl_owner))
         {
             gobj_vis(&x->gl_gobj, x->gl_owner, 1);
             //fprintf(stderr,"yes\n");
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index 0f39f37d07543925858fd9ce498b3940a319ff70..f6bc5151b1c37aad6a1b55071c6c4e2f400778cb 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -311,11 +311,11 @@ void glist_grab(t_glist *x, t_gobj *y, t_glistmotionfn motionfn,
 t_canvas *glist_getcanvas(t_glist *x)
 {
     //fprintf(stderr,"glist_getcanvas\n");
-    while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph &&
-        gobj_shouldvis(&x->gl_gobj, x->gl_owner))
+    while (x->gl_owner && !x->gl_havewindow && x->gl_isgraph)
     {
-            //fprintf(stderr,"x=%lx x->gl_owner=%d x->gl_havewindow=%d x->gl_isgraph=%d gobj_shouldvis=%d\n", 
-            //    x, (x->gl_owner ? 1:0), x->gl_havewindow, x->gl_isgraph, 
+            //fprintf(stderr,"x=%lx x->gl_owner=%d x->gl_havewindow=%d "
+            //               "x->gl_isgraph=%d gobj_shouldvis=%d\n", 
+            //    x, (x->gl_owner ? 1:0), x->gl_havewindow, x->gl_isgraph,
             //    gobj_shouldvis(&x->gl_gobj, x->gl_owner));
             x = x->gl_owner;
             //fprintf(stderr,"+\n");
@@ -1244,7 +1244,6 @@ static void graph_getrect(t_gobj *z, t_glist *glist,
         int hadwindow;
         t_gobj *g;
         int x21, y21, x22, y22;
-
         graph_graphrect(z, glist, &x1, &y1, &x2, &y2);
         //fprintf(stderr,"%d %d %d %d\n", x1, y1, x2, y2);
 
@@ -1266,7 +1265,6 @@ static void graph_getrect(t_gobj *z, t_glist *glist,
             hadwindow = x->gl_havewindow;
             x->gl_havewindow = 0;
             for (g = x->gl_list; g; g = g->g_next)
-                if (gobj_shouldvis(g, x))
             {
                     /* don't do this for arrays, just let them hang outside the
                     box. */
@@ -1435,7 +1433,7 @@ static void graph_select(t_gobj *z, t_glist *glist, int state)
         }
         if (glist_isvisible(glist) &&
                 (glist_istoplevel(glist) ||
-                 gobj_shouldvis(x, glist)))
+                 gobj_shouldvis(z, glist)))
         {
             if (state)
                 gui_vmess("gui_gobj_select", "xs",
diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c
index fc5ee264a3fd8be5777121d395666f78b86c68d7..a5977ada5ff1c3f175370cb5b3c45a427084ae7a 100644
--- a/pd/src/g_mycanvas.c
+++ b/pd/src/g_mycanvas.c
@@ -28,7 +28,7 @@ void my_canvas_draw_new(t_my_canvas *x, t_glist *glist)
     sprintf(cbuf, "#%6.6x", x->x_gui.x_bcol);
 
     gui_vmess("gui_gobj_new", "xxsiii", canvas,
-        x, "iemgui", x1, y1, glist_istoplevel(canvas));
+        x, "iemgui", x1, y1, glist_istoplevel(glist));
     gui_vmess("gui_mycanvas_new", "xxsiiiiii", canvas,
         x, cbuf, x1, y1, x1+x->x_vis_w, y1+x->x_vis_h,
         x1+x->x_gui.x_w, y1+x->x_gui.x_h);
diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c
index 92b5bd7d5cb669d382a0ca847b86257b1976f1a0..a3affb88f8ac10b4cd97e6e523a18e420c7387e3 100644
--- a/pd/src/g_readwrite.c
+++ b/pd/src/g_readwrite.c
@@ -402,6 +402,8 @@ void canvas_doaddtemplate(t_symbol *templatesym,
 
 static void glist_writelist(t_gobj *y, t_binbuf *b);
 
+void binbuf_savetext(t_binbuf *bfrom, t_binbuf *bto);
+
 void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b,
     int amarrayelement)
 {
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 028e834f27fd8bf8d1babcde0cb38a2169e5bee8..854404b3c9857d30b486d5ee33f510f0758f91ba 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -363,12 +363,6 @@ static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto,
         }
         else if (ds->ds_type == DT_ARRAY)
         {
-            t_symbol *arraytemplate = ds->ds_fieldtemplate;
-            if (arraytemplate == tfrom->t_sym ||
-                arraytemplate == tto->t_sym)
-            {
-                return 0;
-            }
             template_conformarray(tfrom, tto, conformaction, 
                 x->sc_vec[i].w_array);
         }
@@ -1744,8 +1738,15 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s,
       need to experiment with gop scalars to make sure I'm not breaking
       anything */ 
     char tag[MAXPDSTRING];
-    int index = (array ?
-        ((((char *)data) - array->a_vec) / array->a_elemsize) : -1);
+    int index;
+    if (array)
+    {
+        int elemsize = array->a_elemsize;
+        if (!elemsize) elemsize = 1;
+        index = (((char *)data) - array->a_vec) / elemsize;
+    }
+    else
+        index = -1;
     if (x->x_type == gensym("g") || x->x_type == gensym("svg"))
     {
         sprintf(tag, "dgroup%lx.%lx",
@@ -2141,7 +2142,22 @@ void svg_register_events(t_gobj *z, t_canvas *c, t_scalar *sc,
     t_template *template, t_word *data, t_array *a)
 {
     t_svg *svg;
-    int index = (a ? ((((char *)data) - a->a_vec) / a->a_elemsize) : -1);
+    int index;
+    if (a)
+    {
+        int elemsize = a->a_elemsize; 
+        /* avoid divide-by-zero in case our elemsize is 0. Currently
+           there's no practical use case for an array of elements which
+           have zero size as there's no way to differentiate their
+           visualization. However if [draw array] changes in the future
+           to allow spacing out element groups or something like that,
+           we will have to revisit this workaround we're using to get
+           the element's index. */
+        if (!elemsize) elemsize = 1;
+        index = (((char *)data) - a->a_vec) / elemsize;
+    }
+    else
+        index = -1;
     char tagbuf[MAXPDSTRING];
     if (pd_class(&z->g_pd) == canvas_class)
     {
@@ -2161,9 +2177,8 @@ void svg_register_events(t_gobj *z, t_canvas *c, t_scalar *sc,
         sprintf(tagbuf, "draw%lx.%lx", (long unsigned int)z,
             (long unsigned int)data);
     }
-    else
+    else /* legacy drawing commands: curve, drawnumber, etc. */
     {
-        error("scalar: can't set event for unknown drawing command");
         return;
     }
     if (svg->x_events.e_mouseover.a_flag)
@@ -2230,8 +2245,6 @@ void svg_setattr(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
    the arguments in an existing [draw svg] object. */
 void svg_update_args(t_svg *x, t_symbol *s, int argc, t_atom *argv)
 {
-post("made it to args");
-if (argc) post("first arg is %s", atom_getsymbolarg(0, argc, argv)->s_name);
     /* "g" doesn't take any args, so check for "svg" arg */
     if (atom_getsymbolarg(0, argc, argv) == gensym("svg"))
     {
@@ -4470,35 +4483,48 @@ static int draw_click(t_gobj *z, t_glist *glist,
    But the one person I know who uses nested ds arrays hasn't asked for
    that, so let's see if we can just make it to the end of this software's
    life before that happens. */
-static void scalar_spelunkforword(t_scalar *x, t_symbol *s, int word_index,
-    t_array **array, t_word **data)
-{
-    /* from glob_findinstance */
-    long obj = 0;
-    if (sscanf(s->s_name, "x%lx", &obj))
-    {
-        t_template *template = template_findbyname(x->sc_template);
-        if (!template)
-        {
-            pd_error(x, "scalar: template disappeared before notification "
-                        "from gui arrived");
+static void scalar_spelunkforword(void* word_candidate, t_template* template,
+    t_word *data, int word_index, t_array **arrayp, t_word **datap)
+{
+    int i, nitems = template->t_n;
+    t_dataslot *datatypes = template->t_vec;
+    t_word *wp = data;
+    for (i = 0; i < nitems; i++, datatypes++, wp++)
+    {
+        if (datatypes->ds_type == DT_ARRAY &&
+            ((void *)wp->w_array) == (void *)word_candidate)
+        {
+                /* Make sure we're in range, as the array could have been
+                   resized. In that case simply return */
+            if (word_index >= wp->w_array->a_n) return;
+            *arrayp = wp->w_array;
+            *datap = ((t_word *)(wp->w_array->a_vec +
+                word_index * wp->w_array->a_elemsize));
             return;
         }
-        int i, nitems = template->t_n;
-        t_dataslot *datatypes = template->t_vec;
-        t_word *wp = x->sc_vec;
-        for (i = 0; i < nitems; i++, datatypes++, wp++)
+    }
+        /* Now swoop through the headers again and recursively search
+           any arrays for nested data. We do this as a second step so
+           that toplevel arrays don't take a performance hit from deeply
+           nested arrays. (Probably not a big deal for click events, but
+           for complex data structures it could be noticeable for drag
+           events */
+    wp = data;
+    datatypes = template->t_vec;
+    for (i = 0; i < nitems; i++, datatypes++, wp++)
+        if (datatypes->ds_type == DT_ARRAY)
         {
-            if (datatypes->ds_type == DT_ARRAY &&
-                ((void *)wp->w_array) == (void *)obj &&
-                word_index < wp->w_array->a_n)
+            t_template* t = template_findbyname(wp->w_array->a_templatesym);
+            if (t)
             {
-                *array = wp->w_array;
-                *data = ((t_word *)(wp->w_array->a_vec +
-                    word_index * wp->w_array->a_elemsize));
+                int i, elemsize = wp->w_array->a_elemsize;
+                char *vec;
+                for(i = 0, vec = wp->w_array->a_vec; i < wp->w_array->a_n; i++)
+                    scalar_spelunkforword(word_candidate, t,
+                        (t_word *)(wp->w_array->a_vec + i * elemsize),
+                            word_index, arrayp, datap);
             }
         }
-    }
 }
 
 void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
@@ -4526,11 +4552,24 @@ void draw_notify(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
        or greater then that's what we have */
     if (index > -1)
     {
-        scalar_spelunkforword(sc, array_sym, index, &a, &data);
+        t_template *template = template_findbyname(sc->sc_template);
+        if (!template)
+        {
+            pd_error(sc, "scalar: template disappeared before notification "
+                        "from gui arrived");
+            return;
+        }
+        long word_candidate = 0; /* from glob_findinstance */
+        if (!sscanf(array_sym->s_name, "x%lx", &word_candidate))
+        {
+            pd_error(sc, "scalar: couldn't read array datum from GUI");
+            return;
+        }
+        scalar_spelunkforword((void *)word_candidate, template, sc->sc_vec,
+            index, &a, &data);
         if (!data)
         {
-            pd_error(x, "scalar: couldn't get array data for event "
-                        "callback");
+            pd_error(x, "scalar: couldn't get array data for event callback");
             return;
         }
     }
@@ -8460,7 +8499,7 @@ static void drawimage_free(t_drawimage *x)
     //sprintf(buf, ".x%lx", (t_int)x);
     sprintf(buf, "x%lx", (long unsigned int)x);
     pd_unbind(&x->x_obj.ob_pd, gensym(buf));
-    gui_vmess("gui_drawimage_free", "x", x);
+    gui_vmess("gui_image_free", "x", x);
 }
 
 static void drawimage_setup(void)
diff --git a/pd/src/m_imp.h b/pd/src/m_imp.h
index 9512a1abd87d3a0293e3d25be82f74c8b5a08674..1eb08e6192aedd84f904fbfcb71eb4e1a70c8fad 100644
--- a/pd/src/m_imp.h
+++ b/pd/src/m_imp.h
@@ -74,7 +74,6 @@ struct _pdinstance
     t_symbol *pd_bendin_sym;
     t_symbol *pd_touchin_sym;
     t_symbol *pd_polytouchin_sym;
-    t_symbol *pd_midiclkin_sym;
     t_symbol *pd_midirealtimein_sym;
 };
 
diff --git a/pd/src/m_pd.c b/pd/src/m_pd.c
index 1bf74a280d2170c7c51b4dc1b0644e3f0478beb8..0583c213c04eae1e7f5ecedc3836b9f2ccc52c08 100644
--- a/pd/src/m_pd.c
+++ b/pd/src/m_pd.c
@@ -478,7 +478,6 @@ static t_pdinstance *pdinstance_donew(int useprefix)
     x->pd_bendin_sym = midi_gensym(midiprefix, "#bendin");
     x->pd_touchin_sym = midi_gensym(midiprefix, "#touchin");
     x->pd_polytouchin_sym = midi_gensym(midiprefix, "#polytouchin");
-    x->pd_midiclkin_sym = midi_gensym(midiprefix, "#midiclkin");
     x->pd_midirealtimein_sym = midi_gensym(midiprefix, "#midirealtimein");
     return (x);
 }
diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h
index c2176996294e5699a8b25557bae0aad4c70ae207..f274ae2423ffb848f1883255487df5afa3bf59cd 100644
--- a/pd/src/m_pd.h
+++ b/pd/src/m_pd.h
@@ -14,7 +14,7 @@ extern "C" {
 #define PD_MINOR_VERSION 48
 #define PD_BUGFIX_VERSION 0
 #define PD_TEST_VERSION ""
-#define PD_L2ORK_VERSION "2.4.3"
+#define PD_L2ORK_VERSION "2.4.7"
 #define PDL2ORK
 extern int pd_compatibilitylevel;   /* e.g., 43 for pd 0.43 compatibility */
 
diff --git a/pd/src/s_file.c b/pd/src/s_file.c
index 8ffcffcaf090df721f794d0b0a26772a6e23e9a6..c12bb98b69cf8b650f151814ba0393f8f0c60db5 100644
--- a/pd/src/s_file.c
+++ b/pd/src/s_file.c
@@ -46,7 +46,7 @@ void sys_doflags( void);
 
 #ifdef UNIX
 
-#define USER_CONFIG_DIR ".pd-l2ork"
+#define USER_CONFIG_DIR ".purr-data"
 
 static char *sys_prefbuf;
 
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
index a3b7fa4540d98e429a5b92fb66b234709279afd0..7039aa4b9a5f8509f3ac8e2fd4cf647dbe9b87aa 100644
--- a/pd/src/s_loader.c
+++ b/pd/src/s_loader.c
@@ -462,7 +462,7 @@ static t_pd *do_create_abstraction(t_symbol*s, int argc, t_atom *argv)
         const char *objectname = s->s_name;
         char dirbuf[MAXPDSTRING], classslashclass[MAXPDSTRING], *nameptr;
         t_glist *glist = (t_glist *)canvas_getcurrent();
-        t_canvas *canvas = (t_canvas*)glist_getcanvas(glist);
+        t_canvas *canvas = (t_canvas*)canvas_getrootfor(glist);
         int fd = -1;
 
         t_pd *was = s__X.s_thing;
diff --git a/pd/src/s_midi.c b/pd/src/s_midi.c
index 565284a360fd800d5d18974d445e0cf1a1fd1f64..289d702433ff094b913db0415de5f2dfcb29d55a 100644
--- a/pd/src/s_midi.c
+++ b/pd/src/s_midi.c
@@ -239,11 +239,6 @@ void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
         pitch, value);
 }
 
-void outmidi_mclk(int portno)
-{
-   sys_queuemidimess(portno, 1, 0xf8, 0,0);
-}
-
 void outmidi_byte(int portno, int value)
 {
 #ifdef USEAPI_ALSA
@@ -291,7 +286,6 @@ typedef struct midiparser
 
     /* functions in x_midi.c */
 void inmidi_realtimein(int portno, int cmd);
-void inmidi_clk(double timing);
 void inmidi_byte(int portno, int byte);
 void inmidi_sysex(int portno, int byte);
 void inmidi_noteon(int portno, int channel, int pitch, int velo);
@@ -316,14 +310,6 @@ static void sys_dispatchnextmidiin( void)
     if (byte >= 0xf8)
     {
         inmidi_realtimein(portno, byte);
-        if (byte == 0xf8) {
-          // AG: Not sure what the timebase for the right outlet is supposed
-          // to be. I'm using msecs right now, which is in line with the other
-          // tempo-related objects such as metro. Multiply with .001 to
-          // get seconds instead.
-          double timing = clock_gettimesince(sys_midiinittime);
-          inmidi_clk(timing);
-        }
     }
     else
     {
diff --git a/pd/src/s_stuff.h.in b/pd/src/s_stuff.h.in
index 0fb85a58a9024504c115fb3d5655f23cad1b2890..5e48f33cec95e009f10a2e67922c3f901c2ae98d 100644
--- a/pd/src/s_stuff.h.in
+++ b/pd/src/s_stuff.h.in
@@ -440,7 +440,7 @@ EXTERN void alist_init(t_alist *x);
 EXTERN void alist_clear(t_alist *x);
 EXTERN void alist_list(t_alist *x, t_symbol *s, int argc, t_atom *argv);
 EXTERN void alist_anything(t_alist *x, t_symbol *s, int argc, t_atom *argv);
-EXTERN void alist_toatoms(t_alist *x, t_atom *to);
-EXTERN void alist_clone(t_alist *x, t_alist *y);
+EXTERN void alist_toatoms(t_alist *x, t_atom *to, int onset, int count);
+EXTERN void alist_clone(t_alist *x, t_alist *y, int onset, int count);
 
 #endif /* __s_stuff_h_ */
diff --git a/pd/src/x_list.c b/pd/src/x_list.c
index d43378a2191d50ed063a0ab1d303873aa3e287c8..e03829441cb2800ad4c5df064d248a3a241a426a 100644
--- a/pd/src/x_list.c
+++ b/pd/src/x_list.c
@@ -79,21 +79,33 @@ void alist_init(t_alist *x)
 
 void alist_clear(t_alist *x)
 {
-    if (x->l_n)
+    int i;
+    for (i = 0; i < x->l_n; i++)
     {
-        int i;
-        for (i = 0; i < x->l_n; i++)
+        if (x->l_vec[i].l_a.a_type == A_POINTER)
+            gpointer_unset(x->l_vec[i].l_a.a_w.w_gpointer);
+    }
+    if (x->l_vec)
+        freebytes(x->l_vec, x->l_n * sizeof(*x->l_vec));
+}
+
+static void alist_copyin(t_alist *x, t_symbol *s, int argc, t_atom *argv,
+    int where)
+{
+    int i, j;
+    for (i = 0, j = where; i < argc; i++, j++)
+    {
+        x->l_vec[j].l_a = argv[i];
+        if (x->l_vec[j].l_a.a_type == A_POINTER)
         {
-            if (x->l_vec[i].l_a.a_type == A_POINTER)
-                gpointer_unset(x->l_vec[i].l_a.a_w.w_gpointer);
+            x->l_npointer++;
+            gpointer_copy(x->l_vec[j].l_a.a_w.w_gpointer, &x->l_vec[j].l_p);
+            x->l_vec[j].l_a.a_w.w_gpointer = &x->l_vec[j].l_p;
         }
-        if (x->l_vec)
-            freebytes(x->l_vec, x->l_n * sizeof(*x->l_vec));
     }
-    x->l_n = 0;
-    x->l_npointer = 0;
 }
 
+    /* set contents to a list */
 void alist_list(t_alist *x, t_symbol *s, int argc, t_atom *argv)
 {
     int i;
@@ -118,6 +130,7 @@ void alist_list(t_alist *x, t_symbol *s, int argc, t_atom *argv)
     }
 }
 
+    /* set contents to an arbitrary non-list message */
 void alist_anything(t_alist *x, t_symbol *s, int argc, t_atom *argv)
 {
     int i;
@@ -143,32 +156,32 @@ void alist_anything(t_alist *x, t_symbol *s, int argc, t_atom *argv)
     }
 }
 
-void alist_toatoms(t_alist *x, t_atom *to)
+void alist_toatoms(t_alist *x, t_atom *to, int onset, int count)
 {
     int i;
-    for (i = 0; i < x->l_n; i++)
-        to[i] = x->l_vec[i].l_a;
+    for (i = 0; i < count; i++)
+        to[i] = x->l_vec[onset + i].l_a;
 }
 
-
-void alist_clone(t_alist *x, t_alist *y)
+void alist_clone(t_alist *x, t_alist *y, int onset, int count)
 {
     int i;
     y->l_pd = alist_class;
-    y->l_n = x->l_n;
-    y->l_npointer = x->l_npointer;
+    y->l_n = count;
+    y->l_npointer = 0;
     if (!(y->l_vec = (t_listelem *)getbytes(y->l_n * sizeof(*y->l_vec))))
     {
         y->l_n = 0;
         error("list_alloc: out of memory");
     }
-    else for (i = 0; i < x->l_n; i++)
+    else for (i = 0; i < count; i++)
     {
-        y->l_vec[i].l_a = x->l_vec[i].l_a;
+        y->l_vec[i].l_a = x->l_vec[onset + i].l_a;
         if (y->l_vec[i].l_a.a_type == A_POINTER)
         {
             gpointer_copy(y->l_vec[i].l_a.a_w.w_gpointer, &y->l_vec[i].l_p);
             y->l_vec[i].l_a.a_w.w_gpointer = &y->l_vec[i].l_p;
+            y->l_npointer++;
         }
     }
 }
@@ -205,20 +218,22 @@ static void list_append_list(t_list_append *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc;
     XL_ATOMS_ALLOCA(outv, outc);
     atoms_copy(argc, argv, outv);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv+argc);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv+argc, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv+argc);
+        alist_toatoms(&x->x_alist, outv+argc, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     XL_ATOMS_FREEA(outv, outc);
@@ -228,21 +243,23 @@ static void list_append_anything(t_list_append *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc + 1;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc + 1;
     XL_ATOMS_ALLOCA(outv, outc);
     SETSYMBOL(outv, s);
     atoms_copy(argc, argv, outv + 1);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv + 1 + argc);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv + 1 + argc, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv + 1 + argc);
+        alist_toatoms(&x->x_alist, outv + 1 + argc, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     XL_ATOMS_FREEA(outv, outc);
@@ -309,20 +326,22 @@ static void list_cat_list(t_list_cat *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc;
     XL_ATOMS_ALLOCA(outv, outc);
     atoms_copy(argc, argv, outv + x->x_alist.l_n);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv);
+        alist_toatoms(&x->x_alist, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     alist_list(&x->x_alist, s, outc, outv);
@@ -333,21 +352,23 @@ static void list_cat_anything(t_list_cat *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc + 1;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc + 1;
     XL_ATOMS_ALLOCA(outv, outc);
     SETSYMBOL(outv + x->x_alist.l_n, s);
     atoms_copy(argc, argv, outv + x->x_alist.l_n + 1);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv);
+        alist_toatoms(&x->x_alist, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     if (x->x_alist.l_n <= 1)
@@ -406,20 +427,22 @@ static void list_prepend_list(t_list_prepend *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc;
     XL_ATOMS_ALLOCA(outv, outc);
-    atoms_copy(argc, argv, outv + x->x_alist.l_n);
+    atoms_copy(argc, argv, outv + n);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv);
+        alist_toatoms(&x->x_alist, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     XL_ATOMS_FREEA(outv, outc);
@@ -431,21 +454,23 @@ static void list_prepend_anything(t_list_prepend *x, t_symbol *s,
     int argc, t_atom *argv)
 {
     t_atom *outv;
-    int outc = x->x_alist.l_n + argc + 1;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc + 1;
     XL_ATOMS_ALLOCA(outv, outc);
-    SETSYMBOL(outv + x->x_alist.l_n, s);
-    atoms_copy(argc, argv, outv + x->x_alist.l_n + 1);
+    SETSYMBOL(outv + n, s);
+    atoms_copy(argc, argv, outv + n + 1);
     if (x->x_alist.l_npointer)
     {
         t_alist y;
-        alist_clone(&x->x_alist, &y);
-        alist_toatoms(&y, outv);
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
         alist_clear(&y);
     }
     else
     {
-        alist_toatoms(&x->x_alist, outv);
+        alist_toatoms(&x->x_alist, outv, 0, n);
         outlet_list(x->x_obj.ob_outlet, &s_list, outc, outv);
     }
     XL_ATOMS_FREEA(outv, outc);
@@ -468,6 +493,162 @@ static void list_prepend_setup(void)
 
 }
 
+/* ------------- list store --------------------- */
+
+t_class *list_store_class;
+
+typedef struct _list_store
+{
+    t_object x_obj;
+    t_alist x_alist;
+    t_outlet *x_out1;
+    t_outlet *x_out2;
+} t_list_store;
+
+static void *list_store_new(t_symbol *s, int argc, t_atom *argv)
+{
+    t_list_store *x = (t_list_store *)pd_new(list_store_class);
+    alist_init(&x->x_alist);
+    alist_list(&x->x_alist, 0, argc, argv);
+    x->x_out1 = outlet_new(&x->x_obj, &s_list);
+    x->x_out2 = outlet_new(&x->x_obj, &s_bang);
+    inlet_new(&x->x_obj, &x->x_alist.l_pd, 0, 0);
+    return (x);
+}
+
+static void list_store_list(t_list_store *x, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    t_atom *outv;
+    int n, outc;
+    n = x->x_alist.l_n;
+    outc = n + argc;
+    ATOMS_ALLOCA(outv, outc);
+    atoms_copy(argc, argv, outv);
+    if (x->x_alist.l_npointer)
+    {
+        t_alist y;
+        alist_clone(&x->x_alist, &y, 0, n);
+        alist_toatoms(&y, outv+argc, 0, n);
+        outlet_list(x->x_out1, &s_list, outc, outv);
+        alist_clear(&y);
+    }
+    else
+    {
+        alist_toatoms(&x->x_alist, outv+argc, 0, n);
+        outlet_list(x->x_out1, &s_list, outc, outv);
+    }
+    ATOMS_FREEA(outv, outc);
+}
+
+/* function to restore gpointers after the list has moved in memory */
+static void list_store_restore_gpointers(t_list_store *x, int offset, int count)
+{
+    t_listelem *vec = x->x_alist.l_vec + offset;
+    while (count--)
+    {
+        if (vec->l_a.a_type == A_POINTER)
+            vec->l_a.a_w.w_gpointer = &vec->l_p;
+        vec++;
+    }
+}
+
+static void list_store_append(t_list_store *x, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    t_listelem *oldptr = x->x_alist.l_vec;
+
+    if (!(x->x_alist.l_vec = (t_listelem *)resizebytes(x->x_alist.l_vec,
+        (x->x_alist.l_n) * sizeof(*x->x_alist.l_vec),
+        (x->x_alist.l_n + argc) * sizeof(*x->x_alist.l_vec))))
+    {
+        x->x_alist.l_n = 0;
+        error("list: out of memory");
+        return;
+    }
+
+        /* fix gpointers if resizebytes() has moved the alist in memory */
+    if (x->x_alist.l_vec != oldptr && x->x_alist.l_npointer)
+        list_store_restore_gpointers(x, 0, x->x_alist.l_n);
+
+    alist_copyin(&x->x_alist, s, argc, argv, x->x_alist.l_n);
+    x->x_alist.l_n += argc;
+}
+
+static void list_store_prepend(t_list_store *x, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    if (!(x->x_alist.l_vec = (t_listelem *)resizebytes(x->x_alist.l_vec,
+    (x->x_alist.l_n) * sizeof(*x->x_alist.l_vec),
+    (x->x_alist.l_n + argc) * sizeof(*x->x_alist.l_vec))))
+    {
+        x->x_alist.l_n = 0;
+        error("list: out of memory");
+        return;
+    }
+
+    memmove(x->x_alist.l_vec + argc, x->x_alist.l_vec,
+        x->x_alist.l_n * sizeof(*x->x_alist.l_vec));
+
+        /* we always have to fix gpointers because of memmove() */
+    if (x->x_alist.l_npointer)
+        list_store_restore_gpointers(x, argc, x->x_alist.l_n);
+
+    alist_copyin(&x->x_alist, s, argc, argv, 0);
+    x->x_alist.l_n += argc;
+}
+
+static void list_store_get(t_list_store *x, float f1, float f2)
+{
+    t_atom *outv;
+    int onset = f1, outc = f2;
+    if (onset < 0 || outc < 0)
+    {
+        pd_error(x, "list_store_get: negative range (%d %d)", onset, outc);
+        return;
+    }
+    if (onset + outc > x->x_alist.l_n)
+    {
+        outlet_bang(x->x_out2);
+        return;
+    }
+    ATOMS_ALLOCA(outv, outc);
+    if (x->x_alist.l_npointer)
+    {
+        t_alist y;
+        alist_clone(&x->x_alist, &y, onset, outc);
+        alist_toatoms(&y, outv, 0, outc);
+        outlet_list(x->x_out1, &s_list, outc, outv);
+        alist_clear(&y);
+    }
+    else
+    {
+        alist_toatoms(&x->x_alist, outv, onset, outc);
+        outlet_list(x->x_out1, &s_list, outc, outv);
+    }
+    ATOMS_FREEA(outv, outc);
+}
+
+static void list_store_free(t_list_store *x)
+{
+    alist_clear(&x->x_alist);
+}
+
+static void list_store_setup(void)
+{
+    list_store_class = class_new(gensym("list store"),
+        (t_newmethod)list_store_new, (t_method)list_store_free,
+        sizeof(t_list_store), 0, A_GIMME, 0);
+    class_addlist(list_store_class, list_store_list);
+    class_addmethod(list_store_class, (t_method)list_store_append,
+        gensym("append"), A_GIMME, 0);
+    class_addmethod(list_store_class, (t_method)list_store_prepend,
+        gensym("prepend"), A_GIMME, 0);
+    class_addmethod(list_store_class, (t_method)list_store_get,
+        gensym("get"), A_FLOAT, A_FLOAT, 0);
+    class_sethelpsymbol(list_store_class, &s_list);
+}
+
 /* ------------- list split --------------------- */
 
 t_class *list_split_class;
@@ -709,6 +890,8 @@ static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
             newest = list_fromsymbol_new();
         else if (s2 == gensym("tosymbol"))
             newest = list_tosymbol_new();
+        else if (s2 == gensym("store"))
+            newest = list_store_new(s, argc-1, argv+1);
         else 
         {
             error("list %s: unknown function", s2->s_name);
@@ -724,6 +907,7 @@ void x_list_setup(void)
     list_append_setup();
     list_cat_setup();
     list_prepend_setup();
+    list_store_setup();
     list_split_setup();
     list_trim_setup();
     list_length_setup();
diff --git a/pd/src/x_midi.c b/pd/src/x_midi.c
index b98034e1b50913476d55824046649503e3ddbcbd..4926b223c2e5945b0956b3f0180ff26431e939fd 100644
--- a/pd/src/x_midi.c
+++ b/pd/src/x_midi.c
@@ -12,7 +12,6 @@ void outmidi_programchange(int portno, int channel, int value);
 void outmidi_pitchbend(int portno, int channel, int value);
 void outmidi_aftertouch(int portno, int channel, int value);
 void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
-void outmidi_mclk(int portno);
 void outmidi_byte(int portno, int value);
 
 
@@ -499,74 +498,6 @@ void inmidi_polyaftertouch(int portno, int channel, int pitch, int value)
     }
 }
 
-/*----------------------- midiclkin--(midi F8 message )---------------------*/
-
-static t_class *midiclkin_class;
-
-typedef struct _midiclkin
-{
-    t_object x_obj;
-    t_outlet *x_outlet1;
-    t_outlet *x_outlet2;
-} t_midiclkin;
-
-static void *midiclkin_new(t_floatarg f)
-{
-    t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
-    x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
-    x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
-    pd_bind(&x->x_obj.ob_pd, pd_this->pd_midiclkin_sym);
-    return (x);
-}
-
-static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv)
-{
-    t_float value = atom_getfloatarg(0, argc, argv);
-    t_float count = atom_getfloatarg(1, argc, argv);
-    outlet_float(x->x_outlet2, count);
-    outlet_float(x->x_outlet1, value);
-}
-
-static void midiclkin_free(t_midiclkin *x)
-{
-    pd_unbind(&x->x_obj.ob_pd, pd_this->pd_midiclkin_sym);
-}
-
-static void midiclkin_setup(void)
-{
-    midiclkin_class = class_new(gensym("midiclkin"),
-        (t_newmethod)midiclkin_new, (t_method)midiclkin_free,
-            sizeof(t_midiclkin), CLASS_NOINLET, A_DEFFLOAT, 0);
-    class_addlist(midiclkin_class, midiclkin_list);
-        class_sethelpsymbol(midiclkin_class, gensym("midi"));
-}
-
-void inmidi_clk(double timing)
-{
-
-    static t_float prev = 0;
-    static t_float count = 0;
-    t_float cur,diff;
-
-    if (pd_this->pd_midiclkin_sym->s_thing)
-    {
-        t_atom at[2];
-        diff =timing - prev;
-        count++;
-
-        if (count == 3)
-        {  /* 24 count per quoter note */
-             SETFLOAT(at, 1 );
-             count = 0;
-        }
-        else SETFLOAT(at, 0);
-
-        SETFLOAT(at+1, diff);
-        pd_list(pd_this->pd_midiclkin_sym->s_thing, &s_list, 2, at);
-        prev = timing;
-    }
-}
-
 /*----------midirealtimein (midi FA,FB,FC,FF message )-----------------*/
 
 static t_class *midirealtimein_class;
@@ -1269,7 +1200,6 @@ void x_midi_setup(void)
     bendin_setup();
     touchin_setup();
     polytouchin_setup();
-    midiclkin_setup();
     midiout_setup();
     noteout_setup();
     ctlout_setup();
diff --git a/pd/src/x_misc.c b/pd/src/x_misc.c
index 27d489e2a9905f231f4dd465e5cfab927bd9143e..e468fe31eba04bb9e9398937f7a037180360858b 100644
--- a/pd/src/x_misc.c
+++ b/pd/src/x_misc.c
@@ -36,6 +36,14 @@
 #define CLOCKHZ sysconf(_SC_CLK_TCK)
 #endif
 
+#ifdef _WIN32
+# include <malloc.h> /* MSVC or mingw on Windows */
+#elif defined(__linux__) || defined(__APPLE__)
+# include <alloca.h> /* linux, mac, mingw, cygwin */
+#else
+# include <stdlib.h> /* BSDs for example */
+#endif
+
 /* -------------------------- random ------------------------------ */
 /* this is strictly homebrew and untested. */
 
@@ -793,6 +801,167 @@ void oscformat_setup(void)
     class_addlist(oscformat_class, oscformat_list);
 }
 
+/* ---------- fudiparse - parse bytelists to to FUDI messages ----------------- */
+
+static t_class *fudiparse_class;
+
+typedef struct _fudiparse {
+  t_object  x_obj;
+  t_outlet *x_msgout;
+  char     *x_bytes;
+  size_t    x_numbytes;
+} t_fudiparse;
+
+static void fudiparse_binbufout(t_fudiparse *x, t_binbuf *b)
+{
+  int msg, natom = binbuf_getnatom(b);
+  t_atom *at = binbuf_getvec(b);
+  for (msg = 0; msg < natom;) {
+    int emsg;
+    for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
+           && at[emsg].a_type != A_SEMI; emsg++)
+      ;
+    if (emsg > msg) {
+      int i;
+      /* check for illegal atoms */
+      for (i = msg; i < emsg; i++)
+        if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) {
+          pd_error(x, "fudiparse: got dollar sign in message");
+          goto nodice;
+        }
+
+      if (at[msg].a_type == A_FLOAT) {
+        if (emsg > msg + 1)
+          outlet_list(x->x_msgout, 0, emsg-msg, at + msg);
+        else outlet_float(x->x_msgout, at[msg].a_w.w_float);
+      }
+      else if (at[msg].a_type == A_SYMBOL) {
+        outlet_anything(x->x_msgout, at[msg].a_w.w_symbol,
+                        emsg-msg-1, at + msg + 1);
+      }
+    }
+  nodice:
+    msg = emsg + 1;
+  }
+}
+static void fudiparse_list(t_fudiparse *x, t_symbol*s, int argc, t_atom*argv) {
+  size_t len = argc;
+  t_binbuf* bbuf = binbuf_new();
+  char*cbuf;
+  if((size_t)argc > x->x_numbytes) {
+    freebytes(x->x_bytes, x->x_numbytes);
+    x->x_numbytes = argc;
+    x->x_bytes = getbytes(x->x_numbytes);
+  }
+  cbuf = x->x_bytes;
+
+  while(argc--) {
+    char b = atom_getfloat(argv++);
+    *cbuf++ = b;
+  }
+  binbuf_text(bbuf, x->x_bytes, len);
+
+  fudiparse_binbufout(x, bbuf);
+
+  binbuf_free(bbuf);
+}
+
+static void fudiparse_free(t_fudiparse *x) {
+  freebytes(x->x_bytes, x->x_numbytes);
+  x->x_bytes = NULL;
+  x->x_numbytes = 0;
+}
+
+static void *fudiparse_new(void) {
+  t_fudiparse *x = (t_fudiparse *)pd_new(fudiparse_class);
+  x->x_msgout = outlet_new(&x->x_obj, 0);
+  x->x_numbytes = 1024;
+  x->x_bytes = getbytes(x->x_numbytes);
+  return (void *)x;
+}
+
+void fudiparse_setup(void) {
+  fudiparse_class = class_new(gensym("fudiparse"),
+                              (t_newmethod)fudiparse_new,
+                              (t_method)fudiparse_free,
+                              sizeof(t_fudiparse), CLASS_DEFAULT,
+                              0);
+  class_addlist(fudiparse_class, fudiparse_list);
+}
+/* --------- fudiformat - format Pd (FUDI) messages to bytelists ------------ */
+
+static t_class *fudiformat_class;
+
+typedef struct _fudiformat {
+  t_object  x_obj;
+  t_outlet *x_msgout;
+  t_atom   *x_atoms;
+  size_t    x_numatoms;
+  int       x_udp;
+} t_fudiformat;
+
+static void fudiformat_any(t_fudiformat *x, t_symbol*s, int argc, t_atom*argv) {
+  char *buf;
+  int length;
+  int i;
+  t_atom at;
+  t_binbuf*bbuf = binbuf_new();
+  SETSYMBOL(&at, s);
+  binbuf_add(bbuf, 1, &at);
+
+  binbuf_add(bbuf, argc, argv);
+
+  if(!x->x_udp) {
+    SETSEMI(&at);
+    binbuf_add(bbuf, 1, &at);
+  }
+  binbuf_gettext(bbuf, &buf, &length);
+  binbuf_free(bbuf);
+
+  if((size_t)length>x->x_numatoms) {
+    freebytes(x->x_atoms, sizeof(*x->x_atoms) * x->x_numatoms);
+    x->x_numatoms = length;
+    x->x_atoms = getbytes(sizeof(*x->x_atoms) * x->x_numatoms);
+  }
+
+  for(i=0; i<length; i++) {
+    SETFLOAT(x->x_atoms+i, buf[i]);
+  }
+  freebytes(buf, length);
+  outlet_list(x->x_msgout, 0, length, x->x_atoms);
+}
+
+static void fudiformat_free(t_fudiformat *x) {
+  freebytes(x->x_atoms, sizeof(*x->x_atoms) * x->x_numatoms);
+  x->x_atoms = NULL;
+  x->x_numatoms = 0;
+}
+
+static void *fudiformat_new(t_symbol*s) {
+  t_fudiformat *x = (t_fudiformat *)pd_new(fudiformat_class);
+  x->x_msgout = outlet_new(&x->x_obj, 0);
+  x->x_numatoms = 1024;
+  x->x_atoms = getbytes(sizeof(*x->x_atoms) * x->x_numatoms);
+  if (gensym("-u") == s)
+    x->x_udp = 1;
+  else if (gensym("-t") == s)
+    x->x_udp = 0;
+  else if (gensym("") != s) {
+    pd_error(x, "fudiformat: unsupported mode '%s'", s->s_name);
+  }
+
+  return (void *)x;
+}
+
+static void fudiformat_setup(void) {
+  fudiformat_class = class_new(gensym("fudiformat"),
+                               (t_newmethod)fudiformat_new,
+                               (t_method)fudiformat_free,
+                               sizeof(t_fudiformat), CLASS_DEFAULT,
+                               A_DEFSYMBOL, 0);
+  class_addanything(fudiformat_class, fudiformat_any);
+}
+
 void x_misc_setup(void)
 {
     random_setup();
@@ -805,4 +974,6 @@ void x_misc_setup(void)
     realtime_setup();
     oscparse_setup();
     oscformat_setup();
+    fudiparse_setup();
+    fudiformat_setup();
 }
diff --git a/pd/src/x_preset.c b/pd/src/x_preset.c
index d618696a8942e074c1a94002910bf5ebd3bf4a1f..e4224c43c40cfadfb1550cc6c1a311fcc8bdf41f 100644
--- a/pd/src/x_preset.c
+++ b/pd/src/x_preset.c
@@ -614,9 +614,9 @@ void preset_node_set_and_output_value(t_preset_node *x, t_alist val)
     if (val.l_n > 0)
     {
         alist_clear(&x->pn_val);
-        alist_clone(&val, &x->pn_val);
+        alist_clone(&val, &x->pn_val, 0, val.l_n);
         XL_ATOMS_ALLOCA(outv, x->pn_val.l_n);
-        alist_toatoms(&x->pn_val, outv);
+        alist_toatoms(&x->pn_val, outv, 0, x->pn_val.l_n);
         outlet_list(x->pn_outlet, &s_list, x->pn_val.l_n, outv);
         if(PH_DEBUG)
         {
@@ -1199,7 +1199,8 @@ void preset_hub_store(t_preset_hub *h, t_float f)
                             }
                         }
                         alist_clear(&np2->np_val);
-                        alist_clone(&hd1->phd_node->pn_val, &np2->np_val);
+                        alist_clone(&hd1->phd_node->pn_val, &np2->np_val,
+                            0, hd1->phd_node->pn_val.l_n);
                         if (PH_DEBUG)
                         {
                             fprintf(stderr,"    node data len = %d, "
diff --git a/pd/src/x_vexp.h b/pd/src/x_vexp.h
index 608a64a486f9c94eb934fd8ed54b256d509e540a..bc3b4204074e9f319dc087abcb62b67912ae3313 100644
--- a/pd/src/x_vexp.h
+++ b/pd/src/x_vexp.h
@@ -5,9 +5,9 @@
 /* "expr" was written by Shahrokh Yadegari c. 1989. -msp */
 /* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */
 
-#define MSP
-#ifdef PD
-#undef MSP
+#define PD 1
+#ifdef MSP
+#undef PD
 #endif
 
 #ifdef PD